復活!CP/M ワンボードマイコンでCP/Mを!
CP/MがTK−80互換のワンボードマイコンの上で復活します
ND80ZVとMYCPU80の上でCP/Mが走ります!
[第83回]
●BIOSの変更
前回からの続きです。
変更箇所は大きく分けて2つになります。
1つはデイスクドライブに関する定義をしているところです。
もう1つはディスクドライブをアクセスしているBIOSルーチンの変更です。
まず最初にディスクドライブの定義部分を変更します。
現行のCP/Mソースプログラムは、[第76回]で作成したCPM22J.TXTです。
それをもとにして、CPM22K.TXTを作ります。
●ディスクドライブの定義部分の追加と変更
1)CSV、ALVの追加と変更
ディスクサイズの変更とBドライブの追加にともない、CSV(チェックサムベクタ)とALV(アローケーションベクタ)を追加および変更します。
下左が変更前(CPM22J.TXT)で下右が変更後(CPM22K.TXT)です。
変更前の
CSV00 EQU 0B880H
ALV00 EQU 0B888H
を、下のように追加、変更します。
CSV00 EQU 0B880H
ALV00 EQU 0B884H
CSV01 EQU 0B886H
ALV01 EQU 0B88AH
CSV01、ALV01はBドライブのために追加しました。
CSV、ALVについては[第33回]で説明をしていますので、そちらを参照願います。
今回の変更により、ディレクトリは4セクタ、ブロック数は12になりました。
2)ディスクパラメータの追加と変更
ディスクパラメータの追加と変更を行ないます。
下左が変更前で下右が変更後です。
まずはdrive No.1を追加します。
drive No.0の記述の下に、以下のようにdrive No.1の記述を追加します。
;drive No.1(b drive)
DEFW 0
DEFW 0
DEFW 0
DEFW 0
DEFW DIRBF
DEFW DPTOP
DEFW CSV01
DEFW ALV01
最後のCSV01とALV01だけが、drive No.0と異なっていることに注意してください。
次にディスクパラメータを変更します。
ディスクサイズ、ディレクトリサイズを小さくしたための変更です。
変更するのは次の3箇所です。
DEFW 23
DEFW 31
DEFW 0C0H
を、下のように変更します。
DEFW 11
DEFW 15
DEFW 80H
最初の数値は、ブロック数が24−1から半分の12−1になったことによる変更です。
2番目の数値はディレクトリサイズが8セクタから4セクタになったことで、FCB数4×8−1=31から4×4−1=15に変更になります。
最後の数値は、ディレクトリが2ブロックから1ブロックになったため、ディスク先頭からの位置が、ビットマップで11000000(C0H)から10000000(80H)に変更になります。
各パラメータの意味と数値の根拠については[第12回]と[第13回]で説明をしていますので、そちらも参照してください。
●BIOSルーチンの変更
Bドライブの追加によってBIOSルーチンも変更が必要になります。
●Bドライブの先頭アドレスを定義する
BドライブのRAM上での先頭アドレスを追加します。
DISKTOP EQU 8800H
の下に、次の行を追加します。
DISKTOP2 EQU 0A000H
●リブートルーチンの変更(Cレジスタをクリア)
ファンクションコール0Eのテストを進めていくなかで見えてきたことがあります。
カレントドライブ(カレントディスク)がどのように決められるのか、というあたりにちょいと疑問があったのですが、おそらくその解明に関係していると思われる動作です。
本来のCP/Mでは、リブートしたとき、カレントドライブはAドライブになります。
この場合AドライブにはCP/Mシステムディスクが装着されている必要があります。
そしてそのシステムディスクからCP/Mシステムプログラムの一部がメモリに再ロードされます。
しかし、今作業中のCP/M仮システムでは、AドライブにはCP/Mシステムはありません。
ZB3BASICシステムにエントリしたときに、必要ならばWindowsのハードディスクから、CP/Mシステムプログラムをロードしてから、BIOSのエントリルーチン(リブートルーチン)にジャンプします(この仕組みは将来は変わるかも知れません)。
そのため、リブートしてもAドライブをセレクトすることは意識していませんでした。
でもいつもCP/Mを起動すると、最初にAドライブが選択されていました。
今回、Bドライブを追加したことによって、そのテストをしていくなかで、CP/M起動時にAドライブが選択されていたのは「たまたま」そうなっていたに過ぎない、ということがわかりました。
こういうところがプログラミングの恐いところです。
「たまたま」動いてしまうことがよくあるのですよねえ。
それでデバッグ完了、のつもりになって納入すると、ユーザーのところにいってから、信じられないような、有り得ない誤動作が発生して悩んでしまう、などということがおこります。
今回もBドライブを追加してからテストをしましたら、
むむむ。おかしいではないか?
という事態が発生してしまいました。
ある条件でリブートすると、Aドライブが選択されません。
でもCP/M起動時のBIOSのリブートルーチンは全く同じように実行されています。
あらためてCP/Mのエントリ部分のソースプログラムを調べてみて、納得いたしました。
CP/Mはエントリ時にCレジスタの値をチェックしていたのです。
Cレジスタの上位4ビットにはユーザー識別No.があって、下位4ビットがカレントドライブbノなっているようです。
現行のBIOSのリブートエントリールーチンを確認しましたら、Cレジスタは全くさわっておりませんでした。
ZB3BASICからCP/Mにジャンプするときに、ZB3BASICのコマンド処理ルーチンの中でCレジスタがクリアされていたようです。
Cレジスタの値が00のときにAドライブが選択され、01のときにBドライブが選択されます(以下同様にして、02ならCドライブ、03ならDドライブ…が選択されます)。
[注記]Cレジスタの上位4ビットはユーザーbナすが、ユーザーによる使い分けは考えないことにしますから、それは0にしておきます。
そこで、BIOSリブートルーチンに、Cレジスタクリアを追加します。
JP CBASE の前に、
LD C,A
を追加します。
●HOMEルーチンの変更
ホームポジションへのスキップルーチンもAドライブだけに対して行なっていたところを、Bドライブに対しても行なうように変更します。
CPM22J.TXT(上図左側)の以下の部分を
HOMEJ: LD HL,DISKTOP LD (TRKADRS),HL LD (SCTADRS),HL XOR A RET |
HOMEJ: LD HL,DISKTOP LD A,(DRVNO) OR A JP Z,HOMEJ2 LD HL,DISKTOP2 HOMEJ2:LD (TRKADRS),HL LD (SCTADRS),HL XOR A RET |
SELDSKJ:LD HL,DPBASE LD A,C LD (DRVNO),A RET |
SELDSKJ:LD HL,0 LD A,C CP 02 RET NC LD (DRVNO),A LD L,A ADD HL,HL;*2 ADD HL,HL;*4 ADD HL,HL;*8 ADD HL,HL;*16 LD DE,DPBASE ADD HL,DE RET |
SETTRKJ:LD HL,DISKTOP LD DE,800H INC C STTRK1: DEC C JP Z,STTRK9 ADD HL,DE JP STTRK1 STTRK9:LD (TRKADRS),HL XOR A RET |
SETTRKJ:LD HL,DISKTOP LD A,(DRVNO) OR A JP Z,SETTRKJ2 LD HL,DISKTOP2 SETTRKJ2:LD DE,800H INC C STTRK1: DEC C JP Z,STTRK9 ADD HL,DE JP STTRK1 STTRK9:LD (TRKADRS),HL XOR A RET |