SSブログ
English Version

レトロマイコンZ80ボードの構想(その17)HALT以外の方法 [Z80]

 「レトロマイコンZ80ボードの構想(その12)CP/M80 BIOS検討4」の記事に書いたようにPICとZ80のインターフェースとしてHALTを使用しています。
 HALT脱出のためにRESETを使っていますがこの場合、割込み用FFと割り込みモードがクリアされるのでZ80側で割込み処理を使いたい場合には今回のHALT+RESET方式は使えません。

 簡単な回路でZ80側で割込みも使用できる方法を思いついたので実験してみました。

 PICとZ80のインターフェースにIORQ/とWAIT/を使う方法です。まずはZ80のIO Input/Outputサイクルのタイミングが下図です。


Z80 Input or Output Cycles


 TWの立下りでWAIT/がサンプリングされます。
 そこで、IORQ/を抵抗を介してWAIT/に接続し、PIC側ではWAIT/の状態を監視します(下図の接続、RA1は1例であり他のポートでも可)。
 PIC側はWAIT/がlowになったら、BUSREQ/をアクティブにしてからWAIT/を監視していたポートを出力に切替でhighを出力しZ80のWAIT状態を解除します。
 Z80側はWAIT/が解除されるのでT3サイクルの立上りでBUSREQ/を検出してBUSACK/をアクティブにしてバスを開放します。



 Z80側は単純にI/O命令(InputでもOutputでも可、Outputの場合はデータバスにPIC側に渡したい情報を載せることも可能)を実行するだけです。
 処理手順は次のようになります(下記のサンプルソースでは「PIC_SRV」部分)
  1. ワークエリアにサービスIDとサービス処理に必要なパラメータを設定
  2. I/O命令を実行
  3. PICがワークエリアに設定した処理結果を参照


 PIC側の処理手順は次のようになります(下記のサンプルソースでは「 PicSrv()」部分)
  1. WAIT/がアクティブになるまで待つ(入力ポートでWAIT/信号を監視)
  2. BUSREQ/をアクティブにする
  3. 上記のWAIT/監視ポートを出力に切替えhighを出力後、ポートを入力状態に戻す
  4. サービスIDとパラメータに従い処理し、結果をワークエリアに保存する
  5. BUSREQ/をインアクティブにする


 「レトロマイコンZ80ボードの構想(その12)CP/M80 BIOS検討4」の記事に書いたHALT+RESETを使った場合に比べてZ80/PIC双方の処理が簡単になります。(但し、WAIT/制御用のポートが余分に必要になるので今回はHALT/RESET方式を採用しています)

 上記の記事と同様にCP/MのBIOSでのコンソール入出力関連の機能で実験してみました。
 Z80のキーセンス処理のループ部分を抜き取ったロジアナ画面も貼っておきます。


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


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

PIC-Z80間I/FにWAITを使用した実験(Z80:アセンブラ)
; PicSrvWa.mac : PIC service call test using IOREQ and WAIT for CP/M BIOS ; Ver 0.01 2018/04/7 by skyriver 000D CR EQU 13 000A LF EQU 10 FF00 PICSRV EQU 0FF00H ; DMA for PIC FFF0 PICWRK EQU 0FFF0H ; PIC service work area 0080 SECSIZE EQU 128 ; sector size 0000 FC_EXIT 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 FF50 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 FF54 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 FF58 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 1F RRA FF3C 1F RRA FF3D 1F RRA FF3E 1F RRA FF3F CD FF43 CALL PRNHNIB FF42 78 LD A,B FF43 PRNHNIB: FF43 E6 0F AND 00FH FF45 C6 30 ADD A,'0' FF47 FE 3A CP '9'+1 FF49 38 02 JR C,PRNHNIB2 FF4B C6 07 ADD A,'A' - '0' - 10 FF4D PRNHNIB2: FF4D 4F LD C,A FF4E 18 08 JR CONOUT ; ; check console key data ; A -> 0ffh:data exist 00h:none FF50 CONST: FF50 3E 01 LD A,FC_CONST FF52 18 0C JR PIC_SRV ; ; input console ; A -> key data FF54 CONIN: FF54 3E 02 LD A,FC_CONIN FF56 18 08 JR PIC_SRV ; ; out console ; C <- data FF58 CONOUT: FF58 79 LD A,C FF59 32 FFF2 LD (FCData),A FF5C 3E 03 LD A,FC_CONOUT FF5E 18 00 JR PIC_SRV ; ; PIC Service Function ; A <- service no ; A -> return value FF60 PIC_SRV: FF60 32 FFF0 LD (FuncNo),A FF63 D3 55 OUT (55H),A ; wait with IORQ and release by PIC FF65 3A FFF1 LD A,(RetVal) FF68 C9 RET END


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

