サブページ
$DFF020

ディスクコントローラの概要

Amigaのフロッピーディスクコントローラは、Paulaカスタムチップに内蔵された専用回路である。専用DMAチャネルを通じて、ディスクドライブとChip RAM間の低レベルデータストリームを処理する。コントローラは生のエンコード済みデータ(MFMまたはGCR)の読み書きを管理し、信頼性の高いセクタ位置検出のためにハードウェア同期ワード検出機能を備える。

ディスクハードウェアは2つの機能領域に分かれる:

  1. ドライブ制御信号 — モーターのオン/オフ、ヘッドステップ、サイド選択、ドライブ選択 — CIA-Bのポートラインで管理(CIAドキュメントで解説済み)。
  2. データ転送 — ドライブヘッドとメモリ間のエンコード済みビットストリーム。PaulaのディスクコントローラとそのDMAチャネルで管理。

コントローラは1回のDMA操作でトラック全体を読み書きできる。標準的なAmigaトラックはそれぞれ512バイトの11セクタ(トラックあたり5632データバイト)を含むが、MFMエンコーディングのオーバーヘッド、ギャップ、ヘッダのため、生のエンコード済みトラックはかなり大きくなる。

ディスクコントローラレジスタ

ディスクDMAおよび制御レジスタ
$DFF020DSKPTH — ディスクDMAポインタ(上位ワード、ビット16–18)
$DFF022DSKPTL — ディスクDMAポインタ(下位ワード、ビット0–15)
$DFF024DSKLEN — ディスクDMA転送長と制御(書き込み専用)
$DFF01ADSKBYTR — ディスクデータバイトとステータス(読み取り専用)
$DFF07EDSKSYNC — ディスク同期ワード(書き込み専用)
$DFF026DSKDAT — ディスクDMAデータ書き込み(書き込み専用)
$DFF008DSKDAT — ディスクDMAデータ読み取り(読み取り専用、早期読み取りレジスタ)
$DFF020

DMAポインタと長さ

ディスクDMA転送を開始する前に、バッファアドレスと転送長を設定する必要がある。

DSKPTH / DSKPTL — DMAポインタ($DFF020 / $DFF022、書き込み)

このレジスタペアは、ディスクデータの読み書き先となる19ビットChip RAMアドレスを保持する。ポインタは上位ワードを先に、2回の個別のワード書き込みでロードされる:

    move.l #DiskBuffer,$DFF020    ; 1回のMOVE.LでDSKPTHとDSKPTLをロード

バッファはChip RAM内に配置する必要がある(OCSでは最初の512 KB、ECSでは1 MB、AGAでは2 MB)。

DSKLEN — 転送長と制御($DFF024、書き込み)

ビット 名前 機能
15DMAENディスクDMAを有効化(有効にするには2回の書き込みが必要)
14WRITE1で書き込み、0で読み取り
13–0LENGTH転送するワード数(最大16383)

LENGTHフィールド

下位14ビットは、ディスクとメモリ間で転送する16ビットワードの数を指定する。

WRITEビット

WRITEが1にセットされると、コントローラは書き込みモードで動作し、データはメモリからディスクに流れる。クリアされている場合、データはディスクからメモリに流れる(読み取りモード)。安全のため、WRITEは実際の書き込み操作を意図する場合のみセットすべきである。

DMAEN — DMA有効化(ダブルライト保護)

DMAENビットはディスクDMAのマスターイネーブルである。重要な安全対策として、DMA転送を実際に開始するにはDMAENを連続して2回1に書き込む必要がある。これにより、誤った1回の書き込みで潜在的に破壊的なディスク操作がトリガーされることを防ぐ。DSKLENへの単発の誤書き込みでは転送を開始できない。

さらに、DMACONレジスタのグローバルディスクDMA有効化ビット(DSKEN、ビット4)もセットされている必要がある。

$DFF020

DMA初期化シーケンス

ディスクDMA操作を開始するための正しい手順は、データ破損を防ぐために厳密なシーケンスに従う:

読み取り操作

    ; 1. 以前のDMAを無効化
    move.w #$4000,$DFF024      ; DSKLENのDMAENをクリア

    ; 2. グローバルディスクDMAの有効化を確認
    move.w #$8010,$DFF096      ; DMACONのDSKEN(ビット4)をセット

    ; 3. バッファアドレスを設定
    move.l #DiskBuffer,$DFF020 ; DSKPTH/DSKPTL

    ; 4. DSKLENに希望する長さとDMAENを書き込む
    move.w #$8000+NumWords,$DFF024  ; DMAEN=1、WRITE=0、LENGTH=NumWords

    ; 5. 同じ値を再度書き込む(ダブルライトで有効化)
    move.w #$8000+NumWords,$DFF024

    ; 6. DSKBLK割り込みを待つ(DMA完了)
    ;    ...(INTREQRのビット1をポーリングまたは割り込みハンドラを使用)...

    ; 7. 安全対策としてDMAを無効化
    move.w #$4000,$DFF024      ; DMAENをクリア

