復活!CP/M ワンボードマイコンでCP/Mを!
CP/MがTK−80互換のワンボードマイコンの上で復活します
ND80ZVとMYCPU80の上でCP/Mが走ります!
[第505回]
●E−80ミニコンOS(CP/M互換DOS)のRS232Cプログラム
連休に入ってやっと少し仕事が片付いてきました。
このところ飛び飛びの更新でなかなかお話がつながりません。
今回は[第503回]からの続きです。
E−80ミニコンはND80ZV(ND80Z3.5)のCP/M互換DOS(ZB3DOS)と同じDOSプログラムを搭載しているのですが、ハードウェアの違いがあるために、ハードウェアに依存する部分を書き換えています。
ND80ZV(ND80Z3.5)のRS232C機能はPIC18F14K50に持たせています。
E−80ミニコンにもPIC18F14K50は載っていますが、E−80ミニコンのPIC18F14K50はUSB専用として使っています。
E−80ミニコンのRS232C機能は、Z8S180CPU内蔵の機能を利用しています。
そのために、その部分のプログラムはND80ZV(ND80Z3.5)のCP/M互換DOS(ZB3DOS)とは全く異なっています。
こういうところがOSのOSたる所以(ゆえん)でありまして、ハードウェアの違いを吸収して、上位のプログラムにその影響を及ぼさないようにするというのが最も重要な役目になります。
それによって、その上で動くアプリケーションは機種の違いを意識することなく実行することができるようになります。
CP/Mの場合、ハードウェアに依存する部分はBIOSにまとめられています。
当然のことながらCP/M互換DOSにおいても、それは同じです。
下はCP/M互換DOSのBIOS(EZBIOS)のRS232C送信、および受信部分のプログラムリストです。
; ;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 CALL RSRDSB E426 CA10E4 JP Z,READERJ E429 79 LD A,C E42A C379E3 JP CONSTJ1 |
さて、ここでは見慣れない命令が使われています。
ここで使われているEDから始まる3バイトの命令はZ80では未定義の命令で、それを利用してZ8S180では固有の命令機能を割り当てています。
Z8S180の内蔵レジスタにアクセスするための命令機能です。
それも整理してお見せするとよいのですが、今それをしているだけの時間がありませんし、それを見たところでZ8S180を使わないならば、何の役にも立たないわけですので、ここはとりあえずそのあたりは省略して、説明を先に進めます。
リストの前半のPUNCHJの部分は名目はパンチャ出力ですが、機能としてはRS232C送信です。
Z8S180内蔵レジスタ[04]のビット2をチェックしています。
Z8S180内蔵232C(CH0)の送信バッファが空になると、このビットが1になります。
それを待ってから、送信バッファレジスタ[06]にCレジスタの値を書き込みます。
内蔵レジスタ[06]にデータを書き込むと、そのデータはシリアル変換されて232Cデータとして送出されます。
送信プログラムはなんてこともない簡単なものです。
しかし受信はそうは簡単にはいきません。
READERJは、名目はリーダー入力ですが、機能としてはRS232C受信です。
ここはちょっと見では意味不明のややこしいことをしています。
RS232C受信は、前に書きましたように、受信割込みを使っています。
割込み処理プログラムはここではなくて、別のところに書いてあります。
ここのRS232C受信プログラム部分は、受信割込みによって受信バッファに蓄えられた受信データを読んでくるだけのプログラムです。
そうは言っても受信バッファからデータを読んでくるという、そのこと自体がそれなりのプログラムを必要とします。
なぜかと言いますと、受信バッファは256バイトのリングバッファになっていて、割込みプログラムによってバッファにデータが逐次書き加えられるのとは独立して、そこから到着順にデータを読み出してこなければならないからです。
リングバッファはバッファの終わりまでくると、続きは先頭に戻って書き込まれます。
ドーナッツ状のバッファで、途中ではデータの先頭がデータの終わりよりも後ろのアドレスになる場合が出てきます。
割込みプログラムがドーナッツの先頭部分を追加していき、それを読み出しプログラムが追いかけて読み出していく、というイメージになります。
ちょいと面倒なプログラムなのですが、実はそのバッファから読み出す部分はZB3BASICのRS232C受信機能として少し前にすでに作成済みです。
それを利用しない手はありません。
それがE423番地のCALL RSRDSBです。
RSRDSBはRAMバンク0の0409番地にあります。
CP/M互換DOSでは0000〜7FFFにバンク2を割り当てていますので、バンクを切り換えなければRSRDSBをCALLすることができません。
E−80のメモリバンクについては[第456回]〜[第460回]をお読みください。
バンクを切り換えるには内蔵レジスタ[39]にバンクb書き込めばよいのですが、ここではそれ以外にSP(スタックポインタ)の退避とSPの設定を行なっています。
なぜ?
CP/Mのアプリケーションの中にはSPをアプリケーションで設定しているものがあって、スタックが0000〜7FFFの領域に設定されていることもあります。
するとバンク0に切り換えて、そこがZB3BASICのプログラムエリアに切り換わっているのに、スタックもその同じ領域に設定されてしまう、ということが起こります。
そうなると当然スタックがシステムプログラムを破壊してしまいますので、まともでは済みません。
それを避けるためにバンクを切り換えてRSRDSBをCALLする前にSPの退避とスタック領域の設定を行なっているのです。
RSRDSBは受信バッファをチェックして受信データが無い場合にはZフラグを立ててリターンします。
受信データがある場合には、そこから1バイトを読み出してCレジスタに入れてリターンします。
RSRDSBをCALLしたあとはSPをもとに戻してRAMバンクも元に戻します。
それが最後のJP CONSTJ1です。
下にCONSTJ1のところのリストを示します。
E379 F5 CONSTJ1:PUSH AF E37A 3E10 LD A,10 E37C D3F4 OUT (F4),A;VFDDLED off E37E ED DB ED;OUT0 [39],A E37F 39 DB 39 E380 39 DB 39 E381 F1 POP AF E382 ED7B76E2 LD SP,(SPWK) E386 C9 RET |
先頭にVFDD(仮想RAMディスク)アクセス表示LEDを消灯する部分がありますが、それが必要なルーチンの続きになっているためで、RS232C受信の処理には直接関係はありません。
ここで必要なのは、内蔵レジスタ[39]に10Hを書き込んでバンクを元に戻すことと、SPを元に戻すことです。
説明の途中ですが本日は時間がなくなってしまいました。
この続きは次回にいたします。
ワンボードマイコンでCP/Mを![第505回]
2013.11.2upload
前へ
次へ
ホームページトップへ戻る