# Super NES Programming/Loading SPC700 programs

In this tutorial, we will create a ROM that initializes the SPC700 to play a song captured from another SNES game.

# Introduction

To produce a sound on the SNES, the registers of the DSP need to be set to appropriate values. This means that to play a song on the SNES, you need a program for the SPC700 that manipulates the DSP, and you need code for the 65816 that transfers the SPC700 program to the SPC700. Fortunately, there are thousands of programs for the SPC700 freely available online in the form of SPC files, solving half our problem.

# SPC files

SPC files contain the state of the SPC700, typically at the very beginning of a song in an SNES game. By restoring the state in an SPC700 and DSP emulator -- a.k.a. an SPC player -- you can listen to the song without the SNES ROM. We can likewise use SPC files to restore the SPC state inside of the SNES to play the song. You can get SPC files either by capturing them yourself using an SNES ROM and emulator or by downloading one of the thousands online at SNESMusic.org.

# Extracting SPC700 state from an SPC file

The SPC700 file contains the SPC hardware state as well as a variety of additional information, such as title, game name, author, capturer, etc. An in-depth description of the format can be found at SNESMusic.org, but the relevant fields for our purposes are:
| Offset | Size | Description |
| 00025h | 2 bytes | Program counter (PC) register |
| 00027h | 1 byte | A register |
| 00028h | 1 byte | X register |
| 00029h | 1 byte | Y register |
| 0002ah | 1 byte | Program status word (PSW) register |
| 0002bh | 1 byte | Stack pointer (SP) register |
| 00100h | 10000h bytes | 64k RAM |
| 10100h | 128 bytes | The contents of the 128 DSP registers |
We need to get this data from inside an SPC file and put it into our ROM. You could write a script to extract this data from the SPC file and turn it into a text file of assembly data directives, and .include in your assembly file. However, the .incbin directive in the WLA assembler makes this process much simpler, since it allows us to include pieces of binary files directly into our ROM. Here is how we include the above data:
Notice that we have not included the SPC RAM data in the data definitions above. Because the SPC RAM data (64k) is larger than the SNES's ROM bank size (32k), we need to break it in half and store it in two banks of its own, separate from the rest of our code and data:

# The Main Program

We use most of the code from the SNES Initialization Tutorial for our main program:
We have added a line to call a subroutine to load the SPC data, just before the graphics code from the initialization tutorial. The advantage of including this graphics code is that it does something on the screen after the music loads. Thus, when we execute the ROM, it tells us visually either that the music was loaded successfully or that execution halted somewhere in the music code.

# Uploading the SPC700 state

The SNES and the SPC700 communicate via four byte-wide channels, which we will call Audio0, Audio1, Audio2, and Audio3. On the SNES side, these are represented by the memory-mapped registers $2140-$2143, while the SPC represents them as $00f4-$00f7. Although there are four channels, there are actually eight values being stored behind the scenes -- four bytes for the channels from the SNES to the SPC and four bytes for the channels from the SPC to the SNES. For example, when the SNES writes a value to its Audio0, it is saved in one location so the SPC can read it from its Audio0. Likewise, when the SPC writes a value to its Audio0, it is saved in another location so the SNES can read it from its Audio0. Thus the value that is read from a channel's memory-mapped register may not be the value that was last written there.

## The SPC's communication routine

When the SNES is reset, the SPC maps a 64-byte chunk of ROM -- called the "IPL ROM" -- to locations $ffc0-$ffff and executes it. While it's mapped there, reads come from this ROM rather than normal RAM. It performs the necessary initialization of the SPC:
* Set the stack pointer to $01ef.
* Zero memory locations $0000-$00ef.
* Wait for data from the SNES.
The IPL ROM routine is capable of copying blocks of data from the SNES into SPC memory and then starting execution at a given location. The documents of the SNES Devkit at SNES Central are somewhat confusing regarding the exact communication protocol of the SPC. You can view the routine by disassembling the IPL ROM bytecode included in the source code of SNES or SPC emulators or in SPC files themselves. Here, however, is a summary of the algorithm the SPC uses:
* Initialization:
** Set AudioOut0 to $aa and AudioOut1 to $bb.
** Wait until AudioIn0 is $cc.
* Prepare to copy a block:
** Read the 16-bit destination address from AudioIn2 (low byte) and AudioIn3 (high byte).
** Copy AudioIn0 to AudioOut0.
** If AudioIn1 is zero, start execution at the destination address.
* Copy a block:
** Wait until AudioIn0 is zero.
** Set a byte-sized counter to zero.
* Copy a byte:
** Wait while the counter is greater than AudioIn0.
** If the counter equals AudioIn0:
*** Copy a byte from AudioIn1 to the memory location.
*** Increment the counter and the memory location.
*** Go to Step 4.
** Otherwise (when the counter is less than AudioIn0), go to Step 2.
A particularly astute and/or paranoid programmer will observe that when the SPC's byte-sized counter rolls over (increments from $ff to $00), it becomes less than the value in AudioIn0, which may cause an error: Unless the SNES updates AudioIn0 in time, the SPC routine may think the block has ended, while the SNES is still sending data. When this happens, the SNES and SPC may end up waiting for each other in different parts of the protocol, freezing the system (this may be incorrect -- see note on discussion page).
To prevent a lockup, then, the SNES must update Audio0 as fast as possible. This means pre-copying the data to the fastest memory available and disabling interrupts whenever using the IPL ROM's protocol. Alternatively, you could restrict yourself to copying blocks of less than 255 bytes so that the counter never rolls over, or you could install a better communications routine in SPC RAM and use that instead.

