CH3: Wave Channel
CH3 reuses the square channels' divider topology with two changes. A single
/2 prescaler runs the divider at 2 MHz, which halves the overflow interval —
Pan Docs' (2048 − period) × 2 T-cycles. A 16-byte wave RAM stepped by a
5-bit wave-position counter replaces the duty machinery. The distinctive
CH3 behaviours are the trigger delay, the locked CPU access, and the
retrigger corruption. All three live in the small synchroniser and SRAM
circuits this chapter maps.
- Same 4+4+3 divider topology as CH1/CH2, but clocked at 2 MHz by a
single-prescaler chain. The trigger synchroniser samples on
ch3_2mhz↓, the opposite edge family from CH1/CH2. - Triggers reset the wave-position counter to 0 (unlike the duty counter), and a wrap interlock dwells that counter at 0 for one extra overflow.
- CPU wave-RAM access while CH3 runs goes wherever CH3 points; writes land unconditionally at CH3's current byte.
- DAC-off freezes, never clears: the wave data latch keeps its last strobed byte through NR30 off/on — only NR52 power-off resets it. A retrigger replays the stale byte until its first strobe.
- Retrigger corruption is a 4-byte row copy on DMG too — the single-byte-on-DMG rule is inaccurate against the gate-level model.
Period divider
Identical 4+4+3 tffnl topology to CH1/CH2
(CH1/CH2), at 2 MHz and with no sweep:
| Gate | Role | Type | Clock / Trigger | Notes |
|---|---|---|---|---|
| CERY | CH3 prescaler /2 stage | dffr | apu_4mhz (via CYBO buffer) | Toggle; free-running; q = ch3_2mhz directly; only reset is apu_reset — never reloaded by triggers |
| GUGU | Channel-disable latch (q_n = ch3_fdis) | nand_latch | Enable: FAJU = NOT(GYRA), the trigger pulse retimed one ch3_2mhz edge behind GYTA; Disable: FUVO = NOR(ch3_amp_en_n, apu_reset) — a held level | While ch3_fdis is high, gates the divider toggle clock low |
| HEFO → JUTY | Divider toggle clock | nor2 + not | ch3_2mhz gated by ch3_fdis | One toggle per T-cycle |
| KUTU KUPE KUNU KEMU | Divider bits 0–3 | tffnl | bit-to-bit ripple | Load enable kyko |
| KYGU KEPA KAFO KENO | Divider bits 4–7 | tffnl | ripple via KYRU inverter | Load enable kaso |
| KEJU KEZA JAPU | Divider bits 8–10 | tffnl | ripple via KESE inverter | MSB q = ch3_ftick — the overflow edge |
| HYFO + HUNO | Overflow detector | not + dffr (/2 toggle) | clk: NOT(ch3_ftick) | One-ch3_2mhz-cycle self-clearing pulse ch3_frst; also async-reset by triggers |
ch3_restart | Trigger synchroniser q | dffr | FABO (= NOT(ch3_2mhz)) | Captures the NR34-bit-7 write on ch3_2mhz↓ — opposite-phase sample edge to CH1/CH2 |
| HERA | CH3 divider load enable (active-low) | nor2 | ch3_frst, ch3_restart | Fanned through jera/kaso/kyko (fan-out split only) |
The period source is the latched NR33/NR34 bits (drlatch_ee cells
written by the apu_wr ∧ ff1d/ff1e strobes). There is no sweep adder in
the path. The reload is level-sensitive exactly as on CH1/CH2.
GUGU's disable side (FUVO) is a held level, so restoring the DAC (NR30
bit 7 back high) does not restart the divider. Only a trigger clears
ch3_fdis, one ch3_2mhz edge after the ch3_restart pulse (measured).
While FUVO holds the disable level it pins GUGU's q_n, so a trigger
arriving during a DAC-off window leaves ch3_fdis set throughout.
Wave-position counter
A 5-bit ripple counter clocked by ch3_frst falling — one step per
overflow. Bit 0 selects the nibble; bits 1–4 drive the wave-RAM byte
address.
| Gate | Role | Type | Clock / Trigger | Notes |
|---|---|---|---|---|
| DERO | CH3 wave-position counter clock | not_x1 | NOT(ch3_frst) | Rising edge = ch3_frst falling |
| EFAR | CH3 wave-position bit 0 (wave_nibble_sel) | dffr | DERO | Toggle; reset by ETAN |
| ERUS / EFUZ / EXEL / EFAL | Bits 1–4 (wave-RAM byte address) | dffr | bit-to-bit ripple | Reset by ETAN; EFAL's q_n clocks FETY |
| ETAN | Wave-position counter reset (active-low) | nor2 | ch3_restart, FETY | Clears the counter on trigger or wrap |
| FETY | CH3 counter-wrap interlock (/2 toggle) | dffr | EFAL↓ (counter wrap 31→0) | Holds the counter at 0 for one extra overflow; cleared by the next ch3_frst↑ |
- Triggers reset the wave-position counter to 0 —
ch3_restartis an input to ETAN. Unlike the duty counter, the wave-position counter does not survive a retrigger. (This asymmetry is the netlist's answer to Pan Docs' CH3-vs-pulse retrigger contrast.) - The wrap interlock (FETY) holds the counter at 0 for one extra overflow after wrapping 31→0 before the next count resumes.
The trigger synchroniser and its delay
An NR34 trigger traverses four stages — with a fifth cell shaping the pulse:
| Stage | Cell | Type | Clock / Enable | Role |
|---|---|---|---|---|
| 1 | GAVU | drlatch_ee | enable: apu_wr ∧ ff1e | Write-strobe latch — captures the trigger bit at T3/T4 of the write M-cycle |
| 2 | FOBA | dffr | apu_phi | M-cycle-boundary DFF |
| 3 | GOFY | nor_latch | — | Tag latch |
| 4 | GARA | dffr | ch3_2mhz↓ | q is ch3_restart |
| 5 | GYTA | dffr | one edge behind GARA | Async-resets GARA — shapes the pulse to exactly one ch3_2mhz cycle |
Measured end to end (dmg-sim measurement): write commits at T4-mid;
boundary DFF at T1 of the next M-cycle; ch3_restart↑ on the next
ch3_2mhz↓ (T2 under quickboot phase); cleared two T-cycles later. The
aggregate from write strobe to first overflow at period 0x7FF is 9–10
T-cycles. The synchroniser accounts for 6–8 of those T-cycles, depending
on phase. That is the silicon content of the community's "+6 T-cycle
trigger delay". The T2-vs-T4 placement is apu_reset-locked, like every
other APU phase (APU clocks).
Wave RAM: address mux, read strobe, CPU access
The wave RAM's 4-bit address is muxed between the CPU bus and the
wave-position counter's bits 1–4. ch3_active steers that mux.
ch3_active is a DFF re-timed copy of the trigger-armed FOZU latch, which
FYGO = OR3(DAC-off, GEDO length-stop, power-off) clears.
CH3's own byte read is strobed by wave_data_latch. That strobe is
ch3_frst pushed through a three-DFF apu_4mhz synchroniser (BUSA → BANO
→ AZUS) — the strobe chain. Measured: the strobe rises ~1.5 T-cycles
after ch3_frst↑ and stays high ~1 T-cycle. The captured byte holds on
eight drlatch_ee cells — the wave data latch — until the next strobe.
Those cells are CYFO CESY BUDY BEGU (bits 0–3) and CUVO CEVO BORA BEPA
(bits 4–7). Playback from the wave data latch is combinational. An
inverting nibble mux steered by wave_nibble_sel feeds the NR32 volume
shift, which feeds the ch3_active output gates (BARY BYKA BOPA BELY).
Those gates drive the channel's 4-bit DAC input.
The wave data latch's only reset is ACOR = NOT(apu_reset), an NR52
power-off. BAMA, the strobe chain's reset, is the same signal. Clearing
NR30 bit 7 raises ch3_amp_en_n. That signal's complete fan-out is FUVO
and FYGO (the divider-freeze and FOZU clears), the global DAC-off term
(TACE), and the DAC power gate. ch3_amp_en_n never reaches the wave data
latch or the strobe chain. Measured across a stop → NR30-on → retrigger
sequence at period $700: the pre-stop byte survives on the cells
throughout. The only zeroing at the DAC input is the ch3_active gate.
Once the retrigger re-arms ch3_active, the DAC input replays the stale
nibble for the full first sample period, until the first wave_data_latch
strobe reloads byte 0. That first sample period is one 512-T overflow
interval plus the strobe chain, measured at 257 ch3_2mhz cycles ≈ 514
T-cycles.
With ch3_active=1, a CPU read or write of FF30–FF3F ignores the CPU's
address entirely — the mux is on the counter side. Reads return CH3's
current byte when the CPU's strobe overlaps the wave_data_latch window,
and an open bus value otherwise. Writes land unconditionally at CH3's
current byte. The SRAM accepts a write whenever the CPU write strobe is
high, with no gating by wave_data_latch.
A hardware-verified nine-subtest sweep pins the write path (samesuite
channel_3_wave_ram_locked_write, dmg-sim measurement). Each NOP of delay
slides the landing byte by exactly one position. All nine landing
addresses match the test's expected pattern. The same sweep pins a gating
subtlety. Between subtests the DAC is off, ch3_fdis freezes the divider,
and the strobe chain is idle. The retrigger corruption (below)
therefore does not fire.
Retrigger corruption: a 4-byte row copy
Triggering CH3 while it is reading corrupts wave RAM. The netlist's SRAM produces a 4-byte row copy on DMG, not the single byte the widely-quoted rule describes.
When
ch3_restart↑ lands in the window where the SRAM bit-line precharge is off —(AZUS | AZET) = 1, spanning fromwave_data_latch↑ to one T-cycle past its fall (≈ 2 T-cycles per overflow) — then withrow = wave_position >> 3:ram[0..3] ← ram[row*4 .. row*4+3], other bytes unchanged. Row 0 is naturally a no-op (source = destination — no special case).
The mechanism, in the SRAM cells: word lines are sticky until the word-line driver precharges. The trigger's address snap to 0 therefore leaves the old row's word line high while row 0's rises. The bit lines still hold the old row's data, because precharge is off. The write-back loop then commits that data to every enabled row, so the whole source row lands in row 0. Verified across 12 retrigger events spanning rows 1–3 and both nibble phases (dmg-sim measurements with the full SRAM model).
Evaluate (AZUS | AZET) at the ch3_restart capture edge; if set, do the
row copy. And gate the divider on ch3_fdis, or the window will be open
when hardware has it closed.
Post-boot state
The boot ROM never touches CH3: divider, wave-position counter, overflow
chain, and ch3_restart all at their reset defaults; ch3_fdis=1; DAC off.
Wave RAM itself has no reset path — it survives NR52 power cycles, and
its cold-boot content is undefined on silicon. See
post-boot state.