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

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

[第509回]


●E−80ミニコンOS(CP/M互換DOS)のRS232C割込み受信プログラム

またしても中2日、間が空いてしまいました。
来週はまた週明けからハードなスケジュールになりそうです。
しかしそんなことばかり言っておりますと、懸案のE−80の232C受信プログラムが片付きませんから、昨日あたりから、まずは記事に仕上げようとして書き始めたのですが。

リストをアップして説明を書き始めましたら、「うう、これは、まずいんじゃないの?」というところがぽつりぽつりと見つかってしまいました。
そこで記事をアップするのはとりあえず一時中止いたしまして、本日は朝からずっとそのあたりのプログラム修正やらデバッグやらをやっておりました。
日が沈むころになりましてから、やっとZB3BASICについてはデバッグが完了いたしました。
でもまだCP/M互換DOSについては、検証ができていません。
そちらのほうも少しずつ進めながら、説明を書いて行くことにいたします。

当初の予定では今回一回でその説明は完了するつもりだったのですが、またまた何回かにわたって書くことになってしまいそうです。

まずは今までの説明の続きから始めることにいたします。
[第506回]では、大分県のH様の指摘によってみつかった、ZBIOSのREADER(RS232C受信)プログラムのバグ訂正を行ないました。
ところでそのリストを見ていただければわかりますが、RS232C受信プログラムとは言うものの、受信らしきところはどこにも見えません。
その実体は、アドレスE423でCALLしているRSRDSB(アドレス0409)です。
といってももう何日も前のことになってしまいましたから、ただ言葉で説明しただけでは、よくわかりませんですね。
下にZBIOSのREADERルーチンのリストを再掲いたします。

              ;
              ;PUNCHER OUT(RS232C OUT)
              ;
E404 ED       PUNCHJ:DB ED;IN0 A,[04]
E405 38       	DB 38
E406 04       	DB 04
E407 E602     	AND 02
E409 CA04E4   	JP Z,PUNCHJ
E40C ED       	DB ED;OUT0 [06],C
E40D 09       	DB 09
E40E 06       	DB 06
E40F C9       	RET
              ;
              ;READER IN
              ;
E410 2274E2   READERJ:LD (HLWK),HL
E413 210000   	LD HL,$0000
E416 39       	ADD HL,SP
E417 2276E2   	LD (SPWK),HL
E41A 2A74E2   	LD HL,(HLWK)
E41D 3100E9   	LD SP,BSP
E420 AF       	XOR A
E421 D339     	OUT (39),A
E423 CD0904   READERJ2:CALL RSRDSB
E426 CA23E4   	JP Z,READERJ2
E429 79       	LD A,C
E42A C379E3   	JP CONSTJ1


アドレス0409はCP/Mではユーザープログラムがロードされる0100〜のユーザーエリア(トランジェントエリア)にありますから、普通はシステムがCALLするアドレスではありません。
ここではメモリバンクを切り換えて、ZB3BASICのシステムルーチンをCALLしているのです。
アドレスE420の
XOR A
OUT (39),A
がメモリバンクを切り換える命令です。
この命令の実行によって、アドレス0000〜7FFFのメモリエリアが切り換えられ、CP/M互換DOSのユーザーエリアが裏に置かれて、代わりにZB3BASICのシステムプログラムエリアがアクセス可能になります。

そしてこちらがZB3BASICのエリア(メモリバンク0)にあるRSRDSBです。

046A F3       RSRDSB:DI
046B E5       	PUSH HL
046C D5       	PUSH DE
046D ED5B00F9 	LD DE,(BFTOP);E=BFTOP,D=BFEND
0471 3A03F9   	LD A,(RSERR)
0474 B7       	OR A
0475 C29504   	JP NZ,RSRDSB3
0478 3A02F9   	LD A,(BFCNTR)
047B B7       	OR A
047C CA9104   	JP Z,RSRDSB2
047F 2100F8   	LD HL,SPTOP;=RSBF
0482 6B       	LD L,E
0483 4E       	LD C,(HL)
0484 1C       	INC E
0485 ED5300F9 	LD (BFTOP),DE
0489 3D       	DEC A
048A 3202F9   	LD (BFCNTR),A
048D C29104   	JP NZ,RSRDSB2
0490 3C       	INC A;reset ZF
0491 D1       RSRDSB2:POP DE
0492 E1       	POP HL
0493 FB       	EI
0494 C9       	RET
0495 D1       RSRDSB3:POP DE
0496 E1       	POP HL
0497 37       	SCF
0498 C9       	RET


E−80のシステムプログラムによるRS232C受信は割込みによって行なわれます。
しかし上のリストのプログラムは割込みプログラムではありません。
単に受信データバッファ(F800〜F8FF)を読んでいるだけで、RS232C受信らしいところはどこにもありません。
割込みプログラムはこれとは別にあります。
なかなかに複雑な仕組みなのです。

