6502tinymachines

スイッチで見た 2C02

P0 報告、作業の後に書かれたもの。

走行スタンプ: 2026-09-02、このリポジトリの最初のコミット、rustc 1.97.1、 halfphi v0.1.2 (公開されたクレート、手を入れていない)、cargo test --workspace 3 テスト緑、MUTATE=1 は赤にならねばならない所で赤。引き継ぎの スケッチは docs/ppu-handoff-v0_1.md で、2026-09-02 にディレクターが tinymachines/2c02 というリポジトリ名で承認した。

閉じたもの

  • 2C02 は halfphi の同一の呼び出しを通る四つ目のチップだ。パーサの変更は ゼロ: parse(ChipSource { rails: gnd/pwr })、Netlist::decode、 Engine::new。一族で三つ目のレールの綴り (6502 は vss/vcc、6800 は gnd/vcc、2C02 は gnd/pwr) が、レールをパラメータにしてある理由だ。
  • 個数、本物のパーサ二つが一致: トランジスタ 16,758 個、ノード 8,770 個 (id は 10,905 まで)、名前 858 個。スケッチの最初の数字 16,871 は、Quietust が transdefs.js のブロックコメントの中に残した 114 個のトランジスタを数えていた 正規表現のものだった。コメントを理解する二つ目の正規表現は 16,757 と言い、 一項目を取りこぼしていた。halfphi とリファレンスの JS エンジン自身は 16,758 で一致し、個数のテストがこの顛末を記録している: 計器はコードより先に嘘をつく。
  • 電源投入はチップ固有の助けなしに収束する (収束しない整定はゼロ)。6800 と Z80 が立てているのと同じ主張だ。
  • 本物のチップの知識が一つだけ必要だった。そしてそれがこのマイルストーンの 発見だ: 2C02 には 38 個の電源ゲート付きトランジスタ (supply-gated) がある (6502 には一つも無い)。シリコンの中ではそれらは永久に導通している。 リファレンスの初期化はそれらをオンにする。halfphi の電源投入はすべての トランジスタをオフから始め、レールは再計算されないので、何もそれらを切り替え ない。Ppu::power_on がまさにその 38 個を一度だけ導通にし、その場で文書化して あり、MUTATE=1 の証明はそれらをオフに戻す: すると再生はステップ 0 で食い違う (以前の妨害は代わりに io_ce ピンを浮かせるもので、ノードはただ電荷を保持した。 対象が設計上生き延びる妨害は何も証明しないので、差し替えた)。
  • リファレンスのトレースが再生する。 tools/golden-trace/gen.js は Quietust 自身のエンジンをヘッドレスで走らせ (wires.js + chipsim.js のみ、初期化と ステップは macros.js から文ごとに実装、両方のバスは両側で駆動しない)、 10,906 個のノード枠に対して 601 状態を出す。Rust のエンジンは 601 状態すべて にわたって 10,906 ノードのうち 10,897 でビット単位で一致する。

食い違う九つと、その一覧が閉じている理由

スプライト経路の入力ラッチ九つは、リセット接続を持たない動的な記憶だ: その電源 投入時の状態は本当に未定義で、二つのエンジンはそのコイン投げを決定的に、しかし 別々に行う。実測: 六つ (スプライトのデータ入力ラッチとそこから導かれる項、うち 二つは無名) は、本物の値が最初にそこを通る半ステップ 14 までに一致へ流し出され る。三つ (x 反転の入力ラッチとその後続) は、メモリ無しの自由走行では一度も書か れず、トレース全体にわたって自分のコインを保持する。ゴールデンのテストはまさに これらを、名前がある所では名前で除外し、早い側と遅い側の分かれ目は実測した流し 出しのステップに置く。十番目のノードがあれば走行は失敗する: マスク付きの比較の 正直さはマスクの小ささまでしかなく、6502 のレール書き込みのバグはまさにこの形の 盲点の陰に隠れていた。

スループット、実測 (スケッチの見積もりを置き換え)

ラング 0 は一族の Ryzen 5 5600X で 50,457 半ステップ/秒で走る: トランジスタ が 4.8 倍あるのに 6502 の 29,600 より速い。描画を切ったリセット済みのチップは ほとんど静止しており、一回の整定は活性なコーンだけを歩くからだ。この状態での 1 フレーム全体はおよそ 14 秒で、スケッチが書き下ろした「数分」ではない。描画を 入れればもっと遅くなり、P1 はそれを推測ではなく実測する。

持ち越し

  • P1: バスのハーネス (VRAM、パレット、OAM、レジスタ)、自由走行の描画、 DotFrame の抽出、ntsc-crt を通した最初の光、そして DAC のタップ (vid_luma*、vid_burst_*、vid_emph はいずれも名前付きノード) を、先に 許容を述べた上で data/nes-levels.toml に対して押さえること。
  • x 反転のラッチ三つ組は、P1 が本物のスプライトデータをそこに書いた瞬間に除外 一覧から外れる。除外が縮むこと自体、P1 で主張する価値のあることだ。
  • スケッチからの未決: DotFrame を共有の規約クレートに移すかどうかと、Quietust の ライセンスへの礼状。

2026-09-04 に置き換え: 未定義のラッチは無かった

上の九ノードの除外は、シリコンではなくエンジンのものだった。halfphi 0.1.6 は、 レールもプルも持たないグループを、リファレンス自身の面積による多数決で解決する (それまでは帯電した構成員が一つあれば高になった。2C02 の getNodeValue は 構成員の面積で重み付けする)。その下では P0 のゴールデンは、x 反転の三つ組も 含め、601 状態すべてにわたって 10,906 ノードすべてでマスク無しにビット厳密に 再生する。P1 のより広い一族も同じ形で閉じた (docs/p1-report.md、この日付の 節)。そこへ導いた書き込み経路の食い違いは docs/p3-report.md にある。テストは すべてのノードを比べる。MUTATE=1 は今もステップ 0 で赤になる。

ビルド時に 2c02/docs/p0-report.md から取り込んだもの。リポジトリが唯一の写しだ。報告は独自の作業用の言葉をいくつか使う: 報告書で使われる言葉。