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

復活!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

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