SSブログ
English Version

レトロマイコンZ80ボードの構想(その12)CP/M80 BIOS検討4 [Z80]

 前回の記事「レトロマイコンZ80ボードの構想(その11)CP/M80 BIOS検討3」でBUSACK/信号のチェックは省略可能なことが判り、Z80と接続する信号はほぼ決まったのでPICとZ80とのソフトインターフェースについて動作検証してみました。

 PIC側で使用するI/O数を削減するため、Z80からのサービスコール時のHALTの脱出は NMI(またはINT)ではなく、RESETを使用することにします。

 NMIを使う場合は66HのコードをRETNコードに書き換えてからHALTします。RESETの場合は0000Hから実行が開始するので0000HのコードをJP XXXXに書き換えてもいいのですが、処理簡略化(かつ高速化)のためにJP (HL):0E9H に書き換えます。

 NMI方式と比較し、スタック操作がなく、書き換えが1バイト(NMI方式は2バイト)なので若干ですが処理が簡易かつ高速になります(NMIのための制御出力が不要であることが最大のメリット)。
 ディメリットとしてはRESETにより割込み用FFと割り込みモードがクリアされるという点がありますが、今回のように割込みを使わない場合は問題ありません。

 Z80がPIC側のサービスを受ける際の手順の概要としては次のようになります(下記のサンプルソースでは「PIC_SRV」部分)
  1. ワークエリアにサービスIDとサービス処理に必要なパラメータを設定
  2. 0000Hのコード(多くの場合、0C3H(=JP XXXX)))を保存
  3. HLレジスタにHALTの次のアドレスを設定
  4. 0000Hに0E9H(=JP (HL))を設定
  5. HALT実行
  6. 0000Hを元のコードに戻す
  7. ワークエリアからPICが設定した処理結果を参照

 PIC側の処理手順は次のようになります(下記のサンプルソースでは「 PicSrv()」部分)
  1. Z80がHALT状態になるまで待つ
  2. BUSREQ/をアクティブ(アサート)にしBUSの制御権を得る
  3. サービスIDとパラメータに従い処理し、結果をワークエリアに保存する
  4. RESETをアクティブにする
  5. BUSREQ/をインアクティブ(ディアサート)にする
  6. RESETをインアクティブにする


 動作検証としてCP/MのBIOSにもあるコンソール入出力関連の処理を実験した際の信号サンプルが下のキャプチャです。
 キーセンスの繰り返し処理の部分を1周期分抜き出したものです。

 Z80側はキー入力状態をチェックする短いループ処理であるということもありますが、PIC側の処理時間(BUSREQ/がLOWの期間)がZ80の3倍弱程度(PIC側の7割程度が外部メモリアクセスの処理)になっています。

 Z80は16MHz、PICは32MHzで動作しています。PIC側はPMPを使っているものの内部のメモリに展開しながらの外部メモリアクセスなので時間がかかっていますが、PIC側もアセンブラで書けば外部メモリアクセス部を数倍程度高速化できると思います。

Z80からPICへのサービス要求処理時の信号サンプル


 Z80側のソースは次のとおりです。
 「Start」と表示後、キー入力状態をチェックし、キー入力があった場合には入力データを読込み16進で表示します。

