softglow's notebook

Dispatches from the Depths of a Super Nintendo

Synchronization in Higan (SMP/DSP)

Background Matter

In case you missed my master plan (e.g.: you’re reading my Github and were never on metconst), I’m trying to build a music editor for, at the very least, SPC files from Super Metroid.

It seems like the fastest way for such an editor to be able to play the music being edited, is to have a real SPC player built-in. But not one that dumps straight to the platform audio output device—one that buffers into RAM to make play/pause and seeking possible.

To that end, I’m presently trying to rip the SMP/DSP subsystem out of higan (née bsnes) and pull it into a library that runs in a subthread and lets the main thread request blocks of audio from it.

Oh yes, I’m going to be building in QT. I may, or may not, eventually borrow some source code from qtractor (certainly not the audio output chain, though; AFAIK, if you don’t really want audio to play, then JACK is an excellent backend for you.) QT appears to be the one cross-platform library that’s monolithic enough to be an easy (if fat) install on Windows, that also provides everything I absolutely need: threads, audio, GUI widgets, and a C++ FFI for binding to higan’s SMP core.

Higan v093

So with that out of the way, let’s take a closer look at higan. I’m specifically using v093 here, which is, as of late September 2013, the latest version published. I hear it even builds on OS X now.

Why higan? Accuracy. There doesn’t seem to be any point in going for anything less, when I won’t have competition for host time from the CPU and PPU. I’ve also heard (but been unable to find any trace of the actual code involved) that the SMW community came up with some music editor(s) once upon a time, but they were based on the ZSNES emulation, and failed hard on the real hardware because ZSNES cheated on echo buffering. Echo didn’t get written back to PSRAM and destroy the code/instruments under emulation.

That’s a mistake that’s worth not repeating.

Synchronization

higan does threading (when threaded) by using its built-in public domain libco (coroutine, I presume) library. But if you just look at sfc/smp/smp.cpp you will find some synchronization functions, but no callers… right there. And the obvious ones like step() don’t seem to do much.

There are some more functions in sfc/smp/timing/timing.cpp, but that turns out to be a very small file, because it’s just providing some more sync functions to be called. The real synchronization is driven from the memory files, sfc/smp/memory/memory.cpp. Quoting my notes:

step(clocks): adjusts clocks only, no sync
cycle_edge: tick SMP timers
add_clocks: step(); sync DSP; may sync CPU
...
add_clocks called in op_{io|read|write}

It appears that higan’s philosophy is to synchronize the bus state of the system. That is, when a CPU (the S-SMP in the case of audio) makes some sort of move like loading the next instruction from memory, it triggers a synchronization with the rest of the system. However many cycles the DSP should have taken while that one SMP instruction was running becomes accounted for, and the DSP state is “caught up” so that its current bus state will be visible to the emulation of the SMP when the thread returns.

That’s pretty much how the main CPU and the SMP are sync’ed, as well: whenever either side writes to an IO port connecting them, at end-of-scanline, and any time they get more than 24 samples of audio output out-of-sync. Or, at every bus transaction, if the debugger is built (or maybe enabled? I forget which.)

I didn’t look, but I’d guess that’s how the CPU and PPU are wired, as well.

struct Everything

Apparently in the C++ world, a struct is a class with default-public instead of default-private. byuu uses a lot of struct and very few, if any, class keywords.

Why you would use C-compatible keywords to build non-C features? I’m baffled. It’s just how Bjarne rolls, I guess.

The Mystery of Privilege

There’s apparently a “privileged” access modifier. How this may differ from private or protected, I’m not really certain, because so far I’ve been unable to find a description of it online. It’s just too generic a word: every discussion of public vs. private tends to use it to talk about access control.

Unfortunately, there’s a good chance I may need to understand it before finishing this library.