MC6800 ROMモニタ自作 その8 〜実機レスで開発! Python で最小エミュレータを作る〜

前回はS-RecordとIntel HEXのローダを実装して、シリアルから直接プログラムを流し込めるようになりました。これで開発効率は爆上がり!……と思いきや、実は別の問題が持ち上がってきました。
「毎回実機の ROM を焼いたり、シリアルで繋いでテストするの、めんどくさくない?」
コードを数行いじって、ビルドして、実機に転送して、D コマンドを叩いて正しく動くか確認する……。趣味の電子工作だから楽しいとはいえ、今後さらに複雑な機能を入れていくとなると、この「手動テスト」のコストがバカになりません。PC 上でサクッとテストできたら最高ですよね。
というわけで、今回は「PC上でこの ROM モニタを動かしてテストする」ためだけの、専用・最小構成の MC6800 エミュレータを作ってしまいました。
なんでわざわざ作るの? 既存のエミュレータじゃダメ?
世の中には素晴らしい 8bit CPU エミュレータがたくさんあります。ただ、今回やりたかったのは「SBC6800 のメモリマップで動き」「ACIA(シリアル通信)がターミナルに直結していて」「自動テストのスクリプトから簡単に叩ける」というニッチな要件でした。
いろいろ探して設定に悩むくらいなら、Python でサクッと自分専用のシミュレータを書いたほうが早い!というエンジニア特有の病気が発症したわけです。
モニタが使う命令「だけ」を実装する
MC6800 の命令セットは全部実装すると結構な数になります。しかし、私の書いた ROM モニタのコードを解析すると、実際に使っているユニークな命令はたかだか 45種類 程度(アドレッシングモードの変形を含めても100個ちょっと程度)しかありません。
そこで割り切って、「今使っている命令だけが動けばヨシ!」という方針で作ることにしました。
- メモリ空間:
$0000-$1FFFは RAM(読み書き自由)、$E000-$FFFFは ROM(読み込み専用)として扱う。 - ACIA(シリアル)の擬似実装:
$8018と$8019へのアクセスを横取りして、PC のターミナルに直結させる。 - 命令実行コア:
LDAA,STAA,BSR,JMPなど、モニタが使っている分だけチマチマと Python でディスパッチ処理を書く。

無事Mac上でエミュレータとモニタバイナリがうごきました!!
自動スモークテストの導入
エミュレータ本体ができたところで、これを使った自動テストも書きました。エミュレータの標準入力に D0000 などの文字列を流し込み、返ってきた文字列をチェックするスクリプトです。
これを実行してみると……

最高です!!! 🎉これまで実機をぽちぽち叩いて数分かかっていた確認作業が、Macのターミナル上でスクリプトを叩くだけで 1秒以内 に終わるようになりました。
気を配った細かいポイント
- Mac / Windows 両対応: 最初、Mac のターミナルで Enter(
LF)を押しても全く反応しない問題に躓きました。エミュレータ側でLFをCRに変換する処理を入れたり、Windowsのmsvcrtモジュールを使って入力処理を分けたりと、地味な互換性対応を行っています。 - G コマンドのユーザープログラム終了監視:
SWI命令を踏んだらモニタにジャンプするようにしておき、自動テスト時にテストが無限ループにならないようにしています。
GitHub 側にも反映しました
今回のまとめ
今回は直接モニタの開発からは少し外れましたが、結果的に後々の開発をめちゃくちゃ楽にする最高のツールが手に入りました。
- Python で SBC6800 とモニタ専用の MC6800 最小エミュレータを作った
- D/M/G/L コマンドの動作確認を自動化するスモークテストを作った
- これで実機レスで、1秒以内にコードのデグレ(破壊)に気づけるようになった
ビルドしたMacローカルで動くとデバグのスピードが上がりそうです。
今回はこのあたりで!