SBC6303でhello world

SBC6303でHello_world HD6301/HD6303

いよいよ完成したSBC6303を使っていきます。
SBC6303ルーズキットにはモニタプログラムLILBUGやサンプルプログラムが同梱されていますが、当時を追体験したいと考えているので、あえてフルスクラッチで作りたいと思います。

とはいえ当時の不自由さまで追体験する根性はありません……。

  • バックアップSRAMではなくEEPROM
  • テレタイプやビデオ端末の代わりにPCの端末エミュレータ
  • ハンドアセンブルではなくクロスアセンブラ

こんな感じで現代の技術のサポートは遠慮なく受けることにします。

クロスアセンブラはSB-Assemblerを使うことにしました。Python3で動作するアブソリュートアセンブラです。
Pythonで動作しますので、macOSでも問題なく動かせます。

シリアル端末はCoolTermを使用します。端末エミュレータではないのでエスケープシーケンスに対応していないのが残念ですが、当面は問題ないと思います。

ROMプログラマはTL866xxを使用します。オープンソースソフトウェアのminiproで制御できます。

私は古くからのMacユーザーなのでmacOSで開発しています。

初めてのプログラムは当然「hollo world」です。

プログラムの構成

Hello worldを実行するには次のルーチンが必要です。

  • チップの初期化
  • SCIへ一文字送信
  • SCIへ文字列送信

上記ルーチンが完成したら、文字列をサブルーチンに渡すメインルーチンを書くだけです。

SB-Assembler特有の設定

SB-AssemblerはCPUの種類や出力ファイル名などをソースコードに記述します。

; * Hello world for SBC6303
; * SB-Assembler

    .cr     6301                    ; Cross Overlay HD6301を指定
    .tf     helloworld.s19,s19      ; Target File Name
    .lf     helloworld              ; List File Name
    .sf     helloworld              ; Symbol File Name

定数の定義

プログラム中で使用する定数を定義しておきます。

; HD6301 コントロールレジスタ
DDR1    .eq     $00             ; Port1 Data Direction Register
PORT1   .eq     $02             ; Port1 Data Register
RMCR    .eq     $10             ; Rate and Mode Control Register
TRCSR   .eq     $11             ; Transmit/Receive Control and Status Register
RDR     .eq     $12             ; Receive Data Register
TDR     .eq     $13             ; Transmit Data Register
; Rate and Mode Control Register
E128    .eq     %00000001       ; E/128
NRZIN   .eq     %00000100       ; Format:NRZ Sorce:Internal Port2:Not use
; Transmit/Receive Control and Status Register
TE      .eq     %00000010       ; bit 1 :Transmit Enable
RE      .eq     %00001000       ; bit 3 :Recevie Enable
TDRE    .eq     %00100000       ; bit 5 :Transmit Data Register Empty
ORFE    .eq     %01000000       ; bit 6 :Over Run Framing Error
RDRF    .eq     %10000000       ; bit 7 :Receive Data Register Full

チップの初期化(init_sbc6303)

起動したら最初に

  • スタックポインタの設定
  • ポートの入出力方向の決定
  • SCIの設定

を行ないます。

init_sbc6303:
.top    sei                     ; 割り込み禁止
        lds     #$1fff          ; スタックポインタ設定
    ;-- Port 1 設定 --
        ldab    #%11111111
        stab    <DDR1           ; Port 1 全ポート -> 出力
    ;-- SCI設定 --
        ldab    #E128|NRZIN     ; 9,600bps、内部クロック使用、ポート2ビットは不使用
        stab    <RMCR
        ldab    #TE|RE          ; SCI有効化(TEとREをセット)
        stab    <TRCSR
        ldab    <RDR            ; 空読み
        cli                     ; 割り込み許可

まず割り込みを禁止し、スタックポインタを設定します。RAMの最終番地にしました。

リセット後のパラレルI/Oは入力になっています。データシートによるとHi-Zになっているのでそのままでも問題なさそうですが、念のため出力にしておきます。

SCIはRMCRとTRCSRを操作して設定します。
このSBC6303は4.9152MHzの水晶振動子を付けていますのでE÷128の9,600bpsで設定したいと思います。
SBC6303はパワーオンリセットするとゴミデータが入っていることがあり、12行目で空読みをしています。

最後に割り込みを許可して終了します。

メインルーチンの前にSCI関連のサブルーチンを作成しておきます。

