6502tinymachines

組み立ての手引き、五回の作業で

印刷用: 図面一式「NES controller-port bridge, v1b」TM-NESB-001 版 P (PDF、英語)、組み上がった v1b、写真の上に検査箇所を書き出したもの (PNG)。

tools/bringup.py のステップの表と docs/lab-log.jsonl のログから、 tools/build-guide.py が生成する。これは実際に走る手順であり、実際にいま ある状態でもあるので、どちらからもずれることができない。あの道具を走らせ 直せば、このページも更新される。

一回につきコマンドは一つ。 どれも何をするかを印字し、待ち、それから何か を測る。ステップがうまくいったかを尋ねることは決してない。失敗したステップ は走行を止め、どれをやり直すかを教える。

すべての試行と写真が入った進行中の記録は ラボノートだ。いま開いているサイクルの作業用の 文書、そして作業者自身の観察を書き留める場所は、このリポジトリの docs/procedures/ だ。

どこまで進んでいるか

回何の回か状態
1計器完了
2コンソールを測る完了
3ブリッジを組む未着手
4接合2 ステップ中 1
5ヘッドの手3 ステップ中 1

最初の回の前に

何より先に噛みついてくるものが二つあり、どちらも一行で済む。

シリアルポートは開くことを拒む。あなたのユーザーが dialout グループに 入るまでは:

sudo usermod -aG dialout $USER

それからログアウトして入り直す。新しいシェルでは足りない。効いたかどうかは id -nG | grep dialout で確かめる。

スコープのアドレスは bench.local.md にあり、git はそれを無視する。 他の何もそれを必要としないし、他の何もそれを持つべきではない。

五回を通して机の上に載るもの: テスター、スコープのプローブ二本、UNO と USB ケーブル、ゲームを入れて開けたコンソール、純正パッド二つ、ブレッドボード、 74HCT04、74HC165、74HC595、100 nF のコンデンサ三個、100 オームの抵抗一個、 ブリッジのトリガをスコープの CH1 へ運ぶプローブか BNC ケーブル、PC817 の モジュール、リレーのモジュール、そして Pi。

第 1 回: 計器

何も配線しない。スコープが応答し、UNO のポートが開き、スケッチがその上に載る。

python3 tools/bringup.py --session 1

0.1 スコープが応答し、自分が何かを言う (通った)

  • スコープに電源を入れ、LAN に載せる。
  • そのアドレスは bench.local.md に置く。git はそれを無視する。他の何もそれを必要としない。

それから LAN 越しに、スコープへ自分が誰かを尋ねる。

最後の走行 2026-09-08 12:41:12: 通った。DS1054Z、ファームウェア 00.04.05.SP2

0.2 ワークステーションがシリアルポートを開ける (通った)

  • Arduino UNO を差す。まだ他には何もつながない: チップも、コンソールも、パッドも。このステップが証明するのは、ポートが開くことだけだ。
  • 差す先はこのワークステーションでも、ヘッドである Raspberry Pi でもよい。Pi にする場合は、そちらで head/serial-bridge.py を走らせ、道具をそこへ向ける:
python3 tools/bringup.py --session 1 --bridge socket://<pi>:6545

それから UNO のシリアルポートを開き、開けなければ直し方を名指しする。

写真:

  • docs/lab/00-uno-bare.jpg (欲しい)

最後の走行 2026-09-08 12:41:14: 通った。socket://:6545 が開く

0.3 ブリッジのファームウェアが UNO に載り、STATUS に答える (通った)

  • スケッチを書き込む。-p の後には自分のポートを置く:
arduino-cli compile --fqbn arduino:avr:uno firmware/bridge-uno
arduino-cli upload  --fqbn arduino:avr:uno -p /dev/ttyACM0 firmware/bridge-uno

それから STATUS を送り、ブリッジの返事を読む。

最後の走行 2026-09-08 12:43:11: 通った。# mode pass latch 0 clocks 0 held 00

第 2 回: コンソールを測る

まだ何も組まない。テスターとプローブ二本を、すでに持っているコンソールに当てる。

python3 tools/bringup.py --session 2

1.1 コントローラのハーネスの色を、ポートのピン番号に照らす (通った)

