読者です 読者をやめる 読者になる 読者になる

BREAK実験

PCからZ80プログラムのデバッグができるよう、BREAKサブルーチンを作ってみました。

call BREAKを実行するとレジスタの内容をRAMにダンプしてHALTします。 PCからはBUSRQでRAMを覗くなり書き換えるなりして、気が済んだらNMIでZ80の実行を再開させます。

ORG_PG: equ     0x0800
STACK:  equ     0xf000
REGDMP: equ     0xc000

        org     0x0000
        ld      sp,STACK
        ; Turn off LED
        ld      a,0
        out     0,a
        ; Jump to the entry point
        jp      ORG_PG

        ; NMI: Continue from the next instruction of "call BREAK"
        org     0x0066
        retn

BREAK:  ; Save A, BC, DE, HL, IX, IY
        ld      (REGDMP),a
        ld      (REGDMP+1),a ; @TODO save flag register
        ld      (REGDMP+2),bc
        ld      (REGDMP+4),de
        ld      (REGDMP+6),hl
        ld      (REGDMP+8),ix
        ld      (REGDMP+10),iy
        ; Save SP, PC
        ld      (REGDMP+12),sp
        pop     hl
        push    hl
        ld      (REGDMP+14),hl
        ld      hl,(REGDMP+6)
        ; It's time for Arduino to control the bus
        halt
        ; Returns here from NMI
        ret

        ; Main program
        org     ORG_PG
        ld      a,0xAA
        ld      bc,0x1234
        ld      de,0x5678
        ld      hl,0x9ABC
        call    BREAK
        ; Turn on LED
        ld      a,1
        out     0,a
        halt

BREAK後にREGDMPのデータを覗くと…

cmd?> dump c000 16
AA AA 34 12 78 56 BC 9A AF BF 00 00 FE EF 0E 08

とりあえず動作する模様。080EH がld a,1のアドレスです。 はじめNMIがPCを退避することを分かってなかったので、SPの位置が想定とズレてしまいプログラム暴走しまくりでした。 これだけ見事に間違えれば NMI → RETN のセットは忘れないでしょう。

[残課題]

  • レジスタの書き出しにPUSHを使う
    • Fレジスタの保存のため。ついでにBREAKルーチンのサイズ圧縮にもなる。
  • BREAK呼び出し方法の策定
    • MSXシステムコールは、ファンクション番号をレジスタに入れてcall 0005Hする形です。この明確な利点がわかれば、似たような方式を採用したい。今は「ラベルで直接callした方が楽じゃん」て思ってます…。

次はCUIツールを改良します。現状はプロセス内の独自プロンプトから連続的にコマンド入力する形式ですが、git のように1コマンド1プロセスとした方が便利だしメンテも楽そうです。