When the netlist isn't the whole truth當網表不是全部的真相

What a brutal 141-test hardware suite taught us about the semantic ceiling of switch-level simulation — and what MOSSIM II would and wouldn't have fixed.一套 141 顆的兇殘硬體測試,教會我們開關級模擬的語意天花板在哪 —— 以及 MOSSIM II 能救哪些、救不了哪些。

1 · The belief we started with1 · 我們一開始的信念

A switch-level netlist looks like the ultimate ground truth: every transistor traced from die photographs, every wire's connectivity captured. Run the transistors, and surely you get the chip — not an approximation of it, the thing itself. That belief is what makes projects like Visual6502 feel magical, and it carried this project through building a bit-exact engine that executes the whole NES (2A03 + 2C02, ~30,000 transistors) at ~140K half-cycles/s on one core.

開關級網表看起來像終極的真相:每顆電晶體都從 die 照片描下來,每條線的連通性都被捕捉。把電晶體跑起來,得到的當然就是晶片本身 —— 不是近似,是本尊。這個信念正是 Visual6502 這類專案令人著迷的原因,也支撐著本專案做出一顆 bit-exact 引擎,在單核上以約 140K 半週期/秒跑完整台 NES(2A03 + 2C02,約三萬顆電晶體)。

The engine's semantics are the Visual6502 family's: propagate every change through the connected group of conducting transistors until the network is quiescent, and resolve each group with a fixed priority — a path to GND wins outright, then VDD, then external drives, then pull-ups, and a group with none of those keeps its previous state (charge storage). One flags-OR and one 256-entry table lookup per group: brutally fast, and faithful — to the algorithm's own model of the chip.

引擎的語意承襲 Visual6502 家族:每個變化沿導通電晶體構成的連通群傳播,直到網路靜止;每個群用固定優先級決議 —— 通往 GND 的路徑無條件全勝,其次 VDD、再次外部驅動、再次 pull-up,全都沒有的群保持前態(電荷儲存)。每群一次 flags-OR、一次 256 格查表:暴力地快,而且忠實 —— 忠實於演算法自己心中的那顆晶片

2 · The adversary: an unattended, hardware-true test suite2 · 對手:無人值守的硬體真值測試套件

AccuracyCoin is a 141-test NES accuracy suite whose expected values are verified on real consoles. We built an unattended fork that runs all 141 back-to-back with no human input. It is qualitatively crueler than the classic test ROMs: it executes code from the floating data bus, assembles instructions out of PPU bus remanence and mid-fetch DMC DMA overwrites, cancels DMAs in flight, and reads registers at the exact cycle where analog corner cases live. Older suites never pushed the model there; AccuracyCoin does so deliberately, test after test.

AccuracyCoin 是一套 141 顆的 NES 精確度測試,期望值全在真機上驗證過。我們做了一個無人值守分支,一口氣連跑 141 顆、全程不需人手。它比經典測試 ROM 兇殘一個量級:它直接從浮接的資料匯流排執行程式碼、用 PPU 匯流排殘值加上取指中途的 DMC DMA 覆寫來拼裝指令、把進行中的 DMA 攔腰斬斷、在類比邊界行為出沒的那個精確週期去讀暫存器。舊測試從不把模型逼到這裡;AccuracyCoin 一顆接一顆,故意逼。

The scoreboard after nine forensic campaigns: the engine executes all 141; the deviations traced to five root-cause categories. The distribution is the finding: exactly one genuine engine bug in the whole campaign, exactly one missing transistor in the data — and nearly everything else lives in what the model, by construction, cannot see.

九場取證戰役後的記分板:引擎能執行全部 141 顆;偏差追到五類根因。這個分佈本身就是研究發現:整場戰役恰好 一個引擎真 bug、恰好一顆資料裡缺失的電晶體 —— 其餘幾乎全部住在模型天生看不見的地方。

3 · Category A: the four blind spots of a binary, quiescent model3 · A 類:二值靜止模型的四個盲區

The core algorithm quantizes two physical dimensions away — voltage becomes {0, 1}, time becomes "settled or not". Four distinct silicon behaviours live precisely in what got quantized out, and each was caught red-handed by a specific test:

