Where phase can hurt相位會咬人的地方

Toolbox study #6 (mechanism M6). The whole cross-chip timing family — dot-339, even_odd, ALERead, BGSerialIn — is one shape: a CPU write, delayed on the die by ~24 hc, meets a 2C02 comparison against a position counter, and the zero-delay engine compares it one dot early. This census walks the interface downstream and enumerates every counter-comparator site: 66 phase-sensitive interfaces, and the four campaign bosses re-found by pure structure.

工具箱研究 #6(機制 M6)。整個跨晶片時序家族 —— dot-339、even_odd、ALERead、BGSerialIn —— 是同一個形狀:一個 CPU 寫入,在晶粒上被延遲 ~24 hc,撞上 2C02 對位置計數器的比較,而零延遲引擎早一個 dot 就比了。這份普查沿著介面往下游走,列舉每一個計數器比較器站點:66 個相位敏感介面,四個戰役魔王被純結構重新找到。

M6 · power-on state & phase m6_interface_census.py JSON 2026-07-18

The problem問題 One dot early, four times over早一個 dot,發生四次

A CPU write to $2001 (rendering on/off) or $2007 (VRAM access) does not take effect on the PPU instantly: the signal crosses the package, the board trace, and the receiver's synchronizer — about 24 hc, three dots (M3 ranked these the slowest nets on the die). The 2C02 then compares the current state against a position counter — "are we at dot 339 yet? at hpos%8==7? in the visible frame?" — and acts on the answer. When the engine erases the 24 hc, the write's effect lands one comparison too early, and a per-dot decision flips. The campaigns hit this four times (dot-339, even_odd, ALERead, BGSerialIn) and fixed each with a delay shim. M6 asks: where else could this happen? Enumerate every site where an interface-controlled signal meets a position counter.

CPU 寫入 $2001(渲染開關)或 $2007(VRAM 存取)不會立刻在 PPU 生效:訊號要穿過封裝、板線、接收端的同步器 —— 大約 24 hc、三個 dot(M3 把這些排成晶粒上最慢的網)。2C02 接著把當前狀態拿去和位置計數器比 —— 「到 dot 339 了嗎?到 hpos%8==7 了嗎?在可見幀內嗎?」—— 然後根據答案行動。當引擎把 24 hc 抹掉,寫入效果早一次比較就落地,一個 per-dot 決策就翻了。戰役撞過這個四次(dot-339、even_odd、ALERead、BGSerialIn),每次用延遲 shim 修。M6 問:還有哪裡會發生?列舉每一個介面控制訊號撞上位置計數器的站點。

The method方法 The P2 funnelP2 漏斗

P2 funnel
173 interface nodes → 8,092 reached → 203 counter-comparators → 66 phase-sensitive. The funnel narrows to an annotatable list.173 介面節點 → 8,092 抵達 → 203 計數器比較器 → 66 相位敏感。漏斗收窄成一張可標註清單。

Results結果 The bosses re-find themselves魔王自己現身

Ranked by fan-in cone (how many decisions each gates), the top phase-sensitive interfaces read like the campaign's diary:

按 fan-in 錐排序(每個閘控多少決策),最頂端的相位敏感介面讀起來像戰役日記:

Node節點fan-inWhat it decides它決定什麼
hpos_eq_65_and_rendering32sprite evaluation start精靈評估起點
hpos_eq_339_and_rendering29dot-339 — the StaleSprite bossdot-339 —— StaleSprite 魔王
hpos_eq_320_to_335_and_rendering17sprite fetch window精靈取圖窗
hpos_mod_8_eq_0_or_1_and_rendering13BGSerialIn — the shifter-reload boundaryBGSerialIn —— 移位器 reload 邊界
in_visible_frame_and_rendering12the master render gate主渲染閘

The scan re-found three of the four bosses from pure structure — dot-339, BGSerialIn (the hpos%8 reload boundary), and ALERead (the io_ce interface) all fall out of "interface-fed ∩ counter-comparator", with no hand-list. The fourth, even_odd, is named (skip_dot) but is the family's edge case: it mixes a frame-parity toggle rather than a $2001 enable, so it sits just outside the pure enable×counter intersection — correctly, since it is the one M6 boss whose trigger is not an interface arrival but a frame counter's least significant bit.

掃描只靠純結構就重新找到四個魔王的三個 —— dot-339、BGSerialIn(hpos%8 reload 邊界)、ALERead(io_ce 介面)全都從「介面餵到 ∩ 計數器比較器」掉出來,沒有手寫清單。第四個 even_odd 有名字(skip_dot)但是家族的邊緣案例:它混的是幀奇偶翻轉而非 $2001 致能,所以它剛好落在純 致能×計數器 交集之外 —— 這是對的,因為它是唯一一個觸發不是介面抵達、而是幀計數器最低位元的 M6 魔王。

anchor validation
Validation against the four bosses: three re-found structurally, the fourth (even_odd) correctly outside the enable×counter shape.對四個魔王驗證:三個結構重找,第四個(even_odd)正確地落在 致能×計數器 形狀之外。

So what所以呢 The delay island's exact perimeter延遲島的精確周界

Honest limits誠實極限 What this census cannot say這份普查說不了的事