答えるもの: wiring.md のポートの表は、このステップがこの基板の上で確認するまで、公開されたピン配置にすぎない。

  • コンソールは壁から抜く。開いていなければ開ける。
  • 色をピン番号に結びつける道は二つあり、どちらを使ったかは記録に残る。ポートのハウジングには、圧着端子の横のプラスチックにピン番号が成型されている。片方の列に四つ、もう片方に三つだ: 両方の列を写真に撮って読み取る。あるいは、ハーネスが基板に着地する白いヘッダを見つけ、各ピンからソケットまでテスターで導通を取る。
  • 成型された番号は、コネクタが自分の番号付けを教えてくれているもので、色の慣習より価値がある。それが教えてくれないのは、ハーネスが各ピンを入れ替えずに基板のヘッダまで運んでいるかどうかだ。それをやるのはテスターだけなので、「両方」が最も強い答えになる。
  • このコンソールのポートのピン配置、2026-09-09 に実測して docs/wiring.md に書き留めたもの: 1 GND、2 CLK、3 OUT0、4 D0、5 +5V。6 と 7 には何も乗っていない。公開された表は 5 に D3、7 に電源を置いている。あれはこの基板を記述していない。
  • 色はそれ自体では証拠にならない。どのピンも番号はコネクタかテスターから得るもので、その色がふつう何を意味するかから得るものではない。
  • ハーネスにブレークアウトを継いでいるなら、このステップはそのリードも地図にする。プローブが実際に着地するのはブレークアウトだからだ。あのリードは手元にあった色で作った新しい線で、慣習は一切載っていない。
  • 気をつけるべき場合は、ブレークアウトのリードが二本同じ色のときだ: プローブのグランドクリップと先端は隣り合ったリードに行くし、駆動されている線にクリップを付ければその線を接地してしまう。このステップは、ハウジングから読み取っただけの色の重複を拒み、まずそのリードを基板のヘッダから導通で追うよう求める。
  • 2026-09-09 に、痛い形で実測した: ケーブルの導通は回路から外して取る。コンソールに差したままのケーブルに流した音は、コンソール自身のプルアップとポートのバッファを通ってしまい、何も共有していないピンでも鳴る。このベンチでの最初の一巡は、一本のリードに二つのピンが乗っているという結果を、繰り返し返してきた。どちらの読みも間違った回路のものだった。ケーブルを抜いてから、導通を取る。

それからあなたの導通の読みを受け取り、四つ未満なら拒む。

写真:

  • docs/lab/01-port-housing-pins-1-4.jpg (届いた)
  • docs/lab/01-port-housing-pins-5-7.jpg (届いた)
  • docs/lab/01-board-header.jpg (欲しい)
  • docs/lab/01-breakout-map-controller.jpg (届いた)
  • docs/lab/01-breakout-ground-marked.jpg (届いた)

最後の走行 2026-09-08 13:26:56: 通った。7 ピン中 7 ピンを地図にした。ポートのハウジングに成型されたピン番号から読み取ったもので、番号付けはハウジング自身のものだ。それを試すのはステップ 1.2 の +5V の読みだ

1.2 コンソールを入れたときのポートのアイドルのレベル (通った)

  • コンソールに電源を入れる。テスターの黒は、ステップ 1.1 が GND と導通で確かめたリードに当てる。
  • 電源のリード、それから OUT0、CLK、D0 を測る。
  • 公開されたピン配置の番号に頼ってはいけない: この基板でどのリードがどれかを言うのはステップ 1.1 であり、この基板では電源は公開された表が置いている場所には無い。
  • 期待する値: 電源は 5 V 近く、OUT0 はアイドルで LOW、CLK はアイドルで HIGH、D0 はプルアップ。
  • このリードにはテスターよりスコープを当てたほうがよく答えられる。ステップはどちらの計器を使ったかを記録する。

それからテスターの読みを四つ受け取り、電源のピンが約 5 V でなければ続行を拒む。

写真:

  • docs/lab/01-meter-on-port.jpg (欲しい)

最後の走行 2026-09-09 21:33:50: 通った。電源 5.0 V。OUT0 のアイドルは 0.091、CLK のアイドルは 5.002、D0 は None。スコープの CH4/CH1/CH2 で、1x、グランドは黄色のリードに。D0 は読んでいない

2.1 ゲームを走らせた純正パッドのポートにスコープを当てる (通った)

答えるもの: wiring.md の書き下ろしの「ラッチが数 us 高、クロックが数百 ns 低、クロックの間が約 7 us、毎秒 60 回のポーリング」。

  • 純正パッドをコンソールのもう一方のポートに差し、ポーリングするゲームを始める。
  • スコープの CH1 のプローブを、そのポートのピン 3 (OUT0、ラッチ) に。
  • スコープの CH2 のプローブを、そのポートのピン 2 (CLK) に。
  • プローブのグランドは両方ともポートのピン 1 に。切り替えがあればプローブは 1x に。
  • これは書き下ろしの数字四つを一度に置き換える測定だ。

それから両方の線を捕捉し、ラッチのパルス、クロックのパルス、クロックの間隔、そして毎秒のポーリング数を測る。

写真:

  • docs/lab/02-probes-on-port.jpg (欲しい)
  • docs/lab/02-scope-screen.jpg (欲しい)

