FPGAでFDDコントローラを作る (2) リード処理
前回ではモータとヘッドを制御する回路を実装して実際に動かすことができました。今回は、実際にFD内のデータを取り出すための実装を考えていきます。
データはもう出ている
3.5インチFDDの場合ヘッドは常に磁気面に接触しているので、モータを回した時点ですでにREAD DATA信号からパルスが出ています。これを一定周期でサンプリングすれば生のデータが得られます。
ここでは、まず16MHzの周期でデータをサンプリングすることにします。サンプリングの開始はINDEX信号がONになってから、1周して再びINDEX信号がONになった時点で終了にします。これだと1周分のデータサイズは16MHz*(60sec/300rpm)=3.2Mビットなので8で割ると約400Kバイトになります。
データの流れを図にするとこんな感じでしょうか。
16MHzの周期でREAD DATA信号をサンプリングしてこれをシフトレジスタに入れます。シフトレジスタは32ビットで左にシフトしていきます。これがいっぱいになったらSDRAMに書き込むようにします。図にすると単純ですが実装となると結構面倒…。
SDRAMに保存
データは基本シーケンシャルに書き込んでいきますが、複数のトラックを一度に読んで書き込むような場合でも各トラックのデータであることが分かるように書き込みを開始したアドレスと書き込んだデータサイズを保持しておくようにします。SDRAMは32Mバイトなので32M/400K=最大80トラック分を一度に格納できます。
SDRAMには制御プログラムからもアクセスするため、データはNiosIIマイコン内にあるSDRAMコントローラに渡します。ちなみに、NiosIIマイコンはマルチレイヤバスなので制御プログラムがSDRAMにアクセスしていなければほぼウェイト無しで書き込めます。
SDRAM R/Wモジュールは以下のように動作します。
- (1) 最初に書込みを開始したアドレスを保存。
- (2) データを書き込む。
- (3) 書き込んだサイズを加算して保存。
- (4) データ末尾まで(2),(3)を繰り返す。
(1)(2)(3)は同時ではなく順序立てて動かす必要があるため、FPGAの実装ではステートマシンを使うことになりますね。
これらハードウェア部分を実装したら、例によってシミュレーションを行います。毎度テストベンチやらテストデータやら作らなければならないのでこれがもう大変。
ソフトウェアも実装
SDRAMに保持したデータをWindows PCにJTAG(USB)経由で送信するための機能を制御プログラムに実装します。PC側にもデータを受信するプログラムを作成します。これらは仮想FDDで作ったものがすでにあるのでこれを流用して実装します。
制御プログラムのデバッグをシミュレーションで行うと時間がかかってしょうがないのでそのまま実機に入れてテストすることにします。
実機で動かしてみる
まずは、FDDからのデータをSDRAMに取り込んでみます。PCからFPGAに指示を出します。MAX10-JB基板に載っているJTAG通信中の黄色LEDが点灯してLCDに反応がありますがそこからダンマリ。
こういう時はロジックアナライザで怪しい信号線を監視して不具合を特定していきます。結果、タイミングが合っていないようです。シフトレジスタからのデータをハザード中にラッチしていたりと、これらを考慮せずシミュレーションしていたため検証も甘かったようです。
この辺りを直し、シミュレーションも一からやり直して、FPGAをコンフィグレーションして…フゥ…あ、動きました。
次は、サンプリングしたデータをPCに送信します。こちらもPCからFPGAに送信指示を出します。ん?動かないですねぇ。これらはソフトウェアで処理しているのでソースを修正して再トライ。こちらは少し直しただけで動きました。
パルス波形を確認
データが受信できたので中身を確認してみます。まずは、データがどういう波形になっているのか見てみます。
波形から、というより2HDだとわかっているので、記録方式はMFMであることがわかります。と、その前にFDにデータがどのように記録されるのか、を簡単に説明すると:
- データにはクロックパルスとデータパルスがある。
- 記録方式としてFM方式とMFM方式がある。
- FM方式は、クロックパルスとデータパルスが交互に記録されている(データが0ならデータパルスなし)。
- MFM方式は、基本データパルスでデータ0が続くような所でクロックパルスが記録される。
- MFM方式はFM方式に比べデータ容量が2倍になる。
- 単密度(S)ではFM方式、倍密度(D,DD)や高密度(HD)ではMFM方式が使われる。
- 高密度(HD)は倍密度(D,DD)のパルス間隔を半分(周期を2倍)にしたもの。
次に、データパルスをビット0/1に置き換えたものを下図に示しました。
ん?ちょっとまった!クロックパルスとデータパルスはどのように見分けるのだ?しかもバイト境界はどうやって決めた?
そう、ここからさらにフォーマットを調べる必要があるのです。ここでフォーマットについて、簡単に説明すると:
- FDのフォーマットはIBMフォーマットと呼ばれる(FM方式はIBM3740,MFM方式はIBMシステム34)。
- フォーマットは、GAP, SYNC, AM, INDEX/ID/DATAの各フィールドがあり、左記の順序を繰り返す。
- FM方式では、GAPが0xFF, SYNCが0x00, AMは0xFC, 0xFE, 0xFBなどとなる。
- MFM方式では、GAPが0x4E, SYNCが0x00, AMは0xC2C2C2FC, 0xA1A1A1FE, 0xA1A1A1FBなどとなる。
- AMフィールドにはいくつかのクロックパルスが記録されないミッシングクロックが存在する。
データビット0/1を決定するには、まずGAPフィールドを、その後にSYNCフィールドがくるようなパターンを探すことになります。その結果、図中の上側のビット列&バイト列であることが決まります。
パルス間隔も確認
パルス間の長さも確認してみます。
図から、2,3,4マイクロ秒に集中していることが分かります。長さが3パターンあることからMFM方式、また最短が2マイクロ秒であることから高密度(HD)、これで2HDであることがわかります。
こちらは2DDです。間隔は4,6,8マイクロ秒と2HDの2倍の長さになっています。
PC-98シリーズのFDは読めるか
次に、NEC PC-98シリーズでフォーマットしたFDを読み出してみます。
データ自体は問題なく読み出せたようです。長さが3パターンあることからMFM方式ですが、長さが2.4, 3.6, 4.8マイクロ秒とPC/AT用より長くなっています。
使用しているFDDは3モードなのでMODE SELECT信号を切り替えてもう一度読み出してみました。
すこしばらついていますが、2,3,4マイクロ秒に集まっています。このことから、NEC PC-98シリーズのFDDはモータの回転数がPC/AT用のものより速かったことが分かりました。PC/AT用が300rpmなのでPC-98用は300*2.4/2=360rpmで動かしていたんですね。
FDDは何もしていない?
結局、FDDは磁気の変化をパルスにして出力しているだけで、記録方式やフォーマットには全く関知してません。だからこそパソコン本体にFDCが必要になるわけですね。
最後にもう1つ、3.5インチFDDは、2HDと2DDの区別は出来るのでパルス幅は変えているのかと思いましたが図を見る限り変わらないですね。やはりFDDは何もしていない?
記録方式やフォーマットはユーザ側で解析していかないといけない、ということで、次回はデータセパレータを実装してハードウェアでフォーマットに即したデータを取り出すようにしていきたいと思います。(つづく)
参考文献
- FDアダプタ - http://ldlabo.hishaku.com/NO46/main.htm
- PC-9821/9801シリーズとFDD - http://www.geocities.jp/cpuparts98/FDD/FDD_0.htm
- マイクロコンピュータMC6809の考え方, オーム社
- TEAC FD-235HG-C304 MICRO FLOPPY DISK DRIVE SPECIFICATION
- FUJITSU MB8877A Datasheet
FDDコントローラを作る (1) ←前 | 次→ FDDコントローラを作る (3)