RESETによるBIOS処理実験(Z80:アセンブラ)
; PIC service call test for CP/M BIOS ; Ver 0.01 2018/03/10 by skyriver 000D CR EQU 13 000A LF EQU 10 FF00 PICSRV EQU 0FF00h ; AP area FFF0 PICWRK EQU 0FFF0H ; PIC service work area 0080 SECSIZE EQU 128 ; sector size 0000 FC_SYSLOAD EQU 0 ; EXIT CP/M 0001 FC_CONST EQU 1 ; CONST 0002 FC_CONIN EQU 2 ; CONIN 0003 FC_CONOUT EQU 3 ; CONOUT 0004 FC_READ EQU 4 ; READ SD Card 0005 FC_WRITE EQU 5 ; WRITE SD Card 0006 FC_PIC EQU 6 ; PIC control ; ++++ work area for PIC Interface FFF0 FuncNo equ PICWRK ; ds 1 : function No FFF1 RetVal EQU PICWRK + 1 ; ds 1 : return value FFF2 FCData equ PICWRK + 2 ; ds 1 : conout data FFF3 SelDk equ PICWRK + 3 ; ds 1 FFF4 Track equ PICWRK + 4 ; ds 2 FFF6 DmaAdr equ PICWRK + 6 ; ds 2 FFF8 Sector equ PICWRK + 8 ; ds 1 0000' ASEG ORG 0100H .PHASE PICSRV .Z80 FF00 31 0100 TEST: LD SP,0100h FF03 21 FF27 LD HL,MSG FF06 CD FF1D CALL PRNMSG FF09 CD FF54 LOOP: CALL CONST FF0C B7 OR A FF0D 28 FA JR Z,LOOP FF0F 21 FF31 LD HL,MSGP FF12 CD FF1D CALL PRNMSG FF15 CD FF58 CALL CONIN FF18 CD FF3A CALL PRNHEX FF1B 18 EC JR LOOP FF1D 7E PRNMSG: LD A,(HL) FF1E B7 OR A FF1F C8 RET Z FF20 4F LD C,A FF21 CD FF5C CALL CONOUT FF24 23 INC HL FF25 18 F6 JR PRNMSG FF27 0D 0A 53 74 MSG: DB CR,LF,'Start',CR,LF,0 FF2B 61 72 74 0D FF2F 0A 00 FF31 20 50 75 73 MSGP: DB ' Pushed:',0 FF35 68 65 64 3A FF39 00 FF3A PRNHEX: FF3A 47 LD B,A FF3B CB 3F SRL A FF3D CB 3F SRL A FF3F CB 3F SRL A FF41 CB 3F SRL A FF43 CD FF47 CALL PRNHNIB FF46 78 LD A,B FF47 PRNHNIB: FF47 E6 0F AND 00FH FF49 C6 30 ADD A,'0' FF4B FE 3A CP '9'+1 FF4D 38 02 JR C,PRNHNIB2 FF4F C6 07 ADD A,'A' - '0' - 10 FF51 PRNHNIB2: FF51 4F LD C,A FF52 18 08 JR CONOUT ; ; check console key data ; A -> 0ffh:data exist 00h:none FF54 CONST: FF54 3E 01 LD A,FC_CONST FF56 18 0C JR PIC_SRV ; ; input console ; A -> key data FF58 CONIN: FF58 3E 02 LD A,FC_CONIN FF5A 18 08 JR PIC_SRV ; ; out console ; C <- data FF5C CONOUT: FF5C 79 LD A,C FF5D 32 FFF2 LD (FCData),A FF60 3E 03 LD A,FC_CONOUT FF62 18 00 JR PIC_SRV ; ; PIC Service Function ; A <- service no ; A -> return value FF64 PIC_SRV: FF64 C5 PUSH BC FF65 E5 PUSH HL FF66 32 FFF0 LD (FuncNo),A FF69 3A 0000 LD A,(0000h) FF6C 47 LD B,A FF6D 21 FF76 LD HL,NEXT_HALT FF70 3E E9 LD A,0E9H ; ope-code : JP (HL) FF72 32 0000 LD (0000H),A FF75 76 HALT FF76 NEXT_HALT: FF76 78 LD A,B FF77 32 0000 LD (0000H),A FF7A 3A FFF1 LD A,(RetVal) FF7D E1 POP HL FF7E C1 POP BC FF7F C9 RET END


 PIC側では上記のZ80のアセンブル結果のバイナリファイルを MemWr() での書込み処理に変換するツールを作り、picleソース内に取り込んでいます。
 PIC側でのリスト表示と実行結果を下記に示します。
 末尾にある「pushed」の部分は '1'、'2'、'3'のキー入力をした結果です。