PIC-Z80間I/FにWAITを使用した実験(PIC側:picle言語)
:l 1:# Test IORQ & WAIT I/F to Z80 by skyriver 2018/04/07 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 = Alloc( 5 ); 12: 13: PmpOn(); 14: 15: PmpSetAdr( 0 ); 16: MemWr( $c3 ); 17: MemWr( $00 ); 18: MemWr( $ff ); 19: 20: PmpSetAdr( ProgStart ); 21: 22: MemWr( $31 ); MemWr( $00 ); MemWr( $01 ); MemWr( $21 ); MemWr( $27 ); 23: MemWr( $ff ); MemWr( $cd ); MemWr( $1d ); MemWr( $ff ); MemWr( $cd ); 24: MemWr( $50 ); MemWr( $ff ); MemWr( $b7 ); MemWr( $28 ); MemWr( $fa ); 25: MemWr( $21 ); MemWr( $31 ); MemWr( $ff ); MemWr( $cd ); MemWr( $1d ); 26: MemWr( $ff ); MemWr( $cd ); MemWr( $54 ); MemWr( $ff ); MemWr( $cd ); 27: MemWr( $3a ); MemWr( $ff ); MemWr( $18 ); MemWr( $ec ); MemWr( $7e ); 28: MemWr( $b7 ); MemWr( $c8 ); MemWr( $4f ); MemWr( $cd ); MemWr( $58 ); 29: MemWr( $ff ); MemWr( $23 ); MemWr( $18 ); MemWr( $f6 ); MemWr( $0d ); 30: MemWr( $0a ); MemWr( $53 ); MemWr( $74 ); MemWr( $61 ); MemWr( $72 ); 31: MemWr( $74 ); MemWr( $0d ); MemWr( $0a ); MemWr( $00 ); MemWr( $20 ); 32: MemWr( $50 ); MemWr( $75 ); MemWr( $73 ); MemWr( $68 ); MemWr( $65 ); 33: MemWr( $64 ); MemWr( $3a ); MemWr( $00 ); MemWr( $47 ); MemWr( $1f ); 34: MemWr( $1f ); MemWr( $1f ); MemWr( $1f ); MemWr( $cd ); MemWr( $43 ); 35: MemWr( $ff ); MemWr( $78 ); MemWr( $e6 ); MemWr( $0f ); MemWr( $c6 ); 36: MemWr( $30 ); MemWr( $fe ); MemWr( $3a ); MemWr( $38 ); MemWr( $02 ); 37: MemWr( $c6 ); MemWr( $07 ); MemWr( $4f ); MemWr( $18 ); MemWr( $08 ); 38: MemWr( $3e ); MemWr( $01 ); MemWr( $18 ); MemWr( $0c ); MemWr( $3e ); 39: MemWr( $02 ); MemWr( $18 ); MemWr( $08 ); MemWr( $79 ); MemWr( $32 ); 40: MemWr( $f2 ); MemWr( $ff ); MemWr( $3e ); MemWr( $03 ); MemWr( $18 ); 41: MemWr( $00 ); MemWr( $32 ); MemWr( $f0 ); MemWr( $ff ); MemWr( $d3 ); 42: MemWr( $55 ); MemWr( $3a ); MemWr( $f1 ); MemWr( $ff ); MemWr( $c9 ); 43: 44:} 45: 46: 47:proc PicSrv() { 48: var i,fno,rval; 49: 50: while (1) { 51: while ( LATA[-1] & 2 ) {} # wait IORQ 52: PmpOn(); # BUSREQ 53: LATA[-2] = LATA[-2] & $fffd; # set port output to set wait to high 54: LATA[-2] = LATA[-2] | 2; # set port input 55: 56: PmpSetAdr( ProgWrk ); 57: 58: fno = MemRd(); # dummy 59: for ( i=0; i<9; i=i+1 ) { 60: _WrkVal[i] = MemRd(); 61: } 62: fno = _WrkVal[0]; # function No 63: if ( fno = 1 ) { # CONST 64: if ( InpChk_() ) { 65: rval = $ff; 66: } else { 67: rval = 0; 68: } 69: } 70: else if ( fno = 2 ) { # CONIN 71: rval = InpChar_(); 72: } 73: else if ( fno = 3 ) { # CONOUT 74: PrnChar_( _WrkVal[2] ); 75: rval = 0; 76: } else { 77: PrnStr_( "\nFunc err" ); 78: } 79: PmpSetAdr( ProgWrk + 1 ); 80: MemWr( rval ); 81: PmpOff(); 82: BusRelease(); 83: } 84:} 85: 86: 87:proc main() { 88: init(); 89: initPmp(); 90: InitProg(); 91: 92: LATA[0] = LATA[0] | 2; # set WAIT release 93: 94: dump( 0 ); 95: dump( ProgStart ); # dump & PmpOff 96: LATC[0] = $0000; # reset on 97: BusRelease(); 98: LATC[0] = $0001; # reset off 99: 100: PicSrv(); 101:} :run 0000 : C3 00 FF 00 00 C3 06 EC FE 43 FE 43 FE 43 FE 43 0010 : FE 43 FE 43 FE 43 FE 43 FE 43 FE 43 FE 43 FE 43 0020 : FE 43 FE 43 FE 43 FE 43 FE 43 FE 43 FE 43 FE 43 0030 : FE 43 FE 43 FE 43 FE 43 FE 43 FE 43 FE 43 FE 43 0040 : FE 43 FE 43 FE 43 FE 43 FE 43 FE 43 FE 43 FE 43 0050 : FE 43 FE 43 FE 43 FE 43 FE 43 FE 43 00 20 20 20 0060 : 20 20 20 20 20 20 20 20 00 00 00 01 00 20 20 20 0070 : 20 20 20 20 20 20 20 20 00 00 00 00 00 FB EE FA FF00 : 31 00 01 21 27 FF CD 1D FF CD 50 FF B7 28 FA 21 FF10 : 31 FF CD 1D FF CD 54 FF CD 3A FF 18 EC 7E B7 C8 FF20 : 4F CD 58 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 1F 1F 1F 1F CD FF40 : 43 FF 78 E6 0F C6 30 FE 3A 38 02 C6 07 4F 18 08 FF50 : 3E 01 18 0C 3E 02 18 08 79 32 F2 FF 3E 03 18 00 FF60 : 32 F0 FF D3 55 3A F1 FF C9 E5 E5 E5 E5 E5 E5 E5 FF70 : 00 00 0A 00 54 00 80 00 00 E5 E5 E5 E5 E5 E5 E5 Start Pushed:31 Pushed:32 Pushed:33



