デジット閉店セールで売られていたジャンク基板「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