6502tinymachines

すべてが立っているタイミングの格子

M0 の報告書。作業の後に書いた。

走行スタンプ: 2026-09-01、このリポジトリの最初のコミット、rustc stable (rustup のツールチェーン)、cargo test --workspace は 16 テスト緑、clippy も 綺麗。以下のどの数字も、その走行か、引いた出典から貼ったもので、仕様書から 打ち直したものではない。M5 がそれらを check-self-counts のスキャンの下に置く。

閉じたもの

ntsc-grid が存在する: 厳密な有理数のサンプルレート (f_sc は 39,375,000/11 Hz として保持し、格子は 472,500,000/11 Hz)、Phase、 phase_at と line_len を備えた二つの Geometry プロファイル、 CompositeFrame の型、そして仕様 3.4 節の CompositeSource/Stage トレイト。 位相は 3.3 節どおりジオメトリの純関数で、自由なパラメータは phase_at_origin だけだ。

剰余: 3.2 節の主張はすべて確認した

tests/residues.rs、12 テスト。写しではなく、テストで確認したもの:

  • NES の 1 行: 2728 サンプル、剰余 4 (120 度)。各行は phase_at 自身を通して 4 だけ後ろにずれて始まる。
  • NES のフルフレーム: 714,736 サンプル、剰余 4。Even のフレーム三つは原点の 位相に戻り、一つは戻らない (描画を切ったときの三フレーム周期)。
  • NES の短いフレーム: 714,728 サンプル、剰余 8。Even のあと OddShort なら 12 個の開始位相すべてから原点に戻り、Even だけならどこからも戻らない。
  • 放送プロファイルの 1 行: 2730、剰余 6 (180 度)。フレームは 1,433,250、 剰余 6。二フレーム (四フィールド) で原点に戻り、一フレームでは戻らない。
  • 閉形式の phase_at は、両プロファイルの全行にわたる総当たりの累積和と 一致し、積算した合計は samples_per_frame と一致する。
  • 放送プロファイルでの OddShort は line_len と phase_at の両方で名指しで 拒まれる (should-panic テスト)。

レート、厳密に

レート厳密値近似
NES フルフレーム29,531,250 / 491,381 Hz60.09848 Hz
NES 短いフレーム8,437,500 / 140,393 Hz60.09915 Hz
NES 二フレーム平均 (描画あり)39,375,000 / 655,171 Hz60.09881 Hz
放送のフレーム30,000 / 1,001 Hz29.97003 Hz
放送のフィールド60,000 / 1,001 Hz59.94006 Hz

仕様との食い違い、v0.3 向け: 3.2 節は「フィールドレート: (6 x f_sc) / (4 x 341 x 262) = フルフレームで 60.0988 Hz」と述べている。式の 形は正しいが、引かれている値は正しくない: 計算すると 60.09848 Hz になる。 60.0988 は短いフレームが交互に入る二フレーム平均、つまり描画を有効にした ときにプレイヤーが実際に見るレートで、文献がふつう引くのもこの数字だ。 field_rates_exact が NES の三つのレートを別々に釘付けするので、二つを再び 取り違えることはできない。放送のレートがちょうど 30,000/1,001 と 60,000/1,001 として出てくること自体が、315/88 とジオメトリが正しく配線されて いることの検査になっている。

データファイルと転記のゲート

data/nes-levels.toml: 終端した状態での実測表 (lidnariq、75 オーム、 +/-2 IRE)、そのページの平均エンファシス減衰係数 0.816328、そして波数について の事実。出典は nesdev wiki の "NTSC video" リビジョン 23864 (2026-06-01) で、生の wikitext から転記した。この wiki はサイト全体のライセンス を宣言していない (API の rightsinfo は空、フッタに告知も無い)。ファイルの ヘッダと NOTICE.md に記録してある。

閉じるゲート、2026-09-01 の走行: 二人目のエージェントが独立に同じリビジョンを 取得し、最初の写しを見ないまま同じスキーマへ転記した。 tools/diff-transcriptions.py が 43 個の数値を比較し、不一致は 0。片方の 写しの 1 桁をわざと狂わせるとゲートは exit 1 になるので、ゲートは違いを言える。 二人の転記者は独立に同じ判断を一つした: $3x の high のスロットは $2x の行 を写す、というもので、ページ自身の levels[16] の表と「$20 と $30 はまったく 同じ」という記述に従っている。転記 B は data/nes-levels-transcription-b.toml として残し、証拠と札を付け、どのクレート からも読まない。

data/yuv-matrix.toml: SMPTE 170M の基本行列、縮小係数 0.492111 / 0.877283、記載されている逆行列の係数、33 度の I/Q 回転、そして 復調の定数。二次資料だ: ITU-R BT.1700 のダウンロードが 2026-09-01 に 404 だったので、これは同じ wiki のリビジョンからの転記であり、あちらは BT.1700 の 4、16、17 ページを引いている。M2 で一次資料に照らして確認するよう、 ヘッダに印を付けてある。

tests/data.rs、4 テスト。転記をそれ自身に照らして保つ:

  • (ボルト、印字された IRE) の組はすべて、$1D を 0 IRE の基準として 1 IRE = 7.14 mV を通して相互検査される。最悪の行は CBH で、計算 29.69 に 対して印字 30。ページ自身の +/-2 IRE が正当化する許容差の内側だ。
  • ページの 0.816328 という平均は、実測された七つの減衰の組から 1e-4 以内で 再計算できる (重複している $3x の行は除く。入れると二重に数えてしまう)。
  • 逆行列の係数はすべて、基本行列と縮小係数から 1e-4 以内で再導出できる (実際の一致は 5e-6 以内)。

MUTATE=1、赤の証明

MUTATE=1 cargo test --workspace --no-fail-fast: 1 行あたり 2 サンプル長い ジオメトリと、狂わせたレベル電圧。結果は 11 テストが赤 (ジオメトリの剰余と レートのテスト 8 個すべて、IRE の相互検査、減衰の再計算、行列の再導出)。 5 個は設計どおり緑で、テストの docstring に名指ししてある: 格子レートの 同一性 (ジオメトリが入っていない)、閉形式と累積和の一致 (定数ではなく位相の式 を検査している)、二つの OddShort の拒否、そして波数の範囲の検査。

持ち越し

  • 仕様 9 節の未解決の問いには、2026-09-01 に監督が答えた: blargg の nes_ntsc は 0.2.2 (最後のリリース) に固定、composite のプリセット、M1 で ハッシュとともに記録する。M2 の RGB 往復には D65 下の CIEDE2000。 ラング D (時間方向のコム) は M2 で欲しい。
  • yuv-matrix の一次資料での確認は M2 の義務だ。
  • 上に書いたフルフレームのフィールドレートの訂正は v0.3 に入る。

ビルド時に ntsc-crt/docs/m0-report.md から取り込んでいる。写しはリポジトリの一つだけだ。報告には私たちの間の言葉がいくつか残っている: 報告書で使われる言葉。