書き込み操作

    ; 1. 以前のDMAを無効化
    move.w #$4000,$DFF024      ; DMAENをクリア

    ; 2. グローバルディスクDMAを有効化
    move.w #$8010,$DFF096      ; DMACONのDSKENをセット

    ; 3. バッファアドレスを設定(Chip RAM内のソースデータ)
    move.l #WriteBuffer,$DFF020

    ; 4. DSKLENにDMAEN + WRITE + 長さを書き込む
    move.w #$C000+NumWords,$DFF024  ; DMAEN=1、WRITE=1、LENGTH=NumWords

    ; 5. 同じ値を再度書き込む
    move.w #$C000+NumWords,$DFF024

    ; 6. DSKBLK割り込みを待つ
    ;    ...(重要:書き込み中にDMAを途中で停止しないこと!)...

    ; 7. DMAを無効化
    move.w #$4000,$DFF024

警告: 書き込み操作を完了前に中断すると、現在のトラックのデータが破壊される可能性がある。書き込み後のDMA無効化はDSKBLK割り込みを必ず待ってから行うこと。

DSKBLK割り込み

コントローラがLENGTHで指定されたワード数を転送し終えると、DSKBLK(Disk Block Finished)割り込みを発生させる — INTREQ/INTENのビット1。これはDMA操作の完了を通知し、バッファに有効なデータが含まれること(読み取りの場合)、またはデータがディスクに完全に書き込まれたこと(書き込みの場合)を示す。

$DFF020

DSKBYTR — ディスクステータス

DSKBYTRレジスタはディスクコントローラのリアルタイムステータスを提供し、データストリームのバイトレベルCPUポーリングも可能にする(ただし通常の転送方法はDMA)。

ディスクバイトおよびステータスレジスタ
$DFF01ADSKBYTR — ディスクデータバイトとステータス(読み取り専用)
ビット 名前 機能
15BYTEREADYビット7–0に完全なデータバイトが利用可能になるとセット
14DMAONディスクDMAがアクティブ(DSKLENのDMAENとDMACONのDSKENが両方セット)
13DSKWRITEDSKLENのWRITEビットを反映(1 = 書き込みモード)
12WORDEQUAL現在のディスクワードがDSKSYNC値と一致
11–8未使用
7–0DATAディスクからの現在のデータバイト

CPUポーリングモード

BYTEREADYとDATAを使用して、CPUはDMAなしでディスクデータを1バイトずつ読み取れる。ディスクから完全なバイトが到着するたびにBYTEREADYがセットされる。DSKBYTRを読み取るとBYTEREADYがクリアされる。この方法はDMAよりはるかに遅く、実際にはめったに使われないが、診断用や特殊用途のコードには利用できる。

WORDEQUAL

WORDEQUALビットは、受信ディスクデータがDSKSYNCに格納された同期ワードと一致するたびに、短時間(約2マイクロ秒)セットされる。セット時間が非常に短いため、ポーリングで捕捉するのは困難であり、DSKSYNC割り込み(INTREQビット12)の方が信頼性が高い。

$DFF020

同期ワードとDSKSYNC

DSKSYNCレジスタにより、ディスクコントローラはデータストリームの任意の地点ではなく特定の位置からDMA転送を開始できる。

ディスク同期レジスタ
$DFF07EDSKSYNC — ディスク同期パターンワード(書き込み専用)

ディスクDMAが開始されると、コントローラはディスクからデータを読み取るが、直ちにメモリには書き込まない。代わりに、受信する各ワードをDSKSYNCの値と比較する。一致が見つかった場合のみ実際のメモリ転送が開始される。このメカニズムにより、コントローラはデータブロックの先頭にある特定の同期マーカーにロックオンできる。

標準Amiga同期ワード

AmigaDOSが使用する標準MFM同期ワードは$4489である。これは通常のMFMエンコード済みデータには出現しない自己同期パターンであり、セクタ境界の信頼性の高いマーカーとなる。

    move.w #$4489,$DFF07E      ; 標準Amiga MFM同期ワードを設定

DSKSYNC割り込み

ディスクデータがDSKSYNCと一致すると、コントローラはDSKSYNC割り込み — INTREQ/INTENのビット12 — を生成する。これはDMA転送が開始されたかどうかに関係なく発生する。ソフトウェアはこの割り込みを使用して、実際にデータを読み取ることなくセクタの開始を検出できる。

ADKCONのWORDSYNCビット(ビット10)をセットして同期ワードマッチングを有効にする必要がある。WORDSYNCがクリアされている場合、コントローラは同期ワードを待たずに即座にDMAを開始する。

$DFF020

MFMエンコーディングとADKCON

データは生のバイナリ形式ではフロッピーディスクに書き込めない。ドライブの読み取り回路がクロック同期を維持するのに十分な信号遷移を保証するエンコーディング方式で、まずエンコードする必要がある。Amigaは2つのエンコーディング方式をサポートする:

  • MFM(Modified Frequency Modulation)— AmigaDOSおよびほとんどのAmigaソフトウェアが使用する標準エンコーディング。
  • GCR(Group Code Recording)— 他のシステムで使用される代替エンコーディング。

エンコーディングモードと関連パラメータはADKCONレジスタのビットで設定される。

