Transferring Data from ROM to the SNES APU The method of transferring data to the sound module of the SNES is a bit screwy, but it works. I've read many docs, looked at a lot of code, and nothing I've seen seems to explain the method to this madness in a straightforward way. I'm hoping I can shed some light on the matter.
During the transfer process, the following ports apply:
$2140 = Status
$2141 = Command / Data
$2142-3 = Address
Initializing the Transfer
- Wait for port
$2140to be$AAand port$2141to be$BB. (This means the ROM program is through initializing, and is ready to begin a transfer.) - Write any value other than 0 to
$2141. (A value of 0 has a different meaning which will be explained later.) - Write the destination address of the transfer to ports
$2142and$2143, with the low byte written to$2142. - Write
$CCto port$2140. - Wait for
$2140to be$CC.
Transferring Data
- Write the first byte to be transferred to port
$2141. - Write
$00to port$2140. - Wait for
$2140to be$00. - Write the next byte to be transferred to port
$2141. - Increase the value in
$2140by 1, and write it back. - Wait for
$2140to be the same as the value written. - Goto step 4 until all bytes are transferred.
Beginning Another Transfer
- Write a non-zero value to port
$2141. - Write the destination address of the transfer to ports
$2142and$2143, with the low byte written to$2142. - Increase the value in
$2140by 2. If it's 0, increase it again. Write it back. - Wait for
$2140to be the same as the value written, then go to the section "Transferring Data".
Ending Transfers
- Write 0 to port
$2141. - Write the address to begin execution to ports
$2142and$2143, with the low byte written to$2142. - Increase the value in
$2140by 2, and write it back.
Summary
Between transfers, a non-zero value sent to $2141 means to begin a transfer, and a zero value means to end a transfer and begin execution.
16-bit addresses are written to $2142-3.
During transfers, in $2140 a value less than means the APU is busy, a value equal means it's ready for the next byte. Writing a value one greater means the next byte ($2141) is ready to be stored. Writing a value two or more greater means to end the transfer and apply the command in $2141. (Because of the internal workings of the ROM program, the value in $2140 must be non-zero if the command is to start another transfer.)
Example
; Wait for SPC700 to initialize
REP #$30 ; (16-bit A and X Y)
LDA #$BBAA
Init: CMP $2140
BNE Init
; Initialize transfer ---------
LDA #SPCExec ; Send starting address
STA $2142
LDA #$1CC
STA $2140 ; Write $CC to 2140 and !0 to 2141
SEP #$20 ; (8-bit A)
Start: CMP $2140 ; Wait for SPC700 to give the go
BNE Start
; Send data -------------------
LDX #0 ; X indexes the current byte being sent
LDY #SPCSize ; Y = Number of bytes that need to be sent
Next: LDA SPCData,X ; Send byte
STA $2141
TXA
STA $2140
Wait: CMP $2140 ; Wait for transfer
BNE Wait
INX
DEY
BNE Next
; Begin execution -------------
REP #$20 ; (16-bit A)
LDA #SPCExec ; Starting address of execution
STA $2142
SEP #$20 ; (8-bit A)
LDA #0 ; JMP to execution address
STA $2141
LDA $2140 ; Break transfer cycle
ADC #2
STA $2140
Copyright ©2000 Alpha-II Productions