コンソールの絵
N6 の報告。作業の後に書かれた。
走行スタンプ: 2026-09-06、rustc 1.97.1。ピン留め: ntsc-crt v0.2.4 をタグで
(ntsc-grid、ntsc-source-nes、ntsc-decode、ntsc-crt。ntsc-source-cap は開発
依存として)、2c02 0b25e83 (v2c02-fast はパスで)、2a03 44277e1、6502
8b9e0b5、nes-bus v0.1.1。cargo test -p nes-console: 8 テスト (N5 の六つ
と、ここの二つ)。計画は docs/n6-plan.md、先に書いた。
ステップ 1 は閉じ、ゲートが付いた。ステップ 2 の機械の側はこの箱の上で端から 端まで走り、計画が述べた許容に対して記録してある: 輝度はどの領域でも成り立ち、 色相と彩度は 436 のうち 69 で成り立たず、その原因はコンソールではなく捕捉模型 の中に位置を特定した。バーのカートリッジを実機で捕捉することは、もとより ベンチの項目だ。
バーのカートリッジが先に必要としたもの
full_palette.nes は、描画を切った状態でパレットの全項目をバーとして描く:
$2006 の対で v をパレット RAM に停め、$2007 の書き込みが行の途中でそれを進め、
$2001 のエンファシスビットが帯ごとに巡る。これをコンソールに通すと青い縞に
なった。描画を切っているとき、高速 PPU は背景色を描き、そう述べていたからだ
(札を付けた書き下ろし。P3 のワールドは描画を一度も切っていなかった)。
スイッチレベルの 2C02 で実測した
(2c02: v2c02-dots/examples/blank-probe.rs、マスク $00 のフレームの
60..67 行): v が $3F00..$3FFF にあるとき、絵はレジスタファイル自身のミラー
規則を通して v が指す項目であり、それ以外のときは背景色だ。$2006 の対は
二度目の書き込みのアクセスが始まってから 5 ドット後に現れ、$2007 の一段は
8 ドット後、エンファシスビットは 3 ドット後だ。ステッパは今それをドット
ごとに描き (blank_colour。$2007 の一段は書き込みから
BLANK_2007_HOLD = 3 ドット後に押さえてあり、2 と 4 は赤)、$2001 の
エンファシスビットをどのドットの横にも運ぶ。2c02: v2c02-fast/tests/blank.rs
で捕捉に押さえてある (MUTATE=1 は背景色だけにして、1,625 ドットで赤)。
エンファシスが 2 ドット先行することは 2c02 の報告に記録してあり、模型には
入れていない: ハーネスはアクセスの始まりでバイトをバスに載せるが、6502 の
書き込みはそうしない。
ステップ 1: 絵
nes_console::picture::Picture: 各フレームを、前のフレームが残した副搬送波の
位相で ntsc-crt の NES ソースが符号化し、ラング C (NES の重みを持つ 3 ライン・
コム) で復号し、ntsc-crt の書き下ろしのパラメータで CRT の各段を通す。倍率は
3 (768 x 720)。このモジュールが ntsc-crt の連鎖に足すものは二つ、フレームを
またいで持ち越す位相と、順序だけで、中に合わせ込んだものは何も無い。run-rom
は CRT=out.ppm でそれを、DECODED=out.ppm で復号したままのグリッドを書き
出す。full_palette.nes を通したもの: バー、八つのエンファシスの帯、そして
コムの絵だ。ラング C と各段に 30 フレームを通すと 1 コアで 2.2 s かかる
(毎秒 13.7 フレーム): 絵は CPU では実時間ではない。N8 のシェルは、それを
屋根の wasm の数値から知っている。
ゲート (tests/picture.rs。ダイデータなし、ゴールデンなし):
- 絵を通したコンソールのフレームは、同じワールドから同じ絵を通した単体の 高速ラングのフレームと、復号した全標本で一致する: 成分 1,474,560 個が等しい (2048 x 240 x 3)。二つのフレームは同じパリティにある。CRT の各段はその上で 走り、768 x 720 の画面に何かを出す。
- 絵がコンソールの 12 フレーム (うち四つは短いフレーム) にわたって持ち越す
位相は、ntsc-grid の算術がそのパリティの列に与える値、4 だ。
MUTATE=1は 全フレームを Even として押し込み (フルフレームの剰余は 4、短いフレームは 8)、 0 と読む: 赤。
ステップ 2: 捕捉の経路、機械の側
examples/capture-score.rs: ROM をコンソールに通し、そのフレームを順に
符号化し、実機の記録 (M4 の道具が読む、スコープのレートの .u8) か、あるいは
コンソールの最後の 3 フレームを同じレートで ntsc-crt のキャプチャカード模型に
通したもの (125 MHz、5 ppm のずれ、20 mV の DC、2 mV の雑音) のどちらかを、
M4 が実機の記録を復元するのと同じやり方で復元し (auto_level_nes、続いて
recover_nes)、同一のデコーダ (ラング C) を通したコンソール自身の合成に
対して領域ごとに採点する。採るのは領域にわたる輝度、彩度、色相の平均で、
各辺から 1 ドット内側までを見る。領域はコンソールのフレームの中で見つける:
区別できる (色、エンファシス) の組ごとに、幅 12 ドット以上、高さ 6 行以上の
最大の平坦な長方形で、バーの段になった辺は併合する (full_palette の $2007 の
タイミングが段を作る)。full_palette.nes では 436 領域、うち 18 が灰色だ。
許容は、測る前に計画が述べたとおり: 輝度は 0.01 以内、色相は合成が色相を持つ ところ (彩度が 0.02 より上) で 1.0 度以内、彩度は合成の 5 パーセントか絶対値 0.005 の大きい方の以内。どれか一つの領域でも外れれば、合成の往復は不合格だ。 実機の捕捉は記録するだけで、押さえはしない。
最初の走行が見つけたものは、計器のものだった。輝度は 130 領域で外れ、その偏り はレベルとともに増える 3.7 パーセントの利得だった: ntsc-crt のレベル基準合わせ が、同期の先端 (sync tip) と消去期間を 4 mV のヒストグラム区画の中心に置いて いて、それは両端でそれぞれ同期の深さの 1.4 パーセントにあたる。それをより 細かく押さえるテストを書くと、同じ検出器の二つ目の弱さが露わになった。消去 期間より下にある絵のレベル (NES の 1 行目の色はその下に潜る) が、記録の 1 パーセントを埋めた時点で消去期間と取り違えられるのだ。べた塗りの暗いフレーム はそれを埋めるし、バーのフレームも埋め得る。どちらも ntsc-crt 0.2.4 で直して あり (レベルは、すべての同期パルスの内側と、その手前のフロントポーチの中央値 として読み、ヒストグラムは閾値を置くためだけに使う。M4 報告の四番目の追記)、 コンソールはピンを張り直した。
それを入れた上での合成の往復 (+0.7 ppm recovered, worst burst residual 0.010):
| 領域 | 以内 | 最悪 | |
|---|---|---|---|
| 輝度 (0.01) | 436 | 436 | 0.0096 |
| 色相 (1.0 度、色相を持つのは 418) | 418 | 352 | 12.1 度、彩度 0.02 の領域で |
| 彩度 (5 パーセントか 0.005) | 436 | 431 | 0.0078 |
| 三つとも | 436 | 367 |
69 領域が外れるので、合成の往復は述べた許容では閉じず、この例は 1 を返して そう言う。外れの正体は一つの残差だ: 大きくても 0.0086 のクロマベクトルの誤差 で、決定的 (雑音をゼロにしても同じ) であり、レート誤差をゼロにしてグリッド 自身のレートでやっても同じなので、再標本化でもロックのレートでもない。彩度の 高い色の上では +0.4 度の回転として読め (バーストロックの残差 0.010 グリッド 標本がその角度だ)、利得のばらつきは 1 パーセント。灰色に近い色では、度の許容が 0.005 のクロマを 12 度に変える。レートと雑音を外して残るのは、カード模型の 折り返し防止ローパス、41 タップの 6.5 MHz が、符号化器の方形波のクロマにかかる ことだ: 合成の側は濾さずに復号され、1 周期 12 標本では方形波の第 11 と第 13 高調波がデコーダの読む基本波に折り返して乗る。だから二つの側は、色の波形に よって 1 パーセント違う基本波を、同一のデコーダに手渡す。これは ntsc-crt の 比較手順の話で、コンソールの絵の話ではない。そして計画の規則は、許容をデータに 合わせ込まないことだった: 数値は実測のまま立ててあり、手順の問い (合成を同じ フロントエンドで濾すか、折り返した高調波から許容を述べるか) は次の計画のために 名指しした。
実機の側: バーの記録は存在しない (手元の五本の記録は Super Mario Bros. と
Duck Hunt で、その ROM はこの箱に無いので、あちらのどの領域もコンソールの
フレームに対して採点できない)。この例は記録を取って同じ手順を走らせる。実機の
コンソールで full_palette.nes を録ることがベンチの項目であり、M4 の終端した
捕捉の発見 (プローブでの走行がクロマをおよそ 40 パーセント良く見せていた) は、
記録は終端して取らなければならないと言っている。
手順の問い、答えが出た (2026-09-06、同じ日)
計画の規則は許容をデータに合わせ込まないことで、上の報告は手順の問いと原因を
名指しした。その原因は間違っていて、試したとたんにゲートがそう言った: 比較の
リファレンス側は今、カード模型のフロントエンド
(ntsc_source_cap::front_end、ntsc-crt 0.2.7。折り返し防止ローパスだけを、
グリッドのレートで模型に押さえたもの) を通る。これは原理として正しい (捕捉と
比べる合成は、その捕捉の帯域制限を帯びていなければならない) のだが、何も
動かさなかった: どちらでも 436 のうち 367 領域だ。次に復元そのものを、バーの
フレームでフロントエンドを通した合成に照らして押さえると、最悪 0.0022 V、
クロマ利得の 0.3 パーセントでそれを再現したので、計器でもなかった。残っていた
のは採点自身の幾何で、領域の余白を掃いてみるとそれが見えた: 16 ドットのバーの
辺から 1 ドット内側は、デコーダのクロマが整定する距離の内側にあり、フィルタの
遷移が残差だったのだ (クロマベクトルの最悪は 1 ドットで 0.0088、2 ドットで
0.003、4 ドットで 0.0001)。
変更が二つ続く。どちらも選んだのではなく導いたものだ。余白は今やデコーダの
ものになった: 間引いたローパスの幅の半分に、補間が届く間引き後の 2 標本を
足した 5 ドットだ (margin_dots。Decoder の実体のフィールドから取る)。
そして blargg の full_palette のバーは幅 16 ドットなので、このリポジトリは
自前のバーのカートリッジを書き下ろした (testrom::bars_program、
export-testrom bars で書き出す。誰のゲームでもない): 32 ドットのセル、
一つの輝度の行に置いた 12 の色相と背景色、行は 120 フレームごとに 1、2、3、0
と進むので、100、220、340、460 フレームの走行が一つの行を採点する。
このカートリッジは、計器の三つ目の欠陥を、輝度の行 0 でだけ見つけた: どの色相 も、ライン上のバーの位置とともに増える回転で外れ、復元は 0 ppm の捕捉でレートを 145 ppm 間違えて読んだ。最も暗い色の低いレベルは、カードのフィルタを通った後、 副搬送波の半周期にわたって同期の閾値の下へ潜り、その谷のどれもがライン歩きには 同期の縁に見えていた。ntsc-crt 0.2.8 は、縁の後に 1 マイクロ秒の同期が続くこと でその縁を資格づける。実機の記録は変わらない。
合成の往復を、バーのカートリッジで、両側にフロントエンドを入れ、導いた余白で、 計画の許容 (輝度 0.01、色相 1.0 度、彩度 5 パーセントか 0.005) のもとに:
| 輝度の行 | 領域 | 三つとも以内 | 最悪の輝度 | 最悪の色相 | 最悪の彩度 |
|---|---|---|---|---|---|
| 1 | 13 | 13 | 0.0001 | 0.3 度 | 0.0011 |
| 2 | 13 | 13 | 0.0001 | 0.3 度 | 0.0012 |
| 3 | 13 | 13 | 0.0001 | 0.3 度 | 0.0005 |
| 0 | 13 | 13 | 0.0001 | 0.3 度 | 0.0008 |
閉じた。full_palette では同じ手順で、採点できる幅の領域が二つしか残らず、 どちらも灰色で、どちらも許容の内側だ: あのカートリッジは、このデコーダの 分解能では色相の判定を運べない。回避せずに記録する。実機の捕捉の手順も同じ もので、バーのカートリッジはいま、ベンチが待っていた ROM でもある。
ベンチに残るもの
- バーの記録: このリポジトリのバーのカートリッジ (
export-testrom bars) を 実機のコンソールで、終端して、スコープのレートで録り、それから画面に出ている 輝度の行の中に入るフレーム数でcapture-score bars.nes frames record.u8 125000000。 - エンファシスの先行 (2c02 の報告): 実機の $2001 書き込みのエンファシスが 本当に色の変化より 2 ドット先に着くのか、それともハーネスの、始まりにデータを 載せるアクセスの形がそう見せていたのか。
- N5 の持ち越し項目はそのまま: スコープで見る NMI の到着、ゲート 3 の ROM、 リセットの保持。(8x16 のスプライトと、スプライト DMA の中の DMC フェッチは 2026-09-06 に閉じた。後者は、衝突時のダイの標本アドレスをロジックアナライザ への問いとして残している。2a03 の docs/n3-report.md。)
ビルド時に nes/docs/n6-report.md から取り込まれる。写しはリポジトリの一つだけだ。報告は独自の作業用の言葉をいくつか使う: 報告書で使われる言葉。