DSP Unmute

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
DSP Unmute
by on (#180966)
I need to unmute the DSP in order to allow expansion audio to play. I understand that this requires uploading code to the SPC. Looking at this document, the process looks pretty straightforward. However, this is only my second time even touching SPC code, and the first time was so far into a caffeine-fueled all-nighter, I am basically starting from scratch here. Now, all I want to do is unmute the DSP and then leave the SPC idle, so I feel like the SPC code should be as simple as:

Code:
arch snes.smp

define REG_FLAG($6C)
define FLAG_ECHO(#$20)
define FLAG_MUTE(#$40)

    lda {REG_FLAG}    // E4 6C
    ora {FLAG_ECHO}   // 08 20
    and ~{FLAG_MUTE}  // 28 BF
    sta {REG_FLAG}    // C4 6C
-;  bra -             // 2F FE


The main thing missing from that link is the actual value of #SPCExec (the start-of-execution address). With that, it seems like all I need to do is transfer the 6-byte code block above and execute it, using the code example from that link verbatim, right? Or is there more to it than that?

Edit: derp, got my bitmask backwards
Re: DSP Unmute
by on (#180970)
You probably can mimic Nocash's Magic Floor code and just instruct the SPC bootloader to write the "unmute" control to the relevant DSP register.
Re: DSP Unmute
by on (#180971)
Code provided by Nintendo back in the 90s is attached; the ! designator you see on the equates is to force 16-bit absolute addressing, the rest should be pretty obvious, barring the 1da/1dy instructions (likely an OCR mistake; should be lda/ldy). I'm attaching this just as a comparison example to what's on the wiki you linked. The actual SNES/SPC communication protocol is in fact officially documented if you'd prefer that.

(2018/08/29 Edit: attachments removed.)
Re: DSP Unmute
by on (#180972)
I'm thinking it would be a good idea to make sure echo is off.
Re: DSP Unmute
by on (#180973)
I made a few stupid mistakes, like getting my bitmask backwards, and never storing the value back to the register. Updated those, and added in disabling echo, but still no luck. Watching the memory viewer in bsnes-plus, I at least see that the data is successfully transferred to the location I specified, it's just still not playing any sound. Maybe do I need to set the volume registers too? Do those affect the volume of audio coming from the cart pins?
Re: DSP Unmute
by on (#180974)
The SPC700 is on the main PCB of the SNES/SFC itself, not the cartridge. Audio provided by the cartridge itself (i.e. some sort of on-cart audio IC) is provided on cartridge pins 31 and 62, and is mixed into the literal audio output circuitry of the SNES -- it does not go through the SPC700. I.e. the on-cart audio IC needs to have a volume control itself, managed through some means of its own (maybe MMIO registers, etc.); the SNES/SFC cannot control this.
Re: DSP Unmute
by on (#180975)
No, the MUTE signal is actually a trace that comes from the S-DSP to a BJT clamp that dramatically reduces the gain on the output amplifier. So for audio fed in through the expansion port, disabling that signal should be all that's necessary.

Do you know whether the S-SMP is executing the code you've uploaded?
Re: DSP Unmute
by on (#180976)
While I'm here: here are a couple official "cautions" -- the 2nd should be good reason not to use the code on that wiki (it does 16-bit writes to $2140/2141).

There has been a past discussion about the /MUTE line: https://forums.nesdev.com/viewtopic.php?f=12&t=10585

Sorry for the attachment order (if they're out of order): I have no software that can easily let me make a long "strip" image from multiple images (please do not let this become a subject of discussion / derail thread subject).

(2018/08/29 Edit: attachments removed.)
Re: DSP Unmute
by on (#180978)
lidnariq wrote:
Do you know whether the S-SMP is executing the code you've uploaded?


If the bsnes-plus trace logger is to be believed, yes. Does the code itself look correct?

Code:
..0100 mov   a,$06c           A:00 X:00 Y:00 SP:01ef YA:0000 nvpbhiZc
..0102 or    a,#$20           A:00 X:00 Y:00 SP:01ef YA:0000 nvpbhiZc
..0104 and   a,#$bf           A:20 X:00 Y:00 SP:01ef YA:0020 nvpbhizc
..0106 mov   $06c,a           A:20 X:00 Y:00 SP:01ef YA:0020 nvpbhizc
..0108 bra   $0108            A:20 X:00 Y:00 SP:01ef YA:0020 nvpbhizc
..0108 bra   $0108            A:20 X:00 Y:00 SP:01ef YA:0020 nvpbhizc
..0108 bra   $0108            A:20 X:00 Y:00 SP:01ef YA:0020 nvpbhizc
..0108 bra   $0108            A:20 X:00 Y:00 SP:01ef YA:0020 nvpbhizc


Oh, wait. That's just writing to SPC RAM address $6C, I need to write to DSP register $6C. So much indirection...
Re: DSP Unmute
by on (#180979)
Got it!

Code:
arch snes.smp

    lda #$6C    // DSP Flag Register
    sta $F2     // DSP Access Address
    lda #$20    // RESET: Off, MUTE: Off, ECHO: Off, NCLK: 0Hz
    sta $F3     // DSP Access Data
-;  bra -
Re: DSP Unmute
by on (#180990)
For time/convenience, you could also do:

Code:
mov $F2, #$6C
mov $F3, #$20
...


The SPC has a couple of instructions that let you write directly to a zero page address without using a register.
Re: DSP Unmute
by on (#181002)
Just as a side note it's good practice to jump back to the IPL (jmp !$ffc0 (yes, I seem to be one of the few here that prefers the "native" mnemonics ;) )) after executing a snippet like this, otherwise it's impossible to communicate with the SPC again until the SNES is reset.
Re: DSP Unmute
by on (#181003)
Optiroc wrote:
Just as a side note it's good practice to jump back to the IPL (jmp !$ffc0 (yes, I seem to be one of the few here that prefers the "native" mnemonics ;) )) after executing a snippet like this, otherwise it's impossible to communicate with the SPC again until the SNES is reset.


I'll keep that in mind. For my current purposes though, unmuting the DSP is literally the only thing I ever want to do (this is for an MSU-1 video player), but it's always good to know The Right WayTM to do things.

Edit: and apparently that fixed an issue I was having where higan v101 refused to lock to 60FPS and started freerunning, even with Synchronize Audio enabled.
Re: DSP Unmute
by on (#181017)
On real hardware, this is generating a very rapid popping sound, somewhere around ~8Hz. Looks like you need to set the echo volume to 0, even with the echo flag disabled. Here's the final (I hope), minimal code:

Code:
arch snes.smp

    str $F2=#$2C    // DSP Echo Volume (Left)
    str $F3=#$00    // Volume 0
    str $F2=#$3C    // DSP Echo Volume (Right)
    str $F3=#$00    // Volume 0
    str $F2=#$6C    // DSP Flag Register
    str $F3=#$20    // RESET: Off, MUTE: Off, ECHO: Off, NCLK: 0Hz
    jmp $FFC0       // Return to IPLROM
Re: DSP Unmute
by on (#181025)
qwertymodo wrote:
On real hardware, this is generating a very rapid popping sound, somewhere around ~8Hz. Looks like you need to set the echo volume to 0, even with the echo flag disabled. Here's the final (I hope), minimal code:

Code:
arch snes.smp

    str $F2=#$2C    // DSP Echo Volume (Left)
    str $F3=#$00    // Volume 0
    str $F2=#$3C    // DSP Echo Volume (Right)
    str $F3=#$00    // Volume 0
    str $F2=#$6C    // DSP Flag Register
    str $F3=#$20    // RESET: Off, MUTE: Off, ECHO: Off, NCLK: 0Hz
    jmp $FFC0       // Return to IPLROM


Sounds like the DSP is reading and outputting uninitialized APU RAM as echo data. DSP register $63.d5 only disables writing into the echo buffer, not reading and mixing it into the final output.
Re: DSP Unmute
by on (#181089)
Quote:
I seem to be one of the few here that prefers the "native" mnemonics


I'm well aware that changing the mnemonics for a CPU is highly controversial.

But I really felt this was a special exception: the SPC700 is absolutely, unequivocally, a shameless 6502 clone. Just like the HuC6280, it adds a few new instructions on top of it. Unlike the HuC, it also reorders the opcode bytes -- but nobody is writing code in db statements, so who cares?

The native mnemonics were almost certainly a thinly veiled attempt to avoid licensing fees for the use of the 6502 instruction set. And in this case, they are truly gross mnemonics that force you to think about parameter ordering (src,dest vs dest,src) and leave tons of holes that are not obvious until you get assembler errors for missing opcodes.

I've emulated ~15 processors now in higan, and the only other time I've made up mnemonics were when opcodes were not documented and I had zero choice (uPD96050 and Cx4). So this was not a decision I made lightly.

That said, I understand and respect if you do not care for this. Sorry to inflict it upon you ... perhaps someone could write a translator so people can work with whichever set they prefer :)
Re: DSP Unmute
by on (#181093)
byuu wrote:
Unlike the HuC, it also reorders the opcode bytes -- but nobody is writing code in db statements, so who cares?

That's good to know. I've occasionally coded in db statements to get around bugs in the ancient version of WLA DX I've been using, and the only piece of real SPC700 code I've ever written is self-modifying... it hasn't been assembled or tested, but I'll get around to it someday...