復活!CP/M ワンボードマイコンでCP/Mを!
CP/MがTK−80互換のワンボードマイコンの上で復活します
ND80ZVとMYCPU80の上でCP/Mが走ります!
[第392回]
●CP/M互換DOSプログラムのデバッグ
本日は朝からずっとCP/M互換DOS操作説明書の補完作業とプログラムのデバッグ作業をしておりました。
説明書を書くという作業は実に疲れる作業です。
今はファンクションの説明のところを検証しています。
説明の内容だけではなくて、サンプルプログラムも念のため実際に動作させてチェックしながら進めています。
もう何回もテストをしているはずなのですが、その当時には気がつかなかったバグや、それ以後にプログラムを修正したために、当初はうまく動いていたものがかえって動かなくなってしまったところなどが出てきて、そのたびにバグつぶしをしていますので、なかなか作業がはかどりません。
それでも本日はやっとファンクション0D(ディスクリセット)まで検証が進みました。
うむむ。
実に牛歩ですなあ。
われながらいやになってしまいます。
さて、そのようなデバッグの作業にはもっぱらCP/M互換DOSで機能アップしましたマシン語デバッグ機能を使っております。
0000〜7FFFの範囲のRAMのプログラムにブレークポイントが設定できるBP@コマンドは、このところのデバッグ作業で真価を発揮しています。
ブレークポイントを設定してのデバッグ作業については[第180回]〜[第188回]で説明をしています。
しかし。
その後に機能を一部変更したりして使い方が少し違ってきているところなども出てきましたので、使用方法についても操作説明書に書くつもりでしたのですが。
いざ、書こうとするとなかなか要領よくまとまりません。
まだ、ホームページに書くほうが、図なども簡単に貼り付けられますし、図のサイズにもそれほど制約がありません。
というわけで、あらためて、デバッグについてのサンプルを以下にお見せすることにしまして、操作説明書では「ホームページの記事を参照してください」と書くことにいたしました。
●/CPM,D
今回新たに作ったコマンドです。
/CPMはCP/M互換DOSを起動するコマンドですが、CP/M互換DOSを起動すると、ZCCP、ZBDOS、ZBIOSの各システムプログラムがディスクからND80ZV(ND80Z3.5)のRAMにロードされます。
これはデバッグにはちょいと都合が悪いのです。
さらに都合が悪いのは、ユーザープログラムを実行するときの手順です。
CP/MではBASICのLOADとRUNのように、プログラムのロードと実行命令が分離していなくて、COMファイルに対して拡張子をつけないでファイル名だけをダイレクトに入力することで、コマンドと同様に実行する仕組みになっています。
たとえばAドライブにABC.COMというユーザープログラムがセーブされているときに、
A>ABC[Enter]
と入力することで、ABC.COMを実行することができます。
この仕組みはMSDOSにもそのまま受け継がれていて、COMファイルやEXEファイルは全く同様の方法で実行することができます。
これはとても便利な仕組みなのですが、そのファイルをデバッグしようとしますと、ちょいと困った仕組みであることに気がつきます。
プログラムをデバッグするためにブレークポイントを設定しようとしても、その時点ではまだプログラムがロードされていないのですからブレークポイントを設定することができません。
そこで以前にBP@について説明をしましたときは、まずZCCPプログラムでユーザープログラムのロードが完了した直後のアドレスにブレークポイントを置いて、それからシステムプログラムを再ロードしないでCP/M互換DOSを起動するアドレスへのジャンプ命令を実行する、という方法を説明しました。
しかしこのやり方は、私は慣れておりますからよろしいのですけれど、皆様方にやっていただこうとしますと、ちょいと敷居が高いかと思います。
前置きが長くなりましたが、そこで少しでも扱いやすくするために、2つの改良をしました。
その1つはZCCPプログラムでユーザープログラムのロードが完了した直後のアドレスをZCCPプログラムの先頭部分に置いてわかりやすいアドレスにしました。
そのアドレスはCC03です。
その2つ目は、システムプログラムを再ロードしないでCP/M互換DOSを起動するためのコマンドの新設です。
それが今回のタイトルの
/CPM,Dです。
/CPM,D[Enter]
と入力すると、システムプログラムをロードすることなくCP/M互換DOSが起動します。
なぜこの機能が必要かといいますと、システムが再ロードされると、せっかく設定したCC03のブレークポイントがクリアされてしまうからです。
なにはともあれ、実際の例を見ていただくことにいたします。
●ユーザープログラムのデバッグ例
参考例として前回説明しましたVFTST0−2.COMをデバッグしてみることにします。
CP/M互換DOSでのデバッグのためには、最初にまず1回は通常の方法で(つまり/CPMコマンドで)CP/M互換DOSを起動して、それからZB3コマンドでZB3BASICに戻る必要があります。
下の画面は前回VFTST0−2を実行したあと、
ZB3[Enter]
でZB3BASICに戻ったところからの画面です。
ユーザプログラムにブレークポイントを設定するには、まず最初にCC03にブレークポイントを設定します。
BP CC03[Enter]
です。
ここは0000〜7FFFの範囲外ですから@をつける必要はありません。
それから
/CPM,D[Enter]
でCP/M互換DOSにエントリしました。
/CPM,Dコマンドでエントリするとカレントドライブは以前のまま変更されません。
Zドライブが選択されたままになっています。
ここで
Z>VFTST0−2[Enter]
を入力しました。
するとロード直後にCC03でブレークしました。
レジスタダンプのPCのところにCC03と表示されています(PCはプログラムカウンタです)。
いよいよここからがデバッグの始まりです。
最初に010Cにブレークポイントを設定してみました。
BP@010C[Enter]
です。
ここは前回のアセンブルリストを参照してください。
あ。戻るのは面倒ですね。
この下のほうに再掲いたしました。
そのあと
RT@[Enter]
を入力すると、ユーザープログラムが普通に実行されます。
*が表示されたあと、入力待ちになりますから e を入力しました。
するとアドレス010Cの命令の実行直前でブレークしました。
ファンクションコール01の実行直後です。
このときの各レジスタの値やフラグの値などが全てレジスタダンプで表示されています。
Aレジスタにはキー入力した文字eのコード65が入っています。
続いて0127にブレークポイントを設定してRT@を実行しました。
すると改行後に : と e が表示されたあと、0127でブレークしました。
DCR B
を実行した直後です。
BレジスタはFFになっています。
実行結果は0ではありませんからレジスタダンプの右にありますフラグのところのZは0(セットされると1になる)です。
FFはマイナスの数ですからSフラグが1になっています。
このようにブレークした時点でCPUの動きを停止させて、そのときのCPUの全レジスタの値を見ることができます。
プログラムがどうにも納得できない動きをしているときに、そのプログラムの進行にあわせてブレークさせながら少しずつCPUの動きを確認していくことで、プログラムのバグをみつけることができます。
レジスタやフラグの値を見ることで、プログラムを書いた時点では気がつかなかった思い違いや考え違いなどが発見できます。
大急ぎで簡単に説明しましたが、ブレークポイントを使ったプログラムデバッグの方法が大体はご理解いただけたと思います。
ここで注意することは、ブレークポイントは必ず命令の最初のアドレスに設定しなければならない、ということです。
今回の例でいいますと、010D、010Eや0128、0129には設定できません。
それからデバッグのコツですが、特にレジスタの値を確認したいところや、条件ジャンプのところにブレークポイントを設定するようにする、ということです。
たとえば010Cや0111、0127などがそのポイントです。
2013/5/5 9:32 vftst0-2.txt END=013C ;;FUNCTION 0,1,2 TEST ;2013/5/4 5/5 ; ORG $0100 FCALL=$0005 ; 0100 0E02 START:LD C,02 0102 1E2A LD E,2A;'*' 0104 CD0500 CALL FCALL 0107 0E01 LD C,01 0109 CD0500 CALL FCALL 010C 323C01 LD (BUFF),A 010F FE12 CP 12;^R 0111 CA3701 JP Z,RESET 0114 0E02 LD C,02 0116 1E3A LD E,3A;':' 0118 CD0500 CALL FCALL 011B 0600 LD B,00 011D 3A3C01 LOOP:LD A,(BUFF) 0120 0E02 LD C,02 0122 5F LD E,A 0123 CD0500 CALL FCALL 0126 05 DEC B 0127 C21D01 JP NZ,LOOP 012A 1E0D LD E,0D 012C CD0500 CALL FCALL 012F 1E0A LD E,0A 0131 CD0500 CALL FCALL 0134 C30001 JP START ; 0137 0E00 RESET:LD C,00 0139 CD0500 CALL FCALL ; 013C 00 BUFF:NOP ; BUFF =013C FCALL =0005 LOOP =011D RESET =0137 START =0100 |