核心演算法把兩個物理維度量化掉了 —— 電壓變成 {0, 1},時間變成「靜止了沒」。有四種矽晶行為恰好住在被量化掉的地方,而且每一種都被特定測試當場抓獲:

Blind spot盲區The physics物理Caught by被誰抓到
A1 Ratioed drive fights比例式驅動打架 Two drivers pull one wire; silicon resolves by resistance ratio. The model has no strength inside a priority class — GND simply wins.兩個驅動源拉同一條線;矽用電阻比決勝。模型在優先級類別內沒有強度概念 —— GND 直接全勝。 Unofficial opcodes LAE/LXA (the accumulator vs a latch driver on a merged bus).非官方指令 LAE/LXA(累加器 vs 閂鎖驅動器在合併匯流排上)。
A2 Window-overlap durations時窗重疊長短 A nanosecond precharge glitch drowns inside a hundred-nanosecond drive window on silicon. A settle model sees two events with no widths — and can commit the glitch, especially onto a floating wire where charge injection is permanent.奈秒級的預充電毛刺在真矽上淹沒於百奈秒的驅動窗內。settle 模型只看見兩個沒有寬度的事件 —— 而且可能讓毛刺落帳,尤其打在浮接線上時,電荷注入是永久的。 OpenBus err4: a data-output-register bit-4 precharge glitch corrupted opcodes fetched from the open bus ($28→$38 — PLP became SEC).OpenBus err4:資料輸出暫存器 bit-4 的預充電毛刺污染了從開放匯流排取到的 opcode($28→$38 —— PLP 變 SEC)。
A3 Transparent-latch tracking透明閂鎖的持續追隨 A real input latch follows the bus through the whole φ2 phase. The netlist's dynamic latch captures once per settle — whatever transient it grabs, it keeps.真正的輸入閂鎖在整段 φ2 追隨匯流排。網表的動態閂鎖每次 settle 只捕捉一次 —— 抓到什麼暫態就留下什麼。 OpenBus err6: at a $4017 read, a bus-buffer turn-on transient resolved the group to $00 mid-settle and the latch kept it — while the structurally identical $4016 read latched correctly.OpenBus err6:讀 $4017 時,匯流排緩衝器的導通暫態在 settle 中途把群解成 $00,閂鎖就留下了它 —— 而結構完全相同的 $4016 讀取閂得正確。
A4 Pipeline / propagation latency管線/傳播延遲 On silicon a $4015 write reaches the DMC DMA's gate cycles later, and the DMA re-checks that gate every cycle. In a quiescent settle the write lands instantly; a committed DMA is immune.真矽上 $4015 寫入要晚幾個週期才傳到 DMC DMA 的閘,而 DMA 每個週期都重查那道閘。靜止 settle 讓寫入瞬間落地;已提交的 DMA 對它免疫。 Explicit/Implicit DMA Abort: a mid-flight disable must kill the fetch on hardware; in the model it couldn't — until a calibrated deferral reproduced all sixteen hardware phases.Explicit/Implicit DMA Abort:硬體上進行中的停用必須攔斷取樣;模型裡攔不到 —— 直到用校準過的延遲重現了與硬體答案鍵完全一致的十六個相位。

Two more categories orbit these. D — the id-order lottery — is an amplifier: floating tie-breaks and settle order depend on node numbering, so the same race resolves differently at two identical sites (that's why $4016 survived and $4017 didn't). B — modelling level — is the CD4021 controller chip story: a CMOS part transliterated into NMOS vocabulary dies under GND-wins by construction, so peripherals get behavioural models instead. And C — genuine engine bugs — numbered exactly one, in the callback machinery, fixed outright.

另外兩類環繞在旁。D —— id 順序彩票 —— 是放大器:浮接平手判定與 settle 順序依賴節點編號,同一場競速在兩個一模一樣的站點解出不同結果(這正是 $4016 活下來、$4017 沒有的原因)。B —— 建模層級 —— 是 CD4021 手把晶片的故事:一顆被翻譯成 NMOS 語彙的 CMOS 零件,在 GND-wins 之下結構性必死,所以周邊改用行為層模型。至於 C —— 引擎真 bug —— 恰好一個,在 callback 機構裡,直接修掉。

4 · Category E: the netlist itself was never the whole truth4 · E 類:網表本身從來不是全部的真相