[TOP] [ 前へ ] 連載記事 [ 次へ ]

nice!(0)  コメント(3) 
共通テーマ:趣味・カルチャー

nice! 0

コメント 3

neko Java

外部割り込みしないならこれでいいかも。

私のはINTを気にしててRD/WRを取り込んだんですけどね。(M1ではじいてもよかったかも)
INTの応答でIOREQがLOWになるので。

PICのRA1を出力にするとIOREQも出力だからちょっと気持ち悪いんだけどプルアップと考えれば問題ないのかも。
1kだと3.3mA。
by neko Java (2018-04-09 00:16) 

skyriver

 コメントありがとうございます。
 上記記事のWAIT方式では外部割込みの時もIORQがLOWになるのでZ80がWAIT状態になってしまいますが、PIC側でWAIT監視しているのでWAIT解除すれば問題ないはずです。
 サービス処理後サービスIDをクリアするようにすれば割込みの判別はできます。

 また、抵抗値ですが、最初10Kで試してNGで2.2Kまで下げてもNG、1Kで動作OKでした。PIC側でポートをプルアップしていたのかもと思い確認しましたがPIC側でPullUp設定はしていませんでした。確かに電流値は気になりますが実機確認の結果です。

by skyriver (2018-04-09 01:24) 

neko Java

PICのポートが出力になったとき、IOREQがLOWのとき3.3mmAの吸い込みでたぶん問題ない。

(実際にそのような状態があるかどうか分からないが一瞬でも)IOREQがHIGHのときPICの出力に電源以上の+5Vが掛かるのでそれがどうなのか良くわからないですね。

PICのポートが入力のとき+5V(IOREQ HIGH)が掛かるのも問題ないんですかね(PICは良く知らない)

出力同士を繋ぐとわけが分からなくなるので私はやらないですw

ところで、スペシャルリセットは驚きました。これはそのうち試してみたいですね。
by neko Java (2018-04-09 03:03) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。