SCIへ一文字送信(write_char)

Bレジスタの内容をSCIに送信します。
AレジスタではなくBレジスタを使っているのは、Dレジスタの下位8ビットがBレジスタになるからです。
2バイトのデータを受け取るときに、Aレジスタで受け取ってしまうと、その値を何処かに退避しておかないといけません。Bレジスタで受け取れば、tba命令でAレジスタに転送してそのまま2バイト目を受け取ればいいわけです。

write_char:
.top    tim     #TDRE,<TRCSR
        beq     :top            ; TDRE=0だったら出力を待つ
        stab    <TDR            ; [TDR] <- B
        rts

tim op1,op2op2のメモリ内容とop1の論理積を取り、フラグを変化させます。レジスタもメモリも内容は変化しませんのでレジスタ数の少ないHD6301にはとても有益な命令です。
ここではTDREビットが立っているかどうか調べるのに使っています。

.topというラベルはローカルラベルです。beq write_charでもいいのですが、ローカルラベルはbeq :topのようにラベルの前にコロンを付けて指定することもできます。ルーチン内の分岐なのかルーチン外への分岐なのか分かりやすくなるので、こうしています。

SCIへ文字列送信(write_line)

インデックスレジスタで指定されたアドレスから始まるデータをSCIに出力します。終端文字はいくつか候補がありますが、転送命令でフラグが変化する68系の特性を考えて$00としました。

write_line:
.top    ldab    0,x             ; B <- [X]
        beq     :end            ; $00だったら終了
        bsr     write_char
        inx                     ; X += 1
        bra     :top
.end    rts

2行目でBレジスタにロードした時、内容が$00だとゼロフラグが立ちます。そうすると比較命令を実行することなく、すぐに条件分岐することができるわけです。

メインルーチン

メインルーチンはインデックスレジスタに文字列の先頭アドレスを転送し、write_lineルーチンを呼び出します。
最後は無限ループに入るようにしました。

hello_world:
        ldx     #MSG_HELLO
        jsr     write_line
.end    bra     :end
MSG_HELLO:      .az     "Hello world from SBC6303!",#$0d,#$0a

ディレクティブ.azはASCII文字列の最後に$00を追加してくれます。

割り込みベクタの設定

割り込みベクタは9種類ありますが、とりあえずRESETベクタのみ設定しておきます。

        .or     $fffe
        .dw     init_sbc6303    ; Reset Vector

完成したプログラム

忘れずにプログラムの先頭アドレスを記載しておきます。ROMの先頭アドレスにしました。

; * Hello world for SBC6303
; * SB-Assembler

        .cr     6301                    ; Cross Overlay HD6301を指定
        .tf     helloworld.s19,s19      ; Target File Name
        .lf     helloworld              ; List File Name
        .sf     helloworld              ; Symbol File Name

; *** 定数 ***
; HD6301 コントロールレジスタ
DDR1    .eq     $00             ; Port1 Data Direction Register
PORT1   .eq     $02             ; Port1 Data Register
RMCR    .eq     $10             ; Rate and Mode Control Register
TRCSR   .eq     $11             ; Transmit/Receive Control and Status Register
RDR     .eq     $12             ; Receive Data Register
TDR     .eq     $13             ; Transmit Data Register
; Rate and Mode Control Register
E128    .eq     %00000001       ; E/128
NRZIN   .eq     %00000100       ; Format:NRZ Sorce:Internal Port2:Not use
; Transmit/Receive Control and Status Register
TE      .eq     %00000010       ; bit 1 :Transmit Enable
RE      .eq     %00001000       ; bit 3 :Recevie Enable
TDRE    .eq     %00100000       ; bit 5 :Transmit Data Register Empty
ORFE    .eq     %01000000       ; bit 6 :Over Run Framing Error
RDRF    .eq     %10000000       ; bit 7 :Receive Data Register Full

        .or     $e000

; *** 初期化 ***
init_sbc6303:
.top    sei                     ; 割り込み禁止
        lds     #$1fff          ; スタックポインタ設定
    ;-- Port 1 設定 --
        ldab    #%11111111
        stab    <DDR1           ; Port 1 全ポート -> 出力
    ;-- SCI設定 --
        ldab    #E128|NRZIN     ; 9,600bps、内部クロック使用、ポート2ビットは不使用
        stab    <RMCR
        ldab    #TE|RE          ; SCI有効化(TEとREをセット)
        stab    <TRCSR
        ldab    <RDR            ; 空読み
        cli                     ; 割り込み許可

; *** メインルーチン ***
hello_world:
        ldx     #MSG_HELLO
        jsr     write_line
.end    bra     :end
MSG_HELLO:      .az     "Hello world from SBC6303!",#$0d,#$0a

; *** 一文字出力 ***
write_char:
.top    tim     #TDRE,<TRCSR
        beq     :top            ; TDRE=0だったら出力を待つ
        stab    <TDR            ; [TDR] <- B
        rts

; *** 一行出力 ***
write_line:
.top    ldab    0,x             ; B <- [X]
        beq     :end            ; $00だったら終了
        bsr     write_char
        inx                     ; X += 1
        bra     :top
.end    rts

; *** Interrupt Vectors ***
        .or     $fffe
        .dw     init_sbc6303   ; Reset Vector

アセンブルします

SB-Asssemblerをダウンロードしたら好みのディレクトリで解凍します。今回はホームディレクトリに/binを作成しました。
パスを通したら正常に動作するかチェックします。

% sbasm -h

SB-Cross Assembler version 3.03.06
Please visit www.sbprojects.net for a complete description.


Sorry, help is not implemented yet.

まだヘルプが実装されていないようですが動作するようです。
早速アセンブルしましょう。

% sbasm helloworld.asm

SB-Cross Assembler version 3.03.06
Please visit www.sbprojects.net for a complete description.

Assembling....

Pass one
Loaded 6301 overlay version 3.01.01

Pass two
0000-                  1      ; * Hello world for SBC6303
0000-                  2      ; * SB-Assembler
0000-                  3
0000-                  4              .cr     6301                    ; Cross Overlay HD6301を指定
0000-                  5              .tf     helloworld.s19,s19      ; Target File Name

0 Errors found during assembly.
0 Warnings found during assembly.

同じ階層にhelloworld.s19helloworld.lsthelloworld.symの3ファイルができました。

ROMに書き込みます

TL866xxの制御ソフトウェアのminiproはHomebrewでインストールするのが簡単です。
関連ソフトウェアのsrecordも一緒にインストールされます。

miniproはs19ファイルを直接ROMに書き込むこともできるのですが、開始アドレスが$e000になっているためうまくいきません。
まずはsrecordでs19ファイルを$0000から始まるバイナリファイルに変換します。

% srec_cat helloworld.s19 -Motorola -offset -0xe000 -o helloworld.bin --Binary
srec_cat: helloworld.s19: 1: warning: no header record

SB-AssemblerはS0レコードを生成しないので警告がでるものの、変換は問題なくされますので大丈夫です。
同じ階層にhelloworld.binができました。

いよいよTL866xxでEEPROMに書き込みます。EEPROMは日立のHN58V65Aを使用します。
HN58V65Aは対応リストにないのですが、代わりにAT28C64BやuPD28C64として書き込み可能です。
TL866xxをつないで、下記のコマンドを入力します。

% minipro -p at28c64b -w helloworld.bin 
Found TL866CS 03.2.86 (0x256)
Erasing... 0.02Sec OK
Protect off...OK
Writing Code...  1.75Sec  OK
Reading Code...  0.16Sec  OK
Verification OK
Protect on...OK

うまく書き込めました。EEPROMをSBC6303に取り付けます。

CoolTermの設定

USB-シリアル変換ケーブルをMacに接続し、CoolTermを起動したら「Options」の「serial Port」を下記のように設定します。

  • Port: お使いのUSB-シリアル変換ケーブル
  • Bandrate: 9600
  • Data Bits: 8
  • Parity: None
  • Stop Bits: 1
  • Flow Control CTS: チェックなし
  • Flow Control DTR: チェックなし
  • Flow Control XON: チェックなし
  • Software Supported Flow Control: どちらでもOK
  • Block Keystrokes while flow is halted: チェックあり
  • DTR: On
  • RTS: On

ほぼデフォルトのままで大丈夫なはずです。

いよいよ実行!

CoolTermツールバーの「Connect」をクリックし、SBC6303の電源を入れてください。

CoolTerm画面_HelloWorld

うまく表示されました!

パワーオンリセットが不安定なので、SBC6303のリセットボタンを押さないとうまくいかないかもしれません。

文字列ひとつ表示するだけでも苦労しますが、その分うまくいったときは嬉しいですね!

コメント

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