MC6800 ROMモニタ自作 その4 〜フェーズ2の最小CLIを実装してみる〜

前回までで、フェーズ1として最小のシリアル入出力と、ROM 書き込み環境まわりがだいぶ整ってきました。
今回はその続きで、フェーズ2の最初の一歩として、対話基盤の最小版を実装してみました。いきなりメモリダンプや実行コマンドまで行くのではなく、まずは「1行入力して、それを内部バッファとして扱える」ところまで持っていく感じです。
見た目としてはエコーバックとあまり変わらなさそうに見えるのですが、やっていることはけっこう違います。最終的にはちゃんと動いて、SBC6800 実機でも確認できました。

今回やりたかったこと
フェーズ1では、受信した1文字をそのまま返すだけの、かなり小さい実装でした。
でもフェーズ2では、その1文字単位の処理から一歩進めて、「1行の入力」として扱えるようにしたいです。
今回の最小 UX はこうしました。
`*
] ABC
= ABC
] `
ポイントは、起動時は従来どおり * を出し、そのあとプロンプトとして ] を表示し、BS / DEL で編集できて、CR で1行確定し、確定した内容を検証用に = 付きで返すところです。
エコーバックと何が違うのか
ぱっと見では、入力中はエコーバックとかなり似ています。
`] ABCD`
ただ、実際には中でやっていることが違います。フェーズ1では受けた文字をその場で返して終わりですが、フェーズ2では受けた文字を RAM 上のバッファへ溜めていて、Enter が押されるまでは確定していません。
その違いがはっきり見えるのが、Enter を押したときの = ABC です。これは今回あえて入れた検証用 UX で、「ちゃんと内部バッファに1行として入っているか」を見るための表示です。
今回工夫したところ
- プロンプトを
]にして見やすくした BS/DELでプロンプトより左へ戻らないようにした- 画面上の削除は
BS SP BSで処理した - 前回の反省で
OUTEEEの A レジスタ保持を見直した
バッファ定義
行バッファ用の定数は hardware.inc に追加しました。
`CHR_BS equ $08
CHR_DEL equ $7F
CHR_SPACE equ $20
CHR_PROMPT equ ']'
CHR_ECHO equ '='
LINE_BUF_SIZE equ 32
LINE_BUF equ RAM_START
LINE_PTR equ LINE_BUF+LINE_BUF_SIZE
LINE_LEN equ LINE_PTR+2`
今回はとりあえず 32 文字です。最小 CLI の実験としては十分かなと思います。
起動後の流れ
main.asm 側では、起動後の流れをこうしました。
`RESET:
lds #STACK_TOP
jsr ACIA_INIT
ldaa #'*'
jsr OUTEEE
ldaa #CHR_CR
jsr OUTEEE
MAIN_LOOP:
jsr PRINT_PROMPT
jsr READ_LINE
jsr ECHO_LINE
bra MAIN_LOOP`
起動マーカーを出して、プロンプトを出して、1行読んで、= 付きで返して、また次の入力へ戻る、という形です。
行入力ルーチン
今回の中心は READ_LINE です。毎回、入力開始時にバッファ先頭、現在位置、入力長を初期化しています。
`READ_LINE:
ldx #LINE_BUF
stx LINE_PTR
clr LINE_LEN`
受信ループでは、LF は無視、CR なら確定、BS / DEL なら削除、それ以外の可視文字は追加、という分岐です。
`READ_LINE_LOOP:
jsr ACIA_GETC
cmpa #CHR_LF
beq READ_LINE_LOOP
cmpa #CHR_CR
beq READ_LINE_DONE
cmpa #CHR_BS
beq READ_LINE_BACKSPACE
cmpa #CHR_DEL
beq READ_LINE_BACKSPACE
cmpa #CHR_SPACE
blo READ_LINE_LOOP`
バックスペース処理
バックスペース処理では、入力長が 0 のときは何もしないようにしています。これで ] より左には戻りません。
`READ_LINE_BACKSPACE:
tst LINE_LEN
beq READ_LINE_LOOP
ldx LINE_PTR
dex
stx LINE_PTR
dec LINE_LEN
ldaa #CHR_BS
jsr ACIA_PUTC
ldaa #CHR_SPACE
jsr ACIA_PUTC
ldaa #CHR_BS
jsr ACIA_PUTC
bra READ_LINE_LOOP`
ここでは OUTEEE ではなく ACIA_PUTC を使っています。OUTEEE は CR のときに LF を足すので、カーソル制御には向かないからです。
検証用の = 表示
確定した行は ECHO_LINE で返しています。まず = を出して、そのあとバッファ内容を1文字ずつ返す形です。
`ECHO_LINE:
ldaa #CHR_ECHO
jsr OUTEEE
ldaa #CHR_SPACE
jsr OUTEEE
ldab LINE_LEN
ldx #LINE_BUF`
この段階ではまだコマンド解釈はしていませんが、ここをあとで本処理に差し替えていくイメージです。
実機で動かしてみた
最終的には SBC6800 実機で確認して、ちゃんと動きました。例えばこんな感じです。
`*
] ABC
= ABC
] HELLO
= HELLO
]
=
] `

BS / DEL で消していったときに、プロンプトより左へ戻らないのも確認できました。このあたりが動いてくれると、ちゃんと行入力の土台になってきた感じがします。
今回のソースもgithubへUPしています。確認してみてください。
今回のまとめ
- フェーズ2の最小 CLI を実装した
- プロンプト
]を追加した - 1行入力バッファを入れた
BS/DELによる編集を入れたCRで1行確定し、検証用に=付きで返すようにしたOUTEEEの A レジスタ保持も見直した
今後の予定
次はこの行入力をベースにして、16進文字のデコード、簡単なコマンド判定、? のような短いエラー表示あたりを入れていきたいです。
その先で、メモリダンプ、メモリ変更、指定アドレス実行みたいな、いわゆる ROM モニタらしい機能へ進めていく感じですね。まだ最小構成ですが、少しずつモニタっぽいものになってきたのがうれしいです。