SPU Registers
I/O registers of the Sound Processing Unit at 1F801C00h to 1F801FFFh.
Summary
The SPU is controlled through 16-bit registers at 1F801C00h to 1F801FFFh. Sony did not publish register-level SPU documentation, so the register names on this page are the ones psx-spx uses.1 The older psx-spx by Martin Korth calls ATTR "SPUCNT" and STATX "SPUSTAT", and both names are common in other documents.2 The register areas are as follows:
| Address | Contents |
|---|---|
| 1F801C00h to 1F801D7Fh | Voice 0 to 23 registers, eight 16-bit registers per voice |
| 1F801D80h to 1F801D87h | Main volume and reverb output volume |
| 1F801D88h to 1F801D9Fh | Voice flags, one bit per voice |
| 1F801DA2h to 1F801DBFh | Memory, control, status and input volume |
| 1F801DC0h to 1F801DFFh | Reverb configuration |
| 1F801E00h to 1F801E5Fh | Current voice volumes |
| 1F801E60h to 1F801E7Fh | Unknown |
| 1F801E80h to 1F801FFFh | Unused |
Bus Access
The SPU sits on a 16-bit data bus. Reads of 8, 16 and 32 bits work, and 16-bit writes work. 32-bit writes are supported but occasionally lost, so a 32-bit value is best written as two 16-bit halves. 8-bit writes are not implemented: a byte write to an odd address is ignored, and a byte write to an even address is performed as a 16-bit write of the low half of the register.3
The SPU processes written values at its 44.1 kHz rate. A new value therefore takes up to 1/44100 second (300h CPU cycles) to take effect.3 Sony states the same limit for libspu: at least 1/44100 second of SPU processing must pass between two calls that set the same function.4
Voice Registers
Each voice N has the eight registers below at 1F801C00h + N x 10h.
| Address | Name | Contents | Page |
|---|---|---|---|
| 1F801C00h + N x 10h | VOLL | Voice volume left | ADSR and Volume |
| 1F801C02h + N x 10h | VOLR | Voice volume right | ADSR and Volume |
| 1F801C04h + N x 10h | PITCH | ADPCM sample rate | this page |
| 1F801C06h + N x 10h | SSA | Sample start address | this page |
| 1F801C08h + N x 10h | ADSR1 | Envelope, low half | ADSR and Volume |
| 1F801C0Ah + N x 10h | ADSR2 | Envelope, high half | ADSR and Volume |
| 1F801C0Ch + N x 10h | ENVX | Current envelope volume | ADSR and Volume |
| 1F801C0Eh + N x 10h | LSAX | Loop start address | this page |
PITCH
PITCH sets the ADPCM sample rate of the voice. The value 1000h is 44100 Hz.5
| Bits | Contents |
|---|---|
| 0 to 15 | Sample rate. 0 stops the voice. 4000h is the fastest rate. 4001h to FFFFh act as 4000h. |
Sony's libspu takes pitch values from 0000h to 3FFFh. The relation between the value set and the interval of the original sample is shown below.6
| Value Set | 0200h | 0400h | 0800h | 1000h | 2000h | 3FFFh |
|---|---|---|---|---|---|---|
| Interval | -3 oct. | -2 oct. | -1 oct. | tone | +1 oct. | +2 oct. |
The pitch for a VAG sample follows from the sampling frequency in its header: pitch = (sampling frequency << 12) / 44100. A 44.1 kHz sample therefore plays at 1000h and a 22.05 kHz sample at 800h.4
The pitch counter of each voice advances by PITCH once per 44.1 kHz cycle. Bits 12 and up of the counter select the sample within the ADPCM block, and bits 4 to 11 are the index into the Gaussian interpolation table. A step above 3FFFh is clipped to 4000h, so the highest rate is 176.4 kHz. However, the mixer outputs only 44.1 kHz, and any rate above that makes the hardware skip samples. PITCH has no effect on noise, whose rate is set in ATTR for all voices at once.5
SSA
SSA holds the start address of the sample in the sound buffer in 8-byte units. Key On copies SSA to the internal current address of the voice, and the register itself does not advance during playback. A write to SSA therefore has no effect on a voice that is already playing.7
LSAX
LSAX holds the loop address in 8-byte units. When the voice reaches a block with the Loop Start flag, the hardware copies the current address into LSAX, and when it finishes a block with the Loop End flag, it jumps to the address in LSAX. Looping therefore works from the sample data alone. Reading LSAX shows whether a Loop Start flag has been reached, and writing it can send a one-shot sample to a silent loop elsewhere in memory.7 The block flags are described in SPU ADPCM.
Voice Flag Registers
Each voice flag is a set of 24 bits in two registers: the low register holds voices 0 to 15 and the high register holds voices 16 to 23.8
| Address | Name | Access | Bit set means |
|---|---|---|---|
| 1F801D88h, 1F801D8Ah | KON0, KON1 | Write | Start attack, decay and sustain |
| 1F801D8Ch, 1F801D8Eh | KOF0, KOF1 | Write | Start release |
| 1F801D90h, 1F801D92h | PMON0, PMON1 | R/W | Modulate pitch by the previous voice |
| 1F801D94h, 1F801D96h | NON0, NON1 | R/W | Play noise in place of ADPCM |
| 1F801D98h, 1F801D9Ah | EON0, EON1 | R/W | Send the voice to the reverb as well as the mixer |
| 1F801D9Ch, 1F801D9Eh | ENDX0, ENDX1 | Read | Voice reached a Loop End flag |
Key On sets the envelope volume of the voice to zero and starts the attack. Key Off is normally written during sustain, but it can be written at any time, and the voice then goes straight to release. Reading KON or KOF returns the last value written, so neither register shows whether a voice is sounding. ENDX is the status register: Key On clears the bit of the voice, and a Loop End flag in an ADPCM header sets it. A value written to ENDX can be read back for a short time before the hardware overwrites it.8
PMON
PMON bit N makes the output of voice N-1 modulate the pitch of voice N, and bit 0 is therefore unused.5 Sony describes the effect as an LFO between adjoining voices, with NewPitch(n) = (1 + V(n-1)) x Pitch(n), where V(n-1) is the volume of voice n-1. Two voices are consequently used to make one tone.9 In the hardware the factor is the output of voice n-1 plus 8000h, which gives a range of 0.00 to 1.99. The product is clipped to 4000h after the multiplication, so PITCH values of 4000h to 7FFFh are useful with modulation. Values of 8000h and up are mistaken for negative numbers.5
NON
A voice with its NON bit set plays the noise generator in place of its ADPCM data. The SPU has one noise generator, and its rate comes only from the shift and step fields in ATTR. All noise voices therefore play at the same frequency, and the only way around this is a random ADPCM pattern in the sound buffer. The generator runs once per 44.1 kHz cycle as follows:10
Timer = Timer - NoiseStep ; NoiseStep is 4 to 7
ParityBit = Level.bit15 xor bit12 xor bit11 xor bit10 xor 1
if Timer < 0: Level = Level * 2 + ParityBit
if Timer < 0: Timer = Timer + (20000h >> NoiseShift)
if Timer < 0: Timer = Timer + (20000h >> NoiseShift)
Control Registers
| Address | Name | Contents |
|---|---|---|
| 1F801D80h | MVOLL | Main volume left |
| 1F801D82h | MVOLR | Main volume right |
| 1F801D84h | EVOLL | Reverb output volume left |
| 1F801D86h | EVOLR | Reverb output volume right |
| 1F801DA2h | ESA | Reverb work area start address |
| 1F801DA4h | IRQA | IRQ address |
| 1F801DA6h | TSA | Transfer start address |
| 1F801DA8h | DATA | Transfer data FIFO |
| 1F801DAAh | ATTR | Control register (SPUCNT) |
| 1F801DACh | RAM_CTRL | Sound RAM transfer control |
| 1F801DAEh | STATX | Status register (SPUSTAT) |
| 1F801DB0h | AVOLL | CD input volume left |
| 1F801DB2h | AVOLR | CD input volume right |
| 1F801DB4h | BVOLL | External input volume left |
| 1F801DB6h | BVOLR | External input volume right |
| 1F801DB8h | MVOLXL | Current main volume left |
| 1F801DBAh | MVOLXR | Current main volume right |
Every register that holds a sound buffer address holds the byte address divided by 8.11
ATTR
| Bits | Contents |
|---|---|
| 15 | SPU enable (0 = off, 1 = on). CD audio plays either way. |
| 14 | Mute (0 = mute, 1 = unmute). CD audio plays either way. |
| 10 to 13 | Noise frequency shift (0 to 15, low to high) |
| 8 to 9 | Noise frequency step (0 to 3 for steps 4 to 7) |
| 7 | Reverb master enable |
| 6 | IRQ9 enable (0 = disabled or acknowledge). Works only with bit 15 set. |
| 4 to 5 | Sound RAM transfer mode (0 stop, 1 manual write, 2 DMA write, 3 DMA read) |
| 3 | External input reverb enable |
| 2 | CD input reverb enable (CD-DA and XA-ADPCM) |
| 1 | External input enable |
| 0 | CD input enable (CD-DA and XA-ADPCM) |
Changes to bits 0 to 5 take effect after a delay, so software waits until the low bits of STATX show the new value. Before a new transfer mode is set, the Stop mode is set first and confirmed in STATX in the same way.12 Clearing bit 7 stops the SPU from writing the reverb buffer, which is needed while the buffer is cleared. However, reads from the reverb buffer still reach the output, and the reverb output volume must be set to zero to silence it.13
STATX
STATX is read-only in practice: a written value reads back for a short time before the hardware overwrites it.12
| Bits | Contents |
|---|---|
| 12 to 15 | Unknown, usually zero |
| 11 | Capture buffer half being written (0 = first, 1 = second) |
| 10 | Data transfer busy |
| 9 | DMA read request |
| 8 | DMA write request |
| 7 | DMA read or write request, same as ATTR bit 5 |
| 6 | IRQ9 flag |
| 0 to 5 | Current mode, ATTR bits 0 to 5 after the delay |
Bit 11 tells which half of the four 1KB capture buffers the SPU is writing. It works only when bit 2 or bit 3 of RAM_CTRL is set.12
Volume Registers
MVOLL, MVOLR, VOLL and VOLR each have a direct mode and a sweep mode, and both encodings are given in ADSR and Volume. AVOLL, AVOLR, BVOLL and BVOLR are plain signed 16-bit volumes from -8000h to +7FFFh. The current volume registers read the live level of each sweep and are not normally written by software.14
| Address | Name | Contents |
|---|---|---|
| 1F801DB8h | MVOLXL | Current main volume left |
| 1F801DBAh | MVOLXR | Current main volume right |
| 1F801E00h + N x 4 | VOLXL | Current volume left of voice N |
| 1F801E02h + N x 4 | VOLXR | Current volume right of voice N |
The level that reaches the mixer for each side of a voice is (ENVX x VOLX) >> 15.14
Sound Buffer Transfer
TSA and DATA
TSA holds the sound buffer address for manual and DMA transfers. A write to TSA also loads an internal current address, and it is this internal address that advances during the transfer while TSA keeps its value. DATA is the FIFO for manual writes and holds up to 32 halfwords.11
RAM_CTRL
RAM_CTRL is not initialized at power on, so software must write it before the sound buffer is accessed.11
| Bits | Contents |
|---|---|
| 0 | Unknown |
| 1 | Enable the bank on /OE1 and /WE1 |
| 2 to 3 | RAM chip size (1 = 512KB, 2 = 2MB) |
| 4 to 15 | Unknown |
The value 0004h selects a single 512KB bank, which is the configuration of all known retail, development and arcade hardware. Other values change the address unit to match a larger memory, and on a 512KB console they corrupt writes by repeating or dropping halfwords from the FIFO.11 Reverb also stays off until RAM_CTRL is set.15
Manual Write
| Step | Action |
|---|---|
| 1 | Set RAM_CTRL to 0004h |
| 2 | Set ATTR to Stop and wait for STATX |
| 3 | Write TSA |
| 4 | Write 1 to 32 halfwords to DATA |
| 5 | Set ATTR to Manual Write and wait for STATX |
| 6 | Wait for STATX bit 10 to clear |
For more than one block, steps 4 to 6 repeat. However, ATTR is then already in manual write mode and STATX does not change, so a delay of at least 300h cycles replaces the wait in step 5.11
DMA Write and Read
| Step | DMA write | DMA read |
|---|---|---|
| 1 | Set RAM_CTRL to 0004h | Set DEV4_CTRL to 220931E1h and RAM_CTRL to 0004h |
| 2 | Set ATTR to Stop and wait | Set ATTR to Stop and wait |
| 3 | Write TSA | Write TSA |
| 4 | Set ATTR to DMA Write and wait | Set ATTR to DMA Read and wait |
| 5 | Start DMA4 with block size 10h, control 01000201h | Start DMA4 with block size 10h, control 01000200h |
| 6 | Wait for DMA4 to finish | Wait for DMA4 to finish |
No method is known to read the sound buffer without DMA. A DMA read is also unstable when bits 24 to 27 of DEV4_CTRL are zero: each block then starts with an inserted FFFFh and loses its last halfword. Setting DEV4_CTRL to 220931E1h avoids the problem.11
libspu Transfers
SpuWrite() transfers data from main memory to the sound buffer and SpuRead() transfers it back. libspu has two transfer modes. DMA transfer is the default: it runs asynchronously, so the CPU can do other work, and SpuIsTransferCompleted() must be called afterward. I/O transfer is write-only and uses the CPU, so nothing else runs until it ends. Because a read always uses DMA, its destination must be a large static variable or a heap area, not a stack or auto variable. SpuSetTransferStartAddr() must be called before any transfer.16
If CDInit() is not called before SpuInit(), detection of transfer completion may fail. This happens in particular with SpuIsTransferCompleted(SPU_TRANSFER_WAIT).16
Interrupt
IRQA holds an address in the sound buffer divided by 8. The SPU raises interrupt 9 when the address is accessed, provided ATTR bit 6 is set, and STATX bit 6 shows the request. The accesses that trigger it are shown below.17
| Source | Condition |
|---|---|
| Voice | A voice reads ADPCM data at the IRQ address |
| Capture | The SPU writes a capture buffer at the IRQ address (0000h to 01FFh) |
| Reverb | The reverb reads or writes the IRQ address |
| Transfer | A DMA or manual transfer touches the IRQ address |
Every voice reads the sound buffer all the time, even in noise mode, at zero volume or after release. A silent voice can therefore trigger the interrupt, and unused voices are best pointed at an endlessly looped silent block. The IRQ address is also best aligned to a 16-byte ADPCM block, because an address inside a block sometimes misses.17
An IRQ address in the capture area (0000h to 01FFh) triggers on the SPU's own capture writes. Each capture buffer holds 200h samples, so the rate is about 86.13 Hz (44100 / 200h). Capture interrupts do not occur when bits 2 and 3 of RAM_CTRL are both zero.17
In libspu, SpuSetIRQAddr() sets the address, SpuSetIRQ() enables or disables the interrupt, and SpuSetIRQCallback() registers the function to call.18
Unknown Registers
1F801DA0h, 1F801DBCh to 1F801DBFh and 1F801E60h to 1F801E7Fh can be read and written, but writes to them have no known effect on sound output, and the SPU does not change them.19
References
-
^ psx-spx. Sound Processing Unit (SPU), SPU I/O Port Summary. https://psx-spx.consoledev.net/soundprocessingunitspu/
-
^ Martin Korth. psx-spx, SPU Interrupt. https://problemkaputt.de/psxspx-spu-interrupt.htm
-
^ a b psx-spx. Sound Processing Unit (SPU), Unstable and Delayed I/O and SPU Bus-Width. https://psx-spx.consoledev.net/soundprocessingunitspu/
-
^ a b Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 16-3.
-
^ a b c d psx-spx. Sound Processing Unit (SPU), SPU ADPCM Pitch. https://psx-spx.consoledev.net/soundprocessingunitspu/
-
^ Sony Computer Entertainment Inc. Run-Time Library Reference. January 1999. Page 15-113, Table 15-8.
-
^ a b psx-spx. Sound Processing Unit (SPU), SPU ADPCM Samples. https://psx-spx.consoledev.net/soundprocessingunitspu/
-
^ a b psx-spx. Sound Processing Unit (SPU), SPU Voice Flags. https://psx-spx.consoledev.net/soundprocessingunitspu/
-
^ Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 16-4, Table 16-1.
-
^ psx-spx. Sound Processing Unit (SPU), SPU Noise Generator. https://psx-spx.consoledev.net/soundprocessingunitspu/
-
^ a b c d e f psx-spx. Sound Processing Unit (SPU), SPU Memory Access. https://psx-spx.consoledev.net/soundprocessingunitspu/
-
^ a b c psx-spx. Sound Processing Unit (SPU), SPU Control and Status Register. https://psx-spx.consoledev.net/soundprocessingunitspu/
-
^ psx-spx. Sound Processing Unit (SPU), SPU Reverb Registers. https://psx-spx.consoledev.net/soundprocessingunitspu/
-
^ a b psx-spx. Sound Processing Unit (SPU), SPU Volume and ADSR Generator. https://psx-spx.consoledev.net/soundprocessingunitspu/
-
^ psx-spx. Sound Processing Unit (SPU), SPU Reverb Examples. https://psx-spx.consoledev.net/soundprocessingunitspu/
-
^ a b Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 16-6.
-
^ a b c psx-spx. Sound Processing Unit (SPU), SPU Interrupt. https://psx-spx.consoledev.net/soundprocessingunitspu/
-
^ Sony Computer Entertainment Inc. Run-Time Library Overview. January 1999. Page 16-7.
-
^ psx-spx. Sound Processing Unit (SPU), SPU Unknown Registers. https://psx-spx.consoledev.net/soundprocessingunitspu/