The most surprising verdict came last. One test (APU Register Activation) failed because the engine's /r4015 read-decode fired on $xx17 reads as well as $xx15 — the APU status register leaked onto the internal bus during every controller-2 read. The decode's product term in the netlist has five inputs and no a1 term at all. An independent silicon re-derivation (BreakNES) has six inputs, including a1. The die coordinates settled it: in the decode PLA, the a1 input column carries fourteen sibling transistors with exactly one vacant grid slot — at that row. And at the vertex level, the polygon data (segdefs) draws the missing transistor completely — source finger, poly gate, ground drain — vertex-identical to its extracted neighbour. Only the polygon-to-transistor extraction step never emitted the device.

最出乎意料的判決留在最後。有一顆測試(APU Register Activation)失敗,是因為引擎的 /r4015 讀解碼除了 $xx15、連 $xx17 讀取也開火 —— 每次讀手把 2,APU 狀態暫存器都洩漏到內部匯流排上。這條解碼在網表裡的乘積項只有五個輸入,完全沒有 a1 條件。獨立的矽逆向(BreakNES)有六個輸入,含 a1。die 座標一錘定音:解碼 PLA 的 a1 輸入直行上站著十四顆兄弟電晶體,恰好空著一個網格交點 —— 就在那一列。而頂點級比對顯示,多邊形資料(segdefs)把這顆缺失的電晶體畫得一清二楚 —— 源極指、poly 閘、接地汲極 —— 與隔壁被正確萃取的鄰居逐頂點同構。只是「多邊形→電晶體」的萃取步驟從未發出這顆器件。

Provenance added a twist: our netlist is byte-identical to MetalNES's copy, which had itself silently repaired a different missing transistor over the raw Visual2A03 download. So the community's most trusted netlist had at least two extraction holes — one found by MetalNES's author years ago, one found by this campaign. We then built a geometric completeness audit (enumerate every poly-between-two-diffusions crossing in segdefs, diff against the transistor list) and ran it on both chips. Calibration: it rediscovered both known holes at their exact coordinates. Verdict: the 2A03 has exactly two functionally significant extraction misses — the two already patched — and the 2C02 has zero. The fix policy that emerged: category-E defects are repaired in the data, as annotated netlist patches with full provenance — not worked around in code.

譜系追查再添轉折:我們的網表與 MetalNES 的副本逐位元相同,而 MetalNES 自己就曾對原始 Visual2A03 下載靜默修補過另一顆缺失的電晶體。所以社群最信任的網表至少有兩個萃取漏洞 —— 一個由 MetalNES 作者多年前找到,一個由本戰役找到。我們隨後做了幾何完備性審計(枚舉 segdefs 所有「poly 夾在兩塊擴散之間」的交叉、對照電晶體清單),對兩顆晶片都跑了一遍。校準:它在精確座標上重新抓回兩個已知洞。判決:2A03 有恰好兩個功能有效的萃取漏 —— 即已補的那兩顆 —— 2C02 是零個。由此確立的修復政策:E 類缺陷直接修在資料裡,以附完整譜系註解的網表補丁處理 —— 不在代碼裡繞。

The lesson in one sentence: a netlist is a faithful snapshot of geometric connectivity — it is not, and never was, a complete description of the chip. Device strengths, continuous time, analog boundary behaviour, and even the occasional dropped device all live outside it. Nothing was wrong with trusting the netlist for forty years of casual use; it took a suite this cruel to map where the description ends.

一句話的教訓:網表是幾何連通性的忠實快照 —— 它不是、也從來不是晶片的完整描述。器件強度、連續時間、類比邊界行為、甚至偶爾被漏掉的器件,全都住在它之外。四十年來大家信任網表沒有錯 —— 要等到一套這麼兇殘的測試,才把描述的邊界畫出來。

5 · Would MOSSIM II have survived? Half of it.5 · 換成 MOSSIM II 會活下來嗎?活一半。

MOSSIM II (Bryant, 1984) is the canonical academic switch-level simulator, and it shares this engine's soul: event-driven propagation, connected-group resolution, charge sharing, iterate-to-fixed-point. Where it goes further is signal-strength algebra: transistors carry discrete conductance strengths, nodes carry discrete sizes, and group resolution solves a small strength calculus instead of a priority OR — plus a third logic value, X, for genuine conflicts.

