Operating Systems Development Series | |
FDC Programming
This series is intended to demonstrate and teach operating system development from the ground up. ![]() 8272A Floppy Disk Controller はじめにやったー!ついにフロッピーディスクドライブを扱う時が来ました!この章では、フロッピーディスクドライブとフロッピーディスクのプログラミン グについて知るべきことをほとんどすべてカバーします!この章のメニューはこんな感じです。
歴史フロッピーディスクコントローラ(FDC)は、フロッピーディスクドライブ(FDD)とインターフェイスするコントローラです。 PCでは通常、NECのPD765 FDCが使用されています。PS/2ではIntel 82077A、ATではIntel 82072Aというマイコンが使われています。フロッピーディスクドライブ(FDD)は、フロッピーディスクに対してデータの読み書きができる装置である。 1971年、IBMのダイレクト・アクセス・ストレージ製品マネージャであったアラン・シュガートに雇われたデビッド・L・ノーブルは、同社のSystem/370メインフレーム用に新しいストレージ・テープ・フォーマットを開発しようとした。IBMは、初期制御プログラムロード(ICPL)のマイクロコードを再ロードする際に、テープドライブよりも小型で高速なものを作ろうと考えていた。ノブレス氏のチームは、「ミノー」というコードネームで「メモリーディスク」と呼ばれる製品に取り組んでいた。これは、80キロバイトの容量を持つ読み取り専用の8インチ・ディスケットである。1971年に市販され、すべてのSystem/370メインフレームに搭載された。 アラン・シュガートがIBMを退職し、メモレックスに移ると、彼のチームは1972年に最初の読み書き可能なフロッピーディスクドライブである「Memorex 650」を出荷した。 フロッピーディスクは、IBMが8インチ、5インチと1/4インチ、3 1/2 インチのフォーマットを発明した。 ディスクの構造物理レイアウトディスクの構造を理解することが大切です。フロッピーディスクはこんな構造になっています。![]() 一般的な3-1/2インチフロッピーディスクの物理レイアウトです。ここではヘッド1(前面)を見ていますが、セクタは512バイトを表します。トラックはセクタの集合体です。 注:1セクタは512バイトで、フロッピーディスクには1トラックあたり18セクタがあることを覚えておいてください。 上の絵を見て、思い出してください。
シリンダー/ヘッド/セクター(CHS)セクタセクタとは、512バイトのまとまりを表します。つまり、セクタ1はディスクの最初の512バイトを表しています。ヘッドヘッド」(またはフェイス)は、ディスクの側面を表します。ヘッド0が表側、ヘッド1が裏側です。ほとんどのディスクは1面しかないため、ヘッドも1つしかありません(「ヘッド1」)。トラックトラックとは、ディスクの周囲にある1つの輪のことです。フロッピーディスクの場合、1つのトラックには18セクタがある。シリンダーは、1枚のディスクのトラック番号を表します。フロッピーディスクの場合、読み出すトラックを表します。 1トラックあたり18セクタあります。片面80トラック。 CHSを理解するフロッピーディスクのアドレスはCHS形式である。ディスク上の任意の場所から読み書きするためには、FDCに読み取り/書き込みヘッドをディスク上の正確なトラック、シリンダー、セクタに移動するよう指示する必要がある。リニアブロックアドレッシング(LBA)また、LBA(Linear Block Addressing)を使って、より抽象的なディスクの読み書きを行うことも可能です。LBAでは、ディスク上のセクタ0〜2880までの任意のセクタに対して読み書きができる。フロッピーディスクのインターフェイスソフトウェアとフロッピーディスクドライブのインターフェースは、フロッピーディスクコントローラを介して制御します。 フロッピーディスクコントローラの違いにより、ここではオリジナルの8272Aフロッピーディスクコントローラに焦点を当てたいと思います。冒頭の画像は、典型的な8272A集積回路(IC)コントローラです。これが、今回取り上げるICです。詳細82072Aフロッピーマイクロコントローラ8272AのICは40ピンあります。ここで見てみましょう。40本のピンを簡単に見ていきますが、電子工作の分野に入ってしまうので、ここでは詳しく見ていきません。![]() これらのピンのほとんどは、コントローラのプログラミングにはあまり役立ちません。しかし、他のピンは、理解することがより重要です。それでは、見ていきましょう。FDCは、プログラマブル割り込みコントローラ(PIC)、システムバス、およびダイレクトメモリアクセスコントローラと間接的に通信していることがわかります。
これは重要です!FDCのピンをすべて把握する必要はありません。むしろ、FDCが3つの主要なコントローラと通信していることだけを覚えておいてください。1つは、4つのフロッピーディスクドライブ(FDD)内部コントローラのうちの1つ、プログラマブル割り込みコントローラ(PIC)、ダイレクトメモリアクセス(DMA)コントローラです。 ソフトウェアは、プロセッサの標準IN/OUTポートi/o命令によってFDCと通信をします。 FDCのいくつかのレジスタは、プロセッサのi/oアドレス空間にマッピングされています。標準的なI/Oポート読み取りと同様に、入出力操作の間、プロセッサはコントロールバスのREADまたはWRITEラインと、アドレスバスのポートアドレスを設定します。これは、システムバスまたはISA(Industry Standard Architecture)バスで行われます。 新しいハードウェアでは、FDCはISAバスに直接接続されておらず、スーパーI/O ICとして統合されており、スーパーI/Oのローピンカウントバスを通じてプロセッサと通信する。 なるほど!ソフトウェアがどのようにFDCと通信できるかはわかった。PICとDMAはどこで登場するのでしょうか? 上のピンリストを見てみると、FDCはINTというピンを持っていることがわかります。このラインは、プログラマブル割り込みコントローラIR 6ラインに間接的に接続されています。FDCは、1バイトのデータが読み書きできるようになると、このラインをハイ(1)に引き上げます。これはPICのIR 6ラインもHighに引きます。ここからはPICが制御を行う。他のラインをマスクして、サービス可能かどうかを判断します。プロセッサの割り込みアクノレッジ(INTA)ピンをアクティブにすることで、プロセッサに割り込みを通知します。プロセッサは、割り込みを処理しても安全であることを確認した後、INTAラインをリセットして、PICに処理を許可します。PICは、このIRQが使用するようにマッピングされた割り込みベクタを配置します(PICの初期化中に設定されます)。プロセッサはIRQを受け取り、idtrからそのアドレスを取得し、ほら - 割り込みが呼ばれた。 FDCは、DMAモードで動作するようにプログラムすることもできます。DMAはまだ見ていないコントローラなので、あまり深く立ち入らないようにします。しかし、次の章では、完全を期すために、このことについて触れるかもしれません。FDCはDMAのチャンネル2に接続されています。 ![]() FDCのハードウェアはこれで全部です。FDCは1つのシステム内に複数個あり、1つのFDCは最大4台のフロッピーディスクドライブ(FDD)を接続することができます。これは重要なことです。FDCと通信する際、どのFDDを要求しているかを選択しなければならないことがよくあります。 フロッピーインターフェイスケーブルFDCとFDDの通信は、Western Digital社から進化したIDE(Integrated Drive Electronics)ケーブルとも呼ばれるPATA(Parallel ATA)ケーブルの一種であるフロッピーインターフェースケーブルで行われる。![]() 上のケーブルにねじれがあることにお気づきでしょうか。それを少し短く説明します。このケーブルには40本のピンがあります。この40本のピンを通じて、FDCはケーブルに接続された異なるFDDと会話することができます。 FDCと通信するためのいくつかのレジスタで、コントローラとケーブルの入力ピンを検出することができます。このため、ケーブルの40本のラインを少し見るくらいはしておいた方がよさそうだ。
FDCプログラミングFDCの動作モード最近のFDCは、8272マイコンより高機能なものが多くなっています。後方互換性を確保するため、新しいFDCはコントローラにピンを追加し、特定のモードで動作するときに異なるレジスタと通信できるようにします。例えば、ステータスレジスタAモードは、コントローラがPC-ATモードで動作しているときのみアクセス可能です。コントローラのリセット時には、コントローラはデフォルトの82077Aモードで動作します。IRQの待ち受けFDCがIRQ 6を使用していることを思い出してください。FDCは、リードまたはライト・コマンドの完了後、あるいはモードによっては1バイトの転送ごとに、1バイトを送信します。また、初期化中にコントローラがリセットされたときにもIRQを送ります。今回は、FDCをDMAモードで動作させます。つまり、リード、ライト、シーク、キャリブレーションの各コマンドが完了したときと、初期化中にのみ割り込みが入るということです。 しかし、いずれの場合も、コマンドの完了を知るためにIRQが発火するのを待つ必要があることを意味します。これを行うには、IRQが発生したときにグローバルをセットし、 IRQを待つirq_waitのような関数を提供し、それが発生したときにグローバルを リセットするようにすればよい。 では、それをやってみましょう。まずIRQです。 これは、PITのIRQと同じくらいシンプルに見えますね?)ああ、そうですか、では、待ちます。 簡単ですね。読み出しや書き込みのようなコマンドを送ったら、flpydsk_wait_irq()を呼び出します。 これが完了したら、コマンドが終了して、続けても安全であることが分かります。クールでしょう?) DMAですか?え?DMAモードでFDCをプログラムしているのですか?でも、まだDMAを説明していませんよ。はい、確かにこれは問題です。当初、FDCはNon-DMAモードでプログラムしようと思っていました。しかし、この方法は場合によっては有効かもしれませんが、多くのエミュレータや一部のハードウェアではサポートされなくなってきています。そこで、ポータビリティを確保するために、DMA(Direct Memory Access Controller [DMAC])を使うのがベストだと判断したのです。 しかし、まだDMAを詳しく説明していないため、問題が発生しました。DMAインターフェース全体を説明なしに投げ出すよりも、3つの基本的なDMAルーチンをハックして、後でもっと詳しく書き直せばいいと思います ;) flpydsk_initialize_dmaは基本的に DMA が使用するバッファを物理アドレス 0x1000 - 0x10000 (64k) に作成します。 ディスクからセクターを読み込むとき、DMA はセクターデータをこの場所に置くので、上書きされるように何もないことを確認してください。他の場所を選択することも可能ですが、いくつかのルールがあります。
dma_readと dma_writeは、FDCが送信したデータの読み取りまたは書き込みを開始するようDMAに指示するだけです。これは、FDCに読み書きを指示したセクタになります。例えば、FDCにセクタを読むように指示すると、DMAにセクタデータを渡して、設定したバッファ(0x1000の位置)に置くように指示します。クールでしょう? もしあなたが上記のコードを理解できなくても、心配しないでください。DMAに関することはすべて書き直し、次のチュートリアルでDMAをより詳しく説明します。 FDCポートマッピングFDCには4つの外部レジスタがあり、i86のI/Oアドレス空間にマッピングされています。これらは、標準的なI/O命令によってソフトウェアからアクセスすることができます。これらのレジスタを太字にしてみました。システムによっては、FDCに4つ以上の外部レジスタが用意されている場合があります。 2番目のFDCは、通常、I/Oポート0x370~0x377にマッピングされます。 2つの異なるFDCのために2組のポートがあるので、この表は両方のポートセットを含んでいます。
次の章では、このレジスタを少しずつ詳しく見ていくことにします。重要なものについては、この章を更新して、他のレジスタを網羅することになるかもしれません。今のところ、上に示した最初の4つのレジスタにのみ焦点を当てます。 このコードはすべてこの章の最後にあるデモに含まれていることを忘れないでください。
レジスタステータスレジスタA (SRA) (PS2モードのみ)このレジスタを知る必要はありません。ここにあるのは完全性のためだけです。本レジスタは、コントローラのインターフェースピンの状態を監視するためのリード専用レジスタです。 コントローラがPC-ATモードの場合は、本レジスタにアクセスできません。本レジスタは読み出し専用です。 このレジスタの正確なフォーマットは、コントローラのモデルによって異なる場合があります。
このレジスタが複雑に見えても心配しないでください。電子工学の経験がなくても大丈夫です。このレジスタは、このシリーズで使用されることはありません。 ステータスレジスタB (SRB) (PS/2モードのみ)このレジスタを知る必要はありません。このレジスタを知る必要はありません。上記のレジスタと同様に、FDCの複数のラインの状態を監視することができます。 FDCがPC-ATモードの時はアクセスできません。このレジスタは読み出し専用である。
このレジスタが複雑に見えても心配しないでください。電子工学の経験がなくても、そう見えるかもしれません。このレジスタは、このシリーズで使用されることはありません。 データレート選択レジスタ(DSR)このレジスタを知る必要はありません。このレジスタを知る必要はありません。このレジスタは書き込み専用で、駆動制御信号のタイミングを変更することができます。I/Oポート0x3f4(FDC0)または0x374(FDC1)に書き込むことで使用します。 これは8ビット・レジスタです。以下のフォーマットで構成されています。
PRE-COMP 0 - PRE-COMP 2は少し複雑です。これらは,フロッピーディスクなどの磁気媒体で発生するビットシフトに対して,WRDATA出力ピンを調整するものです。事前補償の遅延を調整するために、これらのビットを以下のいずれかに設定します。
DRATE SEL0~DERATE SEL1でデータレートを設定します。有効な値は以下の通りです。
デジタル出力レジスタ(DOR)やったー!最初の有用なレジスタです!これは知っておくべき重要なことです。FDDのモータ制御、動作モード(DMA、IRQ)、リセット、ドライブなど、FDCの様々な機能を制御できる書き込み専用レジスタです。フォーマットは次のとおりです。
以下はその例です。例えば、最初のフロッピードライブ(FDD 0)のモーターを始動させたいとします。FDDに対する読み取りまたは書き込み操作を行う前に、FDDのモーターを始動させる必要があります!これを開始するには、モーターを開始または停止したいドライブに対応するビット (4-7) を設定するだけです。DORはプロセッサのi/oアドレス空間であるポート0x3f2にマッピングされているので、これは非常に簡単です。 まず、レジスタのビットマスクを作成し、読みやすさを向上させます。このコードはすべて、このチュートリアルの最後にあるデモに含まれていることを忘れないでください。 上記のビットマスクを使えば、設定したいビットをビットごとにORするだけでよいのです。つまり、フロッピーディスク・ドライブ0用のモーターを始動させる場合です。 FLPYDSK_DORは0x3f2として定義され、これはDOR FDCレジスタのi/oアドレスであることを思い出してください。また、上記はコントローラをリセットしています。 この同じモーターをオフにするには、モータービットを設定せずに同じコマンドを送信するだけです。
警告警告: モーターが起動するまでに少し時間がかかります!内蔵FDDのモーターは機械的なものであり、他の機械装置と同様に、実行中のソフトウェアの速度より遅くなる傾向があることを思い出してください。このため、FDDモーターを起動するときは、必ず少し時間をおいてから読み書きを行ってください。 DORは書き込み専用のレジスタです。これを強制するために、ルーチンを作成します。 次の重要なレジスタに移りましょう。 メインステータスレジスタ(MSR)メインステータスレジスタ(MSR)は、特定のビットフォーマットに従っています。これは予想外だったでしょう?さて、ここで話を元に戻しましょう(シャレです)。これがMSRのフォーマットです。
ここでは、このMSRからビジー状態かどうかを読み取る例を示します。まず、コードで使用されるビットマスクを定義します。上に示した形式に従っていることに注意してください。 簡単でしょう?FLPYDSR_MSRが0x3f4で、MSRのi/oポート・アドレスであることが分かっていれば、あとはこれを実行すればいいだけです。 リードやライトのコマンドを送るときは、このビットが0になるまで待てばいいだけです。 読みやすくするために、これをルーチンに隠すことにしましたので、ここに紹介します。このルーチンは、FDCのステータスを返すだけです。
テープドライブレジスタ(TDR)このレジスタを知る必要はありません。このレジスタを知る必要はありません。このレジスタにより、ドライブの初期化中に特定のドライブにテープ・ドライブ・サポートを割り当てることができます。このレジスタはリード/ライト・レジスタで、8ビット・サイズです。 ただし、最初の2ビットだけが定義されています。ドライブ0はフロッピーブートデバイスとして予約されているため、選択することはできません。このため、以下のビットリストには含まれていません。
データ・レジスタこれは8ビットまたは16ビットのリード/ライト・レジスタです。レジスタの実際のサイズは、コントローラの種類によって異なります。すべてのコマンド・パラメーターとディスク・データの転送は、このデータ・レジスタに読み書きされます。このレジスタは、特定のビット・フォーマットに従わず、一般的なデータ用に使用されます。I/Oポート0x3f5(FDC 0)または0x375(FDC 1)を通じてアクセスします。注:このレジスタを読み書きする前に、まずマスター・ステータス・レジスタ(MSR)のステータスを読んで、このレジスタが有効であることを常に確認する必要があります。 覚えておいてください。すべてのコマンド・バイトとコマンド・パラメータは、このレジスタを通じてFDCに送信されます。 この例については、以下のコマンドのセクションで説明しますので、まだあまり気にしないでください。 無効なコマンドが発行された場合、データ・レジスタから返される値は0x80です。 以下のルーチンは、このレジスタから読み出し、デモで使用しています。データ・レジスタが安全に読み書きできるようになるまで待ち、その後、読み出し(read_data関数)または書き込み(send_command関数)を行うようにしています。
デジタル入力レジスタ(DIR)このレジスタを知る必要はありません。このレジスタを知る必要はありません。さて、デジタル出力レジスタ(DOR)があったので、このレジスタが来ることは予想できたと思います :)このレジスタは、コントローラのすべての動作モードで読み取り専用です。PC-ATモードでは、ビット7のみが定義され、他のビットは未定義であり、使用しないでください。他の動作モードでは、Bit7は未定義です。 ビット7(DSK CHG)は、FDCのDSK CHGピンをモニタします。本章の冒頭のピン配置を見ると,DSK CHG 端子がないことが分かります。これは、FDCの新モデルとオリジナル・モデルの違いに関係しています。新しいモデルは、DMA GATE、DRATE SEL0/1など、FDCの新しいピンを監視するために、このレジスタの異なるビットを追加および変更しました。このレジスタの値は、FDCの動作モードに固有です。 このレジスタのビットは、モデル間で変更される可能性があることに注意してください。 コンフィギュレーション制御レジスタ(CCR)PC/ATモードでは、このレジスタはデータレートセレクトレジスタ(DSR)として知られ、最初の2ビット(ビット0=DRATE SEL0、ビット1=DRATE SEL1)だけが設定されます。もう一度見てみましょう。
ビット2は、30型/CCRモードではNOPRECとなり、機能はありません。その他のビットは未定義で、コントローラによって変更される可能性があります。 他のレジスタと同様に、このレジスタに書き込みができるようにルーチンを作りました。
コマンド概要コマンドは、FDCに接続されたFDDを制御し、読み出しや書き込みなどのさまざまな操作を行うために使用されます。つまり、ポート0x3f5(FDC 0)または0x375(FDC 1)のデータ・レジスタにOUTアセンブリ言語命令を書き込むのです。警告コマンドまたはパラメータ・バイトを送信する前に、まずメイン・ステータス・レジスタ(MSR)のビット 7 をテストして、データ・レジスタがデータを受信する準備ができていることを確認してください。 コマンドは13種類(コントローラによってはそれ以上)あります。各コマンドは1バイトから9バイトの大きさです。FDCは、最初のコマンド・バイトから、何バイトを期待すればよいかを知っています。つまり、最初のバイトは、FDCに何をして欲しいかを伝える実際のコマンドです。FDCは、このコマンドからさらに何バイトを期待すればよいかを知っています(コマンド・パラメーター)。 コマンドはトラックの片方のヘッドにしか作用しません。もし両方のヘッドで動作させたい場合は、Multiple Track Bitを設定する必要があります。これらのコマンドの多くはビットフォーマットに従います(後述)。ここがややこしいところです。 コマンドバイトの上位ビットは、コマンドのオプション設定用です。私はこれを拡張コマンドビットと呼んでいますが、正式な名称はありません。これらのビットのうち、私たちが使用する多くのコマンドに共通するビットが2つあります。これらのビットは、後でコマンドバイトの中で見ていきます。 さて、まずコマンドリストを見てみましょう。次に、それぞれのコマンドを個別に見ていきます。これらはすべてコマンドバイトの最初の4ビットしか使っていないことに注意してください。 FDCにコマンドを送信するには、データ・レジスタ(別名FIFO)に書き込む必要があります。 これを行うには、まずMSRのビットをチェックして、データ・レジスタの準備ができるのを待つ必要があります。flpydsk_read_status ()はMSRからの値を返すだけなので、これをすべてシンプルなメソッドの中に隠してしまいましょう。
拡張コマンドビットこれらのコマンドのいくつかは、コマンドを実行する前に数バイトを渡す必要があります。 また、数バイトを返すものもあります。読みやすくするために、すべてのコマンド、フォーマット、パラメータ・バイトを表にまとめました。各コマンドには説明とサンプルルーチンが付いています。さて、拡張コマンド・ビットの話をしたときに、上のコマンドが4ビットしかないことを思い出してください。上位4ビットは、さまざまな用途に使用することができます。 例えば、Write Sectorコマンドは、M F 0 0 0 1 1 0という形式で、最初の4ビット(0 1 1 0)がコマンドバイト、上位4ビット(M F 0 0)が異なる設定を表します。Mはマルチトラック、Fはコマンドに対してどのような密度モードで動作させるかを選択するために設定されています。 以下、共通ビットの一覧です。
GAP 3GAP 3は、物理ディスクのセクタ間のスペースを指します。GPL (Gap Length) の一種です。コマンドによっては、GAP 3のコードを渡す必要があるため、それを使用します:)。 セクタあたりのバイト数コマンドによっては、セクタあたりのバイト数を渡す必要があります。しかし、これらは任意のサイズにすることはできず、常に式に従います。nは0〜7の数字です。FDCではセクタあたり16Kバイトまで選択することができます。しかし、ほとんどのドライブはそれをサポートしていないかもしれません。 我々のリストには、最も一般的な ...ですから、もしコマンドがセクタあたりのバイト数を渡すことを要求してきたら、512と書いてはいけません!むしろ、FLPYDSK_SECTOR_DTL_512と書いて、これは2です。 コマンドにパラメータを渡す方法思い起こせば、多くのコマンドはパラメータを渡すことを要求しています。パラメータを渡すには、コマンドが送られたのと同じように送ればよいのです。例えば、specifyコマンドは、2つのパラメータを渡す必要があります。これがないとコマンドは起動しませんので...これが全てです。) コマンドから戻り値を取得する方法返り値を無視できるプログラミングの関数と違って、FDCは返り値を何らかの形で処理する必要があります。もちろん、無視することもできますが、FDCから返り値をもらわなければなりません。それが終わらないと、FDCはそれ以上のコマンドを許可しません。コマンドがデータを返す場合は、FIFO(データ・レジスタ)に--1つずつ--返されます。 したがって、それらを読むには、FIFOを継続的に読み込んで、返されたデータをすべて取得する必要があります。 注:コマンドがデータを返す場合、割り込みを送信しますので、それを待つ必要があります。これは、コマンドが終了し、FIFOから戻り値を読んでも安全であることを知るための方法です。 戻り値の良い例は、セクタの読み出しコマンドです。このコマンドでは、IRQを待つ必要があるので、完了したことがわかり、7バイトが返されます。そこで、返されたデータ・バイトをすべて読むために、データ・レジスタから一度に1つずつ読み出す必要があります。 もちろん、エラーチェックのために、いくつかの返り値は実際にチェックする必要があります。 セクタを書き込む
FDDからセクタを読み出すコマンドです。セクタ内の1バイトごとにFDCは割り込み6を発行し、ディスクから読み出したバイトをデータレジスタに入れ、読み込めるようにします。 セクタの読み出し
FDDからセクタを読み出すコマンドです。セクタ内の1バイトごとにFDCは割り込み6を発行し、ディスクから読み込んだバイトをデータレジスタに入れ、読み込めるようにします。 以下は、デモで使用したルーチンです。まず、DMAをセットアップして、読み出し動作の準備をします。次に、セクタ読み出しコマンド(FDC_CMD_READ_SECT)を実行し、コマンドのM、F、Sビットを設定します(マルチトラック・リード、倍密度、削除済みアドレス・マークをスキップします。これらの一覧は上記を参照してください)。 その後、コマンドのパラメータを全て渡し、読み出しコマンドを開始します。セクタサイズパラメータはFLPYDSK_SECTOR_DTL_512 (bytes per sector)で、これは思い起こせば値2です(詳細は上記のBytes per sectorの項を参照してください)。 次のパラメータはトラックあたりのセクター(18)。 次のパラメータはGAP3長です。標準的な3-1/2 "フロッピーディスクのGAP 3長(FLPYDSK_GAP3_LENGTH_3_5、27)の値を渡します。 Data Lengthパラメータ・バイトはセクタ・サイズが0の場合のみ有効です。 それ以外の場合は 0xff となります。 このコマンドは完了後にIRQを送信するため、IRQを待つ必要があります。 ...IRQが発生した後、7つのリターンバイトをすべて読み込んでいます。そして、SENSE_INTERRUPTコマンドをflpydsk_check_int()で送信し、FDCに割り込みを処理したことを知らせます。(以下の割り込みの状態をチェックするセクションを参照してください) 待てよ...。データはどこにあるのでしょうか?上のコマンドを見ると、FDCにデータをどこに置くか教えていません。 これは、面白い問題を提起していると思いませんか? FDCの動作モードにもよりますが、Non-DMAモードでは、1バイトごとにIRQ 6が発火します。ディスクから読み込んだデータのバイトはFIFOにあります。DMAモードでは、DMAにデータを渡し、DMAはそのデータをバッファ(DMAに指示した場所)に入れる。 つまり、この場合、DMAバッファを0x1000に設定したことを覚えていますか?上記のルーチンを呼び出した後、セクタデータは0x1000になります!クールでしょう?DMAに別のアドレスを与えることで、その位置を変更することができます。 ドライブデータの修正/指定
このコマンドは、FDC に接続されているメカニカル・ドライブの制御情報を FDC に渡すために使用されます。このコマンドでの作業を容易にするために、このコマンドのためのルーチンを書きましょう。
ステータス確認
このコマンドは、ドライブのステータスを返します。 ドライブのキャリブレート
このコマンドはリード/ライト・ヘッドをシリンダー0に配置するために使用されます。80トラック以上のディスクの場合、このコマンドを数回発行する必要があります。このコマンドを発行した後は、必ず正しいトラックであることを確認すること(Check Interrupt Statusコマンド)。 コマンドを発行した後、まだシリンダー0に到達していない場合は、再度コマンドを発行する。シリンダ0を見つけたら、モータを停止させ、successを返す。10回やってダメならやめる。 このコマンドの実行中は、モーターが動いていることを確認する必要があることに注意してください。また、SENSE_INTERRUPTコマンド(flpydsk_check_int()コール)を使って、現在のシリンダを取得している点にも注目。
インタラプトステータス確認
このコマンドは、割り込みが復帰したときの FDC の状態に関する情報を確認するために使用します。
シーク/パークヘッド
このコマンドは、リード/ライト・ヘッドを特定のシリンダーに移動させるために使用されます。calibrateコマンドと同様に、このコマンドを複数回送信する必要がある場合があります。check_int()を呼び出すことで、毎回現在のシリンダーを取得していることに注意。そして、現在のシリンダーが探しているシリンダーであるかどうかをテストします。そうでない場合は、もう一度試行する。もしそうであれば、成功を返します。
無効なコマンド無効なコマンドがFDCに送信された場合、FDCはそれを無視してスタンバイ状態になります。FDCをリセットするコントローラの無効化DOR RESETラインがLowであれば、コントローラはディスエーブル状態になります。つまり、DORレジスタに0を書き込むだけで、コントローラはディセーブルになります。
コントローラの有効化コントローラをイネーブルにするには、DORのRESETラインをHighに設定します。また、FDCをDMAモードで動作させたいので、そのビットもDORに設定する必要があります。コントローラを無効化した後に有効化すると、割り込みが発生します。この間、コントローラやドライブのコンフィギュレーションを再初期化する必要があります。 FDCの初期化コントローラのリセット中、コントローラを再初期化する必要があります。コントローラのリセット後、IRQ6が発行されます。発火後、FDCに接続されているすべてのドライブにSENSE_INTERRUPTコマンドを送信する必要があります(flpydsk_check_intを4回呼び出すことで行います)。その後、コントローラを再設定する時間があります。CCR(構成制御レジスタ)はデータ・レートのために2ビットしかないことを思い出してください。両方を0に設定することで、データレートを500Kbpsに設定します。これは素晴らしいデフォルト値です。 次にflpydsk_drive_dataを呼び出し、Fix Drive Data / Specifyコマンドをコントローラに送信して、次のようなドライブの機械的情報を設定します。ステップ速度、ヘッドのロードとアンロードの時間、DMAモードをサポートしているかどうかなどです。 その後、ドライブを再キャリブレーションし、シリンダー0に配置します。 リセットの後、ドライブは私たちが使用できる状態になります。 更新と変更文字列からint型への変換 - stdio.h/stdio.cppこのデモをよりインタラクティブにするために、標準ライブラリにある文字列を整数に変換するための3つの関数を組み込みました。このデモでは、ユーザーから入力された文字列を使用可能な整数に変換するために、atoiを使用しています。フロッピーディスクドライバのインストール - flpydsk.cppフロッピーディスクドライバには、デモが簡単にセットアップできるように、すばらしいインストールルーチンが付属しています。このルーチンは、HAL の setvect () ルーチンを使って割り込みハンドラをインストールし、転送用の DMA を初期化し、コントローラをリセットして使用可能な状態にするだけです。デモでは、初期化中にこの関数を呼び出し、ドライバから読み込もうとする前にドライバをセットアップしています。 任意のセクタを読み込む - LBAとCHS - flpydsk.cppドライバは、2つのすばらしい関数の背後にCHSの詳細を隠します。ドライブはCHS(シリンダ/ヘッド/セクタ)で動作し、LBA(リニアブロックアドレッシング)については何も知らないことを知っているので、この2つの間で変換するルーチンを提供する必要があります。この方法では、物理的な CHS を気にすることなく、単にセクタ番号を渡して読み書きすることができます。LBAをCHSに変換する公式を覚えていますか?ここでそれを応用してみましょう。 FLPY_SECTORS_PER_TRACKは18です。素晴らしい!これで、この関数を呼び出すだけで、任意のリニア・セクタ番号をCHSの位置に変換できるようになりました!クールでしょう? ディスクから任意のセクタを読み込めるようにしたいので、そのためのルーチンを提供します。 また、コントローラに読み込みコマンドを送信するコードを含むflpydsk_read_sector_impが既にあるので、このルーチンは非常にシンプルになります。 デモがセクタを読みたいときはいつでも、このルーチンを呼び出します。このルーチンはセクタをディスク上の物理的な位置(CHS)に変換します。そして、モーターを起動し、このセクタがあるシリンダを探します。その後、flpydsk_read_sector_impを呼び出して実際にセクタを読み込むマジックを行い、その後モータをオフにします。 flpydsk_read_sector_imp の呼び出しの後、セクタのデータは DMA バッファにあるはずです。 このバッファへのポインタを返すと、バッファには今読み込んだセクタのデータが入っています。クールでしょう? これはすべてを結びつける魔法のルーチンです。) 新しい読み込みコマンド - main.cppこのデモは前回のデモの上に構築されています。このため、前回のデモで構築されたコマンドライン・インターフェイス(CLI)を維持しています。このため、このデモは今までで最も複雑なデモになっています。CLI のコマンドのリストに、ディスクから任意のセクタを読み込むことができるreadという新しいコマンドを追加しました。このコマンドは、このチュートリアルで作成したフロッピーディスクドライバを使用しています。 このコマンドは関数の中にあり、デモではreadとタイプすることで実行されます。これは512バイトを読みやすいように128バイトの4つのブロックに分割してダンプします。各ブロックの後、次のチャンクに進むためにキーを押すように促されます。これは新しいatoi関数を使って、入力されたセクタ番号(LBAセクタ番号)をintに変換し、それを読み込んでいます。親愛なる読者の皆さん、これが魔法を起こす関数なのです。
まとめイヤー、これは長いチュートリアルです。より良く、より完全なものにするために、いくつか変更を加えるかもしれません :)次回のチュートリアルでは、DMAについて説明します。DMAをプログラミングするためのインターフェイスを作成し、FDCドライバでよりよく使用できるようにします。この後...またファイルシステムの話になると思います(笑)。心配しないでください - そのあとはマルチタスクです! |