S-DSP registers: Difference between revisions

From SNESdev Wiki
Jump to navigationJump to search
m (Undisbeliever moved page S-DSP Registers to S-DSP registers: Lower case registers to match the other register pages)
(Added Reading and writing S-DSP registers section)
Line 37: Line 37:
* '''RW''' - Readable and Writable
* '''RW''' - Readable and Writable
* '''R''' - Readable (technically writable, but not intended to be written to)
* '''R''' - Readable (technically writable, but not intended to be written to)
== Reading and writing S-DSP registers ==
The S-DSP registers are accessed via the [[S-SMP#$F2-F3_DSP|<tt>DSPADDR</tt> and <tt>DSPDATA</tt>]] S-SMP registers.
Writing to the S-SMP <tt>$F2</tt> <tt>DSPADDR</tt> register will set the selected S-DSP register address.  The S-SMP <tt>$F3</tt> <tt>DSPDATA</tt> register is then used to read or write the selected S-DSP register.
CAUTIONS:
* Writing to <tt>DSPADDR</tt> with the high bit set will disable <tt>DSPDATA</tt> writes.
* Reading <tt>DSPDATA</tt> will return the value stored in the S-DSP's 128 byte register memory.  Some <tt>DSPDATA</tt> reads might not match the internal S-DSP state until the S-DSP register has been written to.
* S-DSP registers are polled by the S-DSP at different points within the 32-cycle sample loop.
** Most S-DSP register writes do not take effect immediately.
** Some S-DSP registers are polled every second sample.
** Overriding a S-DSP register write too early can skip the previous S-DSP register write (with audible glitches with the <tt>KON</tt>, <tt>KOFF</tt> registers).
** The echo buffer registers are polled at unexpected times and should be treated with care.





Revision as of 10:43, 3 November 2024

The S-DSP registers are accessed via the DSPADDR and DSPDATA S-SMP registers.

S-DSP global register summary
Name Address Bits Type Notes
MVOLL MVOL (L) $0C VVVV VVVV RW Left channel main volume, signed.
MVOLR MVOL (R) $1C VVVV VVVV RW Right channel main volume, signed.
EVOLL EVOL (L) $2C VVVV VVVV RW Left channel echo volume, signed.
EVOLR EVOL (R) $3C VVVV VVVV RW Right channel main volume, signed.
KON $4C 7654 3210 RW Key on. Writing this with any bit set will start a new note for the corresponding voice.
KOFF KOF $5C 7654 3210 RW Key off. Writing this with any bit set will put the corresponding voice into its release state.
FLG $6C RMEN NNNN RW Flags: soft reset (R), mute all (M), echo disable (E), noise frequency (N).
ENDX $7C 7654 3210 R Read for end of sample flag for each channel.
EFB $0D VVVV VVVV RW Echo feedback, signed.
- - $1D ---- ---- RW Unused.
PMON $2D 7654 321- RW Enables pitch modulation for each channel, controlled by OUTX of the next lower channel.
NON $3D 7654 3210 RW For each channel, replaces the sample waveform with the noise generator output.
EON $4D 7654 3210 RW For each channel, sends to the echo unit.
DIR $5D DDDD DDDD RW Pointer to the sample source directory page at $DD00.
ESA $6D EEEE EEEE RW Pointer to the start of the echo memory region at $EE00.
EDL $7D ---- DDDD RW Echo delay time (D).
FIR0 C0 $0F VVVV VVVV RW Echo filter coefficient.
FIR1 C1 $1F VVVV VVVV RW Echo filter coefficient.
FIR2 C2 $2F VVVV VVVV RW Echo filter coefficient.
FIR3 C3 $3F VVVV VVVV RW Echo filter coefficient.
FIR4 C4 $4F VVVV VVVV RW Echo filter coefficient.
FIR5 C5 $5F VVVV VVVV RW Echo filter coefficient.
FIR6 C6 $6F VVVV VVVV RW Echo filter coefficient.
FIR7 C7 $7F VVVV VVVV RW Echo filter coefficient.
(table source)


There are 8 voices, numbered 0 to 7. Each voice X has 10 registers in the range $X0-$X9.

S-DSP voice register summary
Name Address Bits Type Notes
VxVOLL VOL (L) $X0 SVVV VVVV RW Left channel volume, signed.
VxVOLR VOL (R) $X1 SVVV VVVV RW Right channel volume, signed.
VxPITCHL P (L) $X2 LLLL LLLL RW Low 8 bits of sample pitch.
VxPITCHH P (H) $X3 --HH HHHH RW High 6 bits of sample pitch.
VxSRCN SRCN $X4 SSSS SSSS RW Selects a sample source entry from the directory (see DIR below).
VxADSR1 ADSR (1) $X5 EDDD AAAA RW ADSR enable (E), decay rate (D), attack rate (A).
VxADSR2 ADSR (2) $X6 SSSR RRRR RW Sustain level (S), sustain rate (R).
VxGAIN GAIN $X7 0VVV VVVV
1MMV VVVV
RW Mode (M), value (V).
VxENVX ENVX $X8 0VVV VVVV R Reads current 7-bit value of ADSR/GAIN envelope.
VxOUTX OUTX $X9 SVVV VVVV R Reads signed 8-bit value of current sample wave multiplied by ENVX, before applying VOL.
(table source)


Register types:

  • RW - Readable and Writable
  • R - Readable (technically writable, but not intended to be written to)


Reading and writing S-DSP registers

The S-DSP registers are accessed via the DSPADDR and DSPDATA S-SMP registers.

Writing to the S-SMP $F2 DSPADDR register will set the selected S-DSP register address. The S-SMP $F3 DSPDATA register is then used to read or write the selected S-DSP register.


CAUTIONS:

  • Writing to DSPADDR with the high bit set will disable DSPDATA writes.
  • Reading DSPDATA will return the value stored in the S-DSP's 128 byte register memory. Some DSPDATA reads might not match the internal S-DSP state until the S-DSP register has been written to.
  • S-DSP registers are polled by the S-DSP at different points within the 32-cycle sample loop.
    • Most S-DSP register writes do not take effect immediately.
    • Some S-DSP registers are polled every second sample.
    • Overriding a S-DSP register write too early can skip the previous S-DSP register write (with audible glitches with the KON, KOFF registers).
    • The echo buffer registers are polled at unexpected times and should be treated with care.


Global registers

MVOLL, MVOLR - Main volume ($0C, $1C)

7  bit  0
---- ----
VVVV VVVV
|||| ||||
++++-++++- left/right channel volume (signed)


EVOLL, EVOLR - Echo volume ($2C, $3C)

7  bit  0
---- ----
VVVV VVVV
|||| ||||
++++-++++- left/right channel volume (signed)


KON - Key on ($4C)

7  bit  0
---- ----
7654 3210
|||| ||||
|||| |||+- key-on voice 0
|||| ||+-- key-on voice 1
|||| |+--- key-on voice 2
|||| +---- key-on voice 3
|||+------ key-on voice 4
||+------- key-on voice 5
|+-------- key-on voice 6
+--------- key-on voice 7

Writing a 1 to a KON voice bit will:

  • Set the voice's envelope to 0
  • Change the voice's ADSR state to Attack
  • Reset the voice's BRR decoder to the start of the sample (as determined by DIR and VxSCRN)

KON is polled every second sample.


ERRATA:[1]

  • Clearing KON too early can cause the voice to not key-on.
  • If a voice's KON and KOFF bits are both set; the key-on will be followed by a key-off, silencing the channel.


KOFF - Key off ($5C)

7  bit  0
---- ----
7654 3210
|||| ||||
|||| |||+- key-off voice 0
|||| ||+-- key-off voice 1
|||| |+--- key-off voice 2
|||| +---- key-off voice 3
|||+------ key-off voice 4
||+------- key-off voice 5
|+-------- key-off voice 6
+--------- key-off voice 7

Setting a voice bit in KON will:

  • Change the voice's envelope state to Release

KOFF is polled every second sample.


ERRATA:[2]

  • Clearing KOFF too early can cause the voice to not key-off.
  • Clearing the KOFF bits after writing to KON might key-on, key-off or silence the channel.
  • If a voice's KON and KOFF bits are both set; the key-on will be followed by a key-off, silencing the channel.


FLG - Flags register ($6C)

7  bit  0
---- ----
RMEN NNNN
|||| ||||
|||+-++++- Noise frequency
||+------- Disable echo write
|+-------- Mute all
+--------- Soft reset


ENDX - End of sample flags ($7C, read-only)

7  bit  0
---- ----
7654 3210
|||| ||||
|||| |||+- Voice 0 BRR block has end-flag set
|||| ||+-- Voice 1 BRR block has end-flag set
|||| |+--- Voice 2 BRR block has end-flag set
|||| +---- Voice 3 BRR block has end-flag set
|||+------ Voice 4 BRR block has end-flag set
||+------- Voice 5 BRR block has end-flag set
|+-------- Voice 6 BRR block has end-flag set
+--------- Voice 7 BRR block has end-flag set

The voice bits are set when the current BRR block has the end-flag set (not at the end of the BRR sample).

If the voice is recently keyed-on, the ENDX bits will be clear (even if the BRR sample is a single BRR block).[3]

ENDX is technically writable and not intended to be written to. The S-DSP updates this register 8 times per sample.


EFB - Echo feedback ($0D)

7  bit  0
---- ----
VVVV VVVV
|||| ||||
++++-++++- echo feedback (signed)


PMON - Pitch modulation enable ($2D)

7  bit  0
---- ----
7654 321-
|||| |||
|||| ||+-- Enable pitch modulation on voice 1
|||| |+--- Enable pitch modulation on voice 2
|||| +---- Enable pitch modulation on voice 3
|||+------ Enable pitch modulation on voice 4
||+------- Enable pitch modulation on voice 5
|+-------- Enable pitch modulation on voice 6
+--------- Enable pitch modulation on voice 7


NON - Noise enable ($3D)

7  bit  0
---- ----
7654 3210
|||| ||||
|||| |||+- Replace voice 0 with noise generator
|||| ||+-- Replace voice 1 with noise generator
|||| |+--- Replace voice 2 with noise generator
|||| +---- Replace voice 3 with noise generator
|||+------ Replace voice 4 with noise generator
||+------- Replace voice 5 with noise generator
|+-------- Replace voice 6 with noise generator
+--------- Replace voice 7 with noise generator


EON - Echo enable ($3D)

7  bit  0
---- ----
7654 3210
|||| ||||
|||| |||+- Enable echo on voice 0
|||| ||+-- Enable echo on voice 1
|||| |+--- Enable echo on voice 2
|||| +---- Enable echo on voice 3
|||+------ Enable echo on voice 4
||+------- Enable echo on voice 5
|+-------- Enable echo on voice 6
+--------- Enable echo on voice 7


DIR - Sample directory page ($5D)

7  bit  0
---- ----
DDDD DDDD
|||| ||||
++++-++++- Page pointer to the sample source directory


ESA - Echo start address ($6D)

7  bit  0
---- ----
EEEE EEEE
|||| ||||
++++-++++- Page pointer to start of the echo buffer


ERRATA:

  • Care must be taken when writing to the EDL and ESA echo buffer registers.
  • The ESA (echo buffer address) register is accessed once per sample and ESA writes can be delayed by a single sample.[4]
  • The echo buffer wraps around the 16-bit Audio-RAM address boundary, clobbering zeropage.
  • The echo buffer will write a minimum 4 bytes to the start of ESA, unless echo writes are disabled in FLG.
  • See EDL errata for more details.


EDL - Echo delay ($7D)

7  bit  0
---- ----
---- DDDD
     ||||
     ++++- Echo delay time (delay = DDDD * 512 samples)

EDL controls the size (DDDD * 2048 bytes) and length (DDDD * 512 samples or 16ms @ 32000Hz) of the echo buffer.


ERRATA:

  • Care must be taken when writing to the EDL and ESA echo buffer registers.
  • Setting echo delay (EDL, register $7D) to 0 continuously overwrites 4 bytes of ARAM at the start of the echo buffer page (selected by ESA, $6D). In particular, ESA = $00 and EDL = $00 overwrites zero page locations $0000-$0003. If not using echo, remember to set the echo write protect bit of FLG ($6C bit 5) to 1.
  • EDL (echo delay / echo buffer size) register writes take effect when the S-DSP reaches the end of the echo buffer.[5]
    • Writing to EDL can take up to 7680 samples (240ms @ 32000Hz) to take effect.
  • The ESA (echo buffer address) register is accessed once per sample and ESA writes can be delayed by a single sample.[6]
  • The echo buffer wraps around the 16-bit Audio-RAM address boundary, clobbering zeropage.
  • To prevent the echo buffer from clobbering memory when initialing the echo buffer, echo buffer writes should be disabled (FLG bit 5 set) before writing to ESA and EDL. There should be a minimum 7680 sample (240ms @ 32000Hz) delay before echo buffer writes are enabled (FLG bit 5 clear).


C0, C1, C2, C3, C4, C5, C6, C7 - Echo FIR filter coefficients ($xF)

7  bit  0
---- ----
VVVV VVVV
|||| ||||
++++-++++- FIR filter tap (signed)


ERRATA:

  • The FIR filter uses a clipped-sum for the first 7 tap calculations and a clamped-sum for only the last tap. [7]
  • This can cause audio clicks if the FIR filter gain exceeds 0dB.
  • To prevent FIR clicks ensure the absolute sum of the FIR taps (S-DSP registers C0-C7) is <= 128.


Voice registers

VxVOLL, VxVOLR - Voice volume ($x0, $x1)

7  bit  0
---- ----
VVVV VVVV
|||| ||||
++++-++++- left/right channel volume (signed)


VxPITCHL, VxPITCHH - Voice pitch ($x2, $x3)

15  bit  8   7  bit  0
 ---- ----   ---- ----
 ..PP pppp   pppp pppp
   || ||||   |||| ||||
   ++-++++---++++-++++- Voice pitch (2.12 fixed point)


VxSCRN - Voice sample source ($x4)

7  bit  0
---- ----
SSSS SSSS
|||| ||||
++++-++++- DIR sample source table entry


VxADSR1, VxADSR2 - ADSR enable and settings ($x5, $x6)

 VxADSR1
7  bit  0
---- ----
EDDD AAAA
|||| ||||
|||| ++++- Attack rate (A)
|+++------ Decay rate (D)
+--------- ADSR enable
 VxADSR2
7  bit  0
---- ----
LLLR RRRR
|||| ||||
|||+-++++- Sustain rate (SR)
+++------- Sustain level (SL)
  • If the ADSR enable bit is clear, the envelope is controlled by the VxGAIN register.
  • If the ADSR enable bit is set, the envelope will be changed depending on the ADSR state
    • Attack:
      • If AAAA == 15, Linear increase +1024 at a rate of 31
      • If AAAA < 15, Linear increase +32 at a rate of AAAA1 (equivalent to VxGAIN == 110_AAAA1)
    • Decay: Exponential decrease at a rate of 1DDD0 (equivalent to VxGAIN == 101_1DDD0)
      • Sustain level controls
    • Sustain: Exponential decrease at a rate of RRRRR (equivalent to VxGAIN == 101_RRRRR)
    • Release: Linear decrease at a fixed rate of -8 every sample.

Adsr envelope.svg


ERRATA:

  • There is a race-condition when changing the ADSR/GAIN envelope mode (bit 7 of ADSR1) in the middle of a note. If the S-DSP registers are written in the order ADSR1 followed by ADSR2/GAIN, the S-DSP might read the old ADSR2/GAIN value before the ADSR2/GAIN write, potentially glitching the rest of the envelope (especially if the previous GAIN was a fixed envelope).[8]
    • Workaround: Write to the ADSR2/GAIN register before the ADSR1 register.
    • Workaround: Only change the ADSR/GAIN envelope mode bit when the channel is in the release state.


See: DSP envelopes


VxGAIN - GAIN envelope settings ($x7)

7  bit  0
---- ----
0VVV VVVV
 ||| ||||
 +++ ++++- Fixed envelope

7  bit  0
---- ----
1MMr rrrr
 ||| ||||
 ||+ ++++- GAIN rate
 ++------- GAIN mode

GAIN envelope is used if the VxADSR1 ADSR enable bit is clear.

GAIN modes
Mode bits Name envelope change per rate
0?? Fixed envelope = VVVVVVV << 4 every sample
100 Linear decrease -32
101 Exponential decrease -1 - ((envelope - 1) >> 8)
110 Linear increase +32
111 Bent increase if envelope < $600 (75%) { +32 } else { +8 }

If the voice is in the release state, the envelope is linear decrease at a fixed rate of -8 every sample.


See: DSP envelopes


VxENVX - Voice envelope value ($x8, read-only)

7  bit  0
---- ----
0EEE EEEE
 ||| ||||
 +++-++++- Upper 7 bits of envelope

VxENVX is technically writable and not intended to be written to. The S-DSP updates this register once per sample.


VxOUTX - Voice sample value ($x9, read-only)

7  bit  0
---- ----
OOOO OOOO
|||| ||||
++++-++++- Upper 8 bits of current sample (signed)

VxOUTX contains the upper 8 bits of the current sample after the envelope has been applied to the Gaussian Interpolation (or noise) output and before the VxVOL channel volume multiplication.

VxOUTX is technically writable and not intended to be written to. The S-DSP updates this register once per sample.


References

  • Anomie's S-DSP Doc
  • ares source code, ares/sfc/dsp directory, by Near and ares team
  1. Anomie's S-DSP Doc: KON and KOFF registers
  2. Anomie's S-DSP Doc: KON and KOFF registers
  3. ares source code, ares::SuperFamicom::Dsp::voice5(), by Near and ares team
  4. Anomie's S-DSP Doc: ESA register
  5. Anomie's S-DSP Doc: EDL register
  6. Anomie's S-DSP Doc: ESA register
  7. SnesLab Wiki - FIR Filter - S-DSP Implementation
  8. Terrific Audio Driver - I found a race condition