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

関連キーワード
  • Z80(TMPZ84C015)に萌えたい。64KRAM化ソフト編その2(モニタ)
  • Z80(TMPZ84C015)に萌えたい。SPI対応モニタ
  • Z80(TMPZ84C015)に萌えたい。モニタの移植
  • Z80(Z8S180)に萌えたい SDCC printf文
  • Z80(Z8S180)に萌えたい モニタROM化
  • Z80に萌えたい 拡張SRAM用モニタ
おすすめの記事
Z8S180
Z8S180のMMUの設定についてレジスターを変更してみます。 3つのレジスタのI/Oアドレスは BBR  0x39 CBR  0x38 C...
monitor
TMPZ84C015を使用したAKI-80ボードに以前作成したZ8S180用モニタを移植してみました。 移植したZ8S180用モニタは、メモ...