ADKCONディスク関連ビット
$DFF09EADKCON — オーディオ/ディスク制御(書き込み専用、ビット15 = SET/CLR)
$DFF010ADKCONR — オーディオ/ディスク制御リードバック(読み取り専用)
ビット 名前 機能
15SET/CLR1 = ビットをセット、0 = ビットをクリア(書き込み専用)
14PRECOMP1プリコンペンセーション選択(上位ビット)
13PRECOMP0プリコンペンセーション選択(下位ビット)
12MFMPRECエンコーディングモード:0 = GCR、1 = MFM
10WORDSYNC同期ワードマッチングの有効化(1 = 有効)
9MSBSYNCMSB同期の有効化(GCRモード)
8FASTディスククロックレート:1 = 2 us/bit(MFM)、0 = 4 us/bit(GCR)

プリコンペンセーション

フロッピーディスクの内側トラックにデータを書き込む際、高いビット密度により隣接する磁気遷移が互いにシフトする可能性がある。プリコンペンセーションはこの効果を打ち消すために書き込みパルスのタイミングを調整する。

ビット14 ビット13 プリコンペンセーション時間
00なし(無効)
01140ナノ秒
10280ナノ秒
11560ナノ秒

標準MFM設定

通常のAmigaディスク操作(880 KB 倍密度ディスク)では、標準ADKCON設定は:

    ; MFMモード、WORDSYNC、FASTクロックレートを有効化
    move.w #$9500,$DFF09E      ; SET + MFMPREC + WORDSYNC + FAST

これによりMFMエンコーディングが設定され、セクタ整列読み取り用の同期ワード検出が有効になり、倍密度メディアでのMFMに適した2マイクロ秒/ビットのクロックレートが選択される。

MFMエンコーディングの原理

MFMエンコーディングでは、各データビットにクロックビットが伴う。クロックビットは、現在のデータビットと前のデータビットの両方が0の場合にのみ1にセットされる。これにより、エンコード済みビットストリーム内で3つ以上の連続するゼロが発生しないことが保証され、ドライブハードウェアによる確実なクロック回復が維持される。

エンコーディングルール:

  • データビット101としてエンコード(クロックビット不要)。
  • データビット1の後のデータビット000としてエンコード(クロックビットなし)。
  • データビット0の後のデータビット010としてエンコード(クロックビットが挿入される)。

つまり、各データバイトはディスク上で16ビットになる(8データビット + 8クロックビットがインターリーブされる)。ソフトウェアがMFMのエンコード/デコードを実行する必要がある。コントローラはエンコード済みビットストリームの物理的な読み書きのみを処理する。

$DFF020

データレジスタ

ディスクコントローラは、DMAチャネルとディスクドライブ間の実際のバイトレベル転送に専用データレジスタを使用する。

DSKDAT — 書き込みデータ($DFF026、書き込み)

このレジスタはディスクに書き込むデータを保持する。DMA書き込み操作中、DMAコントローラはディスククロックで決定されるレートでメモリからこのレジスタを自動的に充填する。

DSKDAT — 読み取りデータ($DFF008、読み取り)

このレジスタはディスクから読み取ったデータを保持する。これは早期読み取りレジスタであり、DMAコントローラ専用でCPUからは読み取れない。CPUによるディスクデータへのバイトレベルアクセスにはDSKBYTRを使用するか、より一般的にはDMAにデータをメモリバッファに直接転送させる。

完全な読み取り例

以下のコードはドライブ0のディスクから1つの生MFMトラックを読み取る:

ReadTrack:
    lea    $DFF000,a5

    ; 以前のDMAを無効化
    move.w #$4000,DSKLEN(a5)       ; DMAENをクリア

    ; バッファポインタを設定
    move.l #TrackBuffer,DSKPTH(a5)

    ; 同期ワードを設定
    move.w #$4489,DSKSYNC(a5)      ; 標準AmigaDOS同期ワード

    ; MFM + 同期用にADKCONを設定
    move.w #$7F00,ADKCON(a5)       ; まずディスクビットをクリア
    move.w #$9500,ADKCON(a5)       ; MFMPREC + WORDSYNC + FASTをセット

    ; ディスクDMAを有効化
    move.w #$8010,DMACON(a5)       ; DSKENをセット

    ; DMA読み取り開始:0x1900ワード = 6400ワード = 12800バイト(1トラック)
    move.w #$8000+$1900,DSKLEN(a5) ; 1回目の書き込み
    move.w #$8000+$1900,DSKLEN(a5) ; 2回目の書き込み(DMAを有効化)

    ; 完了を待つ
.wait:
    btst   #1,INTREQR+1(a5)       ; DSKBLKビットをテスト
    beq.s  .wait

    ; 後処理
    move.w #$4000,DSKLEN(a5)       ; ディスクDMAを無効化
    move.w #$0002,INTREQ(a5)       ; DSKBLK割り込みをクリア
    rts

バッファには同期ワード$4489の最初の出現から始まる生のMFMエンコード済みトラックデータが格納される。ソフトウェアはその後セクタヘッダを特定し、MFMデータをデコードして512バイトのセクタを抽出する必要がある。