openMSXとopenMSX debuggerで開発を加速させよう
openMSXことはじめ
海外発のMSXのエミュレータです。C-BIOSというMSX-BIOS互換のBIOSを使うようになっていて筆者のような実機のない人でもMSXのプログラムができるようになっています。
ただしMSX-BASICは権利の問題から提供されていません。
そのためMSX-BASICも動かしたいひとは、自身が保有する実機からSYSTEM-ROMを引っこ抜いてopenMSXで使うことができるようです。
とりあえず当記事ではC-BIOSのみで使うことを前提に説明します。
機能が盛りだくさんなのですが、それでも抜粋して最低限度を説明するつもりです。それでもけっこうなボリュームになってしまいました。長文、ご容赦ください。
openMSXはこちらのサイトからダウンロードできます。
自分の環境に適したopenMSXをインストールしましょう。
openMSXをインストールすると次のようなアイコンのアプリケーションがインストールされます。ペンギンくんがかわいいですけどKONAMIにあわせたのでしょうか、それともLinuxにあわせたのでしょうか。謎です。。。
openMSXを起動すると次のような画面が表示されます。
この状態だとエミュレーション対象のハードウェアが海外向けMSX(なおかつ、MSX2+)になっています。当記事連載では常にMSX1のノスタルジーモードなので、Hardwareを変更しましょう。左上の「menu」をクリックすると以下のようなメニューが表示されますので
「Hardware」→「Change Machine」を選択します。
そして日本語用のMSX1を選択しましょう。
選択するとopenMSXが再起動(エミュレータ上での再起動)して次のような画面に切り替わります。
ああ、落ち着きます。このカラーリング・・。最高です・・。
さて、次にエミュレータ上で動作させるROMを選択します。
今回は前回のArkosTracker2のデモサンプルプログラムを使います。
「menu」を選択して、「Cart.Slot A: (empty)」を選択し
「Catridges」に「at2study2.rom」を指定しましょう。
at2study2.romが手元にないのであれば前回記事から拾ってください。
https://github.com/sailorman-msx/games/tree/main/src/at2study2
これで「カートリッジA」にat2study2.romのROMカートリッジが装填された状態になりopenMSXが再起動します。起動直前でRAMサイズの選択を促されますが「Auto-Detect」を選択してください。
簡単ですね。あとは通常どおりです。
さて!!!ここから本題です。
openMSXはそれもそれで素晴らしいのですが、openMSX debuggerという最強のデバッガがついてるのがメリットです。
それではopenMSX debuggerの使い方について説明しましょう!!
openMSX debugger
openMSX debuggerはopenMSXに直結してデバッグができるツールです。
openMSXのサイトからこちらもダウンロードできますので、自身の開発環境にあったものをインストールしてください。
openMSX debuggerをインストールすると次のようなアイコンで登録されます。こちらもかわいいです。ペンギンくん、ベリーキュート・・。
それではopenMSX debuggerを起動してみましょう。起動すると以下のような画面が表示されます。
大きくわけて以下のように画面が構成されています。
CodeView: ROMのコードが表示されます(画像ではわかりませんが、マシン語が逆アセンブルされてオペコードも表示されます)
Main memory: メモリダンプできます
CPU registers: レジスタやPC、SPを確認できます
Flags: F(フラグ)レジスタの状態を確認できます
Debug list: デバッグ用のブレイクポイントやウォッチポイントを追加・削除できます。
これらをフル活用してプログラムのデバッグを行う形になります。
さて、起動直後の状態だとopenMSX本体とデバッガはまだ接続できていません。
デバッグではopenMSX本体に接続を行う必要があります。
前述したとおりの操作でopenMSX本体が起動できていることを確認して
画面上のカミナリマークのようなボタンをクリックしてください。
これでopenMSX本体とopenMSX debuggerが接続されデバッガの画面は以下のように表示が変わります。表示されている内容はopenMSX本体で動作している内容そのものになっています。
この状態だとopenMSX本体側はずーーっと動作していて、今回のサンプルではちっとうるさいので、一時停止を本体側に送信して、本体側のプログラムを一時停止させておくことにします。
シンボルファイルを読み込む
マシン語ではすべてがアドレスです。行番号というものは存在してません。でもアドレスなんていちいち覚えていられないし、そのためにZ80ASMでもラベルをつけてプログラミングしています。
openMSX debuggerにも、そのラベル(ラベリングされたアドレス)の情報を取り込みましょう。
メニューの「System」→「Symbol Manager」を選択すると次のようなダイアログが表示されます。
「Add」をクリックして、mapファイルを読み込ませます。
今回はat2study2.mapを使います。
2024/01/21 追記
Z80ASMが出力するmapファイルは素のOpenMSX debuggerで使用できません。openMSX debuggerをちょこっと修正する必要があります。その修正パッチを以下のGitHubに置いてるのでそちらを参照ください。。。
https://github.com/sailorman-msx/games/tree/main/src/debugger-patch
mapファイルを取り込むと以下のような画面になります。
「Address labels」を選択するとラベルが取り込まれたことが確認できるはずです。ラベルはすべて大文字で表示されていますが、実際に使ううえではどちらでもOKになってるようです。(大文字小文字の区別なし)
デバッグしてみる!!
ようやくここまで辿り着きました。
それでは at2study2.rom をデバッグしてみましょう。
at2study2.rom には REDRAW_SCREEN という場所があるので、この場所でブレークする設定を行うことにします。
Search機能で特定のラベルにジャンプ
REDRAW_SCREENのアドレス位置にジャンプするためには、メニューの「Seach」を使います。
「Goto」を選択するとアドレス入力ダイアログが表示されるので、ここで「REDRAW_SCREEN」と入力してOKをクリック。
Code Viewを見るとREDRAW_SCREENのアドレス位置が表示されます。
at2study2.asmと同じであることが確認できますね。
(さすがにコメント行までは反映できないみたいですが)
Debug listにブレークポイントを追加する
REDRAW_SCREENにブレークポイントをつけるのは簡単です。
Debug litの「Break points」の「Add」をクリックします。
あとは「Address」に「REDRAW_SCREEN」と入力するだけ。それだけ。
ただし、この状態ではまだブレークポイントとしては成立していません。
X列のチェックボックスにチェックを入れるとブレークポイントの完成です。チェックボックスにチェックを入れて、一時停止状態を解除します。
一時停止状態を解除すると、ブレークポイントで処理が止まることを確認できるはずです。(ブレークポイントに止まった音とか出ません)
実行制御あれこれ
ブレークポイントで止まった状態であれば以下のボタンで実行制御できます。
よく使うのは左から2つ目のStep Overと一番右のStep backです。
このふたつだけ覚えておけばOK。
StepOver: 次の命令に進みます。
StepBack: 前の命令に戻ります
レジスタやフラグの状態を確認する
「CPU registers」には、そのアドレス時点でのレジスタの情報が確認できます。PC(プログラムカウンタ)が410AHになっているのでばっちり止まってることがわかりますね。
メモリの状態を確認する
今回のサンプルではダブルバッファリング(仮想VRAMを使う方法)で画面表示をしています。
仮想VRAMはRAM上に格納しているので、その内容も見てみましょう。
Main Memoryで確認できます。以下のようにAddressに直接アドレス値を指定すると確認できます。またアドレス値を直接打たずにHLやBCなどの16ビットレジスタに格納されている値をアドレスとしても指定できます。こちらは説明するより、使わないと便利さがわからないので各自ためしてみてください(汗)
Code Viewでも確認できます。Searchを使うとラベルが使えて便利なのでそっちのほうがラクな場合があるかもです。。。
Debug listにウォッチポイントを追加する
マシン語のデバッグでは「この値、なんでこんな値になってるんだよ!どこでこんな値を書き込んでるんだよー・・」という悩みが大半だったりしますが、openMSXではその追跡が出来ます。
特定のアドレスを監視して、値が変わったことをトリガーとしてブレークする。という指定ができます。今回はTIMER_COUNTというアドレスに1という値が格納された、そのタイミングでブレークする。という内容で説明します。$D001のアドレスに数値の1がセットされたタイミングということになりますね。
指定方法は以下のとおり。
まずはDebug listの「Watch points」の「Add」をクリックします。
次にRegion、Conditionを以下のとおり入力します。
Type: write_mem
Region: $D001
Condition: [debug read "memory" 0xD001] == 0x01
Typeはwrite_mem以外にもいろいろありますが私はそれ以外を使ったことはありません・・。
Regionは監視範囲のようです。私は範囲指定をしたことはありません・・。
Conditionはいろんな書き方があるようです。詳細はこちらを参照してください、、、(としか言えない)
さて、ブレークポイントと同様、X列にチェックを入れるとブレークします。
ld (TIMER_COUNTER), a
で、TIMER_COUNTERが1になって止まったようです。
どれどれ、TIMER_COUNTERの値を見てみましょう・・。
なってます!!1になったタイミングで止まってます!!(無意味な興奮)
と、まあ、こんな感じでデバッグを進めていくかんじです。
お分かりいただけたでしょうか?
ちなみに、1がセットされるまでにどんな処理を経てきたんだろ?というときに使うのはStepBackです。
上記ブレークポイントで数回、クリックするとこんな感じ。
これがマジ最強。
VRAMをモニタリングする
WebMSXなどでも出来ますが、openMSXでもVRAMをモニタリングできます(書き込みは出来ないみたいです)
メニューの「View」→「VDP」を選ぶとVDPの内容が見れます。
便利なのはTiles in VRAMとSprites in VRAMですね。
今回はopenMSXとopenMSX debuggerの説明でした。
みなさんのMSXプログラミングが快適になりますように!!
では、また!ノシ
おまけ:現在のゲーム開発進捗
筆者が4月からコツコツ作っているゲームがなんとか見てくれだけは見れる形になりました。WebMSXで触れるようにしています。
今回のアップロードはαテストバージョンです。
まだまだ完成までは時間が必要そうです。精進します。
セーラー服が似合うおじさんです。猫好き、酒好き、ガジェット好き、楽しいことならなんでも好き。そんな「好き」をつらつらと書き留めていきます。