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

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

前回はS-RecordとIntel HEXのローダを実装して、シリアルから直接プログラムを流し込めるようになりました。これで開発効率は爆上がり!……と思いきや、実は別の問題が持ち上がってきました。

「毎回実機の ROM を焼いたり、シリアルで繋いでテストするの、めんどくさくない?」

コードを数行いじって、ビルドして、実機に転送して、D コマンドを叩いて正しく動くか確認する……。趣味の電子工作だから楽しいとはいえ、今後さらに複雑な機能を入れていくとなると、この「手動テスト」のコストがバカになりません。PC 上でサクッとテストできたら最高ですよね。

というわけで、今回は「PC上でこの ROM モニタを動かしてテストする」ためだけの、専用・最小構成の MC6800 エミュレータを作ってしまいました。

なんでわざわざ作るの? 既存のエミュレータじゃダメ?

世の中には素晴らしい 8bit CPU エミュレータがたくさんあります。ただ、今回やりたかったのは「SBC6800 のメモリマップで動き」「ACIA(シリアル通信)がターミナルに直結していて」「自動テストのスクリプトから簡単に叩ける」というニッチな要件でした。

いろいろ探して設定に悩むくらいなら、Python でサクッと自分専用のシミュレータを書いたほうが早い!というエンジニア特有の病気が発症したわけです。

モニタが使う命令「だけ」を実装する

MC6800 の命令セットは全部実装すると結構な数になります。しかし、私の書いた ROM モニタのコードを解析すると、実際に使っているユニークな命令はたかだか 45種類 程度(アドレッシングモードの変形を含めても100個ちょっと程度)しかありません。

そこで割り切って、「今使っている命令だけが動けばヨシ!」という方針で作ることにしました。

  1. メモリ空間: $0000-$1FFF は RAM(読み書き自由)、$E000-$FFFF は ROM(読み込み専用)として扱う。
  2. ACIA(シリアル)の擬似実装: $8018$8019 へのアクセスを横取りして、PC のターミナルに直結させる。
  3. 命令実行コア: LDAA, STAA, BSR, JMP など、モニタが使っている分だけチマチマと Python でディスパッチ処理を書く。

無事Mac上でエミュレータとモニタバイナリがうごきました!!

自動スモークテストの導入

エミュレータ本体ができたところで、これを使った自動テストも書きました。エミュレータの標準入力に D0000 などの文字列を流し込み、返ってきた文字列をチェックするスクリプトです。

これを実行してみると……

最高です!!! 🎉これまで実機をぽちぽち叩いて数分かかっていた確認作業が、Macのターミナル上でスクリプトを叩くだけで 1秒以内 に終わるようになりました。

気を配った細かいポイント

  • Mac / Windows 両対応: 最初、Mac のターミナルで Enter(LF)を押しても全く反応しない問題に躓きました。エミュレータ側で LFCR に変換する処理を入れたり、Windowsの msvcrt モジュールを使って入力処理を分けたりと、地味な互換性対応を行っています。
  • G コマンドのユーザープログラム終了監視: SWI 命令を踏んだらモニタにジャンプするようにしておき、自動テスト時にテストが無限ループにならないようにしています。

GitHub 側にも反映しました

今回のまとめ

今回は直接モニタの開発からは少し外れましたが、結果的に後々の開発をめちゃくちゃ楽にする最高のツールが手に入りました。

  • Python で SBC6800 とモニタ専用の MC6800 最小エミュレータを作った
  • D/M/G/L コマンドの動作確認を自動化するスモークテストを作った
  • これで実機レスで、1秒以内にコードのデグレ(破壊)に気づけるようになった

ビルドしたMacローカルで動くとデバグのスピードが上がりそうです。
今回はこのあたりで!

MC6800 ROMモニタSBC6800