;****************************************************************************
; Init
; Where the sound driver proper initializes everything.
;----------------------------------------------------------------------------
; notes: continues in IdleLoop
;****************************************************************************
Init:
call MutePsgOut ; Mute all PSG channels (they won't
; have been muted if we're booting
; from a soft reset)
xor a ; We don't know for sure which bank
ld (LastBank), a ; is set by default so pick one now
ld hl, BankPort ; instead and keep track of it
ld (hl), a
ld (hl), a
ld (hl), a
ld (hl), a
ld (hl), a
ld (hl), a
ld (hl), a
ld (hl), a
ld (hl), a
exx ; Set up alternate registers with
ld hl, YmAddr1 ; pointers to the YM2612 ports that
ld de, YmData1 ; UpdatePcm needs to access
exx
ld ix, YmAddr1
call InitFmReg ; Set up YM2612 registers
; fallthrough to IdleLoop...
;****************************************************************************
; IdleLoop
; Where the driver stays when there's nothing else to do until the next tick.
;****************************************************************************
IdleLoop:
PollPcm ; Check if PCM needs to be updated
call PollTimerB ; Poll for timer B
ld a, (CmdType) ; Did the 68000 send any command?
or a ; Time to process it if so
jr nz, ProcessCommand
PollPcm
ld a, (BgmTicksHi) ; Check if BGM ticks need to be
BgmTickCheck: equ $ ; processed
or a
call nz, UpdateBgm
SfxSubticks: equ $+1 ; Check if a whole tick has gone by
ld a, $00 ; for SFXs and process them if so
sub SFXTEMPO_DEFAULT ; (this will also update a few other
call nc, UpdateSfx ; things that happen regularly like
; updating PSG envelopes)
CpuMeterCount: equ $+1 ; Update the CPU meter counter
ld a, 0
inc a
ld (CpuMeterCount), a
jr IdleLoop ; Waitiiiing
;****************************************************************************
; ProcessCommand
; Processes a command received from the 68000.
;----------------------------------------------------------------------------
; input a ... command number
;----------------------------------------------------------------------------
; continues in the handler for the passed command (see jump table below
; for the list of every possible handler)
;****************************************************************************
ProcessCommand:
dec a ; Command $00 doesn't exist
ld b, a ; Each entry in the jump table is 3
add a, b ; bytes long and the command number
add a, b ; is not corrected so...
ld (ProcessCommandJump), a ; Overwrite the following jump and
ProcessCommandJump: equ $+1 ; execute it in order to go into the
jr $ ; relevant entry of the jump table
jp PlayPcmCmdCh1 ; CMD_PLAYPCM1
jp PlayPcmCmdCh2 ; CMD_PLAYPCM2
jp StopPcmCmdCh1 ; CMD_STOPPCM1
jp StopPcmCmdCh2 ; CMD_STOPPCM2
jp PlayBgmCmd ; CMD_PLAYBGM
jp PlaySfxCmd ; CMD_PLAYSFX
jp StopBgmCmd ; CMD_STOPALL
jp PauseSoundCmd ; CMD_PAUSE
jp UnpauseSoundCmd ; CMD_UNPAUSE
jp SetStereoModeCmd ; CMD_SETSTEREO
jp SetSsgEgModeCmd ; CMD_SETSSGEG
;****************************************************************************
; EndOfCommand
; Jump here when done processing a command. Pops out the command from the
; queue so the next one can proceed and frees up a slot as well.
;----------------------------------------------------------------------------
; continues in IdleLoop
;****************************************************************************
EndOfCommand:
ld a, 1 ; Tell 68000 to stay out of the way
ld (QueueMutex), a
PollPcm
ld hl, (QueueSlot2+0) ; Copy 2nd slot into 1st
ld (QueueSlot1+0), hl
ld hl, (QueueSlot2+2)
ld (QueueSlot1+2), hl
PollPcm
ld hl, (QueueSlot2+4)
ld (QueueSlot1+4), hl
ld hl, (QueueSlot2+6)
ld (QueueSlot1+6), hl
PollPcm
ld hl, (QueueSlot2+8)
ld (QueueSlot1+8), hl
ld hl, (QueueSlot2+10)
ld (QueueSlot1+10), hl
PollPcm
ld hl, (QueueSlot3+0) ; Copy 3rd slot into 2nd
ld (QueueSlot2+0), hl
ld hl, (QueueSlot3+2)
ld (QueueSlot2+2), hl
PollPcm
ld hl, (QueueSlot3+4)
ld (QueueSlot2+4), hl
ld hl, (QueueSlot3+6)
ld (QueueSlot2+6), hl
PollPcm
ld hl, (QueueSlot3+8)
ld (QueueSlot2+8), hl
ld hl, (QueueSlot3+10)
ld (QueueSlot2+10), hl
PollPcm
xor a ; Free up last slot and the mutex too
ld (QueueSlot3), a ; since we're done with the queue
ld (QueueMutex), a
jp IdleLoop ; Return to idle loop
;****************************************************************************
; PollTimerB
; Checks if timer B fired and acts accordingly.
;----------------------------------------------------------------------------
; breaks ... a,de
;****************************************************************************
PollTimerB:
ld a, (YmAddr1) ; Check if timer B fired yet
and $02 ; Do nothing if not
ret z
PollPcm
ld (ix+0), YMREG_MODE ; Acknowledge timer B
TimerBAck: equ $+3 ; Note that the YMREG_TIMERB will be
ld (ix+1), YMACK_TIMERB ; overwritten when ch3 mode changes
PollPcm
push hl ; Save register
BgmTicks: equ $+1 ; Update BGM subticks
BgmTicksLo: equ $+1
BgmTicksHi: equ $+2
ld hl, 0
BgmTempo: equ $+1
BgmTempoLo: equ $+1
BgmTempoHi: equ $+2
ld de, BGMTEMPO_DEFAULT
add hl, de
ld (BgmTicks), hl
ld hl, SfxSubticks ; Update SFX subticks
inc (hl)
pop hl ; Restore register
PollPcm
ret ; End of subroutine