LSI C-86 で PC-9801のDISK BIOSを使ってみる練習 READ ID
READ IDコマンドを繰り返し発行して、セクタのID情報を表示します。
/*
PC-9801フロッピーディスクBIOSを使ってみるサンプル
ドライブ0のIDを読み出す
LSI C-86 Ver.3.30 試食版用
このソースコードは CC0 パブリック・ドメイン提供です。
https://creativecommons.org/publicdomain/zero/1.0/deed.ja
2016年1月26日 佐藤恭一 kyoutan.jpn.org
READ ID コマンドを繰り返し実行して、IDを表示する。セクタの並び方がわかる。
IDが見つかり次第表示するので、第1セクタからの表示とはならないのが正常だけれど、
PC-9801エミュレータでは必ず第1セクタからの表示になり、
実機では発生しないはずの Missing Address Mark (ID) が発生する場合あり。(エミュレータによる)
エミュレータで動作テストを行う場合、FDイメージにD88形式のようなセクタの並びを再現できるフォーマットを使うこと。
PC-9801やX68000等のFDC(uPD765A)ではX1のMB8877のようにINDEX信号の状態をソフトウェアから見ることができないみたい。
READ DIAGNOSTICコマンドで先頭のセクタ番号はわかる。(たぶん)
*/
/*
メモ
LSIC86試食版の dos.h で定義されている8086のレジスタを格納する構造体
Microsoft C とはセグメントレジスタの所が少し違う
TURBO C では擬似変数を使う
union REGS {
struct XREGS {
unsigned short ax, bx, cx, dx, si, di, bp, ds, es, flags, cflag;
} x;
struct HREGS {
unsigned char al, ah, bl, bh, cl, ch, dl, dh;
} h;
};
struct SREGS {
unsigned short es, cs, ss, ds;
};
DISK BIOSコマンド識別コード
****----
||||++++- コマンド
|||+----- SEEK 1:シークを行う 0:現在のトラック
||+------ ~r 1:リトライしない 0:8回リトライする
|+------- MF 1:MFM 0:FM
+-------- MT 1:マルチトラック(同一シリンダの両面トラックのみ) 0:シングルトラック
デバイスタイプユニット番号
****00**
|||| ++- ユニット番号 (0-3)
|+++----- 000:固定ディスク 001:1MB/640K両用 111:640K
+-------- アクセスモード 0:640K 1:1M
1M/640K両用ドライブのデバイスNO
1M FD 0x9*
640K FD 0x1*
セクタ長
0:128
1:256
2:512
3:1024
*/
#include <stdio.h>
#include <dos.h>
#define DISKBIOS 0x1B
unsigned char buff[16*1024];
char *errmsg(unsigned char ah);
void main()
{
union REGS reg;
struct SREGS seg;
unsigned short pos,count;
reg.h.ah=0x07; /* RECALIBRATE */
reg.h.al=0x90; /* DRIVE #0 */
int86(DISKBIOS, ®, ®);
if(0!=reg.x.cflag)
{
puts("RECALIBRATE ERROR");
puts(errmsg(reg.h.ah));
return;
}
pos=0;
for(count=0; 16!=count; count++)
{
reg.h.ah=0x4A; /* 01001010 ID READ */
/* ||+---- SEEK */
/* |+----- ~r */
/* +------ MF */
reg.h.al=0x90; /*デバイスタイプユニット番号*/
reg.h.cl=0; /*シリンダ番号(ahのSEEKビットが1の時のみ有効)*/
reg.h.dh=0; /*ヘッド番号*/
int86(DISKBIOS, ®, ®);
if(0==reg.x.cflag)
{
/*正常終了*/
buff[pos++]=reg.h.cl; /* C シリンダ */
buff[pos++]=reg.h.dh; /* H ヘッド */
buff[pos++]=reg.h.dl; /* R セクタ番号 */
buff[pos++]=reg.h.ch; /* N セクタ長コード */
}
else
{
puts(errmsg(reg.h.ah));
break;
}
}
printf("%d\n",count);
printf("C H R N\n");
pos=0;
for( ; 0!=count; count--)
{
printf("%d ",buff[pos++]);
printf("%d ",buff[pos++]);
printf("%d ",buff[pos++]);
printf("%d\n",buff[pos++]);
}
/*segread(&seg);*/ /* セグメントレジスタの値を取得 */
}
char *errmsg(unsigned char ah)
{
switch(ah & 0xF8)
{
case 0x08:
return "Corrected data";
case 0x38:
return "Illegal disk Addres";
case 0x88:
return "Direct access an alternate track";
case 0xB8:
return "Data error";
case 0xC8:
return "Seek error";
case 0xD8:
return "Not read the alternate track";
}
switch(ah & 0xF0)
{
case 0x20:
return "DMA Boundary";
case 0x30:
return "End of cylinder";
case 0x40:
return "Equipment check over run";
case 0x60:
return "Not ready";
case 0x70:
return "Not writable";
case 0x80:
return "Error 0x80";
case 0x90:
return "Time out";
case 0xA0:
return "ID CRC error";
case 0xB0:
return "DATA CRC error";
case 0xC0:
return "No data (ID not found)";
case 0xD0:
return "Bad cylinder";
case 0xE0:
return "Missing address mark (ID)";
case 0xF0:
return "Missing address mark (DATA)";
}
return "Unknown error";
}