MC6800 SDFS/68を作る その6 ~.COMでトランジェントコマンドっぽくする~

SDFS/68は、V1.2で DIR、LOAD、RUN、EXIT まで入りました。SDカード上のファイルを見て、S-RecordやIntel HEXをロードして、アドレス指定やentry addressから実行できる。ここまで来ると、もうかなり小さいDOSっぽいです。
でも、DOSっぽいと言い出すと、次に欲しくなるものがあります。トランジェントコマンドです。
DIR や LOAD のような内蔵コマンドだけではなく、SDカードに置いた FOO.COM をその場でロードして実行する。終わったらSDFS/68のプロンプトへ戻る。CP/MやMS-DOSの .COM みたいな使い方であります。
SDFS/68でHELLO.COMとARGS.COMが動いた実機
RUNとは別のものにしたい
最初に考えたのは、今ある RUN をRTS前提にするかどうかでした。
でも、これは分けることにしました。RUN addr や RUN filename は、ROMモニタの G コマンドに近いものです。指定した先へ JMP して、あとは実行先に任せる。戻ってくる保証はありません。
一方で .COM は、SDFS/68が呼び出し元になります。
`SDFS> FOO.COM
SDからFOO.COMを読む
$0100へロードする
JSR $0100
FOO.COM側はRTSで戻る
SDFS>`
この違いをはっきりさせたかったので、.COM は RUN とは別のABIとして設計しました。正常終了は RTS。SWI はROMモニタのブレークや非常口として残す。ここはかなり大事な割り切りでした。
.COMの形はかなり単純にした
今回の .COM は、headerなしのraw binaryです。ロード先もentryも固定で $0100 です。
` CPU 6800
ORG $0100
START ; command body
RTS
END START`
Macro Assembler ASで作るなら、だいたいこんな流れです。
`asl -q -L -o FOO.p FOO.ASM
p2bin FOO.p FOO.bin -q
mv FOO.bin FOO.COM`
CP/MのCOMっぽく、開始アドレスを $0100 にしておく。SDFS/68側はファイルの中身をそのまま $0100 へ置くだけです。余計なheaderやrelocationはありません。
ファイルサイズは $0100 から USER_RAM_END までに収まる範囲だけ許可します。現行の sbcio_vdg と k6802_vdg では USER_RAM_END=$7FFF なので、最大は $7F00 byteです。0 byteの .COM も実行できないので拒否します。
引数はXとBで渡す
トランジェントコマンドなら、やっぱり引数も渡したいです。
`SDFS> ARGS.COM AAA BBB`
こう入力したとき、ARGS.COM の後ろの AAA BBB をどう渡すか。
CP/Mっぽくゼロページの $0080 あたりにコマンドテールを置く案もありました。でもMC6800ではゼロページ、というかdirect pageがかなり貴重です。既存の小さいプログラムが好きに使っている可能性もあります。
なので、今回はゼロページを予約しないことにしました。
`X = 引数テール先頭へのポインタ
B = 引数テール長
A = 0`
引数文字列はSDFS/68の行入力バッファ上に残っています。.COM 側で長く使いたいなら、自分のワークへコピーする作法です。このへんは小さい環境らしい、ゆるいけど明確な約束にしました。
ちょっと悩んだコマンド判定
最初の実装範囲では、FOO と入力して FOO.COM を探すところまではやりません。これは後でやると面白いですが、検索規則や内蔵コマンドとの優先順位が増えます。
今回はあくまで、拡張子まで明示します。
`SDFS> HELLO.COM
SDFS> ARGS.COM AAA BBB`
ただ、ここで少し罠がありました。SDFS/68には D、L、RUN、LOAD などの内蔵コマンドがあります。DUMP.COM や LIST.COM や READ.COM を置いたときに、先頭文字だけで内蔵コマンド扱いされると困ります。
特にレビューで見つかったのが LOAD.COM でした。LOAD prefixとして拾われるので、.COM 候補に落ちてこない。これはかなりありそうな名前なので、内蔵コマンドとして成立しなかった場合には .COM として再判定するようにしました。
このあたりを入れると、だいぶトランジェントコマンドらしくなります。
サンプルもMakefileに入れた
.COM は作法が大事なので、サンプルも残しました。
HELLO.COM:HELLO COMと表示してRTSするARGS.COM:X/Bで渡された引数テールを表示する
make sdfs-tools でS-Recordの HELLO.S と一緒に .COM サンプルも生成します。実機で試すときは、system SDのrootに SDFS.BIN と一緒に HELLO.COM や ARGS.COM を置けばよいです。
`SDFS> HELLO.COM
HELLO COM
SDFS> ARGS.COM AAA BBB
ARGS AAA BBB
SDFS>`
これはかなり気分がよいです。RUN で飛びっぱなしではなく、ちゃんとSDFS/68へ戻ってくる。小さいDOS感があります。
HELLO.COMとARGS.COMを実行したVDG画面
実装して実機でも動いた
実装はSDFS/68側に .COM 専用のparse、サイズチェック、raw load、起動処理を追加しました。既存のS-Record / Intel HEX loaderは通しません。FATのstream読み込みだけ使って、1 byteずつ $0100 以降へコピーしています。
実装後の SDFS.BIN は、両profileとも3115 byteでした。
`build/SDFS-sbcio-vdg.BIN 3115 bytes
build/SDFS-k6802-vdg.BIN 3115 bytes`
SDFS/68の枠は3840 byteなので、まだ少し余裕があります。でも、だいぶ詰まってきました。ここから先は本当に機能を選ばないといけません。
テストでは、通常の .COM 実行、引数渡し、LOAD.COM みたいな内蔵コマンド名との衝突、存在しない .COM、0 byte .COM、サイズ超過 .COM、ネストした JSR / RTS での復帰を確認しました。
そして実機でも、SDFS.BIN を入れ替えて動きました。写真の通り、VDG画面上で HELLO.COM と ARGS.COM AAA BBB が動いて、ちゃんと SDFS> へ戻っています。これはうれしい。
いったんここまで
今回で、#190で考えていた「最小 .COM ABI」はいったん閉じられます。
まだやりたいことはあります。FOO とだけ入力したら FOO.COM を探す本格トランジェントコマンド探索。.COM からSDFS/68のファイルAPIを呼べるようにする話。将来のpath対応後に、どこから .COM を探すかという話。
でも、まずは FOO.COM 明示指定でSDからロードして、RTS でSDFS/68へ戻るところまでできました。
SDFS/68は、最初はSDからSDFS本体を起動するだけの小さい仕組みでした。それが DIR、LOAD、RUN を持ち、今度は .COM まで呼べるようになりました。派手ではないですが、かなりDOSっぽくなってきた感じであります。
関連リンク
- Issue #190: SDFS/68 V1.3: .COMトランジェントコマンドの最小ABIを検討する
- Issue #191: SDFS/68: .COMトランジェントコマンドABIを設計文書化する
- PR #193: docs: SDFS/68 .COM ABIを設計する
- Issue #194: SDFS/68: .COMサンプルとMakefile生成例を追加する
- PR #195: feat: SDFS/68ツールサンプル生成を追加する
- Issue #192: SDFS/68: .COMトランジェントコマンドを実行できるようにする
- PR #196: feat: SDFS/68で.COMトランジェントコマンドを実行する