C++)のようなデバッグ機能を付けてみました。ちなみにデバッグ機能とは、例えばプログラム実行中に特定の位置に来たらプログラムを止め、その時のレジスタやメモリ状態を確認したり、止めた場所からアセンブラコードを1つずつ実行することで、思った通りの遷移が行われているかを確認したりすることが出来る機能です。昔はICEデバッガと呼ばれる専用のハードウェアと組み合わせることで、これらのデバッグ機能を実現することが出来ましたが、デバッグ用に専用のハードウェアを設計したりする必要があるため、製品を作るには時間もコストも掛かりました。その頃のPCは非力だったため、ソフトウェアによるエミュレートでデバッグを行うなんてことは考えられなかったわけですが、今ならこれらのCPUをエミュレータで実行することも出来るので、であればエミュレータにデバッガも入れてしまえばクロス開発がもっと楽になるのではと思い、何かいい方法が無いものかと考えていたところ、なんとSDCCのビルド時に書き出されるファイルにデバッグに必要な情報がすべて出力されていることに気づきました。SDCCはコンパイル時に中間ファイルとしてMAPファイルとLSTファイルを書き出しています。MAPファイルには各ソースや関数の絶対アドレスの情報(メモリマップ)が含まれており、またLSTファイルにはC言語やアセンブラを最終的なアセンブラコードに変換した際の詳細な情報が含まれていて、実はこれらを総合的に解析することでプログラム全体のメモリマップが構築出来ます。ちなみに、最初は逆アセンブラを使ってアセンブラコードを逆算することも考えましたが、これだとあるアドレスの値がデータなのかコードなのか分からなかったり、もしコードの位置がずれてしまっていると逆アセンブルの結果もおかしくなってしまうため、出来るとしたら中断した位置のコードしか正確に分かりません。逆アセンブラはアセンブラコードをデバッグするものであり、C言語のデバッグは一切出来ないわけですが、SDCCが書き出したファイルにはC言語のコードがそのままコメントとしてアセンブラコード上に残っていたり、さらに便利なのがアセンブラコードが実行単位で行ごとに分かれているので、これを利用すればソースコードの位置を正確に把握しながらデバッグ出来るのではと思ったわけです。VCではメモリ上にある構造体の中身を確認することは出来ますが、今回のエミュレータではそれには対応していません。このため、そのアドレスをダンプして自分で値を確認する必要がありますが、例えばレジスタにその構造体のアドレスが代入されているならば、そのレジスタのアドレス先に飛んで直接ダンプすることが出来るので、これを利用すれば間接的に値の確認などが可能です。Layer2ライブラリ)のせいか、起動直後にウィンドウメッセージの処理が滞るようで、デバッグウィンドウが表示されるまで少し時間がかかります。そもそもSDLはWindows以外でも使える汎用のライブラリであり、ウィンドウメッセージの部分は内部でブラックボックス化されているため、外部からいじることが出来ません。(SDLのソースは公開されているので中身をいじることは出来ますが、ライブラリを修正するとなると本末転倒なのでここではいじりません)ということでこれは仕様としてひとまず気にしないことにして、今回はあらためてWindows10でのSDCCのインストールの仕方と、デバッグ機能付きg800エミュレータを同梱したビルドツールv2.01を使ったデバッグ方法について説明します。旧バージョンからのソース移植について以前のビルドツールv2.00で作成したプログラムは、g800ライブラリ(g800.h、g800.c、crt0.s)以外のゲームソース(game.hやgame.c、自分で作成した各データヘッダなど)をv2.01にコピーすることでそのまま利用可能です。v2.01の関数は基本的にv2.00と変わりはないので、各APIの説明は以前の記事を参考にしてください。v1.00のものはライブラリ自体が古いため、v2.01への移植作業が必要となります。※v1.00はもう更新はされないので、新規で作るプログラムは新しいバージョンを使用してくださいSDCCのインストール(改)SDCCにはバージョンがあり、ビルドツールv1.00の時は当時最新だった3.6.0を使用していましたが、現在は3.9.0となっています。※実は最新バージョンを使ってビルドツールv2.xxに同梱のPSG版のサンプルをビルドしようとすると、MMLPlayer.cのコンパイルがフリーズしたかのようにすごく長くなる現象を確認しました。ビルド自体は通るので特に最新バージョンを使用しても問題はありませんが、ビルド時間が長く時間がもったいないため、特に最新が必要でなければ古い3.6.0を使用することをお勧めします。ダウンロードは以下から行います。https://sourceforge.net/projects/sdcc/files/sdcc-win32/※こちらは32bit版のSDCCですが、64bitOSでも問題なく動きます(64bit版のSDCCも別途あります)この中から使用したいバージョンをクリックします。(3.6.0を使う場合は下のそのバージョン番号をクリックしてください)その中にある「sdcc-X.X.X-setup.exe」というファイルをクリックしてください。画面が切り替わり数秒待つとダウンロードが開始されます。※DL先はデスクトップなど適当な場所を選んでくださいDLしたらあとはその実行ファイルをダブルクリックして実行します。Windows10では以下のような警告が出ることがあります。この場合は「詳細情報」ボタンを押すと実行が押せるようになります。インストールはほぼ次へを押すだけで完了します。インストールするファイルを選べますが、ここではすべてインストールしています。PATHの設定が表示されたらチェックを外さずに次へを押してください。※PATHとはコマンドラインで実行ファイルを実行する際に探すフォルダのことですFinishを押したらセットアップ完了です。次に正しくインストールされたかを確認してみます。Shell」をクリックします。※新しいWindows10ではコマンドプロンプトがPowerShellに置き換わっている場合があります。タスクバー」を開き、右側の「[スタート]ボタンを右クリックするか...」の部分のスイッチをオフにしてください。コマンド入力画面で「sdcc」と入力してエンターを押します。ここでsdccのヘルプが表示されたなら、インストールは正しく行われています。これでビルドツールのコンパイルが可能となりました。ビルドツールのダウンロードビルドツールは以下からダウンロードしてください。v2.01ダウンロード※デバッガ対応のg800エミュレータv1.01が同梱されていますビルドツールには2種類のテンプレートプロジェクトフォルダがあります。それぞれ「開発用テンプレート(PSG音源対応)」と「開発用テンプレート(シンプル)」ですが、このテンプレートフォルダが実質1アプリ分のプロジェクトフォルダということになるので、あとあと作成するゲームの名前などに自由に変更してください。※各プロジェクトの詳細や同梱のg800ライブラリの詳細はこちらの記事を参考にしてくださいこのビルドツールには以下のサポートツールが同梱されています。転送の前に必ず一度起動し、転送用の設定(COMポートやボーレート)などを設定する必要があります。g800ライブラリの文字表示関数(DrawString、PPrintf)で表示されるフォント画像のヘッダファイル(ascii.h)を作成します。「ascii.bmp」を編集することで自前のフォントを作成することが出来ます。v1.00では固定サイズ(5x6)で、強制的に全てのASCII文字が登録されてしまっていましたが、v2.00からは文字サイズをパラメータで指定出来たり、ゲーム中に使わない文字タイプを除外することで、メモリの節約が出来るようになっています。MIDIファイルからg800ライブラリのSライブラリで使用する曲データのヘッダファイルを出力します。これは指定した1トラック内にある全ノートを出力するため、和音も表現することが出来ます。IHXファイルとバイナリファイルを相互に変換します。変換の際にオフセットを指定することで全体をズラすことも出来ます。BMPやTGAを変換してg800ライブラリの描画関数で直接使用可能なヘッダファイルを生成します。BMPの場合はマスク無し(アルファチャンネルは無視)、TGAの場合はマスクあり(32bitアルファチャンネルを使用)で変換します。画像がカラーだった場合、一般的なモノクロ変換を行ってから灰色中心で2値化します。ディザ合成は行われないため必要ならばあらかじめ編集段階で白黒化(2値化)しておいてください。透明画像(TGA)TGAファイルでは透明部分を表現することが出来ます。通常の合成とはORで各ビットを合成するため、背景に何らかの画像がすでに存在すると、そのドットはそのまま残ってしまいます。そこでここではマスクという元の画像と同じサイズの専用画像を用意します。最初に背景とANDすることで、今回描画したい画像の部分のみを消しておきます。最終的に白で抜かれた透明部分のある画像を合成することが出来るわけです。画像データフォーマット画像データは先頭にIMGDATA構造体があり、その直後に画像データが続きます。マスクが存在する場合は、画像データ(OR用)のあとにマスクデータ(AND用)が続きます。マスクの存在する画像では通常の画像とマスク画像の2つ分のデータが存在することになるため、メモリ使用量が単純に2倍になります。このため基本的にはマスク無しの画像を使用し、必要な個所だけマスクありで作成することをお勧めします。ポケコンから吸い出したRAM領域(0000h-7FFFh)のバイナリイメージに、SDCCから出力されたコードを結合して最終的なRAMイメージを生成します。これはビルドバッチ内で使用されるもので、基本的に直接使用することはありません。PSG音源ライブラリ用のMMLを作成し、これをヘッダファイルとして出力出来ます。入力したMMLを即座に再生出来るため、MMLのデバッグにも使用出来ます。MIDIからのインポートに対応しているため、既存のMIDIからMMLを手軽に作ることもできます。詳しい使い方やMMLの書式は同根のMMLPlayer.htmlを確認してください。音色定義をTSSに合わせることでTSS側で再生も可能です。※このソフトは音声出力にWASAPIを使用しているため、対応した音源とVistaSP1以上が必要ですポケコンの開発用のみであれば上記のビルドツールだけダウンロードすれば問題ありません。以下はエミュレータのソースコードと、11pinミニI/Oのエミュレーション用のDLLのソースコードです。v1.01のソースダウンロード※SDL2.0.7同梱g800(改)用ミニI/O音源エミュv2.00のソースダウンロード※実機と比べて1オクターブ高く再生されます※全てVC2010用のプロジェクトとなります修正内容は以下の通りです。DAMAGE.---------------------------------------------------------------------------------------PSG音源をWindows上で再現するために、以下のライブラリを使用しています。http://retropc.net/cisc/m88/-------------------------------------------------※この中のPSG音源部のソースのみ利用していますデバッガの使い方ここではビルドツールに含まれているサンプルプログラム「開発用テンプレート(シンプル)」を例に、プログラムのデバッグ方法について説明します。このサンプルは1枚のフルスクリーン画像を描画するだけのプログラムで、ON(BREAK)キーを押すことでプログラムを終了することが出来ます。これらの処理はgame.cに書かれていますが、ここでは参考として以下に全コードを示します。TRUE;}このサンプルではプログラムのコメントに書かれてあるように、EnterFrame()内にあらかじめブレークポイントが設定されています。ブレークポイントを定義するには行の先頭に「$」と書きますが、実行中この処理が行われる直前にデバッガにより動作を停止します。ちなみに「$」は「g800.h」にてC言語上では何もしない空の定数として定義されています。※ブレークポイントはいくつも設定することが出来ますこの状態で「!!!build.bat」を実行してビルドを行い、成功後に何かキーを押すことでエミュレータを起動させますが、この時はまだブレークポイントのコードが実行されないため、プログラムはそのまま動き続けます。逆に言えば、ブレークポイントが設定されていなければ普通にプログラムを実行出来るため、デバッグ機能が有効になっていたとしても、通常通りプログラムのテストを行うことが出来ます。この状態でONキーを押すとif文が評価され、その中のコードに移行するわけですが、この時ブレークが発動することでデバッガがプログラムを停止させます。すると、このブレークが置かれているソース(ここではgame.c)に対するアセンブラコードの位置にカーソルがジャンプします。FALSE;」を実行するコードになっています。SDCCでは、関数の戻り値として8bitの値を返す場合はLレジスタ、16bitの値を返す場合はHLレジスタを使用しますが、EnterFrame()の戻り値は「BOOL型」であり、BOOLは「platform.h」にて符号無し8bitと定義しているため、ここではLレジスタに0を設定したあとでリターンするというコードになっています。ブレークがかかると現在のレジスタの内容が上部に表示されます。表示形式は左上のラジオボタンにより10進数の符号ありや符号なしにも変えることも可能です。8bitレジスタは10進数や16進数の他に2進数によるビット値も表示されます。フラグレジスタは各フラグの状態を1つずつ分かりやすいよう、チェックボックスで分けて表示されるようになっています。16bitレジスタは主にメモリのアドレスの参照に使われるため、横の「→」ボタンを押すことでそのアドレスにジャンプすることが出来るようになっています。メモリダンプを行うには「@RAM」タブを選択します。ポケコンのRAMは32KBしかないため、このタブで表示できるのは32KBまでとなります。PCレジスタのアドレスにジャンプしたい場合、PCレジスタの横の矢印ボタンを押しますが、この時該当するメモリアドレスの値が赤字で表示されるので、その位置をパッと見で把握できるようになっています。以下のようにメモリ内のコードとアセンブラコードが一致しているのが確認できると思います次にこのブレークした位置からステップ実行を行ってみます。ステップ実行とはアセンブラコードを1個分だけ進めることで、これは上のステップボタンを押すことで行います。ステップ実行をすると現在のコードが実行され、次のコードで再び停止します。この時変化したレジスタの色が変わるので、実行したコードで何が行われたのかをすぐに把握することが出来ます※ここではLレジスタに0x00を入れたので、Lレジスタとそれに付随するHLペアレジスタが、またPCレジスタもコードに合わせて進んだため色が付いています(値を代入した結果が同じ値だった場合は、変化無しと判定されるため色は付きません)このステップ実行を繰り返すことで、1つ1つのコードを確認しながら実行することが出来るようになっています。ステップ実行をやめて再び普通の処理に戻したい場合は、上の「再開」ボタンを押します。これを押すと次のブレークポイントが見つかるまで処理を止めずに実行することが出来ます。ブレークポイントは実行中やブレーク中にON/OFFすることが出来ます。赤丸や行番号のあるエリアはブレークポイントを設定することが出来る場所で、クリックすることでブレークポイントを切り替えることが出来ます。実行中にブレークポイントを設定した場合、その位置に到達するとブレークが発動するため、一時的に内容を確認したいといった場合にも使用することが可能です。ちなみにCのソースコード上で指定するブレークポイントは、単にブレーク位置をあらかじめ設定出来るというだけであり、実行中にブレークポイントを解除することも可能です。※ブレークポイントはブレークが可能な行にしか設定出来ませんブレークを利用した裏技このデバッガはC言語用というよりはアセンブラ用に近いものとなっています。ステップ実行はあくまでもアセンブラコード単位のため、アセンブラを知らないと何をやっているのか全く分からないことになりますが、もっと大まかにCの関数単位で動作を確認する方法があります。その方法とはCのソース側でデバッグしたい行全てにブレークポイントを設定し、ステップ実行ではなく再開を使用します。することで関数単位でブレークが発動するため、どこに処理が通っているのかといった大まかな動作を確認することが可能です。TRUE;}ブレークしたら再開ボタンを押すことで次のブレークポイントまで進むので、この方法でCソース上での遷移を把握することが出来ます。※エミュレータのソースコードを見れば分かるかもしれませんが、実はCの関数ごとにブレークするための解析も既に行っており、あとは処理さえ実装するだけで上記のようなブレークポイントを設定せずともCの関数ごとにブレークすることも出来るのですが、今回はとりあえずアセンブラのデバッグがやりたかっただけなのでこの機能は見送りました(時間があったらそのうち実装するかも)同じくアセンブラ上でCALL呼び出しがある場合、ステップ実行ではCALLの呼び出し先のコードにジャンプしてしまいますが、特にCALLの中身を確認する必要が無く即座に次のコードを確認したい場合は、CALL呼び出し直後のコードにブレークを設定してから再開ボタンを押します。することでCALLはそのまま実行され、CALLから戻ってきた際に次のコードでブレークが入るので、結果的にCALLをスキップしたことになります。g800エミュレータのデバッガが使用するファイル構成についてg800エミュレータのデバッグに使用するファイルはMAPファイルとLSTファイルですが、これはビルドバッチを実行すると自動的にエミュレータのデバッグフォルダ(debugger)にコピーされます。エミュレータはこの中にあるファイルをすべて読み取り、メモリマップを構築してデバッグ情報を生成していますが、もしこのフォルダの中に何も無かった場合は、デバッグ機能をONにしていたとしてもメモリマップが作れないためデバッグ処理は行われません。※デバッグウィンドウが表示されませんちなみにデバッグ機能を使用するかどうかは、エミュレータのあるフォルダの直下にある「g800config」をメモ帳で開き、debuggerの定義を「y」か「n」で指定します。自作アセンブラのデバッグこのデバッガでは自分で作ったアセンブラコードもデバッグ出来ます。実はポケコンのブートアップコード「crt0.s」はアセンブラファイルであり、アセンブルするとCのソースと同じくlstファイルが生成されるので、これもデバッガに自動的に読み込まれるようになっているため、デバッガ上でcrt0タブを開くことで同じくブレークポイントを設定することが出来ます。アセンブラのソースはCのソースのようにコード上であらかじめブレークポイントを指定することは出来ないため、この場合はCのソース側でアセンブラコードを呼び出す処理を書いておき、そこにブレークポイントを設定してステップ実行するか、または実行中でもブレークポイントは設定できるので、実行中にアセンブラコード内にブレークを置くことで強制的に停止させることが出来ます。自分でアセンブラファイルを用意した場合は、ビルドバッチにそのファイルのアセンブルとリンク指定を行う必要があります。※面倒なら自分のアセンブラもcrt0.sに書いてしまうのも手ですデバッグウィンドウの操作デバッグウィンドウに表示される各ソースコードは、ドラッグすることで自由にスクロールすることが出来ます。※「@RAM」タブはドラッグによるスクロールには対応していませんスクロールバーによる移動ではウィンドウメッセージによりメイン処理が停止してしまいますが、ドラッグでのスクロールでは停止しないので、実行したままソースコードを確認することが出来ます。コメントコメントはまだ登録されていません。コメントする名前コメント※タグは使用出来ませんこの記事に関連するタグポケコン(PC-G850)次の記事>。