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.
- 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:
- 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_multiplerewrites 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). - 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_wxexercises 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_changefamily): 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_clkbranch stays silent. Measured end to end: the boundary's PANY/RYFA/SEKO/TEVO/NYXU all slip exactly +1.000 dot (dmg-sim measurement).