The retirement test退役測試 Three arms, and the one that must fail三臂,以及那個必須失敗的
The protocol for retiring a shim onto a mechanism is a three-arm experiment:
把 shim 退役到機制的協定是一個三臂實驗:
| Arm臂 | Config設定 | Expected預期 | Proves證明 |
|---|---|---|---|
| baseline | shim onshim 開 | PASS | the known-good reference已知良好基準 |
| control | shim off, no mechanismshim 關、無機制 | FAIL | the shim was load-bearingshim 是承重的 |
| mechanism | shim off, mechanism onshim 關、機制開 | PASS | the mechanism does its job機制做到了它的工作 |
The control arm is the whole game. If it fails, the shim mattered, and a passing mechanism arm is a genuine retirement (this is how io_db decay, DmcLatch, and AluLatch were retired — their controls fail on ppu_open_bus, 7-dmc_basics #19, and 03-immediate). But if the control passes — if the test is green with the shim removed — the experiment is inconclusive. You cannot prove a mechanism replaced something that, on this test, was doing nothing.
對照臂就是全部關鍵。它失敗,shim 就有意義,而機制臂通過就是真正的退役(io_db 衰減、DmcLatch、AluLatch 就是這樣退役的 —— 它們的對照在 ppu_open_bus、7-dmc_basics #19、03-immediate 上失敗)。但如果對照通過 —— 拔掉 shim 測試還是綠的 —— 實驗就無結論。你沒辦法證明機制取代了一個「在這顆測試上根本沒做事」的東西。
The data資料 Which controls actually fail哪些對照真的失敗
Every shim with a kill switch, run against its isolated test with the shim removed:
每個有 kill switch 的 shim,在它的孤立測試上拔掉 shim 跑一次:
| Shimshim | Isolated test孤立測試 | Control對照 | Decidable?可判? |
|---|---|---|---|
| io_db decay | ppu_open_bus (blargg) | FAIL(3) | yes → RETIRED是 → 已退役 |
| DmcLatch | 7-dmc_basics (blargg) | FAIL(#19) | yes → PROVEN是 → 已證 |
| AluLatch | 03-immediate (blargg) | FAIL(1) | yes → PROVEN是 → 已證 |
| OpenBus last-byte | AC OpenBus | FAIL(1) | yes → but CEILING是 → 但天花板 |
| DL | AC OpenBus / ppu_open_bus | PASS | no否 |
| OamBlankEdge | AC OAMCorruption / StaleSprite | PASS | no否 |
| dot-339 | AC StaleSpriteShiftRegs | PASS | no否 |
| BGSerialIn | AC_BGSerialIn: PASS · AC_BGSerialInReal (hunt) | FAIL (0/1) on ...Real...Real 上 FAIL(0/1) | yes → PROVEN是 → PROVEN |
| Dmc4015Abort | AC Explicit/ImplicitAbort | PASS | no否 |
| OamDmaPpuBus | test_ppu_read_buffer #67 (blargg) | FAIL(#67) | yes → PROVEN (M4·P1)是 → PROVEN(M4·P1) |
| even_odd (PpuWriteDelay) | 10-even_odd_timing (blargg) | FAIL(#3) "clock skipped too late"FAIL(#3)「clock skipped too late」 | yes → PROVEN (K=1); 09 undecidable是 → PROVEN(K=1);09 不可判 |
| Dbl2007 | #67: PASS · double_2007_read (hunt) | FAIL (CRC) on double_2007_readdouble_2007_read 上 FAIL(CRC) | yes → PROVEN (M4·P1)是 → PROVEN(M4·P1) |
--reset-hold-extra 1 on every test), so once the baseline was re-certified (AC 141/141 + 147 146/1) the whole table was re-run at K=1 (28 arms). The re-run overturned this section's original headline — that even_odd and Dbl2007 were hc-identical spectators (shim armed, firing window never opening). At K=1: even_odd's control FAILs on 10-even_odd_timing (#3, "clock skipped too late") — the shim is load-bearing there, the M6×M3 mechanism replaces it, and even_odd is now PROVEN. Yet its other isolated test, 09-even_odd_frames, still passes without the shim. The very same shim is undecidable on one ROM and decidable on another — the thesis of this page in a single row: decidability is a property of the test, not the shim. Dbl2007's #67 control still passes (still undecidable) but is no longer bit-identical — removing the shim shifts the trajectory, so even the "spectator" reading was an alignment artifact. One methodological confession does survive the re-run: our first OamDmaPpuBus control used blargg's oam_read — which has no $4014 DMA, so the shim could never fire (a void arm); the correct #67 "DMA + PPU bus" control FAILs(#67) at K=1, so OamDmaPpuBus is decidable. Lesson banked: read the runner's recipe (K, env, per-ROM flags) before trusting any isolated score.
證據等級 —— 以及一個 K=0 → K=1 更正。這一輪最初跑在 K=0 開機對齊,而戰役協定每測釘 K=1(--reset-hold-extra 1),所以基礎重新認證後(AC 141/141 + 147 146/1)整張表在 K=1 下重跑(28 臂)。重跑推翻了本段原本的頭條 —— 說 even_odd 和 Dbl2007 是hc 逐位相同的旁觀者(shim 掛著、開火窗從沒打開)。K=1 下:even_odd 的對照在 10-even_odd_timing 上 FAIL(#3「clock skipped too late」)—— shim 在那裡承重,M6×M3 機制取代得了,even_odd 現在是 PROVEN。但它另一顆孤立測試 09-even_odd_frames,拔了 shim 仍然過。同一顆 shim 在一顆 ROM 上不可判、在另一顆上可判 —— 本頁論點濃縮成一列:可判性是測試的性質,不是 shim 的。Dbl2007 的 #67 對照仍通過(仍不可判),但不再逐位相同 —— 拔 shim 會位移軌跡,所以連「旁觀者」的說法也是對齊假象。有一個方法論自白撐過了重跑:第一版 OamDmaPpuBus 對照用了 blargg 的 oam_read —— 它沒有 $4014 DMA,shim 永遠開不了火(作廢臂);正確的 #67「DMA + PPU bus」對照在 K=1 下 FAIL(#67),所以 OamDmaPpuBus 可判。教訓入帳:信任任何孤立成績前,先讀 runner 的配方(K、env、per-ROM 旗標)。
The pattern規律 It is not blargg vs AccuracyCoin不是 blargg vs AccuracyCoin
The tempting reading is "blargg tests are decidable, AccuracyCoin's aren't." That is almost right but wrong in an instructive way: AC OpenBus is decidable (its control fails). The real distinction is deeper — does the isolated test actually exercise the scenario the shim defends?
誘人的讀法是「blargg 測試可判、AccuracyCoin 的不可判」。那差不多對,但錯得很有教育意義:AC OpenBus 可判(它的對照失敗)。真正的區別更深 —— 孤立測試有沒有真的踩到那個 shim 防守的場景?
- Decidable shims defend a scenario the isolated ROM runs on its own: a DMC channel plays (7-dmc), an immediate op executes (03-immediate), the open bus is read after a known write (AC OpenBus). Remove the shim and that single ROM breaks — clean signal.
- 可判的 shim 防守的是孤立 ROM 自己就會跑的場景:一個 DMC 聲道播放(7-dmc)、一個立即定址指令執行(03-immediate)、已知寫入後讀 open bus(AC OpenBus)。拔掉 shim,那一顆 ROM 就壞 —— 乾淨訊號。
- Undecidable shims defend a scenario that only arises from timing interaction across the suite. dot-339, even_odd, ALERead, BGSerialIn — the whole cross-chip phase family — were diagnosed and fixed in-suite, where one test's rendering state, another's sprite setup, and a precise scanline phase line up. The single-test wrapper boots, runs its own sub-test, and passes: it never reconstructs the fragile alignment. The DMA-abort family is the same — the abort only bites when a specific DMA is in flight at a specific moment the isolated wrapper doesn't stage.
- 不可判的 shim 防守的場景只在套件內的時序互動下出現。dot-339、even_odd、ALERead、BGSerialIn —— 整個跨晶片相位家族 —— 都是在套內被診斷和修好的,那時一個測試的渲染狀態、另一個的精靈設定、和精確的掃描線相位剛好對上。單測試包裝開機、跑自己的子測試、然後通過:它從來沒有重建那個脆弱的對齊。DMA-abort 家族一樣 —— 廢止只在特定 DMA 在特定時刻進行中才咬,而孤立包裝不會擺出那個場景。
What this means這代表什麼 The verification frontier moves in-suite驗證前線移到套內
- The isolated protocol has a ceiling, and we found it — after correcting where it sits. Through it: io_db retired; DmcLatch, AluLatch, even_odd and (via the hunt) BGSerialIn proven; OpenBus, OamDmaPpuBus and Dbl2007 shown decidable — Dbl2007 and OamDmaPpuBus now both PROVEN (the M4·P1 mechanism's ClampBus + QueuedDrive rows replace them hc-identical, on double_2007_read and #67), OpenBus a documented CEILING. Only four interaction shims remain beyond it — DL, OamBlankEdge, dot-339, Dmc4015Abort — whose controls pass on every ROM tried. The K=0 "hc-identical spectator" pair turned out to be an alignment artifact: re-run at K=1, even_odd's control fails (it crossed over into decidable, then proven) and Dbl2007's is no longer bit-identical. That boundary is not a wall in the mechanisms — it is a limit of the measuring instrument, and it moved the moment we fixed the instrument's alignment.
- 孤立協定有天花板,而我們找到了 —— 在更正它的位置之後。透過它:io_db 退役;DmcLatch、AluLatch、even_odd 與(靠獵捕)BGSerialIn 已證;OpenBus、OamDmaPpuBus 與 Dbl2007 證明可判 —— Dbl2007 與 OamDmaPpuBus 現雙雙 PROVEN(M4·P1 機制的 ClampBus + QueuedDrive 兩列在 double_2007_read 與 #67 上 hc 逐位相同地取代它們)、OpenBus 是有文件的天花板。只剩四顆互動 shim 在它之外 —— DL、OamBlankEdge、dot-339、Dmc4015Abort —— 試過的每顆 ROM 對照都會過。K=0 的「hc 逐位相同旁觀者」那一對其實是對齊假象:K=1 重跑後,even_odd 的對照失敗(它跨進了可判、進而已證),Dbl2007 也不再逐位相同。那條界線不是機制的牆 —— 是量測儀器的極限,而我們一修好儀器的對齊,它就移動了。
- The next instrument is the frame-windowed in-suite run. Discriminating an interaction shim means running it in-suite with the shim removed — but not the whole ~8-hour suite. AprNes runs the full 141-test AC in ~20 s; our --ac-frame-map addition records the frame each sub-test's result byte ($0400-$04FF) lands, so S1A confirms one sub-test by running (or snapshot-resuming) just its ~[F(i−1), F(i)] window. An early defender — a controller-read test near frame 1500 — is a couple of hours instead of the full 4925; the earliest are minutes. This campaign is now applying that windowed range-run to the four remaining shims (DL, OamBlankEdge, dot-339, Dmc4015Abort), cheapest window first — the map budgets the run, the range-run returns the verdict.
- 下一個儀器是「frame 窗」的套內跑。鑑別一顆互動 shim,意思是拔掉 shim 在套內跑它 —— 但不必跑整個 ~8 小時套件。AprNes ~20 秒跑完全 141;我們加的 --ac-frame-map 記錄每個子測試結果 byte($0400-$04FF)落地在哪一幀,於是 S1A 只要跑(或 snapshot-resume)那顆子測試的 ~[F(i−1), F(i)] 窗就能確認。早段防守者 —— 例如 frame ~1500 的控制器讀取測試 —— 是兩三小時而非跑滿 4925;最早的只要幾分鐘。這輪 campaign 正把這個「窗內 range-run」用在剩下四顆(DL、OamBlankEdge、dot-339、Dmc4015Abort),從最便宜的窗開始 —— 地圖排預算,range-run 給判決。
- Honesty is the deliverable — including when a re-run overturns us. The undecidable shims stay, clearly labelled "mechanism ready" — not quietly deleted or falsely claimed retired. And when a re-check corrects a verdict, the page changes in public: even_odd was labelled a hc-identical spectator here; the K=1 re-run proved its control fails and it moved to PROVEN, with the old reading kept as the lesson. When the in-suite run happens, each remaining shim will resolve to a genuine retirement or a documented residue. Until then, the map — and its corrections — is the result.
- 誠實就是交付物 —— 包括重跑打臉我們的時候。不可判的 shim 留著、清楚標「機制就緒」—— 不是悄悄刪掉或謊稱退役。而當重確認更正了一個判決,頁面就公開改:even_odd 本來在這裡被標成 hc 逐位相同的旁觀者;K=1 重跑證明它的對照會失敗,它移到了 PROVEN,舊讀法留著當教訓。等套內全跑發生,每一顆剩下的 shim 會解析成真正的退役或有文件的殘留。在那之前,這張地圖 —— 連同它的更正 —— 就是結果。
$0400 + i) the moment that sub-test finishes. So the completion frame of test i is simply the frame byte i first goes non-zero — no screen parsing, no heuristics. AprNes (a fast reference emulator: ~20 s for the whole 141-test suite, versus the switch-level engine's ~8 h) watches all 141 result bytes every frame — that is our --ac-frame-map addition — and dumps the table (offset, addr, first_frame). Test i's window is [F(i−1), F(i)] + a small safety margin: AprNes and the switch-level engine settle into slightly different boot alignments and drift ~100 frames over the full run, so the margin absorbs it while the sequence stays identical. To confirm a shim in-suite the switch-level engine then runs from frame 0 to F(i)+margin (early-stop) — or, for a late test, resumes from a snapshot just before F(i−1) — and reads byte i: base vs shim-off, decidable iff the byte flips. Clean-resume caveat: a snapshot taken under one config is only valid to resume under another if the shim/mechanism has not fired before the resume point — a shim that fires every scanline (dot-339) bakes its effect into the snapshot, so it needs a from-scratch early-stop, not a resume. The window budgets the run; the range-run returns the verdict.
這個 frame 預算是怎麼量出來的 —— 機制。AccuracyCoin 的設計是:每個子測試一完成,就把它的結果碼寫進一個固定的 CPU-RAM byte($0400 + i)。所以第 i 題的完成幀,就是 byte i 第一次變非零那一幀 —— 不用解析畫面、不用啟發式。AprNes(快速參考模擬器:全 141 題只要 ~20 秒,對比開關級引擎的 ~8 小時)每一幀掃全部 141 個結果 byte —— 這就是我們加的 --ac-frame-map —— 然後 dump 出表(offset, addr, first_frame)。第 i 題的窗 = [F(i−1), F(i)] + 小安全值:AprNes 與開關級引擎會落進略微不同的開機對齊、整場漂移 ~100 幀,安全值吸收它,而順序完全一致。要套內確認一顆 shim,開關級引擎就從第 0 幀跑到 F(i)+margin(早停)—— 或對晚段的題,從 F(i−1) 前的快照 resume —— 讀 byte i:base vs 拔 shim,byte 翻了就是可判。乾淨 resume 的但書:某配置下存的快照,要用另一配置 resume 才有效,前提是那顆 shim/機制在 resume 點之前沒開過火 —— 每條掃描線都開火的 shim(dot-339)會把效果烤進快照,所以它得從頭早停、不能 resume。窗排預算,range-run 給判決。