mirror of https://github.com/wwarthen/RomWBW.git
1 changed files with 201 additions and 0 deletions
@ -0,0 +1,201 @@ |
|||||
|
;***************************************************************************** |
||||
|
;***************************************************************************** |
||||
|
;** ** |
||||
|
;** AY-3-8910 Sound Test Program ** |
||||
|
;** Author: Wayne Warthen -- 10/8/2017 ** |
||||
|
;** ** |
||||
|
;***************************************************************************** |
||||
|
;***************************************************************************** |
||||
|
; |
||||
|
;============================================================================= |
||||
|
; Constants Section |
||||
|
;============================================================================= |
||||
|
; |
||||
|
; Hardware port addresses |
||||
|
; |
||||
|
rsel .equ $9A ; Register seelection port address |
||||
|
rdat .equ $9B ; Register data port address |
||||
|
acr .equ $9C ; Aux control register port address |
||||
|
; |
||||
|
; CPU speed for delay scaling |
||||
|
; |
||||
|
cpuspd .equ 4 ; CPU speed in MHz |
||||
|
; |
||||
|
; BDOS invocation constants |
||||
|
; |
||||
|
bdos .equ $0005 ; BDOS invocation vector |
||||
|
print .equ 9 ; BDOS print function number |
||||
|
conwrt .equ 2 ; BDOS console write char |
||||
|
; |
||||
|
;============================================================================= |
||||
|
; Code Section |
||||
|
;============================================================================= |
||||
|
; |
||||
|
.org $100 |
||||
|
; |
||||
|
ld (stksav),sp ; save incoming stack frame |
||||
|
ld sp,stack ; setup our private stack |
||||
|
; |
||||
|
ld de,banner ; load banner string address |
||||
|
ld c,print ; BDOS print function number |
||||
|
call bdos ; do it |
||||
|
; |
||||
|
ld a,$FF ; SCG board activation value |
||||
|
out (acr),a ; write value to ACR |
||||
|
; |
||||
|
xor a ; zero accum |
||||
|
ld (chan),a ; init channel number |
||||
|
; |
||||
|
chloop: |
||||
|
; Test each channel |
||||
|
call tstchan ; test the current channel |
||||
|
ld hl,chan ; point to channel number |
||||
|
ld a,(chan) ; get current channel |
||||
|
inc a ; bump to next |
||||
|
ld (chan),a ; save it |
||||
|
cp 3 ; end of channels? |
||||
|
jr nz,chloop ; loop if not done |
||||
|
; |
||||
|
ld de,crlf ; newline |
||||
|
ld c,print ; BDOS print function |
||||
|
call bdos ; do it |
||||
|
; |
||||
|
ld sp,(stksav) ; restore stack |
||||
|
; |
||||
|
ret ; end of program |
||||
|
; |
||||
|
tstchan: |
||||
|
; Display channel being tested |
||||
|
ld de,chmsg ; point to channel message |
||||
|
ld c,print ; BDOS print function number |
||||
|
call bdos ; do it |
||||
|
ld a,(chan) ; get current channel number |
||||
|
add a,'A' ; offset to print as alpha |
||||
|
ld e,a ; put in E |
||||
|
ld c,conwrt ; BDOS console out function number |
||||
|
call bdos ; do it |
||||
|
ld de,chmsg2 ; point to channel message |
||||
|
ld c,print ; BDOS print function number |
||||
|
call bdos ; do it |
||||
|
; |
||||
|
ld hl,0 ; initial pitch value |
||||
|
ld (pitch),hl ; save it |
||||
|
; |
||||
|
; Setup mixer register |
||||
|
ld a,(chan) ; get channel num (0-2) |
||||
|
inc a ; adjust index (1-3) |
||||
|
ld b,a ; and use as loop counter |
||||
|
xor a ; clear accum |
||||
|
scf ; set carry |
||||
|
mixloop: |
||||
|
rla ; rotate bit |
||||
|
djnz mixloop ; loop based on channel num |
||||
|
cpl ; invert bits |
||||
|
and $FF ; so only target bit is cleared |
||||
|
push af ; save value |
||||
|
ld a,7 ; mixer register |
||||
|
out (rsel),a ; select it |
||||
|
pop af ; recover value |
||||
|
out (rdat),a ; and set register value |
||||
|
; |
||||
|
; Set channel volume to max |
||||
|
ld a,(chan) ; get channel |
||||
|
add a,8 ; adjust for start of vol regs |
||||
|
out (rsel),a ; select register |
||||
|
ld a,$0F ; max volume |
||||
|
out (rdat),a ; write it |
||||
|
; |
||||
|
pitloop: |
||||
|
; Pitch loop |
||||
|
ld a,(chan) ; get channel |
||||
|
sla a ; A := channel pitch reg, 2 bytes per chan |
||||
|
out (rsel),a ; select low byte register |
||||
|
push af ; save register |
||||
|
ld a,l ; get low byte of pitch value |
||||
|
out (rdat),a ; and write it to register |
||||
|
pop af ; recover register index |
||||
|
inc a ; inc to high byte pitch register |
||||
|
out (rsel),a ; select high byte register |
||||
|
ld a,h ; get high byte of pitch value |
||||
|
out (rdat),a ; and write it to register |
||||
|
; |
||||
|
; Delay |
||||
|
ld b,cpuspd ; cpu speed scalar |
||||
|
dlyloop: |
||||
|
call dly64 ; arbitrary delay |
||||
|
djnz dlyloop ; loop based on cpu speed |
||||
|
; |
||||
|
; Next pitch value |
||||
|
ld hl,(pitch) ; get current pitch |
||||
|
inc hl ; increment |
||||
|
ld (pitch),hl ; save new value |
||||
|
ld a,h ; get high byte |
||||
|
;cp 16 ; end of max range? |
||||
|
cp 4 ; end of max range? |
||||
|
jr nz,pitloop ; loop till done |
||||
|
; |
||||
|
; Clean up |
||||
|
call clrpsg ; shut down psg |
||||
|
; |
||||
|
ret ; done |
||||
|
; |
||||
|
; Clear PSG registers to default |
||||
|
; |
||||
|
clrpsg: |
||||
|
ld b,16 ; loop for 18 registers |
||||
|
ld c,0 ; init register index |
||||
|
clrpsg1: |
||||
|
ld a,c ; register num to accum |
||||
|
out (rsel),a ; select it |
||||
|
xor a ; clear accum |
||||
|
out (rdat),a ; and write to register |
||||
|
inc c ; next register |
||||
|
djnz clrpsg1 ; loop through all registers |
||||
|
ret ; return |
||||
|
; |
||||
|
; Program PSG registers from list at HL |
||||
|
; |
||||
|
setpsg: |
||||
|
ld a,(hl) ; get psg reg number |
||||
|
inc hl ; bump index |
||||
|
cp $FF ; check for end |
||||
|
ret z ; return if end marker $FF |
||||
|
out (rsel),a ; select psg register |
||||
|
ld a,(hl) ; get register value |
||||
|
inc hl ; bump index |
||||
|
out (rdat),a ; set register value |
||||
|
jr setpsg ; loop till done |
||||
|
; |
||||
|
; Short delay functions. No clock speed compensation, so they |
||||
|
; will run longer on slower systems. The number indicates the |
||||
|
; number of call/ret invocations. A single call/ret is |
||||
|
; 27 t-states on a z80, 25 t-states on a z180 |
||||
|
; |
||||
|
dly256: call dly128 |
||||
|
dly128: call dly64 |
||||
|
dly64: call dly32 |
||||
|
dly32: call dly16 |
||||
|
dly16: call dly8 |
||||
|
dly8: call dly4 |
||||
|
dly4: call dly2 |
||||
|
dly2: call dly1 |
||||
|
dly1: ret |
||||
|
; |
||||
|
;============================================================================= |
||||
|
; Data Section |
||||
|
;============================================================================= |
||||
|
; |
||||
|
chan .db 0 ; active audio channel |
||||
|
pitch .dw 0 ; current pitch |
||||
|
; |
||||
|
banner .text "\r\nRetroBrew Computers SCG AY-3-8910 Sound Test\r\n" |
||||
|
.text "Set SCG board base I/O address to 0x98\r\n$" |
||||
|
chmsg .text "\r\nPlaying descending tones on channel $" |
||||
|
chmsg2 .text "...$" |
||||
|
crlf .text "\r\n$" |
||||
|
; |
||||
|
stksav .dw 0 ; saved stack frame |
||||
|
.fill 80,$FF ; 40 level private stack |
||||
|
stack .equ $ ; start of stack |
||||
|
; |
||||
|
.end |
||||
Loading…
Reference in new issue