Sona 0.50 Source

Sona 0.50/src-z80/main.z80

;****************************************************************************
; 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