Tachibana

SWD で Neo6502 をデバッグする:Pico W をプローブに

#neo6502 #ファームウェア #ユーティリティ

画面が黒いままでシリアルポートも黙っているとき、RP2040 のデバッグポートが残っています。Pico W と 3 本の線と OpenOCD で、動作中のボードのメモリを読み、キーボード入力まで代わりに行えます。

著者 bmarty · Tachibana · 2026 年 9 月 26 日

Olimex の Neo6502 では W65C02S がプログラムを実行しますが、それ以外はすべて RP2040 が担います:DVI 映像、USB、ファイル、サウンド。私たちのファームウェアのフォーク Trinity を開発するとき、最初の道具はシリアルポート上の端末です。これには限界があります:話せるだけ健全なファームウェアを前提にしていることです。RP2040 にはデバッグポート SWD もあり、プローブはバス経由でメモリを読み書きできます — ファームウェアに何も頼まずに、画面が黒くても、ファームウェアが止まっていても。以下は私たちの作業台、コマンド、そしてそれで決着がついたことです。

1. 作業台

通電中の Olimex Neo6502 ボード:DVI 出力に画面、ホストポートに USB メモリと USB 機器、SWD1 コネクタに 3 本の線
通電中の Neo6502:DVI 出力に画面、USB 給電、ホストポートに USB メモリと機器、そして SWD1 コネクタに 3 本の線。
裏側から見た Raspberry Pi Pico W、USB 給電、GP2・GP3・GND に線
プローブ:PC から USB 給電された Pico W、GP2、GP3 と GND に線。

ボード 2 枚、USB ケーブル 2 本:Neo6502 はいつも通り給電され画面につながり、Pico W は PC につながってデバッグプローブとして認識されます。その間はわずか 3 本の線です。

2. プローブ:Pico W と 3 本の線

Pico W には Raspberry Pi の debugprobe を書き込み、CMSIS-DAP プローブにしています。配線は私たちのスクリプトに記録したとおりです:

Pico W(プローブ)Neo6502、SWD1 コネクタ
GP2SWCLK (SWC)
GP3SWDIO (SWD)
GNDGND

ボードは自分側で給電しておく必要があります:プローブは給電しません。

3. 接続:OpenOCD

OpenOCD がプローブと RP2040 に話しかけます:

openocd -f interface/cmsis-dap.cfg -c "set USE_CORE 0" -f target/rp2040.cfg \
        -c "adapter speed 1000" -c "init"

接続すると、read_memory と write_memory でボードの動作中に任意のアドレスを読み書きできます。ファームウェアの変数のアドレスはビルドごとに変わるので、スクリプトは決して固定せず、書き込んだ版の ELF ファイルから読み直します。

arm-none-eabi-nm firmware.elf | awk '$3 == "frameCounter" { print "0x" $1 }'
# その後、OpenOCD で:
read_memory 0x2000xxxx 16 1

4. 動作中のファームウェアを読む:neoswd.sh

neoswd.sh はファームウェアのカウンタをいくつかループで読みます。最も役立つのは frameCounter で、コア 1 が映像フレームの始まりごとに増やします:まだ増えていれば信号は生きていて絵だけがおかしい、止まっていればエンコーダが停止しています。ほかに lateTotal(遅れて届いた走査線の回数)、stoSectorCount(ストレージドライバが動かしたセクタ数)、そして画面が空なのか見えないだけなのかを見分けるための映像メモリのサンプルです。

firmware/scripts/neoswd.sh 500            # 500 ms ごとにカウンタ
firmware/scripts/neopilot.sh "MODE 1" "DIR"   # 入力してから計測

5. キーボードの代わりに入力する:neopilot.sh

画面が黒いと、入力した内容が見えません。neopilot.sh はファームウェアのキーボードキュー(queue と queueTail)に直接書き込みます:40 ms ごとに 1 文字、最後に Enter。その後、映像を送る PIO の FIFO レベル、そのエラーフラグ、フレームカウンタ、直前のフレームの走査線数を 1 秒に何度も計測します。こうして MODE 1 と DIR というまったく同じ手順を、ファームウェアごとに再現できます。

6. 規則:コア 0 だけに接続する

RP2040 にはコアが 2 つあり、Trinity ではコア 1 が映像を生成します。OpenOCD は両方に接続できますが、コア 1 にも接続するとエンコーダが 毎秒 15 フレーム に落ち、存在しない故障を作り出します(2026 年 9 月 25 日に計測)。そのため、すべてのコマンドで set USE_CORE 0 を指定しています:計測器がエンコーダに触れてはいけません。もう一つの副作用:コア 1 にバスの優先権を与えたときは、デバッグポートがそのバスを共有しているため、SWD の読み出しさえ失敗しました。

7. プローブが決着をつけたこと

Hercules モードで最初の DIR 時に画面が黒くなる間、プローブは、フレームカウンタが毎秒 60 フレームを保っていること、映像メモリには実際にカタログが入っていること、ディスク読み込み中に lateTotal が増えることを示しました:ファームウェアの停止でも画面の消去でもありません。この計測とその後の計測が、説明を一つずつ否定し、本当の原因 — 2 つのコアで共有されていたロック — にたどり着きました。追跡の全体は 画面を消す DIR にあります。

8. 私たちが主張しないこと

プローブが読むのはファームウェアがメモリに置いたものです:ここで挙げたカウンタは私たちが Trinity に追加したものであり、名前も公式ファームウェアではなく私たちのフォークのものです。スクリプトは書き込んだ版の ELF ファイルそのものを前提にしています。SWD1 コネクタのピンはボードのシルク印刷で確認してください。ここでは信号名だけを示します。

出典とリンク

← Neo6502 · Prophet → · AsteroNeo → · Neo6502 →