Sona 0.50 Source

Sona 0.50/src-z80/memory_read.z80

;****************************************************************************
; ReadByteFrom68k
; Fetches a byte from 68000 address space. SLOW!!
;----------------------------------------------------------------------------
; input c ..... current bank
; input hl .... current address
;----------------------------------------------------------------------------
; output b .... byte fetched
; output c .... new bank
; output hl ... new address
;----------------------------------------------------------------------------
; modifies .... a,bc,hl
;****************************************************************************

ReadByteFrom68k:
    ld      a, c                        ; Check if the bank has changed since
LastBank: equ $+1                       ; bank switching is slow and needs to
    cp      $FF                         ; be avoided wherever possible (also
    jp      z, NoBankSwitch             ; yes, the last bank accessed is kept
    ld      (LastBank), a               ; in that instruction...)
    
    push    hl                          ; Save the address for later since
                                        ; we need to overwrite HL for this
    
    ld      hl, BankPort                ; Switch the bank
    ld      (hl), a                     ; This involves writing the new bank
    rrca                                ; bit by bit (because it's a serial
    ld      (hl), a                     ; register) which is why it's so slow
    rrca                                ;
    ld      (hl), a                     ; We use only bits 6-0 (enough to
    rrca                                ; address 4MB of cartridge space),
    ld      (hl), a                     ; the remaining two bits are always 0
    rrca                                ; (a range of $000000..$3FFFFF)
    ld      (hl), a
    rrca
    ld      (hl), a
    rrca
    ld      (hl), a
    ld      (hl), h
    ld      (hl), h
    
    pop     hl                          ; Restore address
    
NoBankSwitch:
    ld      b, (hl)                     ; Read byte from 68000 space
    
    inc     l                           ; Increment the address
    ret     nz                          ; This may look unoptimal, but 99.6%
    inc     h                           ; of the time the first RET will
    ret     nz                          ; return, so this is actually the
    ld      h, $80                      ; most optimal way in practice.
    inc     c
    ret

;****************************************************************************
; ReadByteFromVar
; Fetches a byte from a VM variable.
;----------------------------------------------------------------------------
; output b .... byte fetched
;----------------------------------------------------------------------------
; modifies .... a,b
;****************************************************************************

ReadByteFromVar:
    push    hl                          ; Save HL
    
ReadByteFromVarId: equ $+1
    ld      hl, VmVarList               ; Read variable into B (where
    ld      b, (hl)                     ; ReadArgByte stores its result)
    
    inc     l                           ; Increment pointer, in case this
    ld      a, l                        ; opcode has multibyte operands
    and     $7F
    ld      (ReadByteFromVarId), a
    
    pop     hl                          ; Restore HL
    ret                                 ; End of subroutine

;****************************************************************************
; ReadInstrumentId
;
; Fetches an instrument ID argument. This is like the ReadByte macro, but
; sound effects need an offset applied since their instrument lists don't
; start at 0, and it can't be prebaked as the same sound effect may play
; from different streams.
;----------------------------------------------------------------------------
; input c ..... current bank
; input hl .... current address
;----------------------------------------------------------------------------
; output b .... instrument ID
; output c .... new bank
; output hl ... new address
;----------------------------------------------------------------------------
; modifies .... a,bc,hl
;****************************************************************************

ReadInstrumentId:
    ReadArgByte                         ; Read byte as usual
    
    ld      a, (StreamNum)              ; Check if it's a BGM or SFX stream
    sub     FIRST_SFXSTREAM             ; If it's BGM then the value is the
    ret     c                           ; instrument ID as-is
    
    rrca                                ; Use the SFX stream to determine
    rrca                                ; the base instrument ID and add
    rrca                                ; it to the value we've read to get
    add     $A0                         ; the real instrument ID to use
    add     a, b
    ld      b, a
    
    PollPcm
    
    ret                                 ; End of subroutine

;****************************************************************************
; ReadAddressArg
;
; Reads an address argument for an event. The address is three bytes long
; (little endian) and offset from the beginning of the sound data (NOTE:
; currently only works as intended for BGM!!).
;----------------------------------------------------------------------------
; input c ..... current bank
; input hl .... current address
;----------------------------------------------------------------------------
; output a .... argument bank
; output de ... argument address
; output c .... new bank
; output hl ... new address
;----------------------------------------------------------------------------
; modifies .... a,bc,de,hl (not a')
;----------------------------------------------------------------------------
; NOTE: currently only works as intended for BGM!!
; TO-DO: make it work correctly for SFX streams too
;****************************************************************************

ReadAddressArg:
    ReadArgByte                         ; Get address of the substream
    ld      e, b                        ; relative to the beginning of
    ReadArgByte                         ; the stream
    ld      d, b
    ReadArgByte
    ld      a, b
    
    push    bc                          ; Save current stream address so
    push    hl                          ; we can return back to it later
    
BgmStartAddr: equ $+1                   ; Get where the stream data began
BgmStartAddrLo: equ $+1                 ; in the ROM (this is rewritten by
BgmStartAddrHi: equ $+2                 ; PlayBgmCmd) and compute the real
    ld      hl, $0000                   ; address of the substream to play
BgmStartBank: equ $+1
    ld      c, $00
    
    add     hl, hl                      ; Convert from bank+address format
    srl     c                           ; to a linear address so we can do
    rr      h                           ; math on it easily
    rr      l
    
    add     hl, de                      ; Add both 24-bit values
    adc     a, c
    
    add     hl, hl                      ; Convert linear address back to
    rla                                 ; bank+address format
    scf
    rr      h
    rr      l
    
    ex      de, hl                      ; Put address part where it belongs
                                        ; (bank is already in A)
    
    pop     hl                          ; Restore current stream address
    pop     bc
    
    ret                                 ; End of subroutine