Skip to content
RetrogamingDeep Dive Published Updated 4 min readViews unavailable

openMSX SCC Modes: Register Windows, Waveform Aliasing, and Emulation Boundaries

Compare the Real, Compatible, and Plus register maps implemented by openMSX, including the mirrored fifth waveform and deformation-mode write rules.

The Konami SCC is often summarized as a five-channel wavetable sound chip. That summary hides an emulator-relevant detail: software does not always see five independent, writable waveforms. The exact byte window and the relationship between waveform RAM and the fifth channel depend on the SCC mode being modeled. This article reads those rules from one precisely pinned implementation: openMSX SCC.cc at commit aecaaf6c89620e0f601bfe7830d23c24ad5eecbc. It describes that source revision, not every physical SCC variant or every emulator.

Three modes, different software-visible maps

The class declares Real, Compatible, and Plus modes in the same commit’s SCC.hh. Its peekMem() and writeMem() methods decode a normalized 8-bit SCC address. These are the component’s internal address windows; they should not be confused with a cartridge mapper’s larger CPU address range.

openMSX mode Waveform window Frequency/volume window Deformation window Special behavior in this source
Real 00–7F: four 32-byte waveforms 80–9F E0–FF A0–DF has no function
Compatible 00–7F: four waveforms; A0–BF: fifth waveform on reads 80–9F C0–DF Writes to A0–BF are ignored
Plus 00–9F: five mapped waveform blocks; writes are subject to deformation locks A0–BF C0–DF Five blocks are directly exposed, but deformation state can make them read-only

The ranges are implemented directly in the mode-specific branches of peekMem() and writeMem(). A test that exercises only the Plus map can therefore miss compatibility behavior that real software relies on. In Compatible mode, for example, address A0 is not another frequency register: it reads waveform five, while writes in that range are discarded. In Real mode the deformation block is at the top of the internal window rather than at C0.

There is also a read-side nuance. In this source revision, readMem() applies a deformation-register value of 0xFF when software reads within the mode’s deformation window, then returns the result of peekMem(). That result is not a normal register-value readback. A regression test should check the state transition caused by the read as well as the returned byte; treating the deformation window like an ordinary readable latch would miss this behavior.

The fifth waveform can be an alias

The writeWave() implementation accepts five channels only when the selected mode is Plus. In non-Plus modes, a write to waveform four is copied into the fifth internal waveform array only while channel four is writable. When that condition holds, the fifth channel’s sample data tracks channel four rather than providing a separate writable 32-byte table. It is an aliasing rule, not a claim that all five voices are silent or that waveform four and five share every register.

The source also has separate read-only and rotation state for the wave arrays. The deformation-register helper selects behaviors from bits 6–7: one branch rotates and locks all waveforms; another rotates and locks waveforms four and five; another rotates the first three while locking all five. One mode-specific detail is easy to overlook: outside Real, the implementation masks bit 7 before choosing the branch. Thus the same written byte does not necessarily select the same rotation combination in Compatible or Plus mode. writeWave() and setDeformRegHelper() are the evidence for these statements.

A practical compatibility test

An emulator developer can turn the map into a compact regression matrix. For each mode, write a distinct signed-byte pattern only to waveform blocks that the map marks writable; in Compatible mode, deliberately attempt a write to A0–BF and verify that it is ignored. Read back only locations the implementation exposes as readable, then write waveform four in a non-Plus mode and check whether waveform five follows through the debugger or generated audio. Finally, set each deformation combination and confirm which sample arrays rotate and reject writes. This isolates address decode, aliasing, and waveform phase instead of relying on one subjective listening test.

Do not infer that a successful register readback proves identical analog output. openMSX’s code also maintains phase, period, volume, and resampled output state; the selected sample values can be right while timing or mixing remains different. Conversely, a mismatch against a cartridge capture does not prove that the implementation is wrong until the cartridge mapper, chip mode, and capture timing are known. The source includes comments about measurements and historical observations, but this article intentionally treats implementation code as the claim boundary rather than promoting every embedded note to a universal hardware specification.

The useful lesson is that “SCC support” is not one boolean. A faithful emulator needs the correct mode, mode-dependent register windows, fifth-waveform behavior, and deformation permissions. Pinning a test report to a named openMSX revision makes future changes reviewable: if the mapping changes upstream, rerun the matrix and distinguish an intentional correction from a regression.

Related:

Sources:

Comments