MOSSIM II(Bryant,1984)是學術界開關級模擬的正典,和本引擎共享同一個靈魂:事件驅動傳播、連通群決議、電荷分享、迭代到不動點。它更進一步的是信號強度代數:電晶體帶離散電導強度、節點帶離散尺寸,群組決議解一套小型強度演算而非優先級 OR —— 外加第三個邏輯值 X,標記真衝突。

Blind spot盲區MOSSIM IIWhy原因
A1✅ solves it✅ 能解Strength algebra is precisely a model of ratioed fights — LAE/LXA would resolve naturally, no shim.強度代數正是比例打架的模型 —— LAE/LXA 自然解出,不需任何 shim。
A2❌ dies the same way❌ 一樣踩死Events still carry no durations; a 1 ns glitch and a 100 ns drive weigh the same.事件依然沒有寬度;1 奈秒毛刺和 100 奈秒驅動等量齊觀。
A3⚠ still at risk⚠ 依然危險Settle-to-quiescence still captures once; strength classes don't restore continuous tracking.settle-到-靜止仍是一次捕捉;強度分級救不回連續追隨。
A4❌ dies the same way❌ 一樣踩死Fixed-point iteration is still zero-delay; signals cross the chip instantly.不動點迭代依然零延遲;訊號瞬間穿越整顆晶片。
D⚠ different lottery⚠ 換一種彩票Fewer ties (strength breaks many), but simultaneous-event ordering remains arbitrary.平手變少(強度能拆掉不少),但同時事件的先後仍是任意。
E❌ same data❌ 同一份資料A missing transistor is missing for every faithful executor of the netlist.缺一顆管,對任何忠實執行這份網表的模擬器都缺。

In short: MOSSIM II fixes the amplitude quantization, not the time quantization — one of the four A-blind-spots, none of the rest. And the price is steep: strength calculus in the hot loop plus contagious X states would cost orders of magnitude of speed. This engine's binary priority + O(1) LUT is what makes 140K half-cycles/s possible; MOSSIM II is a scientific instrument, this is a race car on a known-good chip. The right question is not "which model is better" but "which physics do you need, and what will you pay for it".

一句話:MOSSIM II 修的是振幅的量化,不是時間的量化 —— 四個 A 類盲區只救一個,其餘全數陣亡。而且代價高昂:熱迴圈裡的強度演算加上會傳染的 X 態,速度要掉數量級。本引擎的二值優先級 + O(1) 查表正是 140K 半週期/秒的來源;MOSSIM II 是科學儀器,這是一台跑在已知好晶片上的賽車。正確的問題不是「哪個模型比較好」,而是「你需要哪些物理,願意付多少代價」。

6 · A question of fit, not of merit6 · 這是適用域問題,不是優劣問題

It would be easy to read the previous sections as "the model is flawed". The more accurate reading is that every simulation model is a point on a curve of physics captured versus cost paid, and switch-level simulation occupies one specific, well-defined region of applicability. It assumes digital discipline: signals that swing rail to rail, logic that settles to a stable state every phase, storage built from recognizable structures. For chips that keep that contract, it is close to ideal — the whole function emerges from connectivity alone, at speeds that let you run entire systems for hours of emulated time.

前幾節很容易被讀成「這個模型有缺陷」。更準確的讀法是:每一種模擬模型都是「捕捉多少物理 × 付出多少成本」曲線上的一個點,而開關級模擬佔據的是一塊明確、可界定的適用域。它假設數位紀律:訊號滿幅擺動、邏輯每個相位都收斂到穩態、儲存由可辨識的結構構成。對守約的晶片而言,它近乎理想 —— 整個功能單憑連通性湧現,而速度快到能讓整個系統連跑數小時的模擬時間。

The catch is historical: 1970s–80s chips are digital by intent but analog by technique. Designers of that era exploited the physics of their medium deliberately — ratioed NMOS logic where a weak pull-up loses to a strong pull-down by resistance arithmetic, dynamic storage parked as charge on parasitic capacitance, precharged buses, latches whose timing depends on propagation delays, even the bus capacitance itself exposed as observable behaviour (the open bus that game code can read — and that AccuracyCoin weaponizes). The 2A03 and 2C02 compute digital functions, but their boundary behaviours are analog artifacts of the implementation. Ironically, a modern synchronous standard-cell CMOS block — fully complementary, no ratioed fights, static latches — fits the switch-level contract far better than these forty-year-old chips do. The old silicon is the harder target precisely because its designers were allowed to be clever with physics.

麻煩出在歷史:七〇、八〇年代的晶片,意圖是數位的,手法卻是類比的。那個年代的設計者刻意利用介質本身的物理 —— 比例式 NMOS 邏輯讓弱上拉照電阻算術輸給強下拉、動態儲存把電荷寄放在寄生電容上、預充電匯流排、時序仰賴傳播延遲的閂鎖,甚至匯流排電容本身都成了可觀察的行為(遊戲程式讀得到的 open bus —— AccuracyCoin 正是拿它當武器)。2A03 與 2C02 計算的是數位函數,但它們的邊界行為是實作手法留下的類比痕跡。諷刺的是,一塊現代同步標準元件 CMOS —— 全互補、無比例打架、靜態閂鎖 —— 反而比這些四十年前的晶片更守開關級的契約。老矽之所以難,正因為當年的設計者被允許對物理耍聰明。

And the alternative is not "just use a more precise model". The precise model exists — SPICE-class simulation solves the actual nonlinear differential equations, continuous voltages, real time — and it is categorically infeasible at this scale. Cost estimates for a 30,000-transistor system run millions of times slower than this engine: the AccuracyCoin suite covers a bit over a minute of chip time, which at SPICE speeds becomes years of wall-clock computation for a single sweep — before the first regression re-run. Between the extremes, each rung buys one dimension and pays for it: strength algebra (MOSSIM II) buys amplitude and costs an order of magnitude; timing annotation buys propagation delay and costs the settle model's simplicity; SPICE buys everything and costs feasibility itself. The binary quiescent model is not naive — it is the only point on the curve where "run the whole console against a 141-test hardware suite, repeatedly, on one CPU core" is possible at all.

而替代方案也不是一句「換更精確的模型」就完事。精確的模型是存在的 —— SPICE 級模擬解的是真正的非線性微分方程、連續電壓、真實時間 —— 但在這個規模下它根本不可行。三萬電晶體等級的系統,成本估計比本引擎慢以百萬倍計:AccuracyCoin 全套約當一分多鐘的晶片時間,換算 SPICE 速度,單掃一輪就是以年計的牆鐘時間 —— 還沒算第一次回歸重跑。在兩個極端之間,每一階都是「買一個維度、付一筆代價」:強度代數(MOSSIM II)買回振幅、付掉一個數量級;時序標註買回傳播延遲、付掉 settle 模型的簡潔;SPICE 買回全部、付掉可行性本身。二值靜止模型並不天真 —— 它是曲線上唯一一個讓「用單核 CPU 反覆把整台主機跑過 141 顆硬體測試」成為可能的點。

So the fair statement is: switch-level simulation is the right model for digital-intent silicon, applied here to chips whose era guaranteed analog technique at the edges. The deviations this suite exposed are not defects of the model so much as coordinates of its applicability boundary — measured, one test at a time.

所以公道的說法是:開關級模擬是數位意圖矽晶的正確模型,只是這裡把它用在一個「時代注定邊緣藏著類比手法」的晶片上。這套測試暴露的偏差,與其說是模型的缺陷,不如說是它適用域邊界的座標 —— 一顆測試一顆測試量出來的。

7 · What we plan to do about it — general mechanisms, not special cases7 · 我們打算怎麼辦 —— 通則機制,不是特例

Today's fixes are test-mode behavioural shims: each carries the measurement that forced it, acts at the narrowest measured site, and never loads on the benchmark path. That discipline works, but a shim protects only the site it was measured at. The roadmap replaces every hand-written special case with a general, mostly load-time mechanism:

今天的修法是測試模式的行為層 shim:每顆都附著逼出它的量測、只作用在量測定位的最窄站點、永不載入效能基準路徑。這套紀律行得通,但 shim 只保護量測過的站點。路線圖要把每一個手寫特例換成通則的、多半在載入期的機制:

Category類別General mechanism通則機制Status狀態
ENetlist patches with provenance + the geometric completeness audit附譜系的網表補丁 + 幾何完備性審計done & proven已完成並實證
DCanonical renumbering: node order = a physical key (layered polygon area + structural hash), so every id-order arbitration becomes canonical with zero hot-path change; twins get identical verdicts and graph edits stop re-rolling the lottery正準重編號:節點順序 = 物理鍵(分層多邊形面積 + 結構雜湊),所有 id-順序仲裁自動變正準、熱路徑零改動;孿生必同命,圖變更不再重擲彩票proposed提案完成
A1Strength-class LUT, two-tier: a load-time census flags the <1% of nodes where fights can occur; only those groups pay for strength resolution強度類別 LUT,兩層制:載入期普查標出可能打架的 <1% 節點;只有那些群付強度解析的成本designed設計完成
A3Auto-detected transparent latches (pass-gate + storage node + phase net are purely structural) + a single restatement rule: while transparent, latch = settled input自動偵測透明閂鎖(pass-gate + 儲存節點 + 相位網,純結構條件)+ 一條重述規則:透明期內,閂鎖 = 輸入側 settled 值designed — retires three shims at once設計完成 —— 一口氣退役三顆 shim
A2Quiescent-conduction commit: a write to a floating group counts only if its driving path still conducts at quiescence — legitimate half-cycle drives always survive, nanosecond glitches never do靜止導通落帳:對浮接群的寫入,只在驅動路徑活到 settle 靜止時才算數 —— 合法的半週期驅動必然活到,奈秒毛刺必然活不到proposed提案完成
A4One generic delay-element primitive + a calibration data file (which paths, how many ticks) — the mechanism is general, the constants are measured一個通用延遲元件原語 + 校準資料檔(哪些路徑、幾個 tick)—— 機制通則化,常數靠量測proposed提案完成
BBehavioural peripherals + a timestamp-based analog sidecar (RC decay as precomputed integer deadlines)行為層周邊 + 時戳式類比副層(RC 衰減預算成整數期限)pad done; sidecar blueprinted手把已完成;sidecar 藍圖已立

The honest endgame: zero hand-written special cases is reachable; zero mechanisms is not. The A2/A4 residue is continuous time itself — no static analysis will ever derive "this write takes 84 ticks to land" from connectivity alone. What can be done is to make every mechanism site-agnostic and every constant a row in a data file, with the hardware answer keys as the calibration oracle.

誠實的終局:「零手寫特例」可達;「零機制」不可達。A2/A4 的殘餘就是連續時間本身 —— 沒有任何靜態分析能單憑連通性推出「這個寫入要 84 個 tick 才落地」。能做到的,是讓每個機制都不認站點、每個常數都變成資料檔裡的一列,並以硬體答案鍵作為校準的神諭。

8 · Closing: the value of knowing where the description ends8 · 結語:知道描述在哪裡結束,本身就是價值

None of this diminishes switch-level simulation — the opposite. Nine forensic campaigns produced one engine bug, one data hole, and a precise, measured map of exactly which physics a binary quiescent model cannot express. That map is worth more than the comfortable belief it replaced. The netlist remains the best executable description of these chips that exists in the open; it just isn't the whole truth — and now we know, blind spot by blind spot, test by test, where the rest of the truth lives and what each piece of it would cost to bring inside.

這一切絲毫沒有貶低開關級模擬 —— 恰恰相反。九場取證戰役的產出是:一個引擎 bug、一個資料洞,以及一張精確的、量測得來的地圖,標明二值靜止模型到底表達不了哪些物理。這張地圖,比它取代的那個舒服的信念值錢得多。網表仍是公開世界裡這些晶片最好的可執行描述;它只是不是全部的真相 —— 而現在我們知道了,一個盲區接一個盲區、一顆測試接一顆測試地知道了:剩下的真相住在哪裡,把每一塊搬進來各要付出什麼代價。

Full forensic detail: the AccuracyCoin campaign report (taxonomy in §3, the missing-transistor trial in chapter 9). Background: the switch-level primer and the abstraction study.完整取證細節見 AccuracyCoin 戰役報告(§3 分類學、第九章缺管審判)。背景閱讀:開關級模擬入門抽象化研究