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

MC6800 ROMモニタ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 を使っています。OUTEEECR のときに 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 モニタらしい機能へ進めていく感じですね。まだ最小構成ですが、少しずつモニタっぽいものになってきたのがうれしいです。

MC6800 ROMモニタSBC6800