* Bochs BIOS の動作などのまとめ [#h4808cf3]
このページはBochsのBIOS(rombios.c)についてまとめたページです。~
参考にしたバージョンは以下の通りです。~
 $Id: rombios.c,v 1.160 2006/01/25 17:51:49 vruppert Exp $
* もくじ [#mab3844d]
ただし、リンクは使用できません。URLに「#」がつくだけです。
#contents
----
** EBDA (Extended BIOS Data Area) [#gea8ae43]
BIOSが使用するデータバッファです。~
最大でどのくらい使われるのか分かりませんが、大きくても40KB~63KBくらいでしょう。~
640KBの低位メモリの高位(0x0009FC00~0x0009FFFFなど)が使われます。~
-Bochs BIOSでは、1KBを確保しているようです。~
-Bochs BIOSを見ると、40:0Eh(0x0000040E)にセグメントが書き込まれているようです。~
--CD-ROMブート時に使用しているみたい?
--int 74hのルーチンから使用しているみたい?
-自由に使えるメモリの最大値はint 12hで確認する必要がある。
~
** CMOS RAM の意味 (Bochs用) [#aa96121b]
|RAMアドレス|用途/意味|備考|
|0x10|フロッピーディスクドライブのタイプ(high4bits:#0,low4bits:#1)||
|0x12|ハードディスクタイプ(high4bits:#0,low4bits:#1)||
|0x19|ハードディスク#0の拡張タイプ|2Fh(47)固定?|
|0x1A|ハードディスク#1の拡張タイプ||
|0x1B~23|ハードディスクパラメータ#0||
|0x24~2C|ハードディスクパラメータ#1||
|0x2D|b5(0x20):CDブート非対応コンパイル時のブートシーケンス(=0:C,A/=1:A,C)||
|0x38|3rd(high4bits) boot device|[[値の意味はこちら>#cmos]]|
|0x38|FDブート時のboot signature disableの値(bit0)|=0:enable,=1:disable|
|0x39~3A|ATA driver: the translation policy is defined||
|0x3D|1st(high4bits)/2nd(low4bits) boot device|[[値の意味はこちら>#cmos]]|

*** 1st/2nd/3rd boot device [#cmos]
|値|意味|
|0|デバイス未定義(終了?)|
|1|フロッピーディスクドライブ #0|
|2|ハードディスクドライブ #0|
|3|CD-ROMドライブ|
~
** Power On Boot時の一連の動作 [#f9fb0651]
+ F000:E05BhへFAR JMP
+ DMACの初期化
+ CMOSのシャットダウンステータスによって分岐
+ (==0なら:) 割り込みに禁止し
+ スタックの設定,BIOSコミュニケーションエリア(seg:0040h)の初期化
+ biosメッセージの表示
+ 割り込みベクタテーブルのゼロ初期化
+ BIOSコミュニケーションエリアの初期値設定とベクタの設定
-- word [40:13h] = 639;
+ int 17,18,19,1C,12,11,15hベクタの設定
+ EBDA の初期化処理
-- byte [9fc0:0h] = 1; // size(1KB)
-- word [40:0eh] = 9fc0h;
+ PITの初期値設定(18.2Hz)とint 08hベクタの設定(1chは初期化済)
+ Keyboard(int 09,16hベクタの設定)
+ Keyboard関連のコミュニケーションエリアへの書き込み
-- byte [40:17~19,71,97h], 0h;
-- byte [40:96h], 10h;
-- word [40:1a,1c,80h], 1eh;
-- word [40:82h], 3eh;
+ キーボードの初期化処理
+ ;; mov CMOS Equipment Byte to BDA Equipment Word
-- ax = [40:10h]; al = 14h; outpb(70h, al); al = inp(71h); [40:10h] = ax;
+ パラレルポートのスキャン&設定(0378,0278h)
+ シリアルポートのスキャン&設定(03F8,02F8,03E8,02E8h)
+ CMOS/RTCのint 1A,4A,70hベクタを設定
+ timer_tick_postの呼び出し
+ PS/2マウス,FPU,VIDEOBIOSのint 74,75,10hベクタを設定
+ PICの初期化
-- マスクレジスタはマスタ:B8h,スレーブ:8Fhのようだ。
+ PCIBIOSによるIOMEM/IRQSの初期化?
+ 外部ROMのスキャン&CRC検査&実行
-- VGABIOS.BINも実行されint 10hベクタが変更されビデオモード番号が03hに設定される?
+ ROMBIOS.Cのバナー表示
+ フロッピーディスクの設定(CMOSから読み込んでコミュニケーションエリアに設定するだけ)
-- byte [40:3e,3f,40,41,42,43,44,45,46,47,48,8bh], 0;
-- CMOS(10h)の上位,下位4bitをチェックしてドライブが存在すれば[40:8f]の相当のビットを7に変更して書き込み
-- byte [40:90,91,92,93,94,95], 0;
-- al = 2h; outp (0ah, al);
-- int 1e,40(int13_diskette?),0ehベクタの設定
-- ret
+ ハードディスクドライブの設定(CMOSから読み込んでパラメータをコピー?)
-- outp(3f6h, 0ah);
-- byte [40:74,77,8c,8d,8eh], 0;
-- byte [40:75h], 1; byte [40:76h], c0h;
-- int 13,76,41,46hベクタの設定
-- ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
-- CMOS(12h)の状態に従って分岐
-- 拡張タイプの時はCMOS(19,1ah)に従う(=47(user definable?)でないとHALT?)
--- CMOS(1b~23,24~2ch)にユーザーパラメータ?
-- ATA/ATAPIドライバの初期化と存在チェック
+ CDエミュレーションの初期化?
+ boot試行(int 19hの発行)
~
----
** int 19hの動作 [#k837fc7d]
+ int19_relocated: がint 19h;で呼ばれる
+ ds = 0;
+ 1st-3rd boot device をチェック(push 1~3;call _int19_fucntion;add sp,2;test ax,ax; jnz boot_setup;)
-- 戻り値:bl = boot drive; ax = error (="0") or boot segment (exp:07C0h)
-- すべてのdeviceでbootが失敗するとint18_handlerがnear jmpで呼ばれる(int 18hをフックしても…無効?orz)
+ どれかのboot deviceが認識されるとboot_setup:に実行が移行する(dl=device,ax=segment)
+ dl = bl(boot device);  eax = eax(segment)<<4; [ret_ip], ax; eax = eax>>4; ax &= f000h; [ret_cs], ax; ax = 0; es = 0; bp = 0; ax = aa55h; iret(to IPL code);
~
----
** _int19_functionの動作 [#j782cd7e]
-結局、やっていることは指定されたブート順番の時のデバイスから、ブートできる場合はブートセグメントに読み込んで、ドライブ番号とブートセグメントを返すだけ(cd-romブート時はまた別のfunctionを呼んでいる)。 -- ''nika'' SIZE(10){2006/08/10 (木) 21:04:34}
-あれ、FDブート/HDブートの時はint 13hされるように見えるが、なぜかシングルステップ例外での監視時には検出されていないなぁ。int 19hの中でTFをクリアしているわけでも無いのになぁ。ってことはここがカギかな?。 -- ''nika'' SIZE(10){2006/08/10 (木) 21:19:22}
-int 13hをフックしてみたが、もろに無視されてbootできてしまった。メッセージ表示するためだけにフックしてチェインしていたつもりだったが表示されなかったので、int 13hを実行したら即(もちろんcliで)hltを実行させるようにしても普通に起動され…。何故だろう…。何かが干渉でもしているのか・・・? -- ''nika'' SIZE(10){2006/08/11 (金) 00:19:11}
-念のため、ソースじゃなくて逆アセンブルしてみよう…としてもこんなBIOSみたいなものに対応した逆アセンブラってあるのか・・・。 -- ''nika'' SIZE(10){2006/08/12 (土) 20:59:39}
//-NDQNrtjDkvuUrMtdLB -- ''NLaWQHPjKAQIeRHnFde'' SIZE(10){2008/09/14 (日) 19:04:13}

//#comment
 static int int19_function(char bseqhr);
 // リターン値: ax = BOOTセグメント, bl = ドライブ番号
   Bit32u 
 int19_function(bseqnr)
 Bit8u bseqnr;
 {
   Bit16u ebda_seg=read_word(0x0040,0x000E);
   Bit16u bootseq;
   Bit8u  bootdrv;
   Bit8u  bootcd;
   Bit8u  bootchk;
   Bit16u bootseg;
   Bit16u status;
   Bit8u  lastdrive=0;
 
   // BX_ELTORITO_BOOTをdefineしないでコンパイルした場合(古い方法)
   //   CMOS(0x2D)のbit5をDLのbit7にロードする.
   //   これはINT 13hの呼び出し時にセットされる(?)
   //    (0=フロッピーディスク A:, 0x80=HDD C:)
   //     0: ブートする順番はC:が最初でその後にA:
   //     1: ブートする順番はA:が最初でその後にC:
   // BX_ELTORITO_BOOTをdefineしてコンパイルした場合
   //   CMOS(0x3Dと0x38)の内容で以下のように指定する
   //     CMOS(0x3D)の下位4bit : 1st boot device
   //     CMOS(0x3D)の上位4bit : 2nd boot device
   //     CMOS(0x38)の上位4bit : 3rd boot device
   //   boot device の割り当て:
   //     0x00 : 未定義
   //     0x01 : フロッピーディスク(A:)
   //     0x02 : ハードディスク(C:)
   //     0x03 : CD-ROM(D:)
   //     その他 : ブート中断
 
   // ブートデバイスの順番を取得
   bootseq=inb_cmos(0x3d);
   bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
   // bseqhrはboot device の順番(1st/2nd/3rd)
   if (bseqnr==2) bootseq >>= 4;
   if (bseqnr==3) bootseq >>= 8;
   if (bootseq<0x10) lastdrive = 1;
   bootdrv=0x00; bootcd=0;
   switch(bootseq & 0x0f) {
     case 0x01: bootdrv=0x00; bootcd=0; break;
     case 0x02: bootdrv=0x80; bootcd=0; break;
     case 0x03: bootdrv=0x00; bootcd=1; break;
     default:   return 0x00000000;
     }
 
   // CDからブートすることができる場合
   if (bootcd != 0) {
     status = cdrom_boot();
 
     // 失敗した場合
     if ( (status & 0x00ff) !=0 ) {
       print_cdromboot_failure(status);
       print_boot_failure(bootcd, bootdrv, 1, lastdrive);
       return 0x00000000;
       }
     // 成功した場合はセグメントとドライブ値を設定
     bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
     bootdrv = (Bit8u)(status>>8);
     }
 
 
   // ハードディスクかフロッピーディスクから起動する場合
   if (bootcd == 0) {
     bootseg=0x07c0;
 
 ASM_START
     push bp
     mov  bp, sp
 
     mov  ax, #0x0000
     mov  _int19_function.status + 2[bp], ax
     mov  dl, _int19_function.bootdrv + 2[bp]
     mov  ax, _int19_function.bootseg + 2[bp]
     mov  es, ax         ;; segment  ;; BootSegment:0x07c0
     mov  bx, #0x0000    ;; offset
     mov  ah, #0x02      ;; function 2, read diskette sector
     mov  al, #0x01      ;; read 1 sector
     mov  ch, #0x00      ;; track 0
     mov  cl, #0x01      ;; sector 1
     mov  dh, #0x00      ;; head 0
     int  #0x13          ;; read sector
     jnc  int19_load_done
     mov  ax, #0x0001
     mov  _int19_function.status + 2[bp], ax
 
 int19_load_done:
     pop  bp
 ASM_END
     // 失敗した場合
     if (status != 0) {
       print_boot_failure(bootcd, bootdrv, 1, lastdrive);
       return 0x00000000;
       }
     }
 
   // CMOS(0x38)でフロッピーディスクブートが指定
   // された場合のみ、signuatureをチェックする
   // bootchk = 1 : signature check disabled
   // bootchk = 0 : signature check enabled
   if (bootdrv != 0) bootchk = 0;
   else bootchk = inb_cmos(0x38) & 0x01;
 
   // CDブート時はsignatureチェックをしない
   if (bootcd != 0)
     bootchk = 1;
 
   if (bootchk == 0) {
     if (read_word(bootseg,0x1fe) != 0xaa55) {
       print_boot_failure(bootcd, bootdrv, 0, lastdrive);
       return 0x00000000;
       }
     }
   
   // 起動メッセージの表示
   print_boot_device(bootcd, bootdrv);
 
   // リターン値としてブートセグメントを返す
   return (((Bit32u)bootdrv) << 16) + bootseg;
 }


** [#c03f658f]
''(書きかけ)''
~
~
~
----
* FDCのレジスタ [#jb063922]
** I/Oレジスタ周りの配置 [#zbd6745f]
|IOアドレス(FDC#1/#2)|レジスタ名|読み書き|意味|備考|
|3F0/370h|ステータスレジスタA|R||本家ATには無い|
|3F1/371h|ステータスレジスタB|R||本家ATには無い|
|3F2/372h|ディジタルアウトプットレジスタ|W|||
|3F3/373h|テープドライブレジスタ|RW||テープサポートが無ければ関係ない|
|3F4/374h|メインステータスレジスタ|R|||
|3F4/374h|データレートセレクトレジスタ|W||本家ATには無い|
|3F5/375h|データレジスタ(FIFO)|RW|||
|3F7/377h|ディジタルインプットレジスタ|R|||
|3F7/377h|コンフィグレーションコントロールレジスタ|W|||
~
** I/Oレジスタの意味とビット配置 [#k098eee4]
-ステータスレジスタA(03F0h) Read Only (本家ATには無い)~
--bit7:IRQ6
---FDCからの割り込みライン(IRQ6)の状態が読める
--bit6:DRV#2(セカンドドライブコントロール)
---'1':2台目のFDDはない
---'0':2台目のFDDはある
--bit5:STEP
---FDCのSTEP信号出力(ヘッド移動パルス)が読める
--bit4:TRACK0#
---FDCのTRK0信号入力(ヘッドの0トラック検出信号)が読める
---'0':ヘッドはトラック0の位置にある
--bit3:HDSEL
---FDCのHDSEL信号出力(ヘッド表裏選択)が読める
---'0':ドライブ#0/#2を選択中
--bit2:INDEX#
---FDCのINDEX信号入力(FDが1回転するごとに1パルスが出る)が読める
--bit1:WP#
---FDCのWP#信号入力(FDが書き込み禁止信号)が読める
---'0':FDは書き込み禁止
--bit0:DIR
---FDCのDIR信号出力(ヘッドをどちらに動かすかを決める信号)が読める
---'0':0トラック方向(外周方向)
~
-ステータルレジスタB(03F1h) Read Only (本家ATには無い)~
--bit7~6:未使用(常に'1')
--bit5:DR0
---ドライブセレクト0:DORのbit0が読める
--bit4:WDATA
---FDCへのデータ書き込み信号(WDATA)の立ち下がりがあると変化
--bit3:RDATA
---FDCからデータ信号(RDATA)の立ち下がりがあると変化
--bit2:WGATE
---FDCへのWGATE信号が読み出される
--bit1:MTR1
---MTR1出力(ドライブ#1モータON信号)の状態が読み出される
---'1':モータON
---'0':モータOFF
--bit0:MTR0
~
-デジタルアウトプットレジスタ(03F2h) Write Only (PS/2以降はReadも可能)
--bit7:MTR3(ドライブ#3モータON/OFF)
---'1':モータON(回転開始)
---'0':モータOFF(回転停止)
--bit6:MTR2
--bit5:MTR1
--bit4:MTR0
--bit3:DMAEN(DMA/割り込み動作イネーブル)(PS/2では常時%%%'0'でイネーブル%%%)
---'1':DMA/割り込み信号イネーブル
---'0':DMA/割り込み信号ディセーブル
--bit2:RESET#
---'1':津常動作
---'0':FDCをリセットする
--bit1~0:DRVSEL(ドライブセレクト)
---'11':ドライブ#3選択
---'10':ドライブ#2選択
---'01':ドライブ#1選択
---'00':ドライブ#0選択
~
-テープドライブレジスタ(03F3h) Read Write
--bit7~2:未使用
--bit1~0:テープ.ドライブ選択
---'11':テープ#3
---'10':テープ#2
---'01':テープ#1
---'00':無効
~
-メインステータスレジスタ(03F4h) Read Only
--bit7:RQM(Request for Master)
---'1':FDCがデータ/コマンドを受け付け可
---'0':FDCはデータ/コマンド処理中(BUSY?)
--bit6:DIO(Data-I/O:転送方向)
---'1':リード方向(FDC→CPU)
---'0':ライト方向(CPU→FDC)
--bit5:NDM(Non-DMAモード)
---'1':実行フェーズにDMAを使わない
---'0':実行フェーズでDMAを使う
--bit4:CB(FDCビジー)
---'1':FDCがビジー状態(次のコマンド受け付け不可)
---'0':FDCはレディー状態
--bit3:D3B(FD3ビジー)
---'1':FD#3がシーク中/シーク完了割り込み保留中
---'0':通常動作
--bit2:D2B(FD#2ビジー)
--bit1:D1B(FD#1ビジー)
--bit0:D0B(FD#0ビジー)
~
-データレートセレクトレジスタ(03F4h) Write Only (本家ATには無い)
--bit7:S/W RESET (PS/2ではリザーブ)(こちらは自動でリセット解除される)
---'1':通常動作
---'0':FDCをリセットする
--bit6:LOW POWER (PS/2ではリザーブ)
---'1':低消費電力モードになり、動作停止
---'0':通常動作
--bit5:未使用
--bit4~2:プレコンベンセーション(書き込み補償)
---'111':0.0ns
---'110':250ns
---'101':208ns
---'100':167ns
---'011':125ns
---'010':83.3ns
---'001':41.7ns
---'000':デフォルト(データレートに応じて決まる)~
   ・1Mbps時      :41.7ns~
   ・500/300/250kbps時:125ns
--bit1~0:データレート~
・MFMモード(倍密)時
---'11':1Mbps
---'10':500kbps
---'01':300kbps
---'00':250kbps
--~
・FMモード(単密)時
---'11':---
---'10':250kbps
---'01':150kbps
---'00':125kbps
~
-データレジスタ(03F5h) Read Write
--bit7~0:FIFO
---データレジスタ
~
-デジタルインプットレジスタ(03F7h) Read Only
--bit7:DSKCHG
---'1':ディスクが交換された
---'0':通常動作
--bit6-3:未使用(PS/2)
--bit2-1:データレート(PS/2)
--bit0:HIGHDEN#(PS/2)
---'0':1Mbps/500kbps
~
-コンフィギュレーションコントロールレジスタ(03F7h) Write Only
--bit7~2:未使用
--bit1~0:データレート
---データレートセレクトレジスタのbit1~0と同じ
~
~


** FDCの制御手順 [#cbb8cb84]
FDCの動作は以下の3つのフェーズを経て行われます。
*** コマンド(C)フェーズ [#db58d095]
 FDCがアイドル状態(MSR=80h)にあるとき, CPUはFDCへのコマンドの書き込みを開始できます. 
コマンドは1~2バイトで, さらにパラメータが付いて最大9バイトを書き込みます. 
パラメータの省略はできないので, 必ず必要なバイト分すべてを書き込みます.~
 コマンドの書き込みはMSRのRQM = "1", DIO = "0"を確認しながら行います. 
もしFDCがコマンド異常を検出すると, 最後のリザルトフェーズに移行しますが, このときにはDIO = "1" となるので, 異常発生がわかります.~
 コマンドフェーズが終了すると, FDCはエグゼキューションフェーズに移行します. 例外は,~
     ・SENSE INTERRUPT STATUS(直接リザルトフェーズに移行)~
     ・SENSE DEVICE STATUS(直接リザルトフェーズに移行)~
     ・SPECIFY(コマンドフェーズだけで終了)~
などのFDDへのアクセスが不要なコマンド群です.~

*** エグゼキューション(E)フェーズ [#hd98c555]
 コマンドを受け取ると, FDCはCOLOR(red){エグザキューションフェーズに移行}します. 
FDのリード/ライトや, COLOR(red){ヘッドシーク}(ヘッドの移動)などが行われます. 
DMAモードに設定していれば, FDのリード/ライト系コマンドのエグゼキューションフェーズでDMA転送要求が行われます.~
 PCの場合, FDCとのデータ転送は, DMAを用いて行うのがふつうの使い方です. 
エグゼキューションフェーズが完了すると, 通常FDCはリザルトフェーズに移行するとともにホストに割り込みをかけます.~
 例外はSEEKやRECALIBRATE(0トラックへのシーク), RELATIVE SEEKです. 
これらはRフェーズがないので, 動作完了後に割り込みが発生した後, SENSE INTERRUPT STATUSコマンドを発行して結果を引き取ります.~
~

*** リザルト(R)フェーズ [#k944c7c7]
 コマンドのCOLOR(red){実行結果ステータス}を通知するのがこのフェーズです.  
コマンドの種類に応じて1~7バイトのステータスを引き取ります.~
 リザルトフェーズでは1バイトの転送ごとにMSRのRQMが "1" になり, またDIOビットは "1" になっています. 
ステータスはすべて引き取らないと, 次のコマンドが発行できません.~
 ステータスが残っているときはDIO = "1", すべて引き取るとDIOビット="0"となるので, ステータスの引き取りが完了したかを判断することができます.~
~

** FDCコマンド/パラメータ [#e772c0a9]
以下はFDCドライバより引用
 dd	00001b,	4, __mode
 dd	00010b,	8, _readdiagnostic
 dd	00011b,	2, _specify
 dd	00100b,	1, _sensedevicestatus
 dd	00101b,	8, _writedata
 dd	00110b,	8, _readdata
 dd	00111b,	1, _recalibrate
 dd	01000b,	0, _senseinterruptstatus
 dd	01001b,	8, _writedeleteddata
 dd	01010b,	1, _readid
 dd	01100b,	8, _readdeleteddata
 dd	01101b,	5, _writeid
 dd	01111b,	2, _seek
 dd	10001b,	8, _scanequal
 dd	11000b,	0, __nsc
 dd	11001b,	8, _scanloworequal
 dd	11101b,	8, _scanhighorequal
 dd	-1

** FDCコマンド/パラメータ詳細 [#da4edb02]
*** READ DATA (MT/MF/SK/0/0/1/1/0)(ビット配置) [#z0a3b667]
-Cフェーズ(Write)
--MT,MF,SK,0,0,1,1,0
--X,X,X,X,X,HD,US1,US0
--C
--H
--R
--N
--EOT
--GSL
--DTL
-Eフェーズ(Read)
--DMA転送(ひたすらデータ転送してください)
-Rフェーズ(Read)
--ST0
--ST1
--ST2
--C
--H
--R
--N
---C/H/R/Nについて~
正常終了:実行終了セクタの次のセクタID~
異常終了:実行終了セクタのID
-~
 FDからデータを読み出します. コマンド中, US0/US1でアクセスするドライブ番号を, HDでアクセスするヘッドを指定します. ヘッドの四厘だ位置(トラック位置)は, 自前にSEEKコマンドを使って位置づけしておく必要があります. ~
 PS/2(N82077)以降の拡張機能である, COLOR(red){Implied SEEK}を行うように設定している場合には, 次に指定するCHRNパラメータのC(Cylinder)の位置に自動的にシークします.~
 ヘッドがアンロード状態にあるときは, ヘッドロード信号を出力し, SPECIFYコマンドのCOLOR(red){HLT(Head Load Time)}だけ待った後アクセスを開始します. ~
 転送完了はホスト側からTC信号で通知しまし. PCでは通常DMAを使うので, DMAの転送カウンタが0になったときに自動的にTCが出力されます. ~
 1セクタのリードが完了した後, TCが出力されないとFDCは自動的に次のセクタ(セクタ番号が1大きいセクタ)を探しに行きます. また, セクタの途中でTCが出力された場合には, FDCはそれ以上のデータはホストに転送しませんが, データリード自体は継続し, 最後にCOLOR(red){CRCチェック}を行います. ~
 代表的なエラーとその応答は以下の通りです. ~
-(1) NR (Not Ready)~
 コマンド実行時にドライブがレディ状態になっていないと, ST0のNRビットを "1" にして, コマンド実行を異常終了します.~
-(2) MA (Missing Address Mark)~
 コマンドが受け付けられると, FDCは指定されたCHRNパラメータと一致するセクタを探します. FDDはメディアが1回転するたびにINDEXパルスをFDCに送ってきますが, このINDEXパルスが2回検出するまでCHRNデータの開始を示すIDAM(ID Address Mark)を見つけられないと, ST1のMAビットを "1" にしてコマンドを異常終了します.~
-(3) MD (Missing Address Mark in Data Field)~
 指定されたCHRNパラメータをもったセクタが見つかった後, 一定時間たってもデータフィールドの種別を示すDAM(Data Address Mark)かDDAM(Deleted Data Address Mark)が見つからないとST1のMAビットとST2のMDビットを "1" にしてコマンドを異常終了します.~
-(4) ND (No Data)~
 IDAMは見つかったが, コマンドのCHRNパラメータと一致するセクタが見つからない場合, ST1のNDビットを "1" にしてコマンドを異常終了します.~
 さらに, この場合FD上のセクタのC(Cylinder)データがコマンドで与えられたCデータと一致しない場合, さらに以下のステータスビットがセットされます. ~
  ・FD上のセクタのCデータがFFhだったとき~
   ST2のBC(Bad Cylinder)ビットを "1" にする~
  ・FD上のセクタのCデータがFFh以外だったとき~
   ST2のNC(No Cylinder)ビットを "1" にする~
-(5) DE (Data Error) /DD (Data Error in Data Field)~
 FD上ではID情報やデータの直後にエラーチェック用のCRCデータが記録されています(FDへの書き込み時に自動的に付加される). FDCはリード時にこのCRCと読み取ったデータから生成したCRCデータを比較しています.~
 ID情報のCRCが一致しないときはDEビットを "1" にしてコマンドを異常終了します. また, データ領域のCRCが一致しないときはDEとDDの両方を "1" にして, コマンドを異常終了します.~
-(6) CM (Control Mark)~
 読み取ろうとしたセクタのDAMの位置にDDAMが書き込まれていた場合, ST2のCMビットが "1" になります.~
 このとき, コマンドのSK(Skip)ビットが "1" であれば, このセクタへのアクセスは行わず, 次のセクタを処理にいきます. "0" であれば, このセクタのデータ転送を行った後コマンドを正常終了します.~
-(7) OR (Overrun)~
 INTやDRQ信号による転送要求から13μs(500kbosの場合)以内にホスト側が応答しないと, ST1のORビットを "1" にしてコマンドを異常終了します. ~
-(8) EN (End of Cylinder)~
 1セクタ分のデータ転送が終わった後, TCが入力されないと, FDCは次のセクタ(CHRNパラメータのうちRがひとつ大きいセクタ)をアクセスします. もし, コマンド中のEOT(End Of Track)と同じR値のセクタのアクセスが終わってもTCが入力されないと, ST1のENビットを "1" にしてコマンドを異常終了します.~

*** READ DELETED DATA (MT/MF/SK/0/1/1/0/0) [#o2410bb9]
-Cフェーズ(Write)
--MT,MF,SK,0,1,1,0,0
--X,X,X,X,X,HD,US1,US0
--C
--H
--R
--N
--EOT
--GSL
--DTL
-Eフェーズ(Read)
--DMA転送(ひたすらデータ転送してください)
-Rフェーズ(Read)
--ST0
--ST1
--ST2
--C
--H
--R
--N
---C/H/R/Nについて~
正常終了:実行終了セクタの次のセクタID~
異常終了:実行終了セクタのID
-~
 DDAMとDAMの扱いが逆になるほかは, READ DATAコマンドとほぼ同じです.~

*** READ ID (0/MF/0/0/1/0/1/0) [#v214a1d1]
-Cフェーズ(Write)
--0,MF,0,0,1,0,1,0
--X,X,X,X,X,HD,US1,US0
-Eフェーズ
--(無い)
-Rフェーズ(Read)
--ST0
--ST1
--ST2
--C
--H
--R
--N
-~
 ヘッドロード後, 最初に見つけたCOLOR(red){正常な}(DEエラーやMAエラーのない)セクタのID情報(CHRNデータ)をRフェーズの情報として返します. トラック中のどのセクタが最初に見つかるかは不定です.~

*** WRITE ID (0/MF/0/0/1/1/0/1) [#n2328829]
-Cフェーズ(Write)
--0,MF,0,0,1,1,0,1
--X,X,X,X,X,HD,US1,US0
--N
--SC
--GPL
--D
-Eフェーズ(Write)
--(1トラック分のID情報:4バイト/セクタ, セクタ数分)
-Rフェーズ(Read)
--ST0
--ST1
--ST2
--C
--H
--R
--N
---C/H/R/Nについて~
C/H/Rデータに意味は無い~
NはCフェーズのNと同一データ~
-~
 1トラック分の情報書き込みを行うコマンドです. COLOR(red){物理フォーマットコマンド}といったほうがわかりやすいかもしれません. 実際, 「FORMAT TRACK」コマンドと表記しているものもあります.~
 Eフェーズでホストから転送するデータは各セクタのCHRN情報です. 1セクタ当たり4バイトなので, ホストからはセクタ数×4バイト分の転送が行われることになります.~
 CHRN情報以外のデータ(アドレスマークやギャップなど)はFDCが自動的に書き込みを行います. また, 各セクタのデータ領域はコマンドのDバイトで指定した値で埋めつくされます. E5hがもっともきびしいデータであるとして, チェックを兼ねてよく使われた時代もありましたが, 最近はあまり気にせず, 00hを使用しています.~

*** WRITE DATA (MT,MF,0,0,0,1,0,1) [#nfb41735]
-Cフェーズ(Write)
--MT,MF,0,0,0,1,0,1
--X,X,X,X,X,HD,US1,US0
--C
--H
--R
--N
--EOT
--GSL
--DTL
-Eフェーズ(Write)
--DMA転送(ひたすらデータ転送してください)
-Rフェーズ(Read)
--ST0
--ST1
--ST2
--C
--H
--R
--N
---C/H/R/Nについて~
正常終了:実行終了セクタの次のセクタID~
異常終了:実行終了セクタのID
-~
 指定されたCHRNパラメータと同じセクタを見つけ, そこにDAM(Data Address Mark)を書き込んだ後, ホストからの転送データの書き込みを行います. ~
 READ DATAコマンドと同じようなエラーのほか, 以下のようなエラーの可能性があります.~
-(1) NW (Not Writable)~
 FDDは実装されたFDが書き込み禁止になっていると, !WP信号をアサートしてFDCに対して書き込み禁止になっていることを通知します. WRITE DATAコマンド実行時に書き込み禁止であることがわかると, ST1のNWbittoを "1"にして異常終了します.~
-(2) EC (Equipment Check)~
 データのCRCとギャップを1バイト書き込んだ後でFDDからのFLT(Fault)信号がアサートされていると, ST0のECビットを "1" にして異常終了します. ~
 PCの場合, FLT信号がないので, このエラーは発生しません.~

*** WRITE DELETED DATA (MT,MF,0,0,1,0,0,1) [#gab7a049]
-Cフェーズ(Write)
--MT,MF,0,0,1,0,0,1
--X,X,X,X,X,HD,US1,US0
--C
--H
--R
--N
--EOT
--GSL
--DTL
-Eフェーズ(Write)
--DMA転送(ひたすらデータ転送してください)
-Rフェーズ(Read)
--ST0
--ST1
--ST2
--C
--H
--R
--N
---C/H/R/Nについて~
正常終了:実行終了セクタの次のセクタID~
異常終了:実行終了セクタのID
-~
 WRITE DATAコマンドではセクタにDAM(Data Address Mark)を書き込みますが, このコマンドではDDAM(Deleted Data Address Mark)を書き込みます. それ以外の機能はWRITE DATAと同じです.~

*** READ DIAGNOSTIC (0,MF,0,0,0,0,1,0) [#g02d4a32]
(これはサポートしないFDCが多い)
-Cフェーズ(Write)
--0,MF,0,0,0,0,1,0
--X,X,X,X,X,HD,US1,US0
--C
--H
--R(無意味)
--N
--EOT
--GSL
--DTL
-Eフェーズ(Read)
--データ転送
-Rフェーズ(Read)
--ST0
--ST1
--ST2
--C
--H
--R
--N
---C/H/R/Nについて~
正常終了:実行終了セクタの次のセクタID~
異常終了:実行終了セクタのID
-~
 μPD765にはあるのですが, PS/2仕様以降削除されたと思われるコマンドです. DIAGNOSTICという言葉でわかるように, COLOR(red){通常使用するようなものではない}からかもしれません. ~
 READ DATAコマンドとの違いは以下のとおりです. ~
--ST, MKビットはありません.
--CHRNパラメータのうち, RバイトはFDC側で強制的に01hとなります.
--処理はINDEXパルスが入った直後のセクタから開始されます.
--読み取ったセクタのCHRNデータとFDC側で保持しているCHRNパラメータを比較します.
--CHRNデータが一致しないとST1のNDビットを "1" にしますが, 動作はそのまま強行して正常終了します.
--CRCエラーが発生しても, DEやDDビットを "1" にするだけで, 動作はそのまま強行して, 正常終了します.
--DDAMを検出したときもCMビットを "1" にするだけで, 終了はしません.
--RフェーズのCHRNにはエラーを検出したセクタのIDは入らないので, どのセクタに異常があったかの判別はできません.

*** SCAN EQUAL (MT,MF,SK,1,0,0,0,1) [#zdf2b864]
-Cフェーズ(Write)
--MT,MF,SK,1,0,0,0,1
--X,X,X,X,X,HD,US1,US0
--C
--H
--R
--N
--EOT
--GSL
--STP
-Eフェーズ(Write)
--比較データの書き込み
-Rフェーズ(Read)
--ST0
--ST1
--ST2
--C
--H
--R
--N
---C/H/R/Nについて~
比較した最終セクタが返される。
-~
 各セクタ単位で, ホストから送られてくるデータとFDのCOLOR(red){データを比較}します. 最初に送られるデータが上位桁という扱いで比較が行われます. ~
 ホスト, またはFD側のデータがFFhの場合は比較を行わず, 常に一致したものとして次のデータの比較に移ります. 各比較条件が成立するセクタがあれば, その時点でコマンド処理を正常終了します. このときST2のSH(Scan Hit)ビットが "1" になります.~
 もしEOTで示される最終セクタまで比較しても条件を満足するセクタがなかったときは, ST2のSN(Scan Not Satisfied)ビットを "1" にして, コマンドを正常終了します.

*** SCAN LOW OR EQUAL (MT,MF,SK,1,1,0,0,1) [#sa8ee0c4]
-Cフェーズ(Write)
--MT,MF,SK,1,1,0,0,1
--X,X,X,X,X,HD,US1,US0
--C
--H
--R
--N
--EOT
--GSL
--STP
-Eフェーズ(Write)
--比較データ書き込み
-Rフェーズ(Read)
--ST0
--ST1
--ST2
--C
--H
--R
--N
---C/H/R/Nについて~
比較した最終セクタが返される。
-~
→SCAN EQUAL

*** SCAN HIGH OR EQUAL (MT,MF,SK,1,1,1,0,1) [#p9f8746f]
-Cフェーズ(Write)
--MT,MF,SK,1,1,1,0,1
--X,X,X,X,X,HD,US1,US0
--C
--H
--R
--N
--EOT
--GSL
--STP
-Eフェーズ(Write)
--比較データ書き込み
-Rフェーズ(Read)
--ST0
--ST1
--ST2
--C
--H
--R
--N
---C/H/R/Nについて~
比較した最終セクタが返される。
-~
→SCAN EQUAL

*** SEEK (0,0,0,0,1,1,1,1) [#g5dde0d8]
-Cフェーズ(Write)
--0,0,0,0,1,1,1,1
--X,X,X,X,X,HD,US1,US0
--NCN
-Eフェーズ
--(none)
-Rフェーズ
--SENSE INTERRUPT STATUSを発行してください
-~
 FDDのCOLOR(red){ヘッドを指定されたシリンダ位置まで移動}させます. FDC内部には現在のヘッドのシリンダ位置を保持しているレジスタがあり, これとコマンドで与えられたシリンダ番号を比較して, 移動方向と必要な回数のステップパルスを発生します, このコマンドはRフェーズがありません. SEEK動作が完了すると割り込みを発生するので, SENSE INTERRUPT STATUSコマンドを発行して実行結果を引き取ります.~
 FDD側からシリンダ位置データがくるわけではないので, COLOR(red){実際にヘッドが正しい位置}にきたかどうかはわかりません. 運悪く何らかの理由で位置決めに失敗するとFDアクセスに失敗することになります.~
 このようなときのためにFDD, FDCともCOLOR(red){シリンダ位置}を0にもってくるコマンドが次のRECALIBRATEです.

*** RECALIBRATE (0,0,0,0,0,1,1,1) [#o975314d]
-Cフェーズ(Write)
--0,0,0,0,0,1,1,1
--X,X,X,X,X,HD,US1,US0
-Eフェーズ
--(none)
-Rフェーズ
--SENSE INTERRUPT STATUSを発行してください
-~
 FDDには, ヘッドが0シリンダにあるかどうかをCOLOR(red){検出する機構}があり, この情報が, FDCにも伝えられています(!TRK0信号). これを使って, FDDとFDCの両者ともヘッドがCOLOR(red){0シリンダにある状態に初期化する}のがこのRECALIBRATEコマンドです.~
 RECALIBRATEコマンドを発行すると, FDCはTRK#0信号がアサートされるまでヘッドを0トラック方向に移動するようステップパルスを発生します. TRK#0信号が検出されたら, その時点でヘッド移動を停止し, 内部のヘッド位置を管理しているレジスタも0にクリアします.~
 ただし, RECALIBRATEコマンドで発生できるCOLOR(red){ステップパルスの数には制限がある}ので, 注意が必要です. μPD765の場合, 発生できるステップパルスの最大値が77でした. PCでよく使われる720Kバイトや1.44Mバイトフォーマットでは80シリンダ使うので, 1回のRECALIBRATEコマンドではヘッドを戻せないことになります. ~
 このため, いったん真ん中付近のシリンダにSEEKしてからRECALIBRATEしたり, 1回目のRECALIBRATEコマンドでエラーが出ることを容認したうえで, 2回のRECALIBRATEコマンドを発行するなどの細工が必要でした.~
 N82077では85シリンダまで移動可能になりましたし, MODeコマンドのR255ビットを "1" に設定すれば, 255シリンダ, さらにETRビットを "1" にすることで4095シリンダまで移動可能となり, 垂直記録のような高密度デバイスにも対応できるようになっています.~
 このコマンドもRフェーズがなく, 結果は完了割り込み発生後にSENSE INTERRUPT STATUSコマンドを発行して実行結果を引き取ります.

*** SENSE INTERRUPT STATUS (0,0,0,0,1,0,0,0) [#h83252ba]
-Cフェーズ(Write)
--0,0,0,0,1,0,0,0
-Rフェーズ(Read)
--ST0
--PCN
-~
 SEEKやRECALIBRATEコマンドの終了結果や, コマンド実行中でないデバイスの状態遷移(Not READYからREADYになったなど)を通知するものです.~
 このような要因がないときにこのコマンドを発行すると, Invalidコマンド扱いとなり, ステータス80hが返されます.

*** SENSE DEVICE STATUS (0,0,0,0,0,1,0,0) [#eb3ae8c4]
-Cフェーズ(Write)
--0,0,0,0,0,1,0,0
--X,X,X,X,X,HD,US1,US0
-Rフェーズ(Read)
--ST3
-~
 デバイスの状態遷移を示すステータスを返します. PCの場合, FLT, READY, 2SIDE信号は存在しませんので, これらがセットされることはありません.

*** SPECIFY (0,0,0,0,0,0,1,1) [#f1190e7e]
-Cフェーズ(Write)
--0,0,0,0,0,0,1,1
--SRT(4bits),HUT(4bits)
--HLT(7bits),ND(1bit)
-Rフェーズ
--(none)
-~
 各ドライブのヘッド移動信号のパルス周期や, ヘッドをアンロード(メディアから離れている)状態からロード(メディアに密着している)にするまでの時間, コマンド実行後, ヘッドをアンロード状態にするまでの時間, EフェーズでDMA転送を行うか否かなどの設定を行います.

*** CONFIGURE (0,0,0,1,0,0,1,1) [#r480645f]
-Cフェーズ(Write)
-Rフェーズ
--(none)
-~
 N82077以降の拡張コマンドです. μPD765にはなかったCOLOR(red){Implied SEEK}機能や, COLOR(red){FIFO}などを使うか否かなどを設定します.

*** DUMPREG (0,0,0,0,1,1,1,0) [#ha76391e]
-Cフェーズ(Write)
-Rフェーズ(Read)
-~
 FDC内部で保持している各種データを読み出すコマンドです.

*** READ TRACK (0,MF,0,0,0,0,1,0) [#c7ba2ac9]
-Cフェーズ(Write)
-Eフェーズ(Read)
--DMA転送?(ひたすらデータ転送してください)
-Rフェーズ(Read)
--ST0
--ST1
--ST2
--C
--H
--R
--N
---C/H/R/Nについて~
正常終了:実行終了セクタの次のセクタID~
異常終了:実行終了セクタのID
-~
 READ DATAコマンドとほぼ同じようなものですが, 以下の点が異なります.
--R(セクタ番号)パラメータの値は無視され, セクタ番号01hから読み始めます.
--MTやSKビットは無効です
--CRCエラーが発生すると, DEやDDビットを "1" にしますが, リード動作は強行します.

*** RELATIVE SEEK (1,DIR,0,0,1,1,1,1) [#n6a972a2]
-Cフェーズ(Write)
-Eフェーズ
--(none)
-Rフェーズ
--SENSE INTERRUPT STATUSを発行してください
-~
 SEEKコマンドがヘッドの絶対位置を与えるのに対して, このコマンドはCOLOR(red){相対位置}を与えてシークさせます.

*** VERIFY (MT,MF,SK,1,0,1,1,0) [#u24e28a5]
-Cフェーズ(Write)
-Eフェーズ
--実際のデータ転送は無い
-Rフェーズ(Read)
--ST0
--ST1
--ST2
--C
--H
--R
--N
---C/H/R/Nについて~
正常終了:実行終了セクタの次のセクタID~
異常終了:実行終了セクタのID
-~
 与えられたセクタ番号と一致するセクタを見つけ出し, そこにDAM(Data Address Mark)が書き込まれていることや, IDやデータ部分にCRCエラーがないか確認します. Eフェーズでは確認するだけで, ホストとの間のデータ転送は行われません.~
 フォーマット後の, COLOR(red){不良セクタでないかの確認用に使用可能}なコマンドです.

*** VERSION (0,0,0,1,0,0,0,0) [#fb345b37]
-Cフェーズ(Write)
--0,0,0,1,0,0,0,0
-Rフェーズ(Read)
--1,0,0,VER,0,0,0,0
-~
 FDCがμPD765相当か, N82077相当の機能をもっているかを判断するためのコマンドです. N82077相当であれば, このコマンドに対して90hが返りますが, μPD765相当であれば, このコマンドは無効(Invalid)扱いなので, 80hが返ります.

*** MODE (0,0,0,0,0,0,0,1) [#f7eed9d4]
-Cフェーズ(Write)
-Rフェーズ
--(none)
-~
 NS社の拡張コマンドです. 3.5インチFDの3モード(1.2Mバイト)サポートでも使用されます.

*** NSC (0,0,0,1,1,0,0,0) [#bb104aef]
-Cフェーズ(Write)
--0,0,0,1,1,0,0,0
-Rフェーズ(Read)
--0,1,1,0,0,0,1,1または1,0,0,0,0,0,0,0
-~
 FDCがNS社製(または互換品)であるかどうかを判断するためのコマンドです. NS社品なら73hが, 違うものならばInvalidコマンド扱いなので80hが返ります.

** FDCコマンドのパラメータ [#n5ded496]
*** BFR (CMOS Disk Interface Buffer Enable) [#ibb19721]
*** BST (Burst Mode Disable) [#rc40607d]
*** C(Cylinder), H(Head), R(Record), N(Record Length) [#uc161a4a]
*** D (Data) [#l627cddc]
*** DC0~DC3 [#f77f3f7b]
*** DENSEL (Density Select) [#h16f424d]
*** DIR (Direction) [#k301fdcf]
*** DTL (Data Length) [#gc036851]
*** EC (Enable Count) [#vee00aff]
*** EFF (Enable FIFO) [#l46d5e3d]
*** EIS (Enable Implied Seeks) [#aad30197]
*** EOT (End Of Track) [#q809c7e0]
*** ETR (Extended Track Range) [#da369be9]
*** FRD (FIFO Read Disable) [#k952770f]
*** FWR (FIFO Write Disable) [#d209e8d7]
*** GAP, WG [#g8e60a15]
*** GPL (Gap Length) [#v7f98e93]
*** GSL (Gap Skip Length) [#dcf2aa14]
*** HD (Head) [#md7b15f7]
*** Head Settle [#e4efeaa3]
*** HLT (Head Load Time) [#v2ac301c]
*** HUT (Head Unload TIme) [#t34a49c4]
*** AF (Index Address Format) [#g88b41b8]
*** IPS (Implied Seek) [#p5f4cafc]
*** LOWPWR (Low Power) [#uc2633d2]
*** MF (MFM Mode) [#v3726a73]
*** MT (Multi-Track) [#rfe10f9b]
*** NCN (New Cylinder Number) [#taf011ff]
*** ND (Non-DMA) [#g94c7f87]
*** OW (Overwrite) [#e3ee601c]
*** PD (Polling Disable) [#r8660f1a]
*** PU (PUMP Pulse OUTput Diagnostic) [#n0074930]
*** PT0~PT3 (Present Track Number 0~3) [#vb41e953]
*** PTN (Precompensation Track Number) [#ja65d483]
*** R255 (Recalibrate Step Pluses) [#rc83cb96]
*** RCN (Relative Cylinder Number) [#eb9d90c7]
*** RG (Read Gate Diagnostic) [#rd8d88b5]
*** SC (Sector) [#iede3ed0]
*** SK (Skip) [#ma5f41ff]
*** SRT (Step Rate Time) [#k9864a82]
*** STP (Step) [#r721d997]
*** THR (Threshold) [#wd7da0cf]
*** TMR (Timer Control) [#xa656672]
*** US1, US0 (Unit Select 0, 1) [#vd407bf1]
*** WLD (Scan Wilid Card) [#nf342e38]
** リザルトステータス [#l1be05c0]
** 3モードサポート [#i77a9f23]
** 2.88MBFD(垂直記録ドライブ)サポート [#j1a27bc2]

-''(書きかけ)''
* フロッピーディスクのセクタ配置 [#ad117ba0]
LBAに相当するセクタ番号との配置
|通しセクタ番号(LBA)|シリンダ|ヘッド|セクタ|
|   0| 0|0| 1|
|  17| 0|0|18|
|  18| 0|1| 1|
|  35| 0|1|18|
|  36| 1|0| 1|
|  53| 1|0|18|
|  54| 1|1| 1|
|  71| 1|1|18|
|  72| 2|0| 1|
|2879|79|1|18|
~
* こめんとらん [#h40440ee]
-メモ: http://tkralia.hp.infoseek.co.jp/mona/mona1017/vbe.html -- ''nika'' SIZE(10){2006/08/21 (月) 00:34:50}
-READ DATAの説明のところ GSLじゃなくてGPLじゃないですか? -- ''ぶー太君'' SIZE(10){2009/07/04 (土) 16:54:11}
-GPL (Gap Length) は WRITE ID (物理フォーマットコマンド) の場合のみに使用される値です。パラメータの値の意味についてはまだこのページには書いていませんが、手元の資料では GPL は 「セクタのデータ領域の後ろから次のセクタまでのバイト数」となっているので、 今回の場合は GSL (Gap Skip Length) で間違っていないと思います。 -- ''nika'' SIZE(10){2009/07/04 (土) 18:26:41}
-すみません。ちゃんと読んでなかったみたいです -- ''ぶー太君'' SIZE(10){2009/07/05 (日) 22:49:06}

#comment
----

[Reload]   [New] [Edit] [Diff] [Upload]   [Front page] [List of pages] [Search] [Recent changes] [Backup]   [RSS of recent changes]