石原 博の覚書

電子工作に関する日々の覚書を記載します

KBC-Z11でソフトウエアUARTを使用してBASICを動かした

2021-12-27 21:08:20 | 日記

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

 


KBC-Z84015EM ForthでLチカ

2021-12-05 17:51:27 | 日記

デジット閉店セールで売られていたジャンク基板「KBC-Z84015EM」でForthを動かした。

該当の基板では前半32KBはROM,後半32KBはRAMとなっているが、fig-forthやf79, f83はRAM上で動くことを想定している。ForthをROM化する能力も時間もないので、起動時にROM中に保存したForthシステムをRAMにコピーする方式とした。I/Oについては電脳伝説さんのサイト「https://vintagechips.wordpress.com/2021/06/08/kbc-z84015s/」を参考にSIOを利用。DISK I/Oはエラーとなるようにしている。

最初はF83と思ったが、08000H開始でメタコンパイルする方法がわからない。そこで移植したのはfig-forth(ASMだけでアセンブル出来るから楽)。 サイト(https://www.complang.tuwien.ac.at/forth/ftp.dei.isep.ipp.pt/pub/forth/cpm/forth130.asm)からFig-forth1.3のソースをダウンロード。(このForthどうもAppleII用のZ80カードを対象としていたものか、APPLE EQU TRUEなどとの記載がある) TITLEとかPAGE等の疑似命令がエラーになるので修正し ORG 100H -> ORG 08100H, EM EQU 0A000H -> EM EQU 0C000H としてアセンブルしてHexファイルを作る。

I/O部分についてはSTARTUP.ASMとして以下のように作成。プログラムは100H〜で、8000Hをワークとしている。 ロジックは電脳伝説さんのサイトのBASICのI/O部分を使用させていただいた。PIOの初期化も組み込んでいる。なおニーモニックはインテルのものに変更しているが、これは私がその方がわかりやすかったためで他意はない。ForthはROM上400H〜に保存しておき、起動時に8100Hにコピーして制御を移すようにしている。



;	TARGET: KBC-Z84015S
;
TSTACK	EQU	0H
;
;PCTCC0	EQU	10H
;PCTCC1	EQU	11H
PCTCC2	EQU	12H
;PCTCC3	EQU	13H
PSIOAD	EQU	18H
PSIOAC	EQU	19H
PSIOBD	EQU	1AH
PSIOBC	EQU	1BH
;PPIOAD	EQU	1CH
;PPIOAC	EQU	1DH
PPIOBD	EQU	1EH
PPIOBC	EQU	1FH
;
CR	EQU	0DH
LF	EQU	0AH
;
ROMST	EQU	400H		; ROM CONTENTS START
ROMSIZE	EQU	2000H		; ROM SIZE
RAMST	EQU	8000H		; RAM START
FORTHST EQU	8100H
;
;	SYSTEM PARAMETERS
	ORG	RAMST
RBFCNT	DS	01H
RBFRDP	DS	01H
RBFWTP	DS	01H
RECBUF	DS	40H
;
;
;	RESET VECTOR
	ORG	0000H
RST00:	;DI
	JMP	BIOS		;PSEUDO BIOS
;
;	RESTART VECTOR
	ORG	0008H
RST08:	JMP	TXA
	ORG	0010H
RST10:	JMP	RXA
	ORG	0018H
RST18:	JMP	KBHIT
;
	ORG	0100H
BIOS:
	JMP	SINIT		;0
	JMP	CONST		;3
	JMP	CONIN		;6
	JMP	CONOUT		;9
	JMP	LIST		;12
	JMP	ERROR		;15
	JMP	ERROR		;18
	JMP	ERROR		;21
	JMP	ERROR		;24
	JMP	ERROR		;27
	JMP	ERROR		;30
	JMP	ERROR		;33
	JMP	ERROR		;36
	JMP	ERROR		;39
;
CONST:	CALL	KBHIT		;A=COUNT
	RZ
	MVI	A,0FFH
	RET
;
CONIN:	CALL	RXA		;RETURN CHARACTER IN A
	ANI	07FH
	RET
;
CONOUT:	MOV	A,C		;WRITE CHARACTER IN C
	ANI	07FH
	JMP	TXA
;
LIST:	RET			;NOT SUPPORTED
;
ERROR:	LXI	H,ERRMSG
ERROR1:	MOV	A,M
	INX	H
	ANA	A
	JZ	BIOS
	CALL	TXA
	JMP	ERROR1
;
ERRMSG:	DB	'ILLEGAL ',CR,LF,0
;
;	SIOA -> BUFFER BY INTERRUPT
INTRCV:
	PUSH	PSW
	PUSH	B
	PUSH	D
	PUSH	H
	IN	PSIOAC		;CHECK RECEIVE
	ANI	1		;IF NOT
	JZ	RWTEXT		;EXIT
	IN	PSIOAD		;GET DATA
	MOV	D,A		;SAVE TO D
	LDA	RBFCNT		;GET COUNT
	CPI	40H		;IF BUFFER FULL
	JZ	RWTEXT		;EXIT(GIVE UP)
STRWT3:	INR	A		;COUNT UP
	STA	RBFCNT		;COUNT UPDATE
	LDA	RBFWTP		;GET OFFSET
	MOV	C,A		;C, OFFSET LOW
	MVI	B,00H		;B, OFFSET HIGH
	LXI	H,RECBUF	;HL, BUFFER TOP
	DAD	B		;HL, WRITE POINT IN BUFFER
	MOV	M,D		;WRITE DATA
	INR	A		;OFFSET INCREMENT
	ANI	3FH		;WRAP
	STA	RBFWTP		;OFFSET UPDATE
RWTEXT:	POP	H
	POP	D
	POP	B
	POP	PSW
	EI
	DB	0EDH,4DH	;RETI
;
;	BUFER -> A
RXA:
	PUSH	B
	PUSH	D
	PUSH	H
LOPRBR:
	LDA	RBFCNT		;GET COUNT
	ANA	A		;CHECK RECEIVE
	JZ	LOPRBR		;WAIT FOR RECEIVE
	DI			;DISABLE INTERRUPT
	DCR	A		;COUNT DOWN
	STA	RBFCNT		;COUNT UPDATE
	LDA	RBFRDP		;GET OFFSET
	MOV	C,A		;C, OFFSET LOW
	MVI	B,00H		;B, OFFSET HIGH
	LXI	H,RECBUF	;HL, BUFFER TOP
	DAD	B		;HL, READ POINT IN BUFFER
	MOV	D,M		;READ DATA
	INR	A		;OFFSET INCREMENT
	ANI	3FH		;WRAP
	STA	RBFRDP		;OFFSET UPDATE
	MOV	A,D		;GET DATA
	EI			;ENABLE INTERRUPT
	POP	H
	POP	D
	POP	B
	RET
;
;	A -> SIO
TXA:	PUSH	PSW		;SAVE DATA
TXLOOP:	IN	PSIOAC		;CHECK STATUS
	ANI	4		;IF BUFFER NOT EMPTY
	JZ	TXLOOP		;WAIT FOR EMPTY
	POP	PSW		;RESTORE DATA
	OUT	PSIOAD		;TRANSFER
	RET
;
;	CHECK RECEIVE STATUS
KBHIT:	LDA	RBFCNT
	ANA	A
	RET
;
;	INTERRUPT VECTORS
	ORG (($-1) AND 0FFF0H) + 10H
INTVCT:	DW	INTRCV
;
;	SIOA COMMAND CHAIN
SIOACD:
	DB	00011000B	;RESET
	DB	01H,00010000B	;RX INTERRUPT ENABLE
	DB	04H,01000100B	;FORMAT
	DB	05H,11101010B	;TX ENABLE
	DB	03H,11000001B	;RX ENABLE
SIOACL	EQU	$-SIOACD
;
;	SIOB COMMAND CHAIN
SIOBCD:
	DB	00011000B		;RESET
	DB	01H,00000000B		;DISABLE STATUS/AFFECTS VECTOR
	DB	02H,INTVCT AND 00FFH	;SET INTERRUPT VECTOR
SIOBCL	EQU	$-SIOBCD
;
;	PIOB COMMAND CHAIN
PIOBCD:
	DB	0CFH			;MODE3
	DB	9FH			;PB5,PB6 OUT
	DB	07H			;INTERRUPT DISABLE
PIOBCL	EQU	$-PIOBCD
;
;	SYSTEM INITIALIZE
SINIT:	LXI	SP,TSTACK
	XRA	A
	STA	RBFCNT
	STA	RBFRDP
	STA	RBFWTP
;
;	CTC INITIALIZE
	MVI	A,01010111B
	OUT	PCTCC2
	MVI	A,20		;9600bps@6.144MHz
	OUT	PCTCC2
;
;	SIO INITIALIZE
	MVI	B,SIOACL	;LENGTH
	LXI	H,SIOACD	;COMMAND ADDRESS
SIOA:	MOV	A,M
	INX	H
	OUT	PSIOAC		;I/O ADDRESS
	DCR	B
	JNZ	SIOA	
	MVI	B,SIOBCL	;LENGTH
	LXI	H,SIOBCD	;COMMAND ADDRESS
SIOB:	MOV	A,M
	INX	H
	OUT	PSIOBC		;I/O ADDRESS
	DCR	B
	JNZ	SIOB
;
;	PIO INITIALIZE
	MVI	B,PIOBCL	;LENGTH
	LXI	H,PIOBCD	;COMMAND ADDRESS
PIOB:	MOV	A,M
	INX	H
	OUT	PPIOBC		;I/O ADDRESS
	DCR	B
	JNZ	PIOB
;
;	SETUP INTERRUPT
	LXI	H,INTVCT
	MOV	A,H
	DB	0EDH,47H	;LD	I,A
	DB	0EDH,5EH	;IM	2
	EI
;
;	COPY ROMPG TO RAM
	LXI	H,ROMST
	LXI	D,FORTHST
	LXI	B,ROMSIZE
COPY1:	MOV	A,M
	INX	H
	STAX	D
	INX	D
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	COPY1
	JMP	FORTHST

ASMでアセンブルし、SETUP.HEXとFORTH130.HEXの両者をTL866AでROMに書き込み実行。使用したROMはW27C512(64KB)のため有効なのは8000〜FFFF。そのため書き込みは工夫が必要。

SETUP.HEX は

From File Start Addr 0 
TO Buffer Start Addr 8000 
Clear Buffer when loading the file->Clear Buffer with defalult 
FORTH130.HEXは

From File Start Addr 8100 
TO Buffer Start Addr 8400 
Clear Buffer when loading the file->Disable 

としてTL866Aのバッファー領域に両方のHexファイルを読み込んだあと焼き込む。

注意点

[1]ジャンパの設定
この基板はRAMは32KBのHM62256が使用されているが、ジャンパの設定で8KB(8000H〜9FFFH)のみが有効。Fig-Forthはちょうど8KBに収まるのだが、SETUP.ASMで入力用のバッファを使うためほんの少し8KBを超える。そこでジャンパJ2を変更して32KBを有効にした。最初これを忘れて動かず悩んだ。

[2]CONIN, CONOUTではパリティのクリアが必要
最初bit7を気にしていなかったが、Fig-ForthでVLISTするとワードの最後の文字が化けた。(Fig-Forthではワード名の最後のbit7が1になっている) CP/Mマニュアルでは、CONIN 「parity bit is set to zero」 CONOUT「high-order parity bit set to zero」となっており、SETUP.ASM内でbit7を0とするようにした。

これにより以下のLチカが動くことが確認出来た。

===================

HEX OK 
: LED_ON 0 1E P! ; OK 
: LED_OFF FF 1E P! ; OK 
: WAIT 1000 0 DO LOOP ; OK 
: TEST 0 DO LED_ON WAIT LED_OFF WAIT LOOP ; OK 
10 TEST OK