2012.11.25
前へ
次へ
ホームページトップへ戻る

復活!CP/M ワンボードマイコンでCP/Mを!
CP/MがTK−80互換のワンボードマイコンの上で復活します
ND80ZVとMYCPU80の上でCP/Mが走ります

[第255回]


●LLISTとLPRINTが駄目だった理由

前回からの続きです。
ファンクションコール05のテストプログラムでは正しくプリントアウトできたのに、MBASICのLLISTとLPRINTを試してみましたら、まともに動作しませんでした。
いったいなぜ?

その解決の糸口としまして、前回はオリジナルの(実はオリジナルではなくて逆アセンブル版の)CP/Mソースのファンクション05がそのままBIOSのLISTルーチンにジャンプしているので、CP/M互換DOSでもそのようにしたのですが、そこがおかしいのではないか、という意味のことを書きました。

ファンクションコールにつきましては[第196回]で一覧表にまとめています。
下にその一部を切り取って示します。
ファンクション(Cレジスタにセットする値) 機能 パラメータセット
DEまたはEに値をセットする
結果
0  00(16進) システムリセット なし システムがリセットされる
1  01 コンソール入力 なし A=文字コード
2  02 コンソール出力 E=文字コード 文字が表示される
3  03 リーダー(RDR)入力 なし A=文字コード
4  04 パンチ(PUN)出力 E=文字コード PUN:に出力される
5  05 リスト(LST)出力 E=文字コード LST:(プリンタ)に出力される


注目すべきところを着色して示しました。
ファンクションコールではファンクションbCレジスタに入れて、パラメータは8ビットならEレジスタに、16ビットならDEレジスタにいれた上で0005Hをコールします。
ですからファンクションコール05ではプリントアウトする文字コード(ASCIIコード)をEレジスタに入れます。
ここまでのところには間違いはありません。

そしてファンクションコール05の実態はBIOSのプリンタ出力ルーチンそのものでしたので、そのままBIOSにジャンプするようにしました。
そこが間違いだったのです。
当然それを受けてBIOSのプリンタ出力ルーチンもEレジスタから文字コードを取り出してそれをプリンタに出力するようにプログラムしました。

うむ。
いいじゃないの、それで。
どこも間違ってはいないのじゃありませんか?

いえ。実は間違っていたのです。

BIOSの先頭部分には、マシンに直結する部分のプログラムへのジャンプ命令がずらりと並んでいます。
CP/M互換DOSのBIOSのジャンプテーブルについては、いままで説明をしていませんでした。
そこで、下に簡単に表にまとめて示すことにしました。
ファンクションコールはCレジスタにファンクションbセットして0005Hをコールしましたが、BIOSは下の表にある各機能のアドレスをコールします。

アドレス 機能 パラメータセット
BCまたはCに値をセットする
結果
D200 コールドブート なし システムが初期ブートされる
D203 ウォームブート なし アドレス0000Hにジャンプしてリブートする
D206 コンソールステータス なし READY:A=FF,BUSY:A=00
D209 コンソール入力(キーボード入力) なし A=入力文字コード
D20C コンソール出力(画面表示) C=文字コード 画面に表示される
D20F リスト出力(プリンタ出力) C=文字コード LST:(プリンタ)に出力される
D212 パンチ出力(RS232C送信) C=文字コード 1文字分のコードが232C送信される
D215 リーダー入力(RS232C受信) なし A=受信データ
D218 ディスクホームシーク なし ディスクがホームへシークされる
D21B セレクトディスク C=ドライブナンバー(A=0,B=1…) 指定したディスクが選択される
D21E セットトラック
BC=トラックナンバー 指定したトラックが選択される
D221 セットセクタ BC=セクタナンバー 指定したセクタが選択される
D224 セットDMAアドレス BC=DMAバッファアドレス ディスクリード、ライト時のバッファアドレスがセットされる
D227 ディスクリード
なし ディスクから1セクタデータがDMAバッファに読み込まれる
D22A ディスクライト なし DMAバッファのデータがディスクに書き込まれる
D22D リストステータス(プリンタステータス) なし READY:A=FF,BUSY:A=00
D230 セクタトランスレータ BC=論理セクタナンバー 論理セクタが物理セクタに変換される。HL=物理セクタナンバー


表の一番上のパラメータセットの説明をご覧ください。
BCまたはCに値をセットする」と書いてあります。

そうだったのです。
面倒なことに、ファンクションコールでは、パラメータはDEまたはEレジスタにセットするのに対し、BIOSルーチンでは、BCまたはCレジスタにセットするというルールになっていたのです。

しかし、それはそれとして、ファンクションコール05では出力文字コードをEレジスタに入れているので、それをそのままBIOSにもってきて、BIOSのプリンタ出力ルーチンでも、Eレジスタから文字コードを読み出して、それをプリンタに出力するようにしても、正しくプリントアウトされるはずなので、それのどこがいかんのか?

そうなのですよねえ。
もしも[第249回]でお見せしましたように、プリンタ出力の場合には必ずファンクションコール05を使ってくれれば、なんの問題もありませんのです。
しかし。
プログラムの上級者ともなりますと、いちいちファンクションコールなどというものを使うのはだんだんと面倒になってきます。
いっそBIOSルーチンを直接コールしてしまったほうが早いのではないの?
おそらくそういうわけでありましょう、MBASICのLLIST、LPRINTは、どうやらファンクションコール05を使うのではなくて、直接BIOSのプリンタ出力ルーチンをコールしているようなのです。

もうおわかりいただけたことと思います。
MBASICでLLISTとLPRINTが働かなかったわけが。

そうだったのです。
私がそこのところを深く考えずに、BIOSのプリンタ出力ルーチンでもEレジスタの値を文字コードとしてプリンタに出力するようにしていたため、おそらくBIOSのプリンタ出力ルーチンを直接コールしているらしいMBASICでは(当然文字コードはCレジスタに入れるはず)、まともな出力結果が得られなかったのです。

そこで。
[第248回]でお見せしましたBIOSのプリンタ出力ルーチンを下のように修正しました。

              ;PRINTER OUT
D3A5 DB82     LISTJ:IN A,(82)
D3A7 E680     	AND 80
D3A9 C2A5D3   	JP NZ,LISTJ
D3AC 79       	LD A,C
D3AD D380     	OUT (80),A
D3AF AF       	XOR A
D3B0 D383     	OUT (83),A
D3B2 00       	NOP
D3B3 3C       	INC A
D3B4 D383     	OUT (83),A
D3B6 C9       	RET
              ;

あ。勿論CP/M互換DOSのファンクションコール05の部分も修正いたしました。

              ;PRINTER OUTPUT FCALL 05
              ;
C86A 4B       LSTOUT:LD C,E
C86B C30FD2   	JP B_LIST

●MBASICのLLIST、LPRINTで正しくプリンタ出力できるようになりました

下はCP/M互換DOSをそのように修正して、MBASICを起動して、あらためてプリンタ出力テストをおこなったときのログリストです。

B>mbasic
BASIC-80 Rev. 5.21
[CP/M Version]
Copyright 1977-1981 (C) by Microsoft
Created: 28-Jul-81
25400 Bytes free
Ok
load "ptest1"
Ok
list
10 LPRINT "abcxyz"
20 LPRINT "12345"
30 LPRINT "7890";
40 LPRINT "hij"
50 PRINT "end"
Ok
llist
run
end
Ok
llist
Ok
system

そして、これがそのときのプリンタ出力結果です。

正しくプリンタ出力されるようになりました。

やっと。
一件落着いたしました。

ワンボードマイコンでCP/Mを![第255回]
2012.11.25upload

前へ
次へ
ホームページトップへ戻る