2016年4月14日木曜日

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, &reg, &reg);
    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, &reg, &reg);
        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";
}