汎用ディスクルーチンを作る


img
88 を手に入れて何かを作りたくなったとき、常につきまとうのがファイル管理の問題です。
一度作ってしまえばそうそう弄る機会は無いものの、作っていても面倒な上にあまり楽しくありません。

入門的にも、ディスク I/O 周りの資料や FDC のマニュアルだけでは、具体的な起動の手順や
ハンドシェイクのやり方などは理解しにくいかもしれません。

こうした実践例がソース公開かつフリーであると良さそうに思えたので
簡素な出来ですがここに置いておきます。



■ 投

・ソースコードとサンプル filesys_20141128.zip

改変含め自由に使ってください。
永遠に作りかけです。足りないものは適当に補ってください。
例によってThe Macroassembler ASを使用しています。

2HD は実機で書き戻しが出来ないのでテストできていません。
CDOS II の 2HD 起動ディスクも xdisk で書き戻せないので、おそらく同じ原因だろうと思います。
単密度のブートセクタがうまく書けていないようです。

サンプルとして SB2 の ADPCM メモリをテストするプログラムと
SB2 で ADPCM と PCM の同時再生が可能かどうかテストするプログラムを付けておきます。

img img

結論から言うと「同時再生は不可」なんですけどネ。
4MHz で起動、スペースで ADPCM、リターンで PCM 再生します。
M88 では PCM が再生できません。j80 だと ADPCM/PCM 両方ともバッチリ再生できます。

一連の調査でエミュレータと実機の動作の違いが色々分かって中々興味深かったです。


■ 解

ディスクイメージの作成とディスクへのファイルの書き込みには udostool.exe を使います。

d:\>udostool newdisk.d88 -2d 
これで 2D のフォーマット済みディスクが出来ます。-2dd や -2hd でも可。
起動ディスクにするためには、ipl.bin subsys.bin iosys.bin の 3 つのシステムファイルを書き込む必要があります(後述)。

d:\>udostool hoge.d88 folder 
「folder」というフォルダの中に入っている全ファイルを、トラック 1 セクタ 1 から順にディスクに書き込みます。
書き込んだファイルはファイルテーブルに情報が記されて、ファイル名でロード出来るようになります。
このコマンドではシステムファイルを除く既存のファイルは全て消去されます。結果としてディスク上には「folder」下のファイルしか無いことになります。

d:\>udostool hoge.d88 -l 
hoge.d88 の中に入っているファイルの一覧を表示します。小文字のエルです。
ファイルのバイト数、開始トラック、開始セクタ、使用セクタ数も表示します。

d:\>udostool hoge.d88 foo.bin -a 
hoge.d88 に foo.bin を追加します。
同じファイル名がある場合は上書きになります。
フォルダ指定、ワイルドカード指定もできます。フォルダ指定での一括書き込みではまずい場合に便利です。

d:\>udostool hoge.d88 foo.bin -d 
hoge.d88 から foo.bin を削除します。ワイルドカード指定も出来ます。

d:\>udostool hoge.d88 outdir -o 
hoge.d88 の中の全ファイルを outdir というフォルダ(なければ作成)に書き出します。

d:\>udostool foo.d88 file.bin 1 2 3 

と指定すると file.bin を disk=1 trk=2 sec=3 から書き込みます。このときファイルテーブルには登録されません。
d88paste.exe のパクリです。あれ以上のものを思いつかない・・・。

d:\>udostool newdisk.d88 ipl.bin -ipl
d:\>udostool newdisk.d88 subsys.bin -sub 
d:\>udostool newdisk.d88 iosys.bin -sys

順に、ipl.bin, subsys.bin, iosys,bin を Trk.0 の特定の位置に書き込みます。
配置はこのページの下の方に書いてあります。
Trk.0 はセクタ混在なので、本コマンドによる特別な書き込みが必要です。



このファイルシステムは FAT を持ちません。
ホストマシンからファイルの追記や削除をするたびに全ファイルを再配置するので、セクタが飛び地になることがありません。
PC88 システムからはファイル名だけ分かればすぐにロードが可能なファイルシステムとなっています。

ファイル総数は 128 個までです。
ファイルサイズは 16,777,215byte(16MB)まで OK です(そんな大きなファイルは入りませんが)。
ADPCM へのロード等の巨大なファイルのロードは各自で管理してください。

ファイル名は 8+3 制限があります。長いファイル名や空白入りのファイル名はNGです。

具体的なファイルのロードなどは、iosys.z80 にサービスエントリを用意してあるのでそれを使います。
いまのところ非常に原始的な仕組みしかありませんが、ファイルの検索や列挙程度は出来ます。
FATが無いので PC88 システムからの「ファイルセーブ」は出来ません。
トラック・セクタを指定してのセーブは出来るのでそれで代用します。

起動ディスクにした場合は「$xxxx.$$$」というファイルをファイル名に書いてあるアドレスにロード後、実行します。
たとえば $8B00.$$$ というファイルを格納しておくと、$8B00 からロードして実行します。
アドレス指定は必ず4桁(例. $100.$$$ でなく $0100.$$$ にする)で指定します。
複数の同型式ファイルがある場合は、最初に見つかったファイルをロードします・・・が、そんな面倒は敢えてしませんよね。
IPL で RAM 64KB、SP=$C000 TVRAM=OFF にしているので、大抵のアドレスにロード可能だと思います。



ipl.bin と subsys.bin は余り弄らなくても良いと思いますが、実質的なイニシャルローダーである iosys.bin を変更すると
前 2 者も再コンパイルとディスクイメージへの書き込みが必要になります。
また、ipl.bin は 2D/2DD/2HD で別々のバイナリになっています。
この 3 つはバッチ処理で全てコンパイルと書き込みを同時に行った方がいいかもしれません。

iosys.bin のアドレス配置やバッファの位置を変更する → ipl.bin の MainPrg の値を変更
iosys.bin を拡張してディスク上の配置やサイズを変更する → subsys.bin の Sec,Cnt 初期値の変更

重要でないと思われるのでフォーマットはサポートしていません。


■ 探

88 には、電源を ON にするだけで使える BASIC ファイルシステムがあるのですが、
アクセスが遅い上に FAT が変な位置にあるので、出来ればもっと良いものが欲しいところです。

最初は FAT12 互換のシステムを考えていて、実際ロードセーブ出来るところまで作ったのですが、
そもそも「互換」にあまり意味が無いことに気付き、方向転換することになりました。
ツール名に名残が・・・。

実機時代ならメディアを 88<->98 で直接やりとり出来ることに確かに意味はありました。
しかし PC 上での使用がメインになると、どのみち必ず何らかのツール(またはエミュレータ)を
経由する形になるので、無理に互換を維持する必要は無いのでした。


88 はブートセクタのフォーマットが決めうちなので、512byte/sector などを採用しようとすると
少なくとも最初のトラックだけは、混在セクタになってしまいます。
以下は、本システムのフォーマットです。

2D2DD2HD
Trk.0 Sec.1 512byte/sec.
SUBSYS.BIN
Trk.0 Sec.2-3 512byte/sec.
予備
Trk.0 Sec.4-5 512byte/sec.
IOSYS.BIN
Trk.0 Sec.6-9 512byte/sec.
ファイルテーブル
Trk.0 Sec.10-15 512byte/sec.
予備
Trk.0 Sec.1 256byte/sec.
IPL.BIN
ブートセクタ
本体側 0xC000 - 0xC0FF
サブ側 0x5000 - 0x50FFまで
128byte/sec.(単密度)
IPL.BIN(前半)
ブートセクタ#1
本体側 0xC000 - 0xC07F
サブ側 0x4000 - 0x407Fまで
Trk.0 Sec.2 128byte/sec.(単密度)
IPL.BIN(後半)
ブートセクタ #2
本体側 0xC080 - 0xC0FF
サブ側 0x4080 - 0x40FFまで
以下、空き領域 512byte/sec.
Trk.1-79 Sec.1-9
512byte/sec.
Trk.1-159 Sec.1-9
512byte/sec.
Trk.1-159 Sec.1-15


2HD はブートセクタを 2つ連続して読み込みます。

本体側・サブ側とあるのは、FD からロードする際に一旦サブ側システムのバッファにロードしてから
8255 を介して本体側に転送した結果、同じ内容が本体側とサブ側両方にある状態を意味します。
この状態で、本体側からサブ側に対して「たった今転送してもらった内容の xxxx アドレスから実行しておいて」
と指示を出すと、サブ側はバッファ内に残ったプログラムを実行することが出来るのです。
本 ipl.bin もこの仕組みを利用しています。

当初 FAT12 互換 DOS にするつもりだった名残で 512byte/sec. になっていますが、
少しの改造で 256byte/sec や 1024byte/sec での利用も可能です。
ただし、ツールが使えないのでイメージ作成・書き込みなど自前で管理する必要があります。

気になる速度ですが、結構な部分を サブシステム側の ROM 内ルーチンに依存しているので爆速というわけにはいきません。
パラメータの受け渡し部分なども含めてハンドシェイクは 4byte 転送なのでそこそこ。
ま、速さを求めるならフォーマットから変えた方が効果が高いでしょうね。


Trk.0 の Sec.2-3 を空きにしてあります。
subsys や iosys の機能を拡張したいのであれば、ここを潰して使うことができます。
サブ CPU に何らかの処理をさせたい場合などに有効でしょう。

上記方法とは別に、サブ側は普段は通常のコマンド待ちループを回しているので、
メイン側からコマンドを投げれば、普通にサブ側処理を実行できます。
(subsys.bin での高速ロードもコマンドを受け取ってから独自処理に移行、終わったら再び待ちループに戻る。)
なので、一旦メインメモリにサブ側で実行したい処理をロードして、サブ側メモリへの転送コマンドでコピー&実行すれば
サブ CPU に任意の処理を行わせることができます。



★ メイン側メモリマップ(デフォルト)
 MAIN_RAM
 $F800-$FCFF iosys.bin メイン側ディスクルーチン(1024byte)      
 $FE00-$FFFF ディスクルーチン用バッファ(512byte)

IPL で起動直後に SP=$C000 RAM 64KB テキストVRAM=OFF、割り込み禁止にしています。
$F800 からロード/セーブやファイル検索・列挙などのサービスルーチンへのエントリを用意しています。

★ ディスクサブシステム側メモリマップ(デフォルト)
 SUB_RAM
 $4000-$51FF 2D/2DDリードバッファ(4608byte)
 $4000-$5DFF 2HDリードバッファ(7680byte)
 $5200-$7CFF 2D/2DD=11008byte フリーエリア
 $5E00-$7CFF 2HD=7936byte フリーエリア
 $7D00-$7EFF subsys.bin サブシステム側ディスクルーチン  
 $7F00-$7FFF ROM内ルーチンのワークとスタック


▲ TOP