まだ開いているもの
道すがら見えて、まだ閉じていないもの。それぞれに、なぜ大事かと、何が閉じる かを添える。追加した日付を付け、終わったら日付とコミットとともに取り消し線 を引く。測定はここには住まない。項目の中の数字は、それを持ち上げた当の数字 で、日付が付いている。
ベンチ (節目 2026-09-15、milestone-2026-09-15-rig-and-bridge.md)
ヘッドからのリセットと電源が開いている (立ち上げ 6.2、6.3)2026-09-17 に完了: リセットボタンを渡る OK1 (J3 の 3 橙を OUT へ、4 黄を GND へ) と、電源スイッチを渡る K1 (J3 の 1 茶と 2 赤)。どちらも Pi から 駆動し、どちらもbench-check.py --hands headが端から端まで二度通した: ポーリングはリセットで 2.0 s、電源の入り切りで約 3 s 止まり、そして戻って くる。コンソールは、手を触れずに既知の状態へ持っていける。- 短いリセットのパルスは計器の床より下にある (2026-09-17)。 GPIO17 を 100 ms と 250 ms 押し続けても、ポーリングの流れには跡が残らなかった。 500 ms 押し続けると 0.5 s 止まった。ポーリングの流れが分解できるのは約半秒 までだ。Pi のブリッジが行を 100 ms の束で渡すからで、だからこれは コンソールがリセットしたかどうかについて何も言っていない。ヘッドの押し 続けは、いまのところ 0.5 s だ。閉じるのは、ラッチの線にスコープを当てて 1 目盛 50 ms にしたとき (そこならラッチの列の 100 ms の空きは明らかだ) か、グラバーがゲームの再起動を見たときだ。
- ブリッジを通るパッドが開いている (4.2、5.2)。それと一緒に J2 のリード の順序も。組み上がり図の上で最後に残った検査だ。
- CH2 の元のリードが 2026-09-15 に壊れた。新しいリードがラッチに付いて いる。
- ゲームパッドの手は、まだゲームパッドに会っていない (2026-09-21)。
head/pad.pyとヘッドのpadの操作は組み上がって、つじつまが合っている: パッドもブリッジも部屋に無い状態でtools/check-pad.pyの 19 のチェック、 そしてイベントデバイスの代わりに FIFO を置いたfake-bridge.py相手の 端から端までのセッションが一回。その五回の押下は、ブリッジから 08、00、01、 41、00 として出て、b3.pyからは五つの AT として出た。それが触れていない もの: 本物のパッド自身のレポートの流れ (自分の頻度と自分の軸で来る) と、 このヘッドの BlueZ がそもそもパッドとペアリングするかどうか。閉じるのは、 Pi にパッドをペアリングして、bench.py <head> pad onで何かの画面を一つ 遊べたとき。 3V3 での純正パッド (「まず測る」の項目 4、2026-09-07 から開いていた)2026-09-27 に完了: 純正パッド (本物の MN4021B) は P4 の上で 3.3 V でボタンに 従う。pad-diagで 30 秒に A を 27 回、それからpad-usbで八つのビット すべて。最初の試みは、10k のデータのプルアップとして 10 Ω の部品が付いて いて失敗した。- USB のパッドのアダプタは Linux のホストとブラウザで動き、iPhone の上で
ゲームを動かす (2026-09-27、2026-09-28)。 P4 のフルスピードの
コントローラの上の
firmware/pad-usb、ホストは USB と書かれた Type-C の ソケットに: Pi は303a:0002 tinymachines NES Padをフルスピードで列挙し、 すべてのボタンをそのキーとして、同時押しも含めて受け取る。2026-09-28 には ブラウザのページ (tools/keydown-page.html、tinymachines.ai/lab/pad-keydownに載せずに置いてある) が八つすべてをそのcodeとして二回見て、ホストの オートリピートにはホストのものと印が付いた (pad-usb-protocol.mdの ステップ 6。ホストの名前はそこに付けることになっている)。ステップ 7 は 同じ日に Safari の iPhone で、tinymachines.ai/nes/playで走った: 列挙され、 二回目で八つのボタンすべてがゲームを動かした。一回目は A、B、Select、Start が 動かし、十字キーは代わりにハイライトをページの枠に沿って回した。電話は フィールドにフォーカスがない限り、ハードウェアキーボードの矢印を自分の フォーカス移動に取っておくからだ (ステップ 6 のページはフィールド一つに フォーカスを置いておく。エミュレータはそうしていなかったが、いまはそうして いる)。ステップ 7 は通った。まだ開いているのは、UART のケーブルを抜いて 電話だけで基板に電源が足りるか。 - BLE のパッドのアダプタは二枚目の C6 から広告し、まだパッドにも電話にも
会っていない (2026-09-21、2026-09-28)。 2026-09-28 に別の C6 基板が
ベンチヘッドからその USB-Serial-JTAG 越しにファームウェアを受け取り、Pi の
無線が空中の
NES Padを聞いた。そこまでに、P4 が決して届かなかった スケッチの不具合 (作られる前に書き込まれていたメーカーのキャラクタリス ティック) と、Serialを USB に載せる C6 のビルドオプションを見つけて直した (pad-ble-build.md)。その基板の GPIO2、3、6 のパッドが電話を動かせば閉じる。 その日より前:firmware/pad-bleは C6 向けにコンパイルが通り (フラッシュ の 56%)、その割り当てと HID ディスクリプタは机の上の 76 のチェックを通り、 妨害は赤くなる。だが、パッドはまだ配線されておらず、ホストはまだペアリング していない。パッドの半分はいまは上の USB 版が証明した。ペアリングはまだ 電話に会っておらず、P4 の上では基板上の C6 が esp-hosted に応えるまで会え ない。モジュールの C6 が応え (C6 の UART ヘッダ越しの新しいスレーブファーム ウェア)、電話がペアリングすれば閉じる。 パッドのケーブルのリードの色が食い違う (2026-09-21)2026-09-22 に 完了: ブリッジと同じ五色で、ベンチで確かめたので、テスターで測った表はその まま立つ (ピン 1 黄、2 青、3 黒、4 緑、5 赤、tools/wiring-diagram.pyのLEAD)。示された並びは組であって、ピンの順ではなかった。図面はもうそれを 刷っていて、直す所は無い。電源の前に導通を確かめるのは今も決まりだが、先に 片付けるべき食い違いは無い。C6 の devkit のヘッダの並びが、ここのどこにも記録されていない (2026-09-22)同じ日に完了: 基板から手で読んで、tools/breadboard.pyのC6_HEADERとしてコミットした。片側十六、どの列も USB の端から。docs/breadboard-pad-ble.svgはそこから描く。残しておく価値のある発見: pad-ble が要るピンはすべて一つの列にあり、GPIO4、GPIO5、GPIO8 (どれも ストラップのピン) が、使うピンの隣の同じ列に並ぶ。だから穴を一つ数え違える と、ただ動かないのではなく基板が起動しなくなることがある。目が読めなかった 理由は今も本当なので、元の項目を次に残す。- ベンチの目は devkit のシルクを読めない (2026-09-22)。 ほかの図面はどれ
も信号と GPIO の番号で描いていて、回路図と直角のシートにはそれで足りる。
ブレッドボードのシートは「どの穴か」を言わなければならず、それには devkit の
二本のヘッダに沿ったピンの物理的な並びが要る。それは基板についての事実で
あって、ネットリストについての事実ではない。このリポジトリには無く、記憶
から打ってはならない: このベンチはよそから持ち込んだピンの番号をもう断って
いる (
probe-plan.mdはわざと一つも名指さない)。ベンチの目はそれを読め ない。 2026-09-22 に測った: ズーム 1000 でシルクのピンのラベルは約 1 mm、 回転していて、この作業距離で BRIO が分解できる大きさより小さい。フォーカス 26 (devkit の高くなった面に合わせる) は基板の面の 18 よりぼやけるので、 フォーカスではなく分解能の問題だ。基板そのものはよく読め、部品はRGB@IO8からそう特定した。閉じるのは、ラベルを目か手で一度読み、シートを描ける表に することで。 - 手の遅延は測っていない (2026-09-21)。 パッドのレポートは、595 がそれを
保持するまでに Bluetooth、BlueZ、921600 の USB シリアル、そしてブリッジ自身
のループを渡り、そのどれも計っていない。推測せずここで測る価値があるのは、
このベンチには測れるからだ: ブリッジはすべての読み取りにラッチの番号を押す
ので、欲しい数は、ホストがイベントを見てからコンソールがバイトを読むまでに
何回の読み取りが過ぎるかで、それはセッションの
head.logとbridge.logの引き算一つだ。測るまでは、このリポジトリのどこも、このアダプタが遊べる ほど速いと言ってはならない。 Pi の GPIO27 はプルダウンで休んでいる (2026-09-17)。つまり電源投入 からヘッドがそのピンを主張するまで、リレーは入だ。2026-09-17 11:56 EDT に完了: Pi のブート設定にgpio=27=op,dhとgpio=17=op,dlを入れ (古いファイルはその横に残した)、Pi を再起動すると、どちらのピンも出力と して読み返せた。GPIO27 は高 (リレーは開)、GPIO17 は低 (リセットは押されて いない)。まだテスターで測るべきこと: Pi を起動した直後に、リレーの接点が COM と NO の間で開いていること。
較正カートリッジ (計画 2026-09-13)
calibration-plan.mdの C0: 機械側は 2026-09-13 に完了 (nes@ 35cfe6e)、実機側は開いている。cal.nesとそのマニフェストはroms/にあり、Pi に載って配信されている。開いているもの: ROM をフラッシュカート か物理カートへ載せること (手引きはbuild-the-cal-cart.md)、リーダーの ダンプを crc3221091B99に照らすこと、画面がグラバーの上で切り替わって いくのを見ること、そしてグラブしたフレームから最初のストリップを読むこと。 これがtools/cal.py grab(C1 の最初の道具) だ。- C1: 機械側は作った (
tools/cal.py、自己テストは緑、妨害は赤)。実機側は開いている: カートをコンソールに入れた状態で、変種ごとにパレット画面のスコープの記録を取り、それからグラバーのフレームを取る。C2 から C4: 未着手。
模型の側
-
マルチカートのメニューはコールドブートの後 Start を無視する: 2026-09-18 に閉じた。ベンチ自身のものだった。 無視などしていなかった。ヘッドが、 ブリッジの
RESETをまたいで前のブリッジのセッションのラッチ番号を保って いたのだ。だからRESETの後のWAIT nは、前のセッションがラッチ n を 過ぎていればいつでも即座に返り、その後ろのARM(SCPI の三秒) がラッチ 190 あたりでメニューを捕まえてしまった。200 での押しより前だ。Start を 「無視した」走行がそれを示している:head.logのwait for latchからarmedまでが 3.1 から 4.0 s で、これはアームだけの時間だ (024438、 025049、025348、025525、031324、031502)。一方、二度のリセットの後で押しが 「効いた」もの (025800) は 12.8 s を使っていて、これは本物の待ちだ: 二度 のリセットの間の五秒が、ブリッジの新しい計数をヘッドへ届かせた。head/headd.pyで直し (ブリッジの# resetの確認応答が計数をクリアする。 3b22f7f)、もう一度問うた: リセットを一度もしない場合 (電源を切った状態で ブリッジをゼロにし、それから電源。走行 193915)、リセット一度 (194105)、 リセット三度 (194257) で、押しは毎回効き、ポーリングは Super Mario Bros. のタイトルの行 (247、249)、模型のそれと同じ場所で起きる。模型の側は道すがら 作ったもので、そのまま残る:nes-consoleのConsole::reset_buttonとbench-script(秒とリセットを込みで再生する台本。nes @ a2a9f15) で、実機に もう一度問う前に、リセット一度の後と二度の後で押しが効いた。間違った読みか ら書かれたもの (コールドブートの状態で条件付けられたマスク。mario-dissection.mdとencyclopedia.mdの中、そして[ram]のつまみの 動機) は、それが立っていた場所で訂正した。 -
split-score の合成の往復が 0.77 と読んだ: 2026-09-19 に閉じた。復元の バグだった。 合成の記録と模型自身のフレーム F との、絵全体の相関が 0.77 と読み、F+1 と並んだ。綺麗な合成なら 1 と読むはずのところだ。代役のスコープ のつまみはどれも関係なかった (レート、レート誤差、オフセット、雑音をすべて ゼロにしても 0.7735)。オフセットを探すと、四標本、半ドットずれたところで絵 は厳密 (r 1.0000) だった。捕捉の復元 (
ntsc-crtのrecover_nes) は、どの フレームも副搬送波の原点 0 から始まると仮定していた。そして NES は各フレーム を、一周期の三分の一ずつ離れた三つの原点のどれかから始める。そのバースト ロックは、別の原点から始まったフレームを 4 か 8 標本ずらして、仮定を真に してしまっていた。色にも平らな領域にも見えず (E2 の点数は変わらない)、自分 自身のテストにも見えなかった。そのテストの連鎖は、固定されたフレームが原点 0 になるように仕立てられていたからだ。v0.2.12 は原点を実測し、それにロック し、それを名指しする。合成の往復は F で 1.0000 と読み、隣は 0.62 から 0.71 だ。 -
実機の絵は模型の絵より四分の一ドット右にある: 開いている。測定だ。
split-scoreはいま位置合わせを印字する。実機のフレームを模型の F に最も よく重ねるずらし量だ: 復号後の標本で 1 から 3 (一ドットは八標本)、平均 2。 三つのセッションからの 8 本の記録 (分割、E3 の台本による再生と手による再生) で、そこでの r は 0.95 から 0.99。合成は 0 と読む。候補: DAC 自身が絵の エッジを同期のエッジに対して出すタイミングか、スコープのチャンネルの、細部 と同期の間の遅延。記録したもので、当てはめたものではない。バーのカートリッジ の鋭いエッジをスコープだけで見れば (E1)、ゲームの内容に左右されない数字が 得られる。Duck Hunt のフィールド (2026-09-19、exercise.md) は 4 標本と 読む。 2026-09-20 に絞った: Duck Hunt の 4 標本は副搬送波の原点で、これでは ない。split-scoreの六つ目の測定は両側の原点を名指しする。そして Duck Hunt の三本の記録ではどれも、実機の原点が模型のそれより 4 標本進んで いて、位置合わせはちょうど 4 と読む。Super Mario Bros. の分割では原点が 一致し、位置合わせは 2 と読む。だからこの二つは一つの量ではない。下の項目 が想定していたのはそれだった: 二つが重なるのは、原点がずれている場所だけ だ。ここに残るのは、原点が一致したときに残る 2 標本だ。そして 8 本の記録の 1 から 3 は、六つ目の測定を横に置いて読み直し、そのうちどれが原点の差も 抱えていたのかを見るべきだ。 -
Duck Hunt のフィールドは模型の F ではなく F-1 と F+1 に一致する: 2026-09-20 に閉じた。フレームは F だ。読んでいたのは色の位相だった。 ラッチ 900 でのフィールドは、絵 920 から 929 までドット単位で静止している (
nes-consoleのframe-motionのプローブ)。だからあの記録の上で測った ものはどれも、F-1 と F+1 を区別できなかった。ドットが同一の二つのフレーム は、復号後の標本の 9 パーセントで違う。そして五つの候補はきっちり二つの組 に分かれる: F-2、F、F+2 が一つの数字を読み、F-1 と F+1 が別の数字を読む。split-scoreの新しい五つ目の測定は候補を二度採点する。一度は、候補が違う ドットを描いている標本の上で (副搬送波の一周期にわたってぼかし、各候補は 自分の最良の整列で)、もう一度は復号された絵の上で。そして、アヒルが上がって いく二つの捕捉 (exercise/dh-duck.txtはラッチ 989、dh-duck-late.txtは 1020) は、何が描かれたかによって F+0 と読んだ。rms は 0.047 で、次の 候補の 0.117 と 0.158 に対して、床は 0.020 だ。フレームの規則は、行 249 で ポーリングするゲームの上で成り立つ。記録しておく罠: 測定の最初の版は F に 対して当てはめた位置合わせを使っていて、スクロールするゲームではそれが、 測ろうとしている差を吸収してしまう。MUTATE_FRAME=1は緑になった。整列を 当てはめるのは、どの候補も争っていない場所だけにする。 -
コンソールが CPU サイクルの内側のどこでカートリッジに /IRQ を渡すか: 2026-09-20 に当てはめた。開いているのはその当てはめの方だ。 blargg の
4-scanline_timingが通るようになった。そこに至るには二つ必要だった。あの ROM は割り込みの到着を PPU クロック一つに挟み込むのに、コンソールはそれより 大きく、しかも独立した二つの形で外れていたからだ。一つ目は基板の側で、こちらは閉じた。A12 フィルタが A12 の低を 9 ドット取って いたが、実機は 10 ドット取る。9 ドットはちょうど CPU 3 サイクルで、M2 の三回目 の立ち下がりが立ち上がりより前ではなくその上に乗ってしまい、nesdev の 「立ち下がり三回のあいだ低のままであること」を満たさない。これが効くのは 背景が $1000 のときだけで、フレームあたり 1 クロック。A12 はプリレンダ行の 最後のパターンフェッチの後に落ち、行 0 の最初で上がる。実機が 241 クロックに するところ、フレームが一つおきに 242 クロックになっていた。nes-bus 0.1.6 で 直り、コンソールの
mmc3-probeはいま自前のカートリッジをどちらのモードでも 走らせるので、数がそのまま読める。二つ目はコンソールの側で、こちらは当てはめだ。カートリッジの /IRQ には遅れが まったく無く、レベルは次に来た CPU 半サイクルで読まれていた。これは線であり、
CART_IRQ_DELAYはいま基板から 17 マスター半ステップ遅らせて押さえている (CPU 半サイクルに 12、ドットに 8)。1 クロックで挟むにはこの粒度しかない。examples/irq-sweepは遅れを全通り走らせて、それぞれが何を報告するか印字する。 ROM が許すのは 14 から 21 までで、その外は通らない。17 はその真ん中だ。これは CPU 半サイクルより長く、ピン 15 からの配線にしては長すぎる。だからこの値が 肩代わりしているものの大半は、カートリッジ側の何かではなく、コア自身が サイクルのどこで IRQ を標本するかだろう。閉じるのは: ベンチで CPU の phi2 に 対してピン 15 にスコープを当て、帯を真ん中ではなく一つの数に絞り、その余裕が 経路のどちら端のものかを言うこと。どちらにせよ、どのゲームも一行を失わない (分割は 341 ドット幅だ)。 -
MMC3 の A12 フィルタはドットを数えるが、実機は M2 の立ち下がりを数える: 開いている。ここにある ROM ではどれも見えない。 10 ドットは、blargg が 見るところすべてで実機と一致する値だ。しかしその裏にある議論は位相の話で、 M2 の立ち下がり三回が 9 ドットの窓にきっちり収まるかどうかは、その窓が CPU の クロックに対してどこから始まるかで決まる。ドットの数ではそれを言い表せないが、 コンソールには言える。整列を持っているのはコンソールだからだ。決め手になるのは 背景が $1000 のときのプリレンダ行から行 0 への境目で、そこの隙間がちょうど 9 ドットになる。フレームの中の他の窓はどれも 2 ドットか数百ドットで、際どい ところには無い。閉じるのは: フィルタを M2 の立ち下がりを数えるように書き直し、 同じ 5 本の ROM に照らし、どの整列が答えを変えてどの整列が変えないかが出るよう 整列を掃くこと。
-
実機の色の位相は隣のフレームのものだ: 2026-09-20 に原因を名指しした。 残っているのは一フレームぶんだ。 実機の副搬送波の原点は、Duck Hunt の どの記録でも模型のそれより 4 標本進んでいて、Super Mario Bros. の分割では 等しい。そしてその差は四本すべてで二フレームの刻みを越えても残るので、 位相を間違って持ち越したものではなく、定常的なずれだ。静止したフィールドと 遅い方のアヒルでは、実機の原点は F-1 と F+1 で模型のそれとちょうど等しい。 だからそれらのフレームの点数が良かったのだ: 色の位相は原点を読んでいたので あり、下の項目が想定していたとおりで、いまはそれを数字で言える。
仕掛けは
ntsc-gridの中にある: フルフレームは原点を 4 標本進め、短い フレームは 8 進めるので、並びは三つの原点のうち二つを行き来し、三つ目には 決して寄らない。だから F-1 と F+1 は、何が描かれていようと、F の持たない 原点をいつも共有する。五つ目の測定がフレームではなくパリティを名指しする のも、これが理由だ。4 の差は 一フレームぶんだ: 一方が短いフレームと数えたものを、もう一方 はフルフレームと数えた。種のせいではない (
Pictureは位相 0 から始まり、 Super Mario Bros. の経路ではその種は正しい)。刻みのせいでもない。同じ日に手持ちの記録を掃いた。食い違いは早くて、まれだ。 六つ目の測定を 8 本の記録に当てた。どれも自分の
POWER ONから始まっている:ラッチ 経路 差 見落としたフレーム 8、60、124 メニューの最初の二秒 8 2 300、600 Super Mario Bros. のタイトルとレベル 0 3、一周した 900、989、1020 Duck Hunt のフィールド 4 4 それぞれの組の中の三度の別々の電源投入が同じ数字を読むので、実機の 電源投入時の原点は再現する。模型が決して追えないような電源投入のくじ引き ではない。計数は mod 3 で積み上がる。だから範囲の真ん中では、増えていく のではなく 0 と読む: 300 では、模型は三つ見落としているのであって、見落と しが無いのではない。
発見はその形だ。差はフレーム 8 の時点でもう 8 になっていて、 フレーム 124 までは動いていない。だから食い違いは最初の八フレームで二回 起きて、そのあと百フレーム以上何も起きない。もう一回が 300 までに来て、 もう一回が 900 までに来る。これが指しているのは、描画を切ったり入れたり する瞬間、そして何より PPU のウォームアップだ。そこでは実機が最初の数 フレームのあいだ書き込みを無視するし、模型は実機より一フレーム早く、 あるいは遅く描画を有効にしているかもしれない。
模型は実機より四フレーム遅く描画を始め、その後は描画の窓ひとつごとに もう一つぶん増える (2026-09-20)。 足りなかったプローブは
nes-consoleのorigin-walkだ: 模型自身のパリティをフレームごとに、それが持っている 原点を、そして描画の状態が変わったフレームのすべてを出す。F でのその原点 は、三つの経路すべてで六つ目の測定の模型の列と一致する。これは同じ数字を 独立に二度計算したということで、だから残りを読む値がある。経路 F 模型の描画が変わったところ 実機に多かった短いフレーム メニュー 19 11 で入 2 Mario のタイトル 316 11 で入、213 で切、245 で入 3 Duck Hunt 922 11 で入、253 で切、259 で入、623 で切、627 で入 4 最初の食い違いは三つに共通で、いちばん大きい。模型が描画を入れるのは フレーム 11 だ。短いフレームが二つ多いというのは、奇数のフレーム 7 と 9 からしか出てこないので、実機は遅くともフレーム 7 には描画していて、 6 だった可能性もある。模型の側でこれを止めているものは何も無い: PPU の ウォームアップは実装していないので、フレーム 11 は、マルチカート自身の 起動コードが準備ができたと判断した場所だ。実機の側のコードは、四フレーム 早く判断した。
その後は、描画を切っている窓ひとつごとに、もう一つぶん増える。Mario の 経路で計数が 2 から 3 になり、Duck Hunt で 4 になるのはそれだ。模型の 切っている窓は 32、6、4 フレームで、毎回、実機のものより奇数のフレームが 一つ多ければそれで足りる。
閉じるのは: なぜ模型の側で起動の待ちが長くなるのかだ。よくある形は、 ゲームが PPUSTATUS をポーリングして vblank を二度待つものなので、容疑者は vblank のフラグの電源投入時の状態と、最初の vblank のタイミングであって、 符号化器でも原点でもない。ラッチ 900 より早い Duck Hunt の記録があれば、 後の方の食い違いも挟み込めるが、手持ちの記録にはそれが無い。
以下は取って代わられた記述で、そのまま残してある。ここが置いている想定 こそ、測定が覆したものだからだ。
フレームが内容で決着した後でも、同じ記録は実機の色の位相を、模型の F よりも F-1 と F+1 に近いと読む: 静止したフィールドでは 0.183 に対して 0.100 と 0.107、動いて いるフィールドでは 0.121 に対して 0.113 と 0.117 で、一ドット半の内側の どんな整列もそれを直さない。NES は各フレームを、一周期の三分の一ずつ離れた 三つの副搬送波の原点のどれかから始める。
recover_nesは v0.2.12 以来、 実機のそれを実測している。一周期の三分の一は復元の格子では 4 標本で、これは このゲームで位置合わせが読む値でもある。だからこの項目と、上の四分の一 ドットの項目は、一つの量を二度見ているだけかもしれない。候補: 模型の 符号化器が、そのパリティのフレームにどの原点を与えるか。それに対して実機が 実際にどこから始めるか。閉じるのは: 一本の記録の上で、フレームごとに両側の 原点を名指しすること (復元はすでに実機の側を名指ししている)。あるいはバーの カートリッジをスコープだけで見ること。 -
実機のルマは、いちばん下の行では外れが小さい: 2026-09-20 に閉じた。 行ではなく色の話だった。
capture-scoreの新しいPROFILE=<colour>は、ある一色のルマを両側で行ごとに報告する。模型が他の何からも整定距離ぶん 離して描いているドットの上でだ。Super Mario Bros. のタイトルの$22は 行 1 から 207 にわたり、実機は模型より -0.0443 低く、差は百行あたり +0.0001 傾く。Duck Hunt の$21は行 1 から 148 で -0.0444、$29は 157 から 225 で -0.0445、$18は 183 から 239 で -0.0283 と読む。同じ行の 二色が -0.0445 と -0.0283 と読み、一色は絵の三分の二にわたってもずれない。 復元の中で、フレームの下側で弱くなるものは何も無い。 -
垂直同期の最初のドット: 2026-09-18 に閉じた。 スイッチレベルの 2C02 で実測した (
2c02のvsync-probe): 同期は行 244 の水平同期が始まる場所、 ドット 280 から始まり、一行ずつ離れたブロードパルスが三つ。実機の記録も 同じ形を示す。符号化器はそれを 64 ドット遅く置いていた (ntsc-crt v0.2.10 がそれをダイに照らして押さえる)。poll-line.pyはそこから位置を決める。 一行の十分の六は、それにdissect.pyの行の算術 (pre-render の行を 0 と 番号付けし、飛ばしたドットごとに一ドットずれる。同じ日に直した) が足された ものだった。両方が正しくなると、実機のポーリングは、模型自身の記録された ストロボの位置と、メニューでは 0.01 行、ゲームの中では 0.03 行まで一致する (mario-dissection.mdの「実機でやったこと」)。 -
同期の行より後でポーリングするゲームでは、トリガされたフレームが絵一枚 ぶん遅い: 2026-09-18 に閉じた。 最初のスクロールする記録 (F+1) の上で
split-scoreが見つけた。コンソールはいまどのラッチでも PPU の位置を 記録し、run_to_picture_after_latchがそこからフレームを、ダイが示す始まり に照らして置く (nes @ efbcc46、tests/latch_frame.rs、MUTATE=1 で赤)。capture-scoreとsplit-scoreはこの規則を共有し、記録は F+0 を名指し する。E2 の数字は静止した絵の上のもので、これには依存していなかった: 同じ 日の午後に走らせ直すと、朝の記録は千分の一まで同じ点数になり、三本目の記録 も同じ色相を繰り返す (exercise.md、E2 の再走)。 -
模型の色相を実機に照らす (2026-09-12)。 タイトル画面では二つの目が 0.7 度まで一致し、模型は彩度の高い色でそこから 12.6 度と 14.1 度離れて 座っている (
eyes-vs-scope.md)。2026-09-13 に、CPU とスプライト DMA を 直した模型で再走: 12.61 と 14.1 で、小数第二位まで同じだった。だから色相は 絵の連鎖のもので、その上流のものではない。2026-09-13 に位置を特定した (eyes-vs-scope.mdの「色相はどこに住むか」): 目のセッションの負荷の下での 実機のアナログ出力、wiki が微分位相歪みと呼ぶレベル依存のスルーだ。デコーダ ではない (信号の段と復号後の段が同じように違う)。表でもダイでもない (スイッチレベルの 2C02 では、どの色相も表のとおりに話す)。色相 12 でもない (同じ画面を先に録ったものは四度の内側に座る)。閉じるのは: 目と同じ負荷の 下で、そしてスコープだけで、バーのカートリッジを捕捉すること。そして wiki の 電圧依存の RC の段を符号化器に入れ、その定数を負荷ごとに当てはめ、MUTATE で 赤にすること。 2026-09-18 にスコープの上で (E2、exercise.md): ラッチ 300 でトリガした 捕捉から復号した実機のタイトルを、同じラッチでの模型のフレームに照らして、 二度、二つの垂直の尺度で:$22(空) は二度とも -9.1 度、$17(タイトルの 箱) は -3.0 と -3.1。目の発見が言ったとおり、レベルに依存する。実機の上の 二点は残差なしに直線に乗るので、この数字はバーのカートリッジがすべての レベルを与えるまで、knobs.toml(計画 1 の規則) ではなくここに記録して おく。 連鎖のどこか: 符号化器のパレットの位相 (ntsc-source-nes)、模型が合成する バースト、あるいは自分の合成を読んでいるデコーダ。閉じるのは: 模型が符号化 して復号した一つの平らな色を、スコープの記録から復号した同じ色と並べ (title1.u8にはロゴの茶色と文字のシアンがある)、段ごとに位相差を測り、 その段を名指しすること。 -
C0 の妨害は述べられているだけで、走らせていない (2026-09-12)。 閉じた サイクルの計画は、別の ROM なら平らなブロックの一致に失敗しなければならない と言っている。
eyes.py compareには、ROM を一族のテストカートリッジと入れ 替えて赤で終わらなければならないMUTATE=1が必要だ。 -
模型のフレームはフレームで、実機のそれは瞬間だ (2026-09-12)。 三者比較 は、入力なしの電源投入から数えてフレーム 180 を使った。模型のタイトルには 下線の上に小さなスプライトが出ていて、どちらの目もその瞬間には持っていな かった。あのスプライトは 2A03 のラングの古いスプライト DMA (下、完了) だったと分かり、瞬間の違いではなかった。瞬間の問いは残っていて、模型の フレームをラッチに結ぶ C2 のトリガで閉じる。2026-09-13 に、直した模型で 再走: スプライトは消え、人物はコンソールのものと同じ場所に立つ。数字は 動かなかった。
-
チップのリポジトリのテスト群を、既定のまま走らせた (2026-09-12)。 ピン を上げたときに 2c02 は 16 テスト、2a03 は 14 テストを出した。ゴールデンの テストは、必須にしない限りファイルが無ければ飛ばされる。どちらかを次に リリースする前に、両方を
REQUIREの変数を設定して走らせ直す。 -
公開サイトの上で、コンソールの記録を取り込み直す (2026-09-12)。 /nes ページの数値は
board-nes.pyが書く記録から来る。コンソールは 5ecc62d (マッパー 66、新しいピン) へ移り、記録はそれより古い。公開のチェックアウト でboard-nes.py --boardを走らせ、それからデプロイする。 -
コンソールの CPU が直ったラング 3 を走らせるのは、ピンが動いてからだ (2026-09-12)。 2a03 と nes のリポジトリは
v6502-microとv6502-pinsを 89ae24f にピン留めしている。継ぎ目の修正 (trace-plan.md、T0) の一つ前 のコミットだ。閉じるのは: 両方のピンを上げ、コンソールを再ビルドし、 カートリッジのトレースを走らせ直してGAMEが出ること。 -
トレースは走行まるごとだ (2026-09-12)。 リセットから始めて一フレーム 1.69 MB。ピンの形式が h=0 から始まるからだ。窓を切るには T2 の
LOADと いう扉が要る。それまで、長い走行は/mnt/tmの下の大きなファイルになる。 -
6502 自身のオラクルは、インデックスの増加と境界をまたぐ形を一度も組に しなかった (2026-09-12)。 ピンのゴールデンの 256 オペコードのトレースは レジスタをロードで設定する。blargg の命令のテストは、あの並びなしで通る。
tests/seam.rsはいま二十二の対を、すべて書き下ろしで、両方向に押さえて いる。片側だけの最初の版が間違った修正を通してしまった後のことだ。本当に 閉じるもの: 表の記録器の中に、X か Y への ALU の書き込みで終わる文脈を 記録すること。そうすればセレクタの古さは、回りを当て木で固める代わりに 実測される。 -
ラング 3 は、成立した分岐の最後のサイクルに落ちてくる NMI を即座に 取る。ダイは一命令待つ (2026-09-12)。2026-09-12 に完了、6502@ 9b3ad9a (tests/branch_interrupt.rs、表のためには PROBE=1、MUTATE_BRANCH=1で赤)。 -
2A03 のラングの DMA の解放は、ダイが再開する半サイクル前に報告される (2026-09-12)。2026-09-12 に答えが出た: 記録の RDY はピンの言い分 だった。2A03 は自分のコアへ一サイクル遅れて渡す (2a03のrung.rs、 そのダイの上で実測)。そして、ピンが示すとおりに解放された素の 6502 は そのまま先へ進む。トレースはいまコアのレベルを書く (nesのCpuStep::core_rdy)。再生のRDY_RISE_SHIFTは、また実験のつまみに戻った。 -
2A03 のラングのスプライト DMA は、最後に読んだ状態のページを写して いた (2026-09-12)。2026-09-12 に完了、2a03@ 54295cc: DMA の読み 出しが、止められたコアのメモを経由していた。ゲームが固まっていた記録と ラング 0 が一致したことで見つかった。tests/stalls.rsはバス上の二つの DMA、MUTATE_DMA_MEMO=1で赤。三者比較で下線の上にいた迷子のスプライトは、 これだった。 -
フラッシュカートのパッドのカートリッジが古い (2026-09-12)。2026-09-13 に書き出し直した (docs/procedures/2026-09-13-pad-cartridge-for-the-flashcart.md):pad.nes、crc599C4188、600 フレームで 597 回のポーリング。roms/に あり、Pi に載って/nes/pad.nesで配信され、そのハッシュも記録されている。 カードに書くのはあなたの仕事だ。手順の中のチェックサムが、そのカードがどの カートリッジを保持しているかを言う。
グラバーとそのドライバ
- Pi でカーネルを更新すると、黙って
/dev/video2が消える (2026-09-11)。 Roxio のドライバは、走っているカーネルのupdates/の下 にあるツリー外のモジュールだ。新しいカーネルはそれを持たない。カーネルを 連れてくるapt full-upgradeの後は毎回、Pi の上でhead/roxio-em28xx/build.shを走らせる。閉じるのは、同じツリーを DKMS で パッケージすること、あるいは更新の習慣に注記を入れることだ。 - 開くたびにカーネルの警告が一つ (2026-09-11)。
v4l_querycapが、 ドライバの capabilities がそのデバイスの capabilities の上位集合になって いないと警告する。無害だが、dmesgがうるさい。閉じるのは、ドライバのvidioc_querycapがちょうどdevice_caps | DEVICE_CAPSを報告すること。 - 上流へ (2026-09-12)。 パッチの二つの部分はベンチ固有ではない: EM2980
のチップ id と Roxio のボード、そして内蔵デコーダについて
querystdが 現行の規格で答えること。ベンチがしばらく使ったら、linux-media へ投稿する 価値がある。
ベンチ、各回の前と最中
-
ヘッドと立ち上げのブリッジが、どちらも UNO のポートを欲しがる (2026-09-12)。
serial-bridge.serviceが/dev/ttyACM0を握っていて、 ヘッドは起動していない。C1 で閉じる。二つのユニットの間にConflicts=を 置き、立ち上げの道具の問いに答えるためのbridgeという語をヘッドが持つ ことで。 -
カメラが基板に向いていない (2026-09-11)。2026-09-13 に完了: ブレッドボードの上のアームに載せた Logitech BRIO、実測した既定値と三つの 画角を持つtools/eye.py(head/README.md)。QuickCam は無くなった。元の 記述: これまでのフレームはどれも窓だ。向きを合わせ、フレームを一枚グラブ し、それからヘッドのPHOTOという語を。 -
サウンドカードの入力には何も入っていない (2026-09-11)。 C-Media の 入力はマイクレベル、モノラル、ゲインは 0 から 16。コンソールの音声出力には 減衰器が要るか、線のレベルを低く保つ必要がある。それからヘッドの
EARS、 そして模型の段に照らす N7 の比較だ。 -
インバータの空き入力五つ (2026-09-10)。 2026-09-10 から回路図では GND へ行くピンとして描かれていて、配線表と早見表もそれを結べと言っている。 第 3 回でやらなければならない: 浮いた CMOS の入力は発振する。
-
リボンとブレークアウトのヘッダがブレッドボード図に載っていない (2026-09-11)。 あの図はチップを実際の列に描き、ケーブルは基板外の端子と して描いている。九ピンのリボンのヘッダと二つのブレークアウトがどこに座るか は記録されていない。第 3 回でそれを固定したら、その列を
tools/breadboard.pyに入れて、図が基板そのものになるようにする。 -
コンソールがメニューの SMB のロゴを、崩れたタイルで表示する (2026-09-13)。 新しい目を設置している最中に取ったグラバーのフレーム: DUCK HUNT の文字と ® は正しく描かれているのに、SUPER MARIO BROS のロゴの 箱が、間違ったパターンテーブルのタイルで埋まっている。メニューはアニメー ションのために一フレームに二度 CHR バンクを切り替える ($BF02/$BF03) ので、 CHR のバンクの線か、カートリッジのコネクタの接触が最初の容疑者だ。模型は 同じバイトからロゴを正しく描く。閉じるのは: カートリッジを差し直して もう一度グラブすること。それでも残るなら、マッパーのラッチの CHR バンクの ビットにスコープを当て、OSCR のリーダーがカートリッジを触った後にもう一度 グラブする (そのダンプは綺麗だったので、ROM ではない)。一度だけ見えた: 同じ日の 12:02 の時刻付きの画面のフレームはロゴを正しく描いていて、その間 に何も触っていないので、これは間欠的だ。だからいまは五分ごとの画面の フレームがその見張りだ (
captures/pi/の中の、両隣が良好な一枚の崩れた フレームが、スコープへ持っていく証拠になる)。
カードとリーダー
tools/oscr-card.pyは書かれていない (2026-09-12)。 更新と最初の 取り出しは、道具が持つことになっている検査を付けて手でやった (card-plan.md)。udev のマウントは存在していて、働いている。- リーダーはカートリッジを 512 バイトで同定する (2026-09-12)。 バンク 切り替えのある基板では違うゲームの名を挙げることがあり (組み合わせ カートリッジに対して Super Mario Bros. と名付けた)、間違ったサイズで ダンプすることもある。リーダーの側に直すものは無い。ここでの注記は、名前の 付いたカートリッジは、ダンプのチェックサムが一致するまで検査された カートリッジではないということだ。
ビルド時に nes-bench/docs/open-items.md から取り込まれる。写しはリポジトリの一つだけだ。報告は独自の作業用の言葉をいくつか使う: 報告書で使われる言葉。