RESETによるBIOS処理実験(PIC側:picle言語)
:l 1:# Test Reset I/F to Z80 by skyriver 2018/03/10 2: 3:use LibCpm; 4: 5:var ProgStart,ProgWrk,_WrkVal; 6: 7: 8:proc InitProg() { 9: ProgStart = $ff00; # Prog start addr 10: ProgWrk = $fff0; # Prog work addr 11: _WrkVal = Array_(ArIdx); 12: ArIdx = ArIdx + 5; 13: 14: PmpOn(); 15: 16: PmpSetAdr( 0 ); 17: MemWr( $c3 ); 18: MemWr( $00 ); 19: MemWr( $ff ); 20: 21: PmpSetAdr( ProgStart ); 22: 23: MemWr( $31 ); MemWr( $00 ); MemWr( $01 ); MemWr( $21 ); MemWr( $27 ); 24: MemWr( $ff ); MemWr( $cd ); MemWr( $1d ); MemWr( $ff ); MemWr( $cd ); 25: MemWr( $54 ); MemWr( $ff ); MemWr( $b7 ); MemWr( $28 ); MemWr( $fa ); 26: MemWr( $21 ); MemWr( $31 ); MemWr( $ff ); MemWr( $cd ); MemWr( $1d ); 27: MemWr( $ff ); MemWr( $cd ); MemWr( $58 ); MemWr( $ff ); MemWr( $cd ); 28: MemWr( $3a ); MemWr( $ff ); MemWr( $18 ); MemWr( $ec ); MemWr( $7e ); 29: MemWr( $b7 ); MemWr( $c8 ); MemWr( $4f ); MemWr( $cd ); MemWr( $5c ); 30: MemWr( $ff ); MemWr( $23 ); MemWr( $18 ); MemWr( $f6 ); MemWr( $0d ); 31: MemWr( $0a ); MemWr( $53 ); MemWr( $74 ); MemWr( $61 ); MemWr( $72 ); 32: MemWr( $74 ); MemWr( $0d ); MemWr( $0a ); MemWr( $00 ); MemWr( $20 ); 33: MemWr( $50 ); MemWr( $75 ); MemWr( $73 ); MemWr( $68 ); MemWr( $65 ); 34: MemWr( $64 ); MemWr( $3a ); MemWr( $00 ); MemWr( $47 ); MemWr( $cb ); 35: MemWr( $3f ); MemWr( $cb ); MemWr( $3f ); MemWr( $cb ); MemWr( $3f ); 36: MemWr( $cb ); MemWr( $3f ); MemWr( $cd ); MemWr( $47 ); MemWr( $ff ); 37: MemWr( $78 ); MemWr( $e6 ); MemWr( $0f ); MemWr( $c6 ); MemWr( $30 ); 38: MemWr( $fe ); MemWr( $3a ); MemWr( $38 ); MemWr( $02 ); MemWr( $c6 ); 39: MemWr( $07 ); MemWr( $4f ); MemWr( $18 ); MemWr( $08 ); MemWr( $3e ); 40: MemWr( $01 ); MemWr( $18 ); MemWr( $0c ); MemWr( $3e ); MemWr( $02 ); 41: MemWr( $18 ); MemWr( $08 ); MemWr( $79 ); MemWr( $32 ); MemWr( $f2 ); 42: MemWr( $ff ); MemWr( $3e ); MemWr( $03 ); MemWr( $18 ); MemWr( $00 ); 43: MemWr( $c5 ); MemWr( $e5 ); MemWr( $32 ); MemWr( $f0 ); MemWr( $ff ); 44: MemWr( $3a ); MemWr( $00 ); MemWr( $00 ); MemWr( $47 ); MemWr( $3e ); 45: MemWr( $e9 ); MemWr( $32 ); MemWr( $00 ); MemWr( $00 ); MemWr( $21 ); 46: MemWr( $76 ); MemWr( $ff ); MemWr( $76 ); MemWr( $78 ); MemWr( $32 ); 47: MemWr( $00 ); MemWr( $00 ); MemWr( $3a ); MemWr( $f1 ); MemWr( $ff ); 48: MemWr( $e1 ); MemWr( $c1 ); MemWr( $c9 ); 49:} 50: 51: 52:proc PicSrv() { 53: var i,fno,rval; 54: 55: while (1) { 56: while ( LATB[-1] & 8 ) {} # wait halt 57: PmpOn(); 58: PmpSetAdr( ProgWrk ); 59: fno = MemRd(); # dummy 60: for ( i=0; i<9; i=i+1 ) { 61: _WrkVal[i] = MemRd(); 62: } 63: fno = _WrkVal[0]; # function No 64: if ( fno = 1 ) { # CONST 65: if ( InpChk_() ) { 66: rval = $ff; 67: } else { 68: rval = 0; 69: } 70: } 71: else if ( fno = 2 ) { # CONIN 72: if ( InpChk_() ) { 73: rval = InpChar_(); 74: if ( rval = $1b ) { # if ESC then end 75: exit(); 76: } 77: } else { 78: PrnChar_('x'); # __ for debug 79: rval = InpChar_(); 80: } 81: } 82: else if ( fno = 3 ) { # CONOUT 83: PrnChar_( _WrkVal[2] ); 84: rval = 0; 85: } else { 86: PrnStr_( "\nFunc err" ); 87: } 88: PmpSetAdr( ProgWrk + 1 ); 89: MemWr( rval ); 90: 91: PmpOff(); 92: LATC[0] = $0000; # reset on 93: BusRelease(); 94: LATC[0] = $0001; # reset off 95: } 96:} 97: 98: 99:proc main() { 100: init(); 101: initPmp(); 102: InitProg(); 103: 104: dump( 0 ); 105: dump( ProgStart ); # dump & PmpOff 106: LATC[0] = $0000; # reset on 107: BusRelease(); 108: LATC[0] = $0001; # reset off 109: 110: PicSrv(); 111:} :run 0000 : C3 00 FF 43 00 43 00 43 00 43 00 43 00 43 00 43 0010 : 00 43 00 43 00 43 00 43 00 43 00 43 00 43 00 43 0020 : 00 43 00 43 00 43 00 43 00 43 00 43 00 43 00 43 0030 : 00 43 00 43 00 43 00 2D B0 00 64 3A 20 43 C6 2E 0040 : DB 43 00 43 00 43 00 43 00 43 00 43 00 43 00 43 0050 : 00 43 00 43 00 43 00 43 00 43 00 43 00 43 00 43 0060 : 00 43 00 43 00 43 00 43 00 43 00 43 00 43 00 43 0070 : 00 43 00 43 00 43 00 43 00 43 00 43 00 43 00 43 FF00 : 31 00 01 21 27 FF CD 1D FF CD 54 FF B7 28 FA 21 FF10 : 31 FF CD 1D FF CD 58 FF CD 3A FF 18 EC 7E B7 C8 FF20 : 4F CD 5C FF 23 18 F6 0D 0A 53 74 61 72 74 0D 0A FF30 : 00 20 50 75 73 68 65 64 3A 00 47 CB 3F CB 3F CB FF40 : 3F CB 3F CD 47 FF 78 E6 0F C6 30 FE 3A 38 02 C6 FF50 : 07 4F 18 08 3E 01 18 0C 3E 02 18 08 79 32 F2 FF FF60 : 3E 03 18 00 C5 E5 32 F0 FF 3A 00 00 47 3E E9 32 FF70 : 00 00 21 76 FF 76 78 32 00 00 3A F1 FF E1 C1 C9 Start Pushed:31 Pushed:32 Pushed:33



[TOP] [ 前へ ] 連載記事 [ 次へ ]
nice!(1)  コメント(0) 
共通テーマ:趣味・カルチャー