Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Window Edge Cases

The window trigger model (window control) has three edge cases. At the right edge (WX ≥ ~162) the cascade either never fires or fires without observable effect. A second activation on one scanline needs both an LCDC.5 toggle and a WX rewrite. A NUKO pulse landing inside a PANY window slips the BG drain cascade by one dot at that boundary — the NUKO/PANY slip.

At a glance

  • WX = 167 never fires: PX terminates at 167 on the same dot XUGU fires, and TADY resets PX before any further advance.
  • WX ∈ [~162, 166] fires but is observationally inert; measured at WX=166, Mode 3 length is identical to the no-window baseline.
  • A second activation on one scanline needs an LCDC.5 toggle (a PYNU fall) and a WX rewrite ahead of PX.
  • A NUKO pulse landing inside a PANY window slips the whole SEKO → TEVO → NYXU chain by one dot for that boundary.
  • NUKO is gated by REJO but not by LCDC.5: with WX ≡ 7 (mod 8), the slip fires even while no window renders.

The right edge

WX = 167 never fires. PX terminates at 167 on the same dot XUGU fires, and TADY resets PX before any further advance. No NUKO rise is possible.

WX ∈ [~162, 166]: the cascade fires but is observationally inert. Measured at WX=166 (dmg-sim measurement, patched gbmicrotest win0_a ROM; zero variance across 368 firing scanlines, all values sim-dots from AVAP↑):

StageΔ (dots)
NUKO↑ (PX = 166)+172.038
PYCO↑ / NUNU↑ / PYNU↑+172.481 / +172.982 / +172.985
NUNY↑ / MOSU↑+172.988 / +172.989
NUKO↓ / XUGU↓ (PX = 167)+173.040 / +173.042
WODU↑+173.044
XYMU↑ (Mode 3 ends)+173.481
NOPA captures → MOSU↓+173.482

Mode 3 length is identical to the no-window baseline on the same trace. The MOSU-driven NYXU pulse executes: the BG counter resets, steps 1–7 of the sequence all fire, and NOPA captures. But XYMU sets ~0.5 dots after MOSU↑, and the combinational POKY-clear switches the pipeline off before any SACU edge can advance the fresh fetch. The activation is therefore structurally executed but observationally inert. The +6-dot penalty term does not apply once MOSU lands inside the [WODU↑, XYMU↑] closing window.

Right-edge window + sprite collision (WX=166, sprite at OAM X=167, gambatte m2int_wxA6_spxA7 ROM, dmg-sim measurement): on steady-state firing scanlines the window cascade adds nothing, inert as above. The sprite adds exactly +6.000 dots — the right-edge collapse of the single-sprite penalty (sprite pipeline). The one-off first firing scanline (LCDC.5 just enabled, NOPA still 0) measures +17.0 dots. That is the standard 11-dot first-sprite penalty plus the 6-dot core. The MOSU↑ NYXU pulse induces that extra cost by re-firing the fetch, and only on the cascade's maiden activation.

Multi-activation within one scanline

A mid-Mode-3 LCDC.5 1→0 write raises XOFO and clears PYNU on the same dot. NOPA captures the cleared PYNU one ALET edge later, re-opening NUNY's gate. PYCO and NUNU are not reset by XOFO. They keep propagating any NUKO pulse regardless of LCDC.5. PYNU's nor_latch inputs are level-sensitive, so what happens at a subsequent LCDC.5 0→1 restore depends on NUNU's state at the XOFO↓ edge:

  1. NUNU=0 at restore — the match fired long before the disable and has drained. PYNU stays 0. A new activation needs a fresh NUKO rise. Under fixed WX that is impossible same-line, because PX is monotonic, so the CPU must rewrite WX ahead of PX. This is the structurally-new "multi-fire" case. Mealybug m3_lcdc_win_en_change_multiple rewrites WX 24 → 120 between the toggles, and produces two independent MOSU pulses per scanline (dmg-sim measurement: second activation at NUKO↑ +132.013, PYNU↑ +132.996).
  2. NUNU=1 at restore — the match fired inside the disabled window. The restore lands within the ~1-dot NUNU-high pulse (≈ [NUKO↑+1.0, NUKO↑+2.0]). PYNU sets combinationally at XOFO↓ — a deferred completion of the first activation, not a new one. Mealybug m3_lcdc_win_en_change_multiple_wx exercises exactly this. On LY=16 and LY=44 the restore lands inside the NUNU pulse, and MOSU fires within a gate delay of XOFO↓. On LY=22 the match falls between the off-pulses, and the standard sequence runs untouched (dmg-sim measurement).

The window line counter (VYNO → VUJO ripple) clocks on PYNU falling edges. A scanline with N intra-line LCDC.5 1→0 transitions advances the counter N+1 times: once per disable, once at the end-of-line ATEJ. Under WX-only rewrites with LCDC.5 held high the counter advances exactly once per scanline. PYNU's set input saturates (already 1), and NUNY stays closed (NOPA holds). A second NUNY/MOSU pulse is therefore impossible without a PYNU fall.

The NUKO/PANY slip

NUKO has exactly two netlist consumers: PYCO (the capture chain above) and PANY — the BG drain-detector input (BG pipeline). PANY produces the subtlest window behaviour on the DMG.

PANY pulses high for ~1 dot at every tile-boundary drain — the PANY window. A NUKO pulse landing inside the PANY window splits that pulse across RYFA's capture edge. PANY is forced low at NUKO↑, released at NUKO↓, and then falls naturally one dot late. RYFA therefore captures the late half, and the entire SEKO → TEVO → NYXU chain slips by one dot for that boundary. The slip delays the BG-shifter parallel load unconditionally; that branch has no window gating. The slip also delays the window tile-X increment, but only when in_window=1.

  • WX-rewrite form (Mealybug m3_wx_4_change family): a mid-Mode-3 WX rewrite can land PX==WX inside the PANY window. Such a rewrite produces the documented pair-shuffle pattern at recurring tile boundaries. Measured (dmg-sim measurement): three perturbed scanlines per batch, with NUKO arriving in the last sub-dot of the PANY window. Pulses outside the PANY window do nothing. The simulated render is bit-identical to the hardware reference, so the mechanism is fully on-die.
  • Armed-but-disabled form (no rewrite needed): NUKO is gated by REJO but not by LCDC.5. The window can be armed and then disabled (REJO=1, LCDC.5=0). With WX ≡ 7 (mod 8) placing PX==WX at a tile boundary, the natural sweep then fires the same slip. The BG shifts one pixel right, from that column to the line's end. The shift repeats every scanline until VBlank clears REJO. The window itself never renders: PYNU is held reset, so the wx_clk branch stays silent. Measured end to end: the boundary's PANY/RYFA/SEKO/TEVO/NYXU all slip exactly +1.000 dot (dmg-sim measurement).

Pitfall: the slip needs no rendered window

REJO alone arms NUKO. Disabling LCDC.5 does not disarm the coupling; only VBlank's REPU does.