SBC6303で一行入力

SBC6303で一行入力 HD6301/HD6303

出力に続けて入力も実装します。
SCIへの入出力が完成すればターミナルソフトを使ってHD6303との会話が可能になります。

プログラムの構成

一行入力を実行するには次のルーチンが必要です。

  • SCIから一文字受信
  • SCIから文字列受信

SCIから一文字受信(read_char)

SCIから受信したデータをBレジスタに保存します。

read_char:
.top    tim     #RDRF|ORFE,<TRCSR      ; 受信データ有無のチェック
        beq     :top
        tim     #ORFE,<TRCSR           ; エラーのチェック
        beq     :end
        ldab    <RDR                   ; 空読みしてステータスのリセット
        bra     :top
.end    ldab    <RDR                   ; SCIデータの読み込み
        rts

まずはステータスレジスタ(TRCSR)のチェックです。

RDRFORFE状態
00受信データなし
01受信データあり
10フレーミングエラー
11オーバーランエラー

2行目でRDRF、ORFE共にビットが立っていなければ受信データがありませんので、どちらかが立つまでループして待ちます。

4行目ではRDRFビットが立っていればフレーミングエラーかオーバーランエラーなので6行目で空読みしてステータスをリセットします。

オーバーランエラーはデータを取り込む前に次のデータが来てしまった時、フレーミングエラーはボーレートが異なっていたり誤差が大きすぎたりして、ストップビットが来るはずのところでHレベルが来ない時に発生します。

本来はそれぞれのエラー処理が必要なはずですが、フロー制御もできませんし、手抜きして再読み込みするようにしました。
私の環境ではたぶん発生しないエラーですので、合っているのか自信がないです。

8行目でようやく受信したデータをBレジスタに保存して終了です。

SCIから文字列受信(read_line)

SCIから文字列を受信してバッファに保存していきます。
リターン(CR+LFまたはLF)することでルーチンを終了します。
バックスペースくらいは使いたいのでがんばって実装することにしました。

; 定数 Constants
NUL             .eq     $00     ; NUL
BS              .eq     $08     ; Backspace
SPACE           .eq     $20     ; Space
CR              .eq     $0d     ; Carriage Return
LF              .eq     $0a     ; Line Feed
DEL             .eq     $7f     ; Delete
Rx_BUFFER       .eq     $0100   ; SCI Rx Buffer
Rx_BUFFER_END   .eq     $0148   ; 73byte(72文字分)

; 一行入力 改行コードは「CRLF」「LF」
read_line:
        ldx     #Rx_BUFFER
.loop   bsr     read_char
        cmpb    #BS             ; 入力文字がBSならば…
        beq     :bs             ; バックスペース処理へ
        cmpb    #LF             ; LF?
        beq     :end
        cmpb    #DEL            ; b >= DEL ?
        bcc     :loop           ; なにもしない
        cmpb    #SPACE          ; b < SPACE ?
        bcs     :loop           ; なにもしない
        cpx     #Rx_BUFFER_END  ; バッファ終端チェック
        beq     :loop           ; 73文字目ならなにもしない
        bsr     write_char      ; echo
        stab    0,x             ; バッファに文字を収納
        inx                     ; ポインタを進める
        bra     :loop           ; 次の文字入力
; ----- バックスペース処理 -----
.bs     cpx     #Rx_BUFFER      ; ポインタ位置が一文字目ならば…
        beq     :loop           ; なにもしない
        bsr     write_char      ; 一文字後退
        ldab    #SPACE          ; 空白を表示(文字を消去)
        bsr     write_char
        dex                     ; バッファポインタ-
        ldab    #BS             ; 一文字後退(カーソルを戻す)
        bsr     write_char
        bra     :loop
; ----- 終端処理 -----
; 文字数が72文字の時、次のアドレスを指していない。その場合はポインタを+1する。
.end    cpx     #Rx_BUFFER_END-1
        bne     :noinc
        inx
.noinc  clrb                    ; $00:終端記号
        stab    0,x
        bra     write_crlf      ; 改行してrts

12行目のread_charで入力文字を読み込み、通常文字であればバッファに保存、write_charでエコーバックしていきます。
通常文字ではない制御コードであれば無視して次の文字を読み込みます。

LF($0a)を読み込むと、代わりにに$00をバッファに書き込んで終了します。

BS($08)を読み込むと、バックスペース処理に移ります。
バックスペースは一文字分カーソルが後退するだけなので、そのままでは文字が消えません。
そのため、後退→空白出力→後退して文字が削除されたように見せています。

たいていのターミナルソフトではBSでカーソルを後退させてくれるのですが、CoolTermは制御コードに対応していませんのでこのままでは一文字削除できません。
Options > Terminalの「Handle BS and DEL Characters」にチェックを入れてください。ソフト的にバックスペースを再現してくれます。

メインルーチン

メインルーチンはメッセージとプロンプト「$」を表示してからread_lineルーチンを呼び出します。
入力が終わったらXレジスタに入力バッファを代入し、write_lineルーチンを呼び出して入力された文字列を出力します。
出力したらプロンプトの表示に戻り、これを繰り返します。

        ldx     #MSG_TEST
        jsr     write_line
        
prompt: ldab    #'$'
        jsr     write_char
        jsr     write_space
        
        jsr     read_line
        ldx     #Rx_BUFFER
        jsr     write_line
        jsr     write_crlf
        bra     prompt

MSG_TEST        .az     "*** Line Input Test ***",#CR,#LF

実行します

前回の出力ルーチンと合わせてROMに焼きます。

CoolTerm画面_一行入力

うまく表示されました!

入出力ができるようになったので、次はプログラムファイルの転送を実装します。
いちいちROMに焼き込む必要がなくなるのでかなり楽になるはずです。

コメント

タイトルとURLをコピーしました