最後の走行 2026-09-09 21:24:27: 通った。ラッチ高 3.32 us、クロック低 0.580 us、クロック周期 10.62 us、毎秒 60.10 回のポーリング、15 回のラッチにわたってラッチあたり 8 クロック

第 3 回: ブリッジを組む

ブレッドボードを二つの半分に。接合する前に、別々に試す。

python3 tools/bringup.py --session 3

3.1 U1 と U2 を基板に、H..A に配線リンク、QH に模様

  • コンソールは切る。ブレッドボードにはコンソール側の半分だけを組む:
  • 電源は UNO 自身の 5 V ピンで、Pi からの USB で給電される。コンソールのピン 7 ではない。v1b は 5 V の一領域だけ (回路図の一葉目がそう言っている) で、コンソールが共有するのはグランドだけだ: そのピン 1 を UNO の GND へ。それが使える唯一の 5 V でもある。ブレークアウトがピン 7 を外に出していないからだ。
  • リードは、ステップ 1.1 で導通を取った地図から: 黄 GND、青 CLK、黒 OUT0、緑 D0、赤 +5V。リードに付けた印を使う。ポートのピン番号でも、公開されたピン配置でもない。
    • 74HCT04 (U1): ピン 14 を UNO の 5V へ、ピン 7 を GND へ、ピン 1 を黒のリード (OUT0) から。
    • 74HC165 (U2): ピン 16 を UNO の 5V へ、ピン 8 を GND へ、ピン 15 (/CE) を GND へ、ピン 10 (DS) を GND へ、ピン 1 (/PL) を U1 のピン 2 から、ピン 2 (CP) を青のリード (CLK) から、ピン 9 (QH) を緑のリード (D0) へ。
  • 黄のリードは、UNO がコンソールと共有するグランドだ。赤のリードには何も付けない: あれはコンソール自身の 5 V で、このブリッジは UNO の 5 V で走る。
    • 各チップの電源ピンの間に 100 nF。
    • 八つの入力に配線リンクを渡して、既知のバイトを作る。パッドの順、A、B、Select、Start、上、下、左、右で、それぞれピン 6、5、4、3、14、13、12、11 であり、LOW が押された状態だ。
  • スコープの CH1 は OUT0 のまま、CH2 は QH (U2 のピン 9) へ移す。コンソールを入れ、ゲームを走らせる。

それから QH を捕捉し、八ビットを、あなたのリンクが作るバイトに照らして復号する。

写真:

  • docs/lab/03-console-side-built.jpg (欲しい)
  • docs/lab/03-qh-on-scope.jpg (欲しい)

4.1 UNO が 595 を駆動し、その出力で実測する

  • コンソールは切り、ポート側の半分はそのままにしておく。基板の UNO 側で:
    • 74HC595 (U3): ピン 16 を UNO の 5V へ、ピン 8 を GND へ、ピン 13 (/OE) を GND へ、ピン 10 (/SRCLR) を 5V へ、ピン 14 (SER) を UNO の D11 から、ピン 11 (SRCLK) を UNO の D13 から、ピン 12 (RCLK) を UNO の D10 から。
    • その電源ピンの間に 100 nF。
  • U3 の出力を U2 の入力にはまだつながない。テスターを QA (ピン 15) に、黒は GND に。

それからバイトを一つ設定し、STATUS から読み返し、レジスタの出力二本をあなたにテスターで測らせる。

写真:

  • docs/lab/04-uno-and-595.jpg (欲しい)

4.2 ブリッジが純正パッドを 5 V でポーリングする

  • これは切ったコントローラのケーブルのパッド側の半分、コンソールの基板のヘッダに対して導通が鳴らない方で、先にパッドが付いているものだ。
  • そのリードはプラグ側の半分と同じ色を運ぶ。同じケーブルだからだ: 黄 GND、青 CLK、黒 OUT0、緑 D0、赤 +5V。
    • 黄を GND へ、赤を UNO の 5V へ (ここではパッドの電源はブリッジから来るし、このケーブルでは赤が電源のリードだ)、黒 (OUT0) を UNO の D6 へ、青 (CLK) を UNO の D7 へ、緑 (D0) を UNO の D8 へ。
  • コンソールはまだ切ったまま。この半分はブリッジが駆動し、もう一方はコンソールが駆動する。
  • ボタンを押し続けるよう求められる。ブリッジ自身のポーリングがそれに追従するはずだ。

それからボタンを三つ押し続けるよう求め、その一つずつがブリッジのパッドのバイトに届いているかを検査する。

写真:

  • docs/lab/04-pad-on-bridge.jpg (欲しい)

第 4 回: 接合

二つの半分を配線でつなぐ。B0 の最初のゲートだ。

python3 tools/bringup.py --session 4

5.1 二つの半分を接合、ゲームでラッチあたり八クロック (通った)