## The SNES's communication routine

Now that we have examined the protocol from the SPC's side, we need an SNES routine to interface with it. First, we will examine a routine similar to the one used in open-source demos (and, presumably, actual SNES games). Then, we will make a slight modification to it that simplifies our code.
Here is the general algorithm used in open-source demos:
* Wait until Audio0 is $aa, signifying that the SPC has completed its initialization.
* Initialize a byte-wide counter to $cc.
* If there are no more blocks to send:
** Send the 16-bit execution address to Audio2 and Audio3.
** Send $00 to Audio1.
** Send the counter to Audio0.
** Wait until the counter value is echoed on Audio0.
** End routine.
* Otherwise:
** Send the 16-bit destination address to Audio2 and Audio3.
** Send $01 to Audio1.
** Send the counter to Audio0.
** Wait until the counter value is echoed on Audio0.
** Reset the counter to zero.
* If there are bytes left in the current block:
** Send the current byte to Audio1.
** Send the counter to Audio0.
** Wait until the counter value is echoed on Audio0.
** Move on to the next byte.
** Increment the counter.
** Go to step 5.
* Otherwise:
** Add $03 to the counter. If the counter is now zero, add $03 again.
** Move on to the next block.
** Go to step 3.
(Note: there's nothing magical about the value $03. We can add almost any value to the counter -- the important thing is that the counter value the SNES sends needs to be greater than the value the SPC expects it to be, which is how the SPC knows the block has ended.)
This routine sends all the blocks at once. It would be nice, however, if we had a routine that just copied one block so that we could do other things between transferring blocks. If we tried to modify the above routine to do this, though, we would either need to know the address of the next block ahead of time or we would need to save the terminating byte of the previous block and send it with the next one. A simple solution to this problem is to send exactly one block, then give the start of the communications routine ($ffc9) as the address at which to begin execution. This resets the protocol state, so that we do not need to store any information between sending blocks.

### The communications routine in assembly

This section describes in detail our assembly routine to copy a block of memory from SNES RAM to SPC RAM.
First, we need to consider the parameters to our routine. We will need to pass the source location, the destination location, and the length of the block to copy. Since there is 64k of SPC RAM, the destination and length will fit in 16-bit variables, so we can pass those in the X and Y registers. The source memory location, on the other hand, is 24 bits long, since we will be reading from the expanded RAM block from $7f:0000-$7f:ffff. Thus, we define a location in the zero page where we can store the three bytes of a pointer to our source data:
While we are at it, we can define the values of the audio ports and CPU flags, so that our code uses recognizable identifiers instead of hex values:
While writing the routine, we frequently will be waiting for the SPC to echo back the value we just sent to the Audio0 register. Rather than write this code repeatedly, we can put it in a macro, and the assembler will make the necessary substitutions:
With these initial definitions out of the way, we can write our routine. Here is the initialization phase, which waits until the SPC is ready to accept data, then sends the destination address. Note that we can send the two bytes of the destination address with a single 16-bit write to Audio2.
Here is the communication routine's main loop, which sends a byte and waits for the SPC's response, then updates the memory and counter values. Note that we can swap the high and low bytes of a with the xba operation, even though a is in 8-bit mode at the time. Again, we use the trick of writing a 16-bit value to send to Audio0 and Audio1 in a single operation.
Finally, we end the block and tell the SPC to start execution at the beginning of the SPC's communication routine, resetting the protocol:

## Sending the SPC state

The SPC state consists of three parts:
* The memory
* The DSP registers
* The CPU registers
The hardest thing to restore is the CPU state, since it changes just by executing the SPC communications routine. Also, restoring the program counter means that the SPC then will be executing the stored code, not the communications routine, so we can't send anything else after we have restored the program counter. Thus, we need to restore the CPU state last, after we have set up everything else. Whether we restore the memory or DSP registers first doesn't matter too much, but it will turn out to be convenient to restore the memory first.

### Sending memory state

Earlier we noticed that the SPC communications routine could freeze if the SNES doesn't send data fast enough. This means that any data we send needs to be stored in RAM; it can't be directly copied to the SPC from its original location in ROM. Thus, we use the following routine to assemble the two 32k banks of ROM containing the SPC memory state into one 64k segment in SNES RAM:
Now, we can use the macro we wrote earlier to transfer the SPC memory state:
We do not transfer the first two and last sixty-four bytes of memory because they are used by the communications routine: the last sixty-four bytes contain the routine itself and the first two bytes are used during the routine to store the destination address.
Most SPCs will not overwrite the communications routine, so we will simply not restore that section of memory. It is quite possible, on the other hand, that an SPC will use the first two bytes of RAM, since they are in the zero page and easy to access. Therefore, we will set those bytes when we restore the CPU state, taking care not to overwrite them in the SNES RAM until then.
Note that because we are overwriting the block $f0-$ff, we actually write to a number of memory-mapped registers. This has the effect of restoring the timer state, as well as one DSP register. It also manipulates the Audio0-3 ports, but this doesn't seem to interfere with the memory transfer process, probably because the SNES is only listening for a certain value on Audio0.

### Sending DSP state

To set the value of a DSP register, you first need to write its number to address $f2 of the SPC's memory, then you need to write its value to address $f3 of the SPC's memory. Because these addresses are right next to each other, we can restore a DSP register value by using our memory-copying routine to send a block of two bytes to $f2. We repeat this process for each of the 128 DSP registers:

### Sending SPC initialization routine

Our SPC initialization routine restores the parts of the SPC state that would be altered just by running the SPC's communications routine. We will pass the SPC's control to the initialization routine after we are done copying everything, and the routine, as its final step, will jump to the saved program counter location. Here are the things our initialization routine needs to do:
* Restore the first two bytes of RAM.
* Restore the stack pointer (S).
* Push the restored PSW register onto the stack.
* Restore the A register.
* Restore the X register.
* Restore the Y register.
* Pop the PSW register value into its register.
* Jump to the saved program counter location.
We'll write the routine starting at (arbitrary) memory location $7f0000. Since we'll be needing the first two bytes at that location (that we have been careful thus far not to overwrite), we will first save these on the stack. Since we'll restore the first byte first, we push it last:
Next, we write the code to restore the first byte. Looking up the mov dp,#imm opcode in an SPC reference, we see that the opcode byte is $8f, so we write that, followed immediately by the first argument byte (imm -- the value to restore), then the second argument byte (dp -- the address to which to write the byte):
We do the same thing for the second memory byte:
As there is no opcode to write a value to S directly, we first move the stack value into X -- mov x, #imm ($cd) -- then we move X into the stack register -- mov sp, x ($bd).
Now we write code to push the program status ward (PSW) register value onto the stack, so that we can pop it later. We need to push the value before we restore the other registers because we overwrite X in the process of pushing the value. We can't pop the value until after the other registers are restored, since the mov instruction that we use to restore them changes the PSW register.
Here we write the code to restore the registers:
Writing the code to restore PSW from the stack is fairly straightforward:
Finally, we write the code to send control to the saved program counter position:
After this routine is called, then, the region $7f0000-$7f0015 contains the initialization routine, so sending it using our communications routine is fairly straightforward. We must, however, have somewhere in the SPC RAM to put it. Here, we gamble that the region of memory just before the IPL ROM code is not in use:
Calling the routine:

# Starting SPC execution

Now that we have restored the memory and DSP state, and we have written an initialization routine to complete restoration, all we need to do is to tell the SPC to begin execution at our initialization routine. We do this by modifying our communications routine to send no blocks, but rather immediately start execution at the given address:
At this point, the SPC should start playing the music originally stored in the SPC file.

# Analysis

This technique is really only good for playing one song on a ROM; after you start playing an SPC file, it is hard to stop it, upload another song, or play a sound effect. This is because the code in the SPC only understands the communications protocol of the game from which it is captured. To discover the protocol, you would have to reverse-engineer the code of either the SPC state or the original SNES ROM, and even then there is no guarantee that the protocol would support whatever you wanted to do. Writing a custom protocol for the audio in a game would be a good subject for a future tutorial.

## Problems

There are a number of reasons why the SPC state, restored in the manner described here, would refuse to play:
* The original SPC program used either the IPL ROM area or the area where we stored our initialization code. If it used the initialization area, we can write the code to another location, and this should allow the SPC to play. Restoring the IPL ROM region is harder because you need a communications routine somewhere else in SPC memory to allow you to do this. In either case, we can't get away from the fact that some space in RAM is needed for initialization and will not match the original RAM.
* The state of the SPC when control is passed to the original code does not exactly match the state when it was captured, since the DSP and timers begin updating their values immediately upon restoration. If the SPC was waiting for some state change, like a timer or DSP value, then it may miss it and lock up.
* It is possible for the SNES to play music entirely by sending values to the SPC in real-time. For instance, it could modify the DSP registers as we did when we were restoring them, except it would modify them over time so as to produce music, much as other SPC code would. In this way, the SPC could produce music with the IPL ROM communications routine as the only code in its memory. Such SPC files would not even play in a player, since they rely on the SNES for information.