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

  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

        ; 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