KBC-Z11でソフトウエアUARTを使用してBASICを動かした
デジット閉店セールで売られていたジャンク基板には、「KBC-Z84015EM」と「KBC-Z11」があった。前者については電脳伝説さんのサイト「https://vintagechips.wordpress.com/2021/06/08/kbc-z84015s/」で解説されておりBASICが動く。
ところが後者については、CPUがTMPZ84C011のためSIOが内蔵されておらず、シリアルによる入出力が簡単には出来ない。そこでソフトウエアによるシリアル入出力を行ない、BASICを動かしてみた。
KBC-Z84015EMに使用されているCPUであるTMPZ84C015はSIO,PIO,CTCを内蔵しているが、KBC-Z11に使われているTMPZ84C011は単純なパラレルの入出力(割り込みなし)とCTCだけである。このため工夫が必要となる。
シリアルの速度については9600baudとした。txdについては比較的単純で、startbit、bit0からbit7まで、stopbitの順で 1/9600 = 104uS ソフトウエアで遅延させながら出力されば良い。
問題なのはrxd。8bitマイクロコンピュータが全盛のころは、キーボードスキャンをCPUでデコードしているものも多かった。これはCPUに比較して非常に遅い人間がキーボードを押している時間内に、CPU主体で都合の良いときに読みに行く(ポーリング)というものである。ところがシリアルの入力については、たとえ五月雨式のキー入力であろうが、CPUの都合とは関係なく9600buadで突然送らられてくるわけでポーリングするわけには行かない。そこでCTCのカウンタモードを利用した割り込みでスタートビットをチェックし、その後はソフトウエアの遅延により約100uSec毎に読み取る仕組みとした。
rxd----+-----para bit1(CN2 pin 34PA1)
+-----CTC (CN2 pin5 CLK/TRG0 )
===出力部プログラム(waitループのカウントについて試行錯誤で決めている)===
出力中は割り込みを停止している(ソフトウエアでwaitしているので割り込みはさせられない)ので、半二重といえる。
OUTCH: DI
PUSH AF
IN A,(PPAD)
AND 0FEH ;START BIT
OUT (PPAD),A
CALL WAIT0
POP AF
PUSH DE
PUSH BC
LD B,8
OUTCH1: LD C,A
AND 1 ;BIT0
LD D,A
IN A,(PPAD)
AND 0FEH
OR D
OUT (PPAD),A
CALL WAIT0
LD A,C
RRCA
DEC B
JP NZ,OUTCH1
IN A,(PPAD)
OR 1
OUT (PPAD),A
CALL WAIT0
POP BC
POP DE
EI
RET
WAIT0: PUSH BC
LD B,37
WAIT1: DEC B
JP NZ,WAIT1
POP BC
RET
出力波形(「H」055Hを出力した例)
===入力部プログラム===
本来ならストップビットまで確認し、フレーミングエラーをチェックすべきだが、もともとのSIOバージョンでもエラーチェックなしだし手を抜いた。
; 9600BAUD
INCH: CALL WAITS ;SKIP START BIT(HALF)
PUSH BC
LD BC,0800H ;B=8,C=0
INCH1: CALL WAIT0
IN A,(PPAD)
AND 2
RRCA
OR C
DEC B
JP Z,INCH2
RRCA
LD C,A
JP INCH1
INCH2: RRCA ;B6,B5,B4,B3,B2,B1,B0,B7->B7..B0
POP BC
RET
;
WAITS: PUSH BC
LD B,13
WAITS1: DEC B
JP NZ,WAITS1
POP BC
RET
入力波形
最終的に電脳伝説さんのサイトにあるソースを以下のように変更し、動作させることが出来た。
(アセンブラはARCPIT XZ80.EXEとあったが見つからないため、CP/M上でSLR Z80を使用した)
=======================================
; MS-BASIC START UP ROUTINE
; TARGET: KBC-Z11
; ASSEMBLER: SLR Z80
;
TSTACK: EQU 80EDH
;
PCTCC0: EQU 10H
PPAC: EQU 54H
PPAD: EQU 50H
;
; SYSTEM PARAMETERS
ORG 08000H
RBFCNT: DS 01H
RBFRDP: DS 01H
RBFWTP: DS 01H
RECBUF: DS 40H
;
;
; RESET VECTOR
ORG 0000H
RST00: DI
JP SINIT
;
; RESTART VECTOR
ORG 0008H
RST08: JP TXA
ORG 0010H
RST10: JP RXA
ORG 0018H
RST18: JP KBHIT
;
; PORTA BIT1 -> BUFFER BY INTERRUPT
INTRCV:
PUSH AF
PUSH BC
PUSH DE
PUSH HL
CALL INCH
LD D,A ;SAVE TO D
LD A,(RBFCNT) ;GET COUNT
CP 40H ;IF BUFFER FULL
JR Z,RWTEXT ;EXIT(GIVE UP!)
STRWT3: INC A ;COUNT UP
LD (RBFCNT),A ;COUNT UPDATE
LD A,(RBFWTP) ;GET OFFSET
LD C,A ;C, OFFSET LOW
LD B,00H ;B, OFFSET HIGH
LD HL,RECBUF ;HL, BUFFER TOP
ADD HL,BC ;HL, WRITE POINT IN BUFFER
LD (HL),D ;WRITE DATA
INC A ;OFFSET INCREMENT
AND 3FH ;WRAP
LD (RBFWTP),A ;OFFSET UPDATE
RWTEXT: POP HL
POP DE
POP BC
POP AF
EI
RETI
;
; BUFER -> A
RXA:
PUSH BC
PUSH DE
PUSH HL
LOPRBR:
LD A,(RBFCNT) ;GET COUNT
AND A ;CHECK RECEIVE
JR Z,LOPRBR ;WAIT FOR RECEIVE
DI ;DISABLE INTERRUPT
DEC A ;COUNT DOWN
LD (RBFCNT),A ;COUNT UPDATE
LD A,(RBFRDP) ;GET OFFSET
LD C,A ;C, OFFSET LOW
LD B,00H ;B, OFFSET HIGH
LD HL,RECBUF ;HL, BUFFER TOP
ADD HL,BC ;HL, READ POINT IN BUFFER
LD D,(HL) ;READ DATA
INC A ;OFFSET INCREMENT
AND 3FH ;WRAP
LD (RBFRDP),A ;OFFSET UPDATE
LD A,D ;GET DATA
POP HL
POP DE
POP BC
EI ;ENABLE INTERRUPT
RET
;
; OUTCH
TXA: JP OUTCH
;
; CHECK RECEIVE STATUS
KBHIT: LD A,(RBFCNT)
AND A
RET
;
; INTERRUPT VECTORS
ORG (($-1) & 0FFF0H) + 10H
INTVCT: DW INTRCV
;
; 9600BAUD
OUTCH: DI
PUSH AF
IN A,(PPAD)
AND 0FEH ;START BIT
OUT (PPAD),A
CALL WAIT0
POP AF
PUSH DE
PUSH BC
LD B,8
OUTCH1: LD C,A
AND 1 ;BIT0
LD D,A
IN A,(PPAD)
AND 0FEH
OR D
OUT (PPAD),A
CALL WAIT0
LD A,C
RRCA
DEC B
JP NZ,OUTCH1
IN A,(PPAD)
OR 1
OUT (PPAD),A
CALL WAIT0
POP BC
POP DE
EI
RET
;
; 9600BAUD
INCH: CALL WAITS ;SKIP START BIT(HALF)
PUSH BC
LD BC,0800H ;B=8,C=0
INCH1: CALL WAIT0
IN A,(PPAD)
AND 2
RRCA
OR C
DEC B
JP Z,INCH2
RRCA
LD C,A
JP INCH1
INCH2: RRCA ;B6,B5,B4,B3,B2,B1,B0,B7->B7..B0
POP BC
RET
;
WAIT0: PUSH BC
LD B,37
WAIT1: DEC B
JP NZ,WAIT1
POP BC
RET
;
WAITS: PUSH BC
LD B,13
WAITS1: DEC B
JP NZ,WAITS1
POP BC
RET
;
; SYSTEM INITIALIZE
SINIT: LD SP,TSTACK
XOR A
LD (RBFCNT),A
LD (RBFRDP),A
LD (RBFWTP),A
;
; CTC INITIALIZE
LD A,11000111B ;COUNTER MODE
OUT (PCTCC0),A
LD A,1 ;COUNT=1
OUT (PCTCC0),A
LD A,INTVCT & 0FFH
OUT (PCTCC0),A
;
; Z84C011 PORT I/O INITIALIZE
LD A,00000001B
OUT (PPAC),A ;PORT1=IN PORT0=OUT
IN A,(PPAD)
OR 1
OUT (PPAD),A
;
; SETUP INTERRUPT
LD A,(INTVCT SHR 8) AND 0FFH
LD I,A
IM 2
EI
;
; START BASIC
JP COLD
;
以降BASIC部分は変更なし。
基板上のLEDはPE5とPE6に接続されている。
===Lチカ例=======
10 OUT &H44,&H60
20 FOR I=0 TO 10
30 OUT &H40,0
40 FOR J=0 TO 100
50 NEXT J
60 OUT &H40,&H60
70 FOR J=0 TO 100
80 NEXT J
90 NEXT I
※コメント投稿者のブログIDはブログ作成者のみに通知されます