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
1. |
Wait for port $2140 to be $AA and port $2141 to be $BB. (This means the ROM
program is through initializing, and is ready to begin a transfer.) |
2. |
Write any value other than 0 to $2141. (A value of 0 has a different meaning which
will be explained later.) |
3. |
Write the destination address of the transfer to ports $2142 and $2143, with the low
byte written to $2142. |
4. |
Write $CC to port $2140. |
5. |
Wait for $2140 to be $CC. |
Transferring data
1. |
Write the first byte to be transferred to port $2141. |
2. |
Write $00 to port $2140. |
3. |
Wait for $2140 to be $00. |
4. |
Write the next byte to be transferred to port $2141. |
5. |
Increase the value in $2140 by 1, and write it back. |
6. |
Wait for $2140 to be the same as the value written. |
7. |
Goto step 4 until all bytes are transferred |
Beginning another transfer
1. |
Write a non-zero value to port $2141. |
2. |
Write the destination address of the transfer to ports $2142 and $2143, with the low
byte written to $2142. |
3. |
Increase the value in $2140 by 2. If it's 0, increase it again. Write it back. |
4. |
Wait for $2140 to be the same as the value written, then go to the section "Transferring
data". |
Ending transfers
1. |
Write 0 to port $2141. |
2. |
Write the address to begin execution to ports $2142 and $2143, with the low byte
written to $2142. |
3. |
Increase the value in $2140 by 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
Init: Start: Next: Wait: |
;Wait for SPC700 to initialize -- ReP #$30 LdA #$BBAA Cmp $2140 BNE Init ;Initialize transfer ------------ LdA #SPCExec StA $2142 LdA #$1CC StA $2140 SeP #$20 Cmp $2140 BNE Start ;Send data ---------------------- LdX #0 LdY #SPCSize LdA SPCData,X StA $2141 TXA StA $2140 Cmp $2140 BNE Wait InX DeY BNE Next ;Begin execution ---------------- ReP #$20 LdA #SPCExec StA $2142 SeP #$20 LdA #0 StA $2141 LdA $2140 AdC #2 StA $2140 |
;(16-bit A and X Y) ;Send starting address ;Write $CC to 2140 and !0 to 2141 ;(8-bit A) ;Wait for SPC700 to give the go ;X indexes the current byte being sent ;Y = Number of bytes that need to be sent ;Send byte ;Wait for transfer ;(16-bit A) ;Starting address of execution ;(8-bit A) ;Jmp to execution address ;Break transfer cycle |
Copyright ©2000 Alpha-II Productions