ベンチの道具が示したこと
2026-09-06 に B0 の報告として始め、ハードウェアが届く前に B1、B2、B3 が道具を手にしていくにつれて、ベンチの継続的な報告へ育った。計画は docs/bench-plan.md、そちらが先だ。下の節はセッション 1 (2026-09-08) で止まっている。橋が書き込み済みで Pi につないだまま応答し、コンソールのポートにはまだつないでいなかった時点だ。その後のことは milestone-2026-09-15-rig-and-bridge.md にある: 2026-09-15 にコンソールに載った v1b の橋がすべてのバイトを読み返し、2026-09-17 にはリセットと電源に置いた Pi の手が持ちこたえた。下の文が橋はまだ無いと言っているところは、それを書いた日付の話だ。閉じたのは、四つの節目が機械の上で閉じられるものすべてで、どの道具にも合成の上での緑の走行と、赤になる妨害の走行が付いている。そして B0 が実物で測るつもりだった一つのことは、先にダイで測れることが分かり、それが模型を変えた。節は書かれた順に並んでいる。各節目の実物の側は、末尾の一覧だ。
すでにあるもの
firmware/bridge/bridge.ino: ESP32 のスケッチ。コンソールのラッチとクロックをパルスカウンタの周辺回路で数え (OUT0 の立ち上がり、クロックの立ち下がり、50 ns のグリッチフィルタ、割り込みの中では何もしない)、元のパッドを橋自身の線で 1 ミリ秒ごとにポーリングし、74HCT165 の八つの入力をポーリングの合間に書き、ラッチごとに 1 行を USB シリアルで 921600 で出す:L <latch index> <byte the register held> <clocks the poll took>。 コマンドはMODE PASS、MODE INJECT、SET hh、AT n hh、TRIG n、RESET、STATUS。arduino-cli の下で esp32 コア 3.3.11 の汎用 ESP32 向けにコンパイルできる (281 KB)。まだ基板の上で走らせていない。tools/sniff.py: シリアルの側。コマンドを送り、それからファイルへの流しっぱなし。tools/compare-logs.py: 二つのログをラッチごとに、ポーリングあたりのクロック数のヒストグラム、クロックかバイトが最初に食い違うラッチ、そしてポーリングが一つも無いログとの比較の拒否。- 模型のログ:
nes-consoleのpad-logの例が、ROM とAT frame hhの行の台本から、ラッチごとに同じ行を印字する。そしてexport-testrom padとpad-dmcが、ポーリングするカートリッジを書き出す (NMI ごとにストローブ一回と読み出し八回。最速のレートでループする DMC の標本を付けるか付けないか)。
2026-09-07 に追加: 頭、そして両側の台本
head/headd.py は Pi のデーモンだ。一つの台本 (docs/script.md) を橋、リレー、スコープに向けて演奏し、走行を返す。これは tools/fake-bridge.py、後ろに実物の無いプロトコルの代役に対して端から端まで走り、取ってきたログは同じ台本に対する模型のものと tools/compare-logs.py で差分を取った: すべてのラッチが一致し、予定のバイトは両側でちょうど自分のラッチに着地した (橋はラッチ n-1 の後にそれを書き、模型のコントローラはラッチ n の前のストローブの立ち上がりで適用する。nes @ a99b4eb、tests/pad_log.rs)。スコープの側は scope-capture が証明済みの方言を共有し、そこに外部トリガの単発を足した。こちらは未検証だ: これを書いた時点でスコープは LAN から外れていた。リレーには Pi が配線されていない (2026-09-17 に配線した: リセットに OK1、電源に K1)。
2026-09-07 に追加: B1 の道具、捕捉が一つも無いうちに合成で緑
tools/b1-score.py runs/<stamp> rom.nes は、走行の台本からその TRIG n を、捕捉の .toml からレートとトリガの標本番号を読み (頭がそれをスコープ自身のプリアンブルから読むので、オフセットの符号の約束は一つも信じない)、台本とラッチとトリガを渡して nes-console の capture-score を走らせる: 模型は同じ SET と AT の行を、ラッチ n の後に完成する最初のフレームまで演奏し、記録はトリガの標本から先を切り出して、復元の最初の完全なフレームが実物でのそのフレームになるようにし、すべての平坦な領域が N6 の許容で往復を通して採点される。復元には切り出しの後に完全なフレームが二つ必要なので、頭は水平のオフセットを、トリガが記録の早い側に来るように設定する。符号が正しいかどうかは最初の実物の捕捉が言うことで、.toml がそれを言う。
その緑の走行 (SYNTH_TRIGGER=1): カードの模型を通してフレームを六つ合成し、四つ目を採点し、そこに置かれたトリガがそうするように三つ目の内側から合成を切り出す。バーのカートリッジで 13 領域のうち 13、輝度行の刻みにわたって試したすべてのフレーム数で。MUTATE_TRIGGER=1 は 1 フレーム遅く切り出し、その刻みでは 13 のうち 1 になる (フレーム 122)。これが、色だけでなくフレームの選択も検査されていることを示す。公開サイトは公開の前に両方をもう一度走らせ、妨害が赤にならなければ拒む。nes @ 59d42c8。
2026-09-07 に追加: B2 の分類器、自分の合成で緑
tools/b2-align.py は、コンソールの CPU と PPU の位相合わせを三チャンネルの捕捉 (マスタクロック、M2、ALE) から読み、sweep を付ければ電源投入の台本を頭を通して N 回演奏してヒストグラムを印字する。その二つの事実は先にダイで実測した。2A03 の M2 は、その clk0 が落ちるまさにその半ステップで落ちる。phi1 の始まりだ。そして三つ早く上がる (24 のうち 15 が高い。実物の文書どおりの 62.5 パーセントのデューティ。v2a03-sim の m2-phase、2a03 @ 51c9b4a)。2C02 の ALE は、pclk0 が上がるまさにその半ステップで上がる。ドットの始まりで、描画中は 1 ドットおきに (v2c02-sim の ale-phase、2,508 の立ち上がりのうち 2,508、2c02 @ c3a4b9b)。だから ALE の立ち上がりから次の M2 の立ち下がりまでのオフセットを、コンソール自身のマスタクロックを定規にした半ステップで測ったものが、模型の cpu_phase から ppu_phase を引いたものであり、その mod 8 がクラスだ。模型が走る組 (4, 3) はクラス 1 になる。オフセットが半ステップに乗らない捕捉、クラスが綺麗に出ない捕捉は、分類されずに拒まれる。
その検査 (selftest): 三つのチャンネルを、実測したピンのオフセットを使って、頭の三チャンネルのレートで 72 通りの位相合わせについて合成し、どれも自分のクラスとして読み返された。合成した ALE を半ステップ動かすと (MUTATE) 24 通りすべてでクラスが動く。それから頭を通した経路の全体: tools/fake-scope.py が頭の SCPI にその合成した記録で答え、B2 の台本 (電源オフ、ALE の最初の立ち上がりで三チャンネルを構え、電源オン、捕捉) を sweep が三回演奏し、各走行が取ってこられ、偽物に与えた位相合わせとして分類された。頭の ARM はチャンネルの一覧、トリガのソース、時間軸、そしてそのための深さを取るようになった (DS1054Z は三チャンネルでは最大 6 M 点しか保てないので、B2 の窓は 1.2 M で 6 ms だ。B1 の窓は一チャンネルで 12 M の 60 ms のまま)。
ベンチにしか言えないこと: 百回の電源投入にわたる実物のヒストグラムが、そのクラスの上で平らなのか、いくつかを好むのか。それが B2 の最初の検査だ。そして模型の (4, 3) がその中にあるのか。
2026-09-07 に追加: B3 の道具、仕込んだダイバージェンスを見つける
tools/b3.py が四つの動詞になった B3 だ。record は走行の橋のログ (MODE PASS、元のパッドに手を置いて) を台本に変える: MODE INJECT、最初のバイトを SET、変化ごとに AT。ファームウェアの予定表はそのために二千項目まで育った。replay はその台本を実物の上で、名指しされたラッチごとに一度演奏し、どの再生も RESET から始めてそのラッチでトリガした捕捉を一つ取り、すべての捕捉を b1-score を通してそのラッチでの模型のフレームに照らして採点する。1 走行あたり捕捉は一つだ。記録を読むのに数秒かかるあいだコンソールは走り続けるからで、そして台本の中では構えがトリガより先に来る。構えは数秒の SCPI であり、先に設定したトリガは誰にも聞かれずに発火しうる。どちらもここで見つかった。agree は二つの再生の、同じラッチでの捕捉を互いに突き合わせる。実物を実物自身に照らして、領域ごとに B1 の許容の下で。bisect は、ダイバージェンスが単調であると仮定して、捕捉が模型と食い違う最初のラッチを、区間の log2 ほどの回数の再生で見つける。
実物なしでそれを試すために、nes-console のポーリングするカートリッジに変種 pad-paint ができた。これは自分の帯をポーリングしたバイトで塗る。そして capture-score は自分の合成を、トリガの標本番号を隣に添えた記録として書き出す (SYNTH_OUT)。tools/fake-scope.py --video がその合成を、偽の橋がトリガしたラッチで、走行自身の台本に --diverge-at N hh を足したものの下で差し出すので、「実物」はラッチ N から違うバイトを演奏する。ダイバージェンスをラッチ 200 に仕込むと: 100 と 400 での再生は、そうあるべきとおりに模型と一致し、また食い違う。二つの再生は両方で互いに一致する。そして bisect は 0..1024 の上で、十一回の再生でラッチ 200 を名指しし、ラッチ 199 は一致する。nes @ e1839eb。
その試験が見つけて直したバグが一つ。合成は自分のトリガでの切り出しの後に書き出されていて、トリガの標本番号が短くなった記録から計算されていたので、その標本番号で切り出す読み手は 2 フレーム遅く着地し、二分探索は 198 を名指ししていた。書き出された記録はいま、プロセス内の経路と同じフレームを、アンカー行ごとに復元する。
2026-09-07 に追加: 電子回路のレビューが返したシート、そしてそれが変えたもの
ベンチの電子回路のレビューは、回路図四枚と組み立ての文書 (docs/bench-build-v1-v2.md、bench-v1.svg、bench-v2.svg、logical-timing.svg、pad-adapter.svg。tools/draw-schematics.py が描く) を返し、レビュー自身の二度目の確認が直したものの注記を付けてきた (LM1881 のピンのラベル、Pi のレールに載っていたリレーの電源、書き下ろしの幅の一つ、自分自身と矛盾していた組み立ての手順、デカップリングの個数)。来たとおりに取り込み、残りからずれられないように二つ足した: tools/check-sheets.py が v1 のシートの C6 のピンをすべて配線の表に押さえ、コミットされた SVG を生成器に押さえる。そして組み立ての文書がシートを埋め込む。
タイミングのシートが見えるようにしたファームウェアの変更が一つ、同じ日に bridge.ino に入った。165 は OUT0 が高いあいだロードするのに、レジスタの八本のピンは一本ずつ書かれていたので、ポーリングが半分古く半分新しいバイトをラッチしうる。いまは GPIO の出力レジスタへの一回の書き込みで、しかも OUT0 が前後で低いと読めたときにだけ行い、そうでなければ次のループへ先送りする。ループは書く前にカウンタを読んでラッチを記録する。そして MUTATE ON が二つのカウンタの線を入れ替えるので、B0 の妨害は台本の一行になる。偽の橋も同じことをする。C6 と古典的な ESP32 の両方でコンパイルできる。まだ基板の上で走らせていない。
v2 (SPI でバイトを不可分に、二つ目のポート、ラッチごとにフィールドと行を与える LM1881) とパッドのアダプタは、四つの節目の後に来るものとして計画に入っていて、それぞれに条件が付いている。
2026-09-07 に追加: 実物の計器の上での頭の捕捉経路
スコープが新しいネットワークに移り、一日行方不明になった。原因は差し込みの浅い Ethernet ケーブルだった。そのアドレスはリポジトリの規則が求めるとおり、無視される bench.local.md にある。戻ってきたので、頭の Scope クラスが初めて実物の計器に会った。以下はすべて、その書き写しではなく head/headd.py そのものを通して、ファームウェア 00.04.05.SP2 の DS1054Z に対して走った。最初のコマンドの前に前面パネルを保存し、最後のコマンドの後に戻してある。スコープは別の実験のものだからだ。
クラスがする順に、通ったもの: 接続と識別。save_setup が 2,085 バイト、そして時間軸とスイープを見つけたときのままに戻した復元。arm を一チャンネル、5 ms/div、12 Mpoint で。メモリ深さは走行中にしか受け付けないという回避も含めて、計器は読み返しでそれを確認した。単発が WAIT に達してから STOP へ。そして read_record の、記録全体をまとめて読む分割生読み出しで、1200 万点を 27.9 秒、TCP 上でおよそ 0.43 Msample/s、.toml をその隣に書いた。
水平オフセットの符号は決着し、それは初めから正しかった。 ドキュメント文字列には以前、約束は信じていないので最初の実物の捕捉がトリガを遅い側に置いたら反転せよと書いてあった。トリガは早い側に来る。上のとおりに構えて :TFORce で撃つと、プリアンブルは 1 標本 8 ns で xorigin -0.028 s を報告するので、MAIN:OFFSet を正の四目盛にするとこうなる:
| 記録 | 12,000,000 点、125 MSa/s で 96.0 ms |
| トリガの標本番号 | 3,500,000、29.2 パーセントの位置 |
| トリガより後の記録 | 68.0 ms、NES のフレーム 4.09 個ぶん |
| B1 が要求するもの | 完全なフレーム 2 個 |
いずれにせよ、下流の何もこの符号に依っていない。トリガの位置は仮定せずプリアンブルから読むからだ。だが四目盛が B1 の復元の要求を、望みではなくフレーム一つの余裕をもって満たすことは、これで分かっている。
この捕捉は時間軸も再確認した。それが目的ではなかったのに。 プローブはまだコンソールのコンポジット映像に乗っていて、コンソールは走っていたので、記録には中央値 4.664 マイクロ秒の幅の同期パルスが 1,512 本入っていて、色の副搬送波は 0.280 マイクロ秒の周期として現れる。1,512 本すべての同期の時刻に最小二乗を当てると、残差 53.9 ns で行の周期が出て、それに対して二つのリファレンスが食い違う:
| リファレンス | 行のレート | この捕捉が読む値 |
|---|---|---|
| NES 自身のマスタクロック、341 ドット | 15745.80 Hz | +5.3 ppm |
| 放送の NTSC | 15734.26 Hz | +739 ppm |
これはあの ntsc-crt の発見をもう一度、六日後に、別のネットワークの上で何も引き継がずに得たものだ: コンソールは構造上、放送からおよそ 733 ppm ずれていて、間違っているのはスコープではない。以前の作業はスコープ自身の誤差を約 -7 ppm に置いていた。この捕捉はスコープとコンソールの組を互いに 6 ppm の内側に置き、それは安物の水晶が一人で覆う範囲だ。このコンソールの映像を放送の行のレートに照らして採点するものは、千分の 4 分の 3 だけ間違い、しかも時間軸の故障のように見えるだろう。
この時点でこれでは閉じていなかったもの: トリガは :TFORce 以外の何にも発火させられていなかった。それを立てる橋がまだ存在しなかったからだ。2026-09-15 に閉じた: 橋からの TRIG n が CH1 で単発を止める (DS1054Z に EXT 入力は無い)。ここで証明されたのは構え、待ち、読み出し、そして記録の幾何であり、それはトリガの周りのすべてである。
実物より先にダイが言ったこと
B0 の検査は実物でのラッチあたりのクロック数を求め、DMC のフェッチがポーリングの読み出しに重なるところでは 9 を予期していた。それはスイッチレベルの 2A03 が答えられる問いなので、先にそちらに訊いた (2a03 の joy-clock-probe、あちらの docs/n3-report.md):
- DMC のフェッチが重なる読み出しでは、/OE1 が読み出しとともに落ち、停止サイクルのあいだ低いまま (連続した一つのパルス) で、フェッチ自身が標本を読み出すあいだに上がり、コアが RDY を高くして読み出しをやり直すときにまた落ちる。立ち上がりが二つ: 4021 は二度シフトし、コアは自分が求めたビットの次のビットを取る。停止サイクルはそれを叩かない。
- ただし標本のアドレスがポートの下位 5 ビットを持つときは別だ ($4016 なら $xx16、$4017 なら $xx17)。二つのループの刻みにわたる二十のエイリアスは /OE1 をフェッチの間ずっと低いままにし、パッドは一度だけクロックされる。エイリアスの素の読み出しはストローブを立てないし、コアが待機している状態でのエイリアスからのフェッチも立てない。つまりストローブの上位のアドレスビットはコアが保持しているアドレスから来て、下位 5 ビットは DMA が駆動するピンから来る。ダイのデコーダについての事実だ。
三つの変更が続き、それぞれに、無ければ失敗するテストが付いた:
- 6502 の高速コア (
tinymachines/6502@ 89ae24f) は、RDY で保持された読み出しの phi2 ごとにバスに訊き直し、最後のバイトを保つ。DL がするのがそれだ。MUTATE_HELD=1は最初のバイトを保ち、赤になる。 - 2A03 の高速チップ (
tinymachines/2a03@ dbf116b) は、コアが保持されているあいだその訊き直しをメモから答え、やり直しのときに一つだけ通す。エイリアスの規則が当てはまる場合を除く。tests/joypad.rsが高速チップの命令あたりの訊き直しを、二つの刻みにわたるダイの /OE1 のパルス、{1: 2820, 2: 6} と {1: 2245, 2: 4} に、命令ごとに押さえる。MUTATE_QUIET=1(衝突あたり五回の訊き直し) は赤になる。 - コンソール (
tinymachines/nes@ 2ec0fc3) がポーリングを記録する。DMC のループを付けたポーリングするカートリッジでは、模型は 600 フレームにわたる 596 のラッチのうち 21 で、読み出し九回のポーリングを予測する。tests/pad_log.rsに記録されている。
こうして B0 の三番目の検査、模型の DMC フェッチの予定を実物の九クロックのポーリングと並べるものには、文書が触れていない例外つきの予測が付いた。決めるのは実物だ。
2026-09-08 に追加: UNO の橋、そしてコンパイラが決めたこと
ベンチの電子回路のレビューは、部品が届いた後に五枚目のシート v1b (いまは bench-v1b-1.svg と bench-v1b-2.svg) を返した: 橋を Arduino UNO に載せ、すべてを 5 V で動かす。棚にある 74HC の部品は 3.5 V の高を必要とし、3.3 V の部品はそれを出さないからだ。これが最初に組むものとして v1 に取って代わる。それを描く生成器ごと丸ごと取り込み、tools/check-sheets.py はいま、v1 を docs/wiring.md に押さえていたのとまったく同じように、v1b の UNO のピンをすべて文書自身の表に押さえる。その検査に対して妨害を三つ走らせ、三つとも赤になった: 文書の中でピンを一つ動かす、そこから一行消す、生成器が書くものからシートを一枚編集して離す。
ファームウェアは存在し、コンパイルできる: firmware/bridge-uno/bridge-uno.ino を arduino:avr:uno 向けに、フラッシュ 8,018 バイト、SRAM 1,521 バイト。それを書くことがシートを一組の決定に変えたのであり、そのうち四つは、文書の計画が不完全だったというより間違っていた。
| 注記が計画していたもの | 実物が許すもの |
|---|---|
SPI.transfer(b) | SPI.transfer(~b): 押された状態は LOW |
L の行に micros() の欄 | 欄は四つ。三つの道具がちょうど四つを要求するから |
| D2 と D5 のジャンパと設定ピンによる MUTATE | ラッチの線の PCINT21、ソフトウェアで |
| C6 の 2048 項目の予定表 | 128。2 KB の SRAM が保てるのがそれだから |
uint64_t のカウンタと %llu | uint32_t と %lu。avr-libc に 64 ビットの printf は無い |
効いたのは予定表で、これは数字としてではなく罠として述べる価値がある。橋が保てるよりも多くのバイトの変化を持つ記録は、失敗しない。違う入力の履歴を再生しながら、L の行はどれも健康に見える。それはコンソールについての偽の発見の形そのものだ。だから上限は各ファームウェア自身のソースから読み出し、決して打ち込まず、三箇所で拒む: tools/b3.py record が走行を試みる前にそれを名指しし、tools/fake-bridge.py が同じ上限を強制するのでハードウェア無しで失敗の予習ができ、頭は橋が # schedule full と答えた瞬間にそれを走行のエラーとして上げる。偽物に対して端から端まで証明済み: 120 項目の台本は done まで走り、200 項目の台本は 72 回の拒否を引き出し、それを起こした行で止まる。
図面も二つ間違っていて、訂正はレビューの外から来た。 手元にあるリレーモジュールは 5 V のコイルにフォトカプラ入力の部品なので、v1 のシートの 3.3 V のレールはそれには間違いだった。両方のシートはいま Pi の 5 V ピンとアクティブ LOW の入力を示す。そして両方のシートは、コンソールの映像をスコープの CH1 に置いていたが、実際は CH3 だ。scope-capture.py がずっとそこを既定にしてきた場所であり、2026-09-07 にプローブが座っているのを測った場所であり、そして CH1 は B2 の位相合わせの分類器がマスタクロックのために欲しいチャンネルだ。別の道具が必要とするチャンネルを主張する図面は、ベンチで午後を一つ持って行く種類のものである。
2026-09-15 までは本当だったこと: ここにあるものはコンソールに会っていなかった。証明されたのは、ファームウェアがコンパイルできること、プロトコルが変わっていないこと、検査が失敗できること、そして一つの新しいハードウェアの上限が走行を黙って壊すことはできないことだ。
2026-09-08 に追加: 立ち上げの道具、そしてそれが書く実験ノート
部品は机の上にあるので、次にすることは配線であり、配線は、ベンチが計器になるか、もっともらしい間違った答えの一週間になるかが分かれる場所だ。tools/bringup.py がその手順書だ: v1b の組み立て順に十四の手順があり、それぞれが何を配線するかを印字し、待ち、それから何かを検査する。手順がうまくいったかを尋ねることは決してしない。スコープで測るか、橋自身のログを読むか、メーターの読みを求めてそれを範囲に押さえる。
そのうち二つの手順が効くもので、どちらも書き下ろしの数字を実測のものに置き換える:
- 2.1 は、ゲームが走っているあいだ元のパッドのポートにスコープを当てて、ラッチのパルス幅、クロックのパルス幅、クロックの間隔、毎秒のポーリング数を測る。この四つの数字は
wiring.mdとタイミングのシートの全体で書き下ろしと札が付いていて、これがそれを引退させる。 - 5.1 は B0 の最初の検査が早く来たものだ: 橋をつなぎ、ゲームがポーリングしている状態で、どのポーリングもクロックを八つ運ばなければならない。橋を二十秒聞いて、ヒストグラムを印字する。
失敗した手順は走行を止める。次の手順は前の手順を前提にしているからだ。一つの検査は報告する代わりに拒む: コンソールの電源ピンが約 5 V を読まないなら、道具は先へ行かない。ハーネスの対応付けの間違いと、間違ったピンに乗った 5 V の線は同じ失敗であり、その一方は部品を一つ持って行くからだ。
これは何かに会う前に予習された。 手順 0.1 は本物のスコープに対して走った。橋の手順は同じプロトコルを話す tools/fake-bridge.py に対して走り、パッドの検査は両方向で証明された: 何も持っていない代役に対しては失敗し、すべてのボタンを持っている代役に対しては通る。電源の門番も同じやり方で、悪い読みと良い読みで証明した。予習は、ハードウェアで初めて現れていたはずの本当の欠陥を見つけた: コマンドの読み手が「何も待っていない状態になるまで」ポートを汲み出していて、コンソールが毎秒六十回ポーリングし橋がポーリングごとに一行を流しているあいだ、それは決して戻らない。いまは時間で区切られている。
予習の試みはログに印を付け、実験ノートはそれが起きたことは述べつつ記録からは除く。偽物に対する予習は道具の開発であって、ベンチの作業ではないからだ。
記録は docs/lab-notebook.md で、docs/lab-log.jsonl から生成される。うまくいったものだけでなく、すべての試みを見せる: 三回かかった手順は、実験ノートの取っておく価値のある部分だ。ファイルが docs/lab/ に入れば写真を埋め込み、それまでは保留と名指しするので、壊れた画像を一つも運ばず、何も忘れない。
2026-09-08 に追加: 最初のセッションが通り、何も数えていなかった計数器
ベンチに拠点ができた。Uno を挿した Raspberry Pi 4 だ。head/serial-bridge.py がそのシリアルポートを LAN に出し、そのために Pi には何もインストールしていない。あの機械は別のサブネットにある DNSCrypt のリゾルバで DNS を引くので、ここからは apt にも GitHub にも届かないからだ。一つの TCP ポートが、pyserial の socket:// を通して道具に、net: を通して avrdude に、両方に応える。だからファームウェアはワークステーションでコンパイルしてネットワーク越しに書き込み、7,996 バイトで検証された。
セッション 1 は通る。 スコープが応え、ポートが開き、スケッチが STATUS に返事をする。実験ノートの中で予習ではない最初のベンチ作業だ。
そしてそれは最初の発見も生んだ。それは検査からではなく、返事を読むことから来た。 手順 0.3 の STATUS の行は、基板に何一つ配線されていない状態で latch 482 と言った。Timer1 はハードウェアのカウンタであり、何も問わない: その入力ピンは浮いていて、三秒で 3,647 ラッチ、およそ 1.2 kHz の雑音を取っていた。何も失敗しなかった。そこが要点だ。B0 の最初の検査はまるごとラッチあたりのクロック数であり、AT n hh はラッチ番号で引かれ、B3 の再生は全体がラッチ番号だ。コンソールに電源を入れる前に始めた走行は、何も意味しない番号を運んでいて、その下流の数字はどれも実物についての発見のように見えただろう。
直しは同じ一語を二度: コンソール側の二つの入力を INPUT ではなく INPUT_PULLUP にする。コンソールは点いているとき両方の線を強く駆動するので、30 キロオームの内部プルアップは何も損なわないし、消えているときや抜かれているときはピンが部屋を拾う代わりに決まったレベルに座る。同じ基板で前後を実測: 三秒で 3,647 ラッチ、そのあと十秒で 0。
それ自身のために取っておく価値のあること: これは計画がベンチに期待している形そのものだ。検査が赤になるのではなく、計器が、そうであるはずのない数字を報告するということ。
B0 がまだベンチに必要としているもの
計画の順序で。橋が組まれる前に書いたものだ。橋は組まれ (v1b、2026-09-15)、項目 1 は成り立っている: どのポーリングもクロック 8 本、約 1,200 ポーリングの走行が三回、tools/bench-check.py。項目 2 から 5 は書いたとおりのままだ。
- DMC の無いゲームでのラッチあたりのクロック数: 1 分にわたってどのポーリングも 8。
tools/sniff.pyのあとtools/compare-logs.pyで、同じカートリッジ (棚から取ったダンプ) のpad-logに照らす。 - 毎秒のラッチ数を、スコープのフィールドの数え上げに照らす。
- フレームあたりのポーリング数を、ラッチ番号で模型のものと並べる。
- DMC が鳴っているゲーム: ラッチ番号での九の並びを模型のものに照らす。エイリアスの規則がそこで見えるか見えないかが決まる。
- 橋の上の MUTATE: クロックのカウンタにラッチの線を食わせると、ラッチあたり 8 の検査が失敗する。
どれもここでは偽れない。報告はそう述べる。
ビルド時に nes-bench/docs/bench-report.md から取り込まれる。写しはリポジトリの一つだけだ。報告は独自の作業用の言葉をいくつか使う: 報告書で使われる言葉。