開発の動機は、太古の昔に製作したS-OSハードウェアのFM音源ボードとZ80 PIO基板が発掘され、それから暫くして購入した事を忘れていたMB89352(以下、SPCと略すかも)が発掘され、これら過去の遺物からX1turboにSCSIボードを作ってみよう。 そして、256バイト/セクタの設定ができる変換番長をX1turboで・・・という事だったのですが、現在ではセクタサイズに関わらず512バイト/セクタのHDDや、2048バイト/セクタのMOディスク等が、HuBASICならびにturboCP/Mで使用可能になってしまって、変換番長要らずに・・・
まず基本となるBIOS ROM、次にHuBASICとturboCP/Mと解析をします。
参考文献3による次のアドレスから解析を進めた。
アドレス | ラベル名 | 機能 |
---|---|---|
739DH | FDCRED | 書き込み |
73AAH | FDCWRT | 読み出し |
73B7H | FDCVFY | ベリファイ |
78D9H | HDINIT | HDDの初期化 |
78E2H | HDOFFS | HDDのOFF |
解析を進めた結果、次のような具合。
アドレス | 説明 |
---|---|
78C1H~7AA2H | HDD処理ルーチン全体(482バイト) |
78D9H~ | HDINIT リゼロユニット(01H)、初期化コマンド(C2H)を実行 |
78E2H~ | HDOFFS シーク(0BH)で40523へシークを実行 |
7906H~ | FDCREDからの読み出しルーチン |
7928H~ | FDCWRTからの書き込みルーチン |
7AB8H~ | コマンド送信設定(DMA転送) |
7ABEH~ | データアウト設定(DMA転送) |
7AE2H~ | データイン設定(DMA転送) |
7B09H~7B15H | データアウト用DMAコマンド |
7B16H~7B22H | データイン用DMAコマンド |
7B23H~7B2CH | HDD初期化データ |
7EC5H~7EEFH | HDDデータDMA転送ルーチン(F929Hに展開) |
ベリファイはDMA転送でのFDアクセスと同じで、何もしていない。ただRETあるのみ。 DMAへの設定や転送ルーチンは、ポートアドレスを変えるだけで使えそう。
アドレス | ラベル名 | 説明 |
---|---|---|
F929H | HDDMAS | HDDデータDMA転送ルーチン |
FAB9H | DMAIOF | DMAアクセス対象フラグ |
FADEH | UNITNO | ドライブ番号 |
FDAFH | HDBORD | ターゲットIDビット |
FDB0H | ターゲット初期化済みフラグ | |
FDB1H | CMDTBL | コマンドコード |
FDB2H | HDDRV | LUN |
FDB3H | HDREC | 論理ブロックアドレス |
FDB5H | HDLEN | 転送長 |
FDB6H | コントロールバイト | |
FDB7H | HDSPCB | HDD初期化データバッファ(10バイト) |
表中のラベルは参考文献3からのものです。
論理ブロックアドレスの最上位は未使用。コマンドはCMDTBLに転送してから実行に移される。おそらくこれは、コマンド転送中にバンク切り替えが行われても問題が出ないような対処だろう。データ転送中は常に割り込み禁止状態でRAMバンクが選択される。これも、データ転送中に割り込みが原因でROMバンクに切り替えられては拙いからだろう。
"DISK SYSGEN.Uty"..."DISK UTILITY.Obj"の呼出しと、DEVO$でDEVI$でFATを読み書き。システム転送処理でDMAIOFを操作。
"HD FORMAT.Uty"..."DISK UTILITY.Obj"を呼出し、DEVO$でFATと代替領域の処理。もしや、代替領域無しなら、数100Kバイトの容量増が出来る?
"DISK UTILITY.Obj"...BIOSは使わず自前でHDD処理ルーチンを持ち、物理フォーマットを行う。実際には8台までサポートしている。4ヘッド、トラック数1224、セクタ数33を想定?
"HD MAP.Uty"...BASICだけで作られている事を、この件で初めて知る。DEVI$、DEVO$でFATを読み書き。使用済みクラスタを他OS領域とする?
HDOFFコマンド...ほぼHDOFFSを呼ぶだけ。
余程の事が無い限り、SCSIで物理フォーマットは不要なので、"DISK UTILITY.Obj"は何もせず正常終了を返せば良いはず。どうしても物理フォーマットがしたい場合は他でやる。あとは、BIOSが動けばそのまま動くと思われる。
turboCP/M BIOS...HDDのバスをリセットする処理がある。SCSIでは、これに対応する必要はない。
HDMAINT.COM...BIOSのFDCRED/FDCWRT。非公開なレコード領域を操作しているような・・・
HDOFF.COM...ほぼHDOFFSを呼ぶだけ。
以上の事から、HuBASICでSCSIが使える環境になれば、何もする必要はないと思われる。
とにかくBIOS・・・しかし、482バイトに収まるの?
以上を踏まえ(?)、次の様になります。
SCSIバスはシングルエンドで非同期転送のみ、I/Oアドレスは1つの8入力NANDで済むアドレスとして0F70H~0F7FHと設定しました。このポートアドレスはシャープ予約領域ですが、いままでこのアドレスを使用していないので問題無いという判断です。
まず叩き台となる回路図です。Z80バスのBUSAKをSPCのDACKにほぼそのまま接続しているため、DMAがバス制御をしているときにDREG以外へアクセスすると異常なレジスタ操作をしてしまいますが、DMAのバス制御中はDREGを対象とした転送のみ行われるため問題無いでしょう。さらに、LS245等のバストランシーバ・バスバッファを入れません。参考文献5のSPCボードの記事を見て、PC9801で大丈夫なら、よりスロット数の少ないX1turboでも大丈夫だろうと。
最終的には、回路上で汎用ロジックICの部分はBIOS解析中に発掘されたPLDに置き換え、こんな回路図になりました。なんかもう、こうなっちゃうとわけわかんないですね・・・PLDの内容はこちらです。CUPLでコンパイルしてください。本来はオープンコレクタ(又はオープンドレイン)でドライブすべきEXRDYを手抜きしてトーテムポール出力でドライブしていますが、他にそんな事をしている拡張ボードが存在するとは思えないので大丈夫でしょう(GAL16V8からGAL20V8に変更した際、OEで制御するようにしたので、他に手抜きなボードがあっても問題無し)。こちらのPLDを用いた回路では、BUSAKが有効の間は、DREGしかアクセスできないようしてあります。
なるべく一般的な部品を用いたいところですが、年代的にそうもいかないわけで・・・
ターミネータ用の集合抵抗が手に入らなければ、大変ですがバラバラの物でも良いし、アクティブターミネータを組んでも良いでしょう。ターミネータ回路の部品は、ジャンクのSCSIカードから外すと良いかもしれません。セラロックの発振回路ですが、手持ちに8MHzとHCU04があったので面白半分で作りましたが、わざわざ作らずとも発振器で済ませた方が無難な上に安価で再現性が高まります。SPCにはTTLレベル(CMOSレベルでも可)の5~8MHzを入力します。
とくに難所はありませんが、サンハヤト製X1用ユニバーサル基板(MCC-153)は寸法がおかしいので、拡張スロットに納まるように削る必要があります。配線時に、裏面(ハンダ面)の配線に厚みが出てしまうと、スロット1(上段)に入れたときに、スロット2の部品(FM音源ボード等)に引っ掛けたり、スロット2に入れようとしてパネルにぶつかる可能性もあるので、その事を考えながら作業する必要があります。
難所はある意味、SCSIコネクタをD-Subにするかどうするかという事かもしれません。D-Sub25pinのSCSIは、Macintoshやサンプラー等で使われているのでそこそこ普及していますが、日本国内では一般的と言えるかどうかは微妙な所で、このSCSIケーブルの入手性がイマイチ良くありません(そもそも、現時点でSCSIケーブルの新品なんか手に入らないか・・・)。一般的なハーフピッチのSCSIコネクタで、ケーブル接続用は手ハンダが容易な構造の物もありますが、基板取り付け用は専用基板で無いとかなり大変です。いわゆるアンフェノール50ピンは、パネルに入りきらないので困ったものです。
割り込みは使用しないので挿入するスロットは問いませんが、拡張I/Oボックスでの動作はしないかもしれません。電源を入れてから、プログラムを作ったのでは手遅れになる可能性も考えられるので、先に確認用プログラムを作ります。次の1行プログラムを入力しセーブしておきます。
100 FOR A=0 TO 7:OUT &HF70,A:PRINT INP(&HF70);:NEXT
電源を入れて本体が起動し、部品が発熱していなければ問題ありません。先のプログラムを実行して"1 2 4 8 16 32 64 128"と表示されればSPCへのアクセスは成功しています。それ以外の場合は・・・
SCSIバスを0から6までスキャンしてINQUIRYデータを表示するプログラムです。動作が非常に遅く、こんなに遅くてマシン語にしてどの程度速くなるのかと、ちょっと不安になるくらいです。
HuBASICで作ったテストプログラムの動作実績を踏まえ、同様の構成とします。既存BIOSではレコード番号が40391を超えるとエラーに飛ばしていますが、これは不要なので仕様に入れません。上限値処理は将来性を無くすのでBIOSですべきではありません。
初めは500バイトを超える大きさになってしまったため、デバッグ時には使わないであろうハードコピー処理を潰し、そこへサブルーチン群を収めました。デバッグを始めると、意外とすんなり動いたので、コードの圧縮に移ります。
コード圧縮をしてみると意外と縮まるもので、すっかり収まり、だいぶ余裕が。どんだけ無駄なコードが在ったの・・・
これで暫く使っていたのですが、X1turboで変換番長を使うのは何か勿体無い感じがして、ちょっと余り気味のHDDが使えたらいいのにな~などと考え始め、セクタ長の512バイトの前半部分だけ使って疑似的に256バイトに出来ないか・・・もしや、パディング転送って・・・参考文献2を読んでいて試してみる事に。
パディング転送に変更するには、転送の完了がコマンドコンプリート割り込みから、フェーズ遷移の確認になるだけで、プログラムはほぼ同じになりコードサイズの増加はありません。ただ疑似的に256バイトにするには1セクタ毎に処理を行なう必要があるため、その分だけコードが増えてしましたが、なんとか収まりました。
そして、テストしてみると、これが意外と使える。256バイト分のパディングをする分だけ確実に遅くなっているはずですが、そもそもの転送量が少ないためか、違いが全く分かりません。
そしてすぐ思いつくワケですが、セクタ長512バイトが使えるのなら、MOドライブは使えないものか、メディアをとっかえひっかえ出来れば、ほぼ無限の容量ではないか・・・そこで、MOドライブを接続してテストしてみると・・・やはり、案の定使えません。なぜ使えないのかというと、メディアの交換が可能なデバイスは、電源投入直後やメディア交換直後には読み書き出来ない状態(チェックコンディション)になっています。これをクリアするためには、SCSIコマンドのリクエストセンスを実行する必要があります。
すぐに対応したいところですが、セクタ長512バイトへの対応をしたため、使える様な空き領域がありません。BIOSのどこを潰すか・・・もう一生使わないであろう、8"FDD処理を・・・潰したところで、大して空かない上に5.25"FDDの処理と共通の可能性もあるため、迂闊に手を出せません。
そうしてあちこち探った末、無くなっても全く影響がでない処理を思い出しました。X1turboのIPLの隠しコマンドの1つに有るメモリクリアは無くても全く困りません。むしろ、クリアしない方が良いくらいです。(いまさら、テレビタイマーも要らないといえば要りませんが・・・)
ちょうどこのメモリクリア処理のあった領域に、MOドライブへ対応させる処理が収まりました。これでMOドライブも使えるようになり、セクタ長2048バイトの640MBメディアも使える事が分かりました。
そしてまたまた、暫く使っていたのですが、1つのデバイス(10MB)に1つのSCSI IDでは、非常に効率が悪い事が気になり出しました。どんなに容量があっても、先頭からの10MBしか使わないのはもったいない。そこで従来のHDD処理と同様の、大容量ディスクをLUNで分割使用する処理を思い付きました。通常、X1turboでは21ビットあるLBA(論理ブロックアドレス)の下位16ビットしか使用しておらず、上位5ビットは未使用(00H)になっています。ここを上手く利用すれば、32倍も使えるようになります。
LBAの上位5ビットをLUN相当として、次のようにしました。
デバイス名 | SCSI ID | LBAの範囲 |
---|---|---|
HD0: | 0 | 000000H~00FFFFH |
HD1: | 0 | 010000H~01FFFFH |
HD2: | 1 | 000000H~00FFFFH |
HD3: | 1 | 010000H~01FFFFH |
こうすることで、1つのドライブで2倍の容量が使えるようにはなったのですが、留意しておくことがあります。X1turboにおけるレコード番号の最大値は40391(16進で9DC7H)なので、通常の使い方をしている分にはデバイスを跨いでアクセスするような事はありませんが、BIOSを直接呼び出すときにLBAの末尾付近から複数ブロックのアクセスをすると、後ろのデバイスの先頭領域をアクセスしてしまうという事です。例えば、"HD0:"のFFFFHから2ブロック分のアクセスをすると、1ブロック目は"HD0:"ですが2ブロック目は"HD1:"の0000Hだという事です。
しかし、まだまだ残りがもったいない・・・
デバイス名 | SCSI ID | LBAの範囲 |
---|---|---|
HD0: | 0 | 000000H~00FFFFH |
HD1: | 0 | 010000H~01FFFFH |
HD2: | 0 | 020000H~02FFFFH |
HD3: | 0 | 030000H~03FFFFH |
1台で4ドライブ、40MBもの容量を使えるようになりました、が・・・1ドライブしか使えなくなってしまうと、バックアップを取るのが大変です。いまさらFDでのバックアップは考えられません。ということで、(その1)方式に決定したいところですが、せっかく作ったのでBIOSワークの設定で選べるようにしました。
どの程度の速度が出ているのか、気になるトコロだと思います。
Z80ではI/Oアクセスに4クロック、メモリアクセスに3クロック、都合1バイト分のアクセスには7クロック掛かり、4MHzで動作するX1turboでは1.75μsです。CPUで転送を行う場合、命令のフェッチとリフレッシュサイクル、アドレスのインクリメント等々で25クロック(6.25μs)ちょっと掛かってしまいますが、DMAの場合はI/Oとメモリへのアクセスだけで転送が完結するため7クロック(1.75μs)です。
この仕様で10MBのDMA転送をした場合に掛かる時間は18.35秒(=1.75×10485760)で、転送速度は558.04KB/秒です。これは飽くまで理論値で、Z80ではメモリもDMAの最大転送長も64Kバイトしかありませんので、10MBを小分けにして転送を行う事となり、盛大なオーバーヘッドが生じます。そもそもHuBASICで計測するため1秒程度の誤差が出るので、気にするだけ無駄でしょう。
ターゲット | 処理時間[秒] | 転送速度[KB/秒] | DMAデータ転送モード | 備考 |
---|---|---|---|---|
変換番長 | 40 | 256.00 | バイトモード | |
変換番長 | 19 | 538.95 | バーストモード | 理論値の96%の速度 |
MOドライブ | 45 | 227.56 | バイトモード | メディア容量によらず同じ |
MOドライブ | 24 | 426.67 | バーストモード | メディア容量によらず同じ |
変換番長をバーストモードで転送させると、理論値に迫る転送速度を叩き出しています。オーバーヘッドを考えると、なかなか良い結果だと思います。ちなみに、メモリ側を2クロックに設定した場合、バーストモードで640.00KB/秒でした。
但し、DMAが比較的長い期間、バスを制御する事になるバーストモードで動作させた場合、拡張スロットにDRAMを用いたEMMやバンクメモリがあると、リフレッシュ不足で内容が化ける等の障害が発生するかもしれません。
以上は、SCSI BIOSで単純な転送を行った結果なので、HuBASIC等で使用する場合とは異なります。実際にはBIOSのFDCRED/FDCWRTを使うので、さらにオーバーヘッドが加わります。
ターゲット | 処理時間[秒] | 転送速度[KB/秒] | DMAデータ転送モード |
---|---|---|---|
変換番長 | 95 | 107.79 | バイトモード |
変換番長 | 75 | 136.53 | バーストモード |
MOドライブ(128MB) | 143 | 71.61 | バイトモード |
MOドライブ(128MB) | 123 | 83.25 | バーストモード |
MOドライブ(230MB) | 142 | 72.11 | バイトモード |
MOドライブ(230MB) | 121 | 84.63 | バーストモード |
MOドライブ(640MB) | 167 | 61.32 | バイトモード |
MOドライブ(640MB) | 147 | 69.66 | バーストモード |
なんということでしょう(笑)。純粋にSCSIで転送した時に比べ、とんでもない遅さです。特にMOドライブの落ち込みが大きいのですが、いくつかのMOドライブで試したところ、機種によっては変換番長に迫るドライブ(回転速度や先読みキャッシュ処理の違い)もあるので、メーカでドライブの個性がありそうです。さらにここで特筆すべきは、640MBメディア使用時の速度の落ち込みです。これは、1セクタ長が2048バイトのため、SPCが1792(=2048-256)バイト分のパディングをしているためだと思われます。実質10MBの転送に、パディングを70MBもしています(1セクタ512バイトならパディングは10MBで済む)。128MBと230MBの差は、単純に記録密度の差によるものでしょう。
従来のデバイスで、同様のベンチマークを行った結果を見て安心してください。
ターゲット | 処理時間[秒] | 転送速度[KB/秒] |
---|---|---|
EMM | 159 | 64.40 |
MEM(GRAM) | 169 | 60.59 |
5.25"2HD | 424 | 24.15 |
5.25"2D | 821 | 12.77 |
アドレスのインクリメントもハードで行なうため超高速だと思われているEMMさん、意外と遅いんです。オーバーヘッドてんこ盛りのSCSIに勝てません。
X1turboのEMM転送ルーチン(読み出し)は次のようになっています。
1バイトの転送にDMA転送の8倍ほどの時間が掛かっています。DMAや高速化手法を用いれば速くは出来ますが、メモリ容量の限られる環境では現状がベストと言えるでしょう。このルーチンは書き換えてベリファイやMEM(GRAM)の転送処理にも使用されるため、NOPで長さの調整がされています。LF9B0: IN A,(C) ;12 LD (HL),A ; 7 NOP ; 4 NOP ; 4 INC HL ; 6 DEC DE ; 6 LD A,D ; 4 OR E ; 4 JR NZ,LF9B0 ;7/12
なぜEMMは10ドライブあるのだろうと考えた事はありませんか?FDが4台までなのはFDDのハードウェア仕様なので仕方ありません(そもそも拡張I/Oボックスを用いてもEMMを10枚も取り付けられませんが)。HDDは規格で8台(SCSIは7台)まで接続できるのですが、X1turboではFDと同じ数に制限されています。これはおそらく、IPLで起動ドライブを選択する際の0~3に合わせたものと思われます。それと、当時はHDD自体が超高価だったため、そんなに多くは接続しないだろうという考えがあったかもしれません。
『HDも10ドライブにしたいなぁ・・・』
『できるんです!!』
CZ-8FB02(おそらくCZ-8FB03も同様)は、各デバイスのドライブ数をテーブルにして持っていて、ここを書き換える事で10ドライブ、合計100MBになります。この方法は、SCSIのみならず通常のHDDでも使う事が可能です。
アドレス | デバイス名 | ドライブ数 | FDCNOの値 |
---|---|---|---|
32DCH | SCR | 1 | 0 |
32DDH | CRT | 1 | 1 |
32DEH | KEY | 1 | 2 |
32DFH | LPT | 1 | 3 |
32E0H | CAS | 1 | 4 |
32E1H | MEM | 2 | 5 |
32E2H | EMM | 10 | 6 |
32E3H | 5.25", 3" | 4 | 7 |
32E4H | 8" | 4 | 8 |
32E5H | HD | 4 | 9 |
32E6H | COM | 1 | 10 |
上記、表中のHDにあたる32E5Hの値を、4から10への変更でHD4:~HD9:が拡張され、使用可能になります。"Start up.Bas"にPOKE &H32E5,10と追加しておくと良いでしょう。
以下のような対応や、
デバイス名 | SCSI ID | LBAの範囲 |
---|---|---|
HD0: | 0 | 000000H~00FFFFH |
HD1: | 0 | 010000H~01FFFFH |
HD2: | 1 | 000000H~00FFFFH |
HD3: | 1 | 010000H~01FFFFH |
HD4: | 2 | 000000H~00FFFFH |
HD5: | 2 | 010000H~01FFFFH |
HD6: | 3 | 000000H~00FFFFH |
HD7: | 3 | 010000H~01FFFFH |
HD8: | 4 | 000000H~00FFFFH |
HD9: | 4 | 010000H~01FFFFH |
以下のように、全てを1つにも出来ます。
デバイス名 | SCSI ID | LBAの範囲 |
---|---|---|
HD0: | 0 | 000000H~00FFFFH |
HD1: | 0 | 010000H~01FFFFH |
HD2: | 0 | 020000H~02FFFFH |
HD3: | 0 | 030000H~03FFFFH |
HD4: | 0 | 040000H~04FFFFH |
HD5: | 0 | 050000H~05FFFFH |
HD6: | 0 | 060000H~06FFFFH |
HD7: | 0 | 070000H~07FFFFH |
HD8: | 0 | 080000H~08FFFFH |
HD9: | 0 | 090000H~09FFFFH |
但し、この手法では、テーブルを変更していないシステムで起動した場合には追加したHD4:以降が見えないのと、IPL起動も出来ないので注意が必要です。
10ドライブ化よりも、この方が実用性、安全性ともに高いと思います。
製作したSCSI BIOSは、レコード番号の上限チェックは無いので0~65535までの値をとる事が可能なので、16MBの領域に対応します。しかし、レコード番号40392以降の6MBはFATの管理外なので、HuBASICで使うにはDEVO$とDEVI$を用いる以外にはありません。
『HuBASICで、まるっと16MB使えたらなぁ・・・』
『できるんです!!』(またか
そのためには、増える分のFATと、増えた分への処理を行う様にBASICを改造しなければなりません。
まずFATですが、HDのFATは16MB化を見越したかのような場所に存在しているため、容易に6MB分の拡張が可能です。通常の使用開始手順と同様に"HD FORMAT.Uty"でフォーマットした後、"HD MAP.Uty"でマッピング後、次のプログラムを実行します。処理としては、既存FATの次レコードからの内容を、空きクラスタを意味する00Hで埋めているだけです。
100 A$=STRING$(128,0) 110 FOR R=28 TO 39 120 PRINT R; 130 DEVO$"HD4:",R,A$,A$ '"HD4:"は各自の環境に合わせる 140 NEXT
これで6MB分のFATの初期化は完了です。ちなみに、上記プログラムを既に使用中のドライブに対して実行しても、未使用領域を書き換えているだけなので害はありません。
次に、CZ-8FB02(おそらくCZ-8FB03も同様)に対し、増加した6MBのFATを走査するための改造を行います。HDのFAT領域はレコード番号8~27に存在し、20レコード分あります。この"20"を設定している場所が 32AFH で、ここを追加した12レコード分のFATも処理されるように、"32"へと変更します。これも、"Start up.Bas"にPOKE &H32AF,32と追加しておくと良いでしょう。
この6MBの領域はHuBASICでしか利用出来ませんが、16MBの前半8MBをturboCP/M、残りをHuBASICといった事は可能です。
但し、この手法でも、改造をしていないシステムで起動した場合には追加した6MBが見えないので注意が必要です。
実際に製作した基板の写真です。後からバンクメモリ、EMM、BASIC ROM互換フラッシュメモリを追加していったため、SCSI回路が隅に追いやられた感じになりました。回路図には入れてませんが、左下隅のLEDはTERMPWRの供給が有るときに点灯し、周辺機器の電源の切り忘れに役立っています。そしてハンダ面です。カードエッジ周辺の配線が盛り上がり過ぎて引っ掛かります・・・