TMPZ84C015を使用したAKI-80ボードに以前作成したZ8S180用モニタを移植してみました。
移植したZ8S180用モニタは、メモリの読み書きとI/Oの読み書き、HEXファイルのダウンロードができる基本的なモニタです。
Z8S180との違いは、シリアル通信のI/Oと、OUT,IN命令の違いがあります。したがって、シリアル通信の初期化と1文字読み出し、書き出しのプログラムの変更が必要になります。またI/Oの読み書きのアセンブラの命令文が異なりますのでここも修正します。
まずは用意するもの。
AKI-80ボード(秋月電子から購入)
ROMはパラレルEEPROMのAT28C64B15PU(Digikeyにて購入)
パラレルEEPROMを書き込みするために 書き込み器TL866ⅡPLUS(amazonにて購入)を使用
USB-シリアルアダプター(AE-UM232R)(秋月電子)
水晶発振子 20MHz(システムクロック用)
水晶発振器(クリスタルオシレータSG-8002DC(5V) 4.9152MHz(秋月電子)
分周用IC 74HC4040
他、ユニバーサル基板、コネクタ、5V電源アダプタなど
回路図
AKI-80のCN1から電源及びリセットボタン、確認用にHALT端子にLEDを接続しました。
CN2はシリアル関係の端子になっています。今回はBチャンネルを使用します。
シリアル用のクロックは専用にハードで作成しています。
USB-シリアルアダプター(AE-UM232R)のJ1は2-3間をジャンパーでショートしVCCから供給に設定、J2はジャンパーオープンで外部からVCC供給に設定しています。
原発振は4.9152MHzで74HC4040にて32分周して、0.1536MHzを作成しています。この信号をクロック源として、 TMPZ84C015内部で16分周して0.0096MHz(9600bps)を設定します。余談ですが、分周値を変えることで19200bps、38400bpsでも通信できることを確認しています。
また、DCD端子、CTS端子は、GNDに接続しています。(常にアクティブ)
なぜか、 TMPZ84C015内部で分周なしに設定すると、受信データの文字化けが発生してしまいます^^; この個体だけなのか?原因不明です。
モニタソフトの移植
シリアルI/Oのイニシャライズ
TMPZ84C015のシリアルレジスタは、 A/Bチャンネルごとにコントロールレジスタとデータレジスタがあります。各レジスタの同じアドレスにレジスタ番号、データの2対の組み合わせで読み書きを行います。コントロールレジスタの書き込みはレジスター番号0~5、読み込みは0~3の指定を行います。
com_init:
ld b,12
ld hl,SIO_init_data
com_init01:
ld a,(HL)
out (SIOBC),a
inc hl
djnz com_init01
ret
;
SIO_init_data:
.db 0x00,0b00110000 ;WR0=WR0:set ,WR0: reset
.db 0x01,0b00000000 ;WR0=WR1:set ,WR1: all init reset
.db 0x02,0b00000000 ;WR0=WR2:set ,WR2: init set
.db 0x03,0b11000001 ;WR0=WR3:set ,WR3: RxBit=8bit Rx=ready
.db 0x04,0b01000100 ;WR0=WR4:set ,WR4: clock=1/16 stop=1bit parity=non
.db 0x05,0b11101010 ;WR0=WR5:set ,WR5: char=8bit DTR/RTS=EN Tx=ready
シリアルからの一文字読み書きは次のようになります。
SIOBの呼び出し(RR0:通信ステータス)を行うことで受信読み出し状態(0bit目)と送信書き込み状態(2bit目)を確認して、それぞれ受信可(”1”)であればSIOBDから受信データを読み込みます。送信可(”1”)であれば、SIOBDに送信データを書き込みます。
getchar:in a,(SIOBC)
bit 0,a
jr z,getchar
in a,(SIOBD)
ret
putchar:push af
putchar01:
in a,(SIOBC)
bit 2,a
jr z,putchar01
pop af
out (SIOBD),a
ret
i/oデータのモニタからの直接操作(iコマンド)は in a,(c)及び out (c),a命令に入れかました。
ioreg: ;ioreg change
ld a," " ;space
call putchar
call input_l ;change i/o register
cp 0x00
jr z,ioreg1 ;no address hex code
ld a,0x0d
call putchar
ret
ioreg1:
ld a," " ;current i/o address display
call putchar
ld b,0x00
ld c,l
in a,(c)
call hex_a_disp
ld a," "
call putchar
call input_l ;new i/o conntents address input
cp 0x00
jr z,ioreg2
xor a
ret
ioreg2:
ld a,l ;new i/o address update
out (c),a
ld a,0x0d
call putchar
ret
全体のモニターのコードは以下の通りです(ちょっと長いです^^;)
アセンブルには asxxxxを使用しています。
; TMPZ84C015 monitor ver0.71 by Pinecone 2019/7/9
;
; TMPZ84C015 cpu
; rom 0000h -- 7fffh
; ram 8000h -- ffffh
; External clock 20MHz
; TMPZ84C015 serial communication (CH-B)
; extemal Clock 0.1536MHz (1/16=9600bps)
; assembler
; program start 0000H
; main 0100H
;
; assemblers ASxxxx and ASlink V5.10
; file name tmpz84c015_moni071.asm
; $ asz80 -l -s -o tmpz84c015_moni071.asm
; $ aslink -i tmpz84c015_moni071
; $ rom-writer TL866-2 plus tmpz84c015_moni071.ihx
;
.z80
.area TEST(ABS)
SIOBD .equ 0x1A ;SIO-B CH DATA REG
SIOBC .equ 0x1B ;SIO-B CH CONTL REG
.org 0x0000
jp start
.org 0x100
start: ;cold start
ld sp,0x0000 ;stack pointer set
call com_init ;serial channel initialize
ld hl,msg_op ;opening message display
call msgout
prompt: ld a,">" ;main routine
call putchar ;prompt display
call getchar
call putchar
cp "?" ;help ?
call z,help
cp "d" ;memory display?
call z,dump
cp "m" ;memory rewrite ?
call z,memory
cp "l" ;hex file load?
call z,loadhex
cp "j" ;address jump?
call z,jump
cp "i" ;i/o register rewite
call z,ioreg
cp "c"
call z,calling ;address call
cp 0x0d
jr z,prompt
cp 0x00
jr z,prompt
call cr
jr prompt
help: ld hl,help_msg ;help ?
call msgout
ret
cr:
ld a,0x0d
call putchar
ret
jump: ;address jump?
ld a," "
call putchar
call input_hl ;dump address input
cp 0x00
jr nz,crret
ld a," "
call putchar
ld a,"y"
call putchar
ld a,":"
call putchar
call getchar
cp "y"
jr nz,crret
call cr
jp (HL)
crret:
call cr
ret
calling: ;address call?
ld a," "
call putchar
call input_hl ;call address input
cp 0x00
jr nz,crret
ld a," "
call putchar
ld a,"y"
call putchar
ld a,":"
call putchar
call getchar
cp "y"
jr nz,crret
call cr
ld de,callret
push de
jp (HL)
callret:
ret
loadhex:
call loadhexline ;load 1line Hex file
cp 0xff ;hex file read err
jr z,loadhexerr
cp 0x01 ;hex file end?
jr nz,loadhex
ld a,0x0d
call putchar
ld a,"O"
call putchar
ld a,"K"
call putchar
ld a,0x0d
call putchar
ret
loadhexerr:
ld a,0x0d ;hex file read skip
call putchar
ld a,"E"
call putchar
ld a,"R"
call putchar
ld a,"R"
call putchar
ld a,0x0d
call putchar
ret
loadhexline:
ld a,0x0d
call putchar
ld d,0x00 ;checksum count clr
call getchar ;record mark is ":"
cp ":"
jr nz,loadhexlineerr
call input_l ;data size 1byte
ld b,l ;checksum = checksum + data size
ld a,d
add b
ld d,a
call input_hl ;offset address 2byte
push hl
pop ix ;offset address HLreg >> IXreg
ld a,d ;checksum = checksum + address Low
add l
add h ;checksum = checksum + address Hi
ld d,a
call input_l ;record type
ld a,l
cp 0x00 ;data record
jr nz,checkrecord
;; *** data record job ****
data_hex:
call input_l ;read hex 1byte in Lreg(hex)
ld (ix),l ;offset address < hex data
inc ix ;offset address +1
ld a,l
add d ;cheksum Dreg = Dreg + Lreg
ld d,a
djnz data_hex ;Breg(data size) == 0?
call input_l ;chechsum OK?
ld a,d
add l
cp 0x00
jr nz,loadhexlineerr
call getchar
cp 0x0a ;load 1line hex LF?
jr nz,loadhexlineerr
ld a,0x00
ret
checkrecord: ;end record ?
cp 0x01
jr nz,loadhexlineerr
call input_l
ld a,l
cp 0xff
jr nz,loadhexlineerr
ld a,0x01
ret
loadhexlineerr:
ld a,0xff ;read record err (no support)
ret
dump: ;memory dump
ld a," "
call putchar
call input_hl ;dump address input
cp 0x00
jr z,dump1
push iy ;memory dump address set
pop hl
dump1:
call dump_hl ;memory dump
push hl ;memory address IY set
pop iy
ret
memory: ;memory change
ld a," " ;space
call putchar
call input_hl ;change memory address
cp 0x00
jr z,memory1 ;no address hex code
ld a,0x0d
call putchar
ret
memory1:
ld a," " ;current memory display
call putchar
ld a,(HL)
call hex_a_disp
ld a," "
call putchar
push hl
call input_l ;new memory conntents input
cp 0x00
jr z,memory2
pop hl
xor a
ret
memory2:
ld c,l ;memory contents update
pop hl
ld (hl),c
ld a,0x0d
call putchar
ret
ioreg: ;ioreg change
ld a," " ;space
call putchar
call input_l ;change i/o register
cp 0x00
jr z,ioreg1 ;no address hex code
ld a,0x0d
call putchar
ret
ioreg1:
ld a," " ;current i/o address display
call putchar
ld b,0x00
ld c,l
in a,(c)
call hex_a_disp
ld a," "
call putchar
call input_l ;new i/o conntents address input
cp 0x00
jr z,ioreg2
xor a
ret
ioreg2:
ld a,l ;new i/o address update
out (c),a
ld a,0x0d
call putchar
ret
input_l: ;input Lreg hex (1byte)
push bc
ld b,0x02
jr input_loop
input_hl: ;input HLreg hex (2byte)
push bc
ld b,0x04
input_loop:
ld hl,0x0000 ;HL reg cler
jr input_hl2
shift_hl:
add hl,hl ;HL reg shift left 4bit
add hl,hl
add hl,hl
add hl,hl
input_hl2:
call getchar ;input ascii hex 1char
call putchar
call ascii_hex ;ascii hex 1char >> Areg
cp 0xff
jr z,input_hl_err
and 0x0f ;Areg low order 4bit >> Lreg
or l
ld l,a
djnz shift_hl
input_hl_end:
pop bc
xor a ;OK >> Areg 0x00
ret
input_hl_err:
ld a,0xff ;NG >> Areg 0xff
pop bc
ret
dump_hl: ;memory dump 1line(+0 -- +f)
ld a,0x0d
call putchar
push hl
ld hl,dump_msg ;dump address msg output
call msgout
pop hl
ld a,h ;dump address HLreg
call hex_a_disp ;dump address output
ld a,l
call hex_a_disp
ld a," "
call putchar
call putchar
ld b,0x10 ;address --> address +0f
hl_disp:
ld a,(HL) ;dump addres data (HL)
inc HL
call hex_a_disp
ld a," "
call putchar
djnz hl_disp
ld a,0x0d
call putchar
ret
hex_a_disp: ;Areg(HEX) >> putchar(areg)
push af
rrca ;7-4bit Right shift
rrca
rrca
rrca
call hex_ascii ;3-0bit Hex >> Hex ascii(0-F)
call putchar ;7-4bit putchar
pop af
call hex_ascii ;3-0bit Hex >> Hex ascii(0-F)
call putchar ;3-0bit putchar
ret
ascii_hex:
sub 0x30
jr c,err_hex
cp 0x0A ;0-9
jr c,hex_1_9
sub 0x11
cp 0x06 ;A-F
jr c,hex_A_F
sub 0x20
cp 0x06 ;a-f
jr nc,err_hex
hex_A_F:
add 0x0a
hex_1_9:
ret
err_hex:ld a,0xff
ret
hex_ascii: ;Areg(HEX) >> Areg(ascii code)
and a,0x0f
cp 0x0a
jr c,ascii0_9
add 0x37
ret
ascii0_9:
add 0x30
ret
msgout:
ld a,(hl) ;(HL)reg is output disp at 0x00
cp 0x00
ret z
call putchar
inc hl
jr msgout
getchar:in a,(SIOBC)
bit 0,a
jr z,getchar
in a,(SIOBD)
ret
putchar:push af
putchar01:
in a,(SIOBC)
bit 2,a
jr z,putchar01
pop af
out (SIOBD),a
ret
;
com_init:
ld b,12
ld hl,SIO_init_data
com_init01:
ld a,(HL)
out (SIOBC),a
inc hl
djnz com_init01
ret
;
SIO_init_data:
.db 0x00,0b00110000 ;WR0=WR0:set ,WR0: reset
.db 0x01,0b00000000 ;WR0=WR1:set ,WR1: all init reset
.db 0x02,0b00000000 ;WR0=WR2:set ,WR2: init set
.db 0x03,0b11000001 ;WR0=WR3:set ,WR3: RxBit=8bit Rx=ready
.db 0x04,0b01000100 ;WR0=WR4:set ,WR4: clock=1/16 stop=1bit parity=non
.db 0x05,0b11101010 ;WR0=WR5:set ,WR5: char=8bit DTR/RTS=EN Tx=ready
msg_op: .str "Monitor TMPZ84C015 CPU ver0.71 by Pinecone 2019/7/9"
.db 0x0d
.db 0x00
help_msg:
.db 0x0d
.str "? Help"
.db 0x0d
.str "d memory dump"
.db 0x0d
.str "m memory change address old new"
.db 0x0d
.str "l hex file load"
.db 0x0d
.str "j jump"
.db 0x0d
.str "i i/o register i/o-address old new"
.db 0x0d
.str "c call"
.db 0x0d
.db 0x00
dump_msg:
.str "addr +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F"
.db 0x0d
.db 0x00