Last Updated on 2019年10月26日 by kabekin
コンソールI/O関係の不具合原因が分かりました!
何かの参考になるかもしれないのでメモしておきます(何とも凡ミスで恥ずかしい・・・
現象はCP/M起動後、Bdos Err On A: が32回表示された後にa>プロンプトが出たら「^@」が
126個出力されて改行され、停止するまで延々と続く不具合。
この「^@」表示不具合ですが、samさんからコメントを頂いた通りでCONINでNULLを渡していた
ことが原因でした^^
BIOS09からBIOS80に渡しているデータはOKっぽいが、
エコーバックで戻ってくるのは^@
この「^@」という処理はCP/M80内のSHOWITというサブルーチンにあるようです。
; Output (A) to the screen. If it is a control character ; (other than carriage control), use ^x format. ; SHOWIT: LD A,C CALL CHKCHAR ;check character. JP NC,OUTCON ;not a control, use normal output. PUSH AF LD C,'^' ;for a control character, preceed it with '^'. CALL OUTCHAR POP AF OR '@' ;and then use the letter equivelant. LD C,A ;
詳しくは分かりませんがどうやら文字以外のコードを受取った場合に置き換えられる文字っぽいということが判明。
但し、Bdos Err On A:というBDOSからのメッセージは正常に出力されていることからCONOUTやCP/Mのメッセージ出力部は正常だと思われます。
と、いうわけでBIOS80のコンソールCONSTとCONINを調べてみたところ問題がありました。
今作っているS1用CP/MのBIOSですがZ80とS1の間をコマンドとステータスフラグでやり取りしています。
CONINのやり取りの中でS1からZ80に処理を戻した際に共有メモリをクリアしている部分でやらかしてました^^
CONINサブルーチンはこんな感じで実装していました(ダメな例)
;+++ コンソール インプット(A←入力キャラクタ) ;現在の"CON:"に割当て中のデバイスから1文字入力しアスキーコードをAレジスタにセットしてリターン ;ANKの場合最上位ビットは0でなくてもOK ;入力があるまで内部でループさせる CONIN: ld A,3 ;BIOS09 CmdNo=3 ld (CMDNO),A ;BIOS09を呼び出す call REQ09 call RES80 ld A,(DATAREG) ;BIOS09から1文字受取り BIOS09でCONINの値を渡すとバッファクリアしているのでループしない call SHREGCLR ;共有レジスタクリア ret
このSHREGCLRサブルーチンですが、BIOS80→BIOS09→BIOS80の一連の処理が終了したときにZ80と6809で共有しているメモリをゼロクリアしているのですが、ここで単純なミス^^
;+++ 共有レジスタクリア SHREGCLR: xor A ld (CMDNO),A ld (IOSTAT),A ld (DATAREG),A ret
CONIN内でBIOS09から受け取ったAレジスタを壊してます^^;;
と、いうわけで^@のエコーバックが戻ってきておりました・・・・
一つ問題解決!!
続いて「^@」が126個表示されて改行が延々と表示される原因
こちらは参考書の注意書きを守っていなかったことによるものでした。
CP/Mの参考書にはCONINは入力があるまでCONIN内でループしなければいけないとの説明があります。
CONSTでデータを確認したらCONINが呼ばれるのではないかと勝手に解釈していたのでBIOS09側に
キー入力データが無くなったらCONSTで$00を返すのでループしなくてもいいだろうと勝手に思っていたのが失敗^^
CONIN内のループは必要です→これ重要^^
2つ目の問題も解決!!
CONINの2点の問題を修正したものがこちら
;+++ コンソール インプット(A←入力キャラクタ) ;現在の"CON:"に割当て中のデバイスから1文字入力しアスキーコードをAレジスタにセットしてリターン ;ANKの場合最上位ビットは0でなくてもOK ;入力があるまで内部でループさせる CONIN: ld A,3 ;BIOS09 CmdNo=3 ld (CMDNO),A ;BIOS09を呼び出す call REQ09 call RES80 ld A,(DATAREG) cp 0h ;入力無しならループさせて抜けない jp Z,CONIN CONIN1: call SHREGCLR ;共有レジスタクリア ret ;+++ 共有レジスタクリア SHREGCLR: push AF xor A ld (CMDNO),A ld (IOSTAT),A ld (DATAREG),A pop AF ret
正常に動作するようになりました^^
コンソールI/Oが正常になってキーボード入力とCRT表示ができるようになったので、
DIR してみます^^
おっ!反応がありました。
ディスクI/Oのサブルーチンが実装されていないので、エラーになりますが応答があります^^
DIRとキーインしたときのエコーバックはあったものの改行されずにCPMからの出力があるのでDIRが消えてしまっていますが、キーボードからの指示に対してCCPが応答してCRTに表示される一連の動作は確認できました^^
これでZ80Bカードのハードはほぼ問題なく動作していることも確認できました。
指示に対してCP/M80が応答してくれた、そんな記録・・・
問題が解決してよかったですね。
これでZ80の動作と最小限のI/Oが実現できたのであとはこれをベースに拡張していきましょう。
Z80からBIOS09の呼び出し処理でREQ09(BIOS09に要求する)とRES80(Z80処理を再開する)は
自分が提供したソースの名残かと思います。
おそらくSHREGCLRとRES80はREQ09に統合できるかな?と思っています。最適化してみてはどうでしょうか?
CP/Mに限らず普通にZ80プログラムを作成する場合の”作法”をなるべく単純にするのがおすすめです。
はい!CONSOLE I/Oは一応動作OKのところまで目途がつきました。
しかし、DISKIOを実装しないとエラー出まくりで何もできないので、ここからが本番かと思います^^
今は自分でも分からなくならないように効率など全く考慮されていませんが、ある程度基本的な動作が動くようになったらコードや機能の整理もしたいですね。
>CP/Mに限らず普通にZ80プログラムを作成する場合の”作法”をなるべく単純にするのがおすすめです。
そうですね。今のソフトは逐次処理で分岐や繰り返しをしている部分が今風のコーディングでアセンブラ特有の処理を進めながらデータを完成させるような流れにはなっていないと思いますので、このようなコーディングが正しいのかどうか自分では不安です^^;;
冗長ですが分かりやすいのではないかと自分では満足していたりします・・・(笑