ここではBFCNTR(バッファカウンタ)の値を見ています。
あ、その前にRSERR(受信エラー)のチェックをしていますが、実はそこはちょいと訳有りであることに気が付きましたので、説明は後回しにいたします。
BFCNTRが0ならそのままリターンします。
バッファに溜まっている受信データはありません。
BFCNTRが0でないならばバッファに未読データがありますから、バッファから1バイト読むとともに、BFCNTRの値を−1します。

前にも書きましたように、この受信バッファはリングバッファです。
最後のF8FFまでデータが埋まると、先頭のF800に戻って続きが書き込まれます。
そのままではどこが先頭でどこが最後のデータかわかりませんから、未読データの先頭のアドレスと最後のアドレス+1は、そのためのカウンタ(アドレスF900、F901)に維持されています。
バッファアドレスがF800〜F8FFというキリのよいアドレスに置かれているのは意図的にそうしたのです。
この場合、アドレスの上位8ビットは無視できますから、1バイトの数値で管理することができます。

そして、こちらが割込みプログラムです。

              ;    rs232c int
E5BA E5       RSINT:PUSH HL
E5BB D5       	PUSH DE
E5BC C5       	PUSH BC
E5BD F5       	PUSH AF
E5BE ED       	DB ED;IN0 A,[04]
E5BF 38       	DB 38
E5C0 04       	DB 04
E5C1 E670     	AND 70
E5C3 C2E8E5   	JP NZ,RSINTE
E5C6 ED       	DB ED;IN0 D,[08]
E5C7 10       	DB 10
E5C8 08       	DB 08
E5C9 3A02F9   	LD A,(BFCNTR)
E5CC 3C       	INC A
E5CD CAE1E5   	JP Z,RSINT2
E5D0 ED4B00F9 	LD BC,(BFTOP)
E5D4 2100F8   	LD HL,SPTOP;=RSBF
E5D7 68       	LD L,B
E5D8 72       	LD (HL),D
E5D9 04       	INC B
E5DA ED4300F9 	LD (BFTOP),BC
E5DE 3202F9   	LD (BFCNTR),A
E5E1 F1       RSINT2:POP AF
E5E2 C1       	POP BC
E5E3 D1       	POP DE
E5E4 E1       	POP HL
E5E5 FB       	EI
E5E6 ED4D     	RETI
E5E8 3203F9   RSINTE:LD (RSERR),A
E5EB F1       	POP AF
E5EC C1       	POP BC
E5ED D1       	POP DE
E5EE E1       	POP HL
E5EF ED4D     	RETI

ZB3BASICにもこれと同じプログラムがあります。
最初はRSRDSBと同じように、ZB3BASICにある受信割込みプログラムをそのまま使うつもりだったのですが、それは使えないことに気が付きました。
CP/M互換DOSの実行時には、ユーザープログラムエリア(トランジェントエリア)の裏に隠れているメモリバンク0に置かれているプログラムを割込みによって実行することはできないからです。
そこで上のように、ZBIOSの中に置くことにしました。

ここまで説明を書いてきて気がついたのですが、このプログラムにはバグではないのですがまずいところがあります。
どこかといいますと、アドレスE5CDのJP Z,RSINT2です。
ここはBFCNTR(バッファカウンタ)の値を+1した結果の処理をするところです。

BFCNTRはこの割込みプログラムによって受信データを受信データバッファに入れた時に+1し、RSRDSBによって受信データバッファからデータを読み出した時に−1されます。
BFCNTRの値を+1したときに結果が0になるのはどんなときかといいますと、それは実は受信バッファがバッファフルになったときなのです。
受信バッファはF800〜F8FFの256バイトですから、バッファのデータ数がFF+1=00ということは256バイト、つまりバッファフルです。

厳密にはまだ異常事態ではなくて、この状態のまま次にデータが受信されるとはじめてバッファオーバーになるのですが、システムとして考えると、ここまでバッファにデータが溜まったままになっているということは、もう十分に異常事態ですから、本来はエラー処理に行くべきところです。
このプログラムを書いたときにこのJP Zはそういう気持ちで書いたはずでした。
しかしこのジャンプ先では受信バッファゼロということで処理されてしまいます。

あ、いや、そうではなかったかもしれません。
なにしろもうずいぶん前のことなので、そこのところはよく思い出せません。
リングバッファですから引き取られていない古いデータを上書きすることでよいのではないかと考えたようでもあります。
しかし、それはやっぱりちょっとまずいでしょう。
ここは直すべきでありましょう。

ということで、説明はここまで書いたところで中断して、プログラムの変更とその結果をテストによって確認する作業にとりかかりました。

本日は時間がなくなってしまいましたので、この続きは次回にすることにいたします。

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

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