答えるもの: 計画の B0 のゲート 1。実機が答えることになる最初のものだ。

  • コンソールは切る。U2 の入力から配線リンクを外し、二つの半分をつなぐ:
    • U3 の QA..QH (ピン 15、1、2、3、4、5、6、7) を U2 の H..A (ピン 6、5、4、3、14、13、12、11) へ。
    • UNO の D5 をポートのピン 3 (OUT0) へ。UNO の D2 をポートのピン 2 (CLK) へ。
    • コンソールの GND、ブレッドボードの GND、UNO の GND は一つのネットだ。
  • コンソールを入れ、パッドをポーリングするゲームを走らせ、MODE PASS に。
  • これが B0 の最初のゲートだ: どのポーリングでも八クロック。

それから二十秒間ブリッジを聴き、ポーリングあたりのクロック数のヒストグラムを印字する。

写真:

  • docs/lab/05-bridge-joined.jpg (欲しい)
  • docs/lab/05-console-running.jpg (欲しい)

最後の走行 2026-09-15 17:52:14: 通った。20 s で 1202 回のポーリング (毎秒 60.1)、ポーリングあたりのクロック数 {8: 1202} <- B0 のゲート 1 が通った

5.2 押したボタンがブリッジを通ってコンソールに届く

  • 同じ配置。ボタンを一つ押し続けるよう求められる。ゲームはそれを見るはずで、ブリッジのログは同じラッチで同じバイトを運ぶはずだ。

それからゲームが反応するか、ログがそのバイトを運んでいるかを検査する。

写真:

  • docs/lab/05-button-through.jpg (欲しい)

第 5 回: ヘッドの手

トリガ、リセットのフォトカプラ、そして電源のリレー。

python3 tools/bringup.py --session 5

6.1 トリガがスコープに届く (通った)

  • UNO の D3 を 100 オームの抵抗を介してスコープの CH1 へ (プローブか BNC ケーブルで): DS1054Z に外部トリガの入力は無い。2026-09-15 に実測、ソース EXT は拒まれる。
  • CH1 は後でマスタクロックのチャンネルになる。メインボードにプローブを当てるまでは空いていて、その後は TRIG とクロックが交代で使う。

それからスコープを CH1 でアームし、ラッチのところでブリッジのトリガを撃つ。

写真:

  • docs/lab/06-trigger-cable.jpg (欲しい)

最後の走行 2026-09-15 21:14:18: 通った。TRIG 20 が CH1 でスコープを止めた

6.2 リセットのフォトカプラがコンソールにパルスを入れる

  • ブレークアウトの J3 は五本が色ごとにそのまま通っている (1 茶、2 赤、3 橙、4 黄、5 白)。3 の橙と 4 の黄がリセットボタンで、コンソールを入れると橙は黄より 4.40 V 高い (2026-09-17 に実測)。
  • PC817 のモジュール: OUT を 3 の橙へ、その GND を 4 の黄へ、VCC は未接続、そして Pi の GPIO17 を INPUT + へ、INPUT - を Pi の GND へ。前面パネルのボタンは並列に配線したままにする。

それからリセットのパッドのどちらがグランドかを記録し、そのパルスがコンソールをリセットするかを検査する。

写真:

  • docs/lab/06-reset-pads.jpg (欲しい)
  • docs/lab/06-breakout-map-power-reset.jpg (届いた)

6.3 電源のリレーがコンソールを入り切りする

  • リレーの COM と NO を、J3 の 1 の茶と 2 の赤、つまり前面パネルの電源スイッチ (2026-09-17 にテスターで確認) に並列に渡す。このステップでは前面のスイッチは切ったままにする。商用電源の安全: ここにあるものは一つも、商用電源の側には無い。
  • リレーのモジュールの VCC を Pi の 5V ピンへ、IN を GPIO27 へ (高がコンソールに電源を入れる。2026-09-17 に実測)、GND を Pi の GND へ。

それから、接点がアダプタ側に無ければ拒み、そのうえで切り替わるかを検査する。

写真:

  • docs/lab/06-relay-inline.jpg (欲しい)

一回が終わったら

python3 tools/lab-notebook.py     # 走行をノートに畳み込む
python3 tools/build-guide.py      # そしてこのページの状態を更新する

写真は docs/lab/ に、道具が求めた名前そのままで置く。それを push して、 あの二つを走らせ直す: ノートは届いた写真を埋め込み、まだ届いていないものは 名前を挙げ続ける。だから、ここに壊れた画像が出ることは決してないし、黙って 忘れられるものも無い。

ビルド時に nes-bench/docs/build-guide.md から取り込まれる。写しはリポジトリの一つだけだ。報告は独自の作業用の言葉をいくつか使う: 報告書で使われる言葉。