この記事は愚痴です。
動かないIOラッパ
まさかIOでハマるわけがないと思っていた。IOなんて夏学期と夏休みで何回も書いたはずなのに...
Carina 内部で用いるデータは4byte単位なので、夏学期に書いたIOをword=4bytes 単位アクセスできるようにちょっとラッパするだけだ。1日あれば終わるはずだった。まさか20日もハマるなんて。Carina 最大の誤算がこれだ。シミュレータでは動くのに実機では全く動かない現象。完全に寿命が縮んだ。
絶対ucfファイル確認しような(12 days)
実機は0x00を返すばかり。完全に謎だった。
SRAM とRS232Cを用いる。そこでucfファイルは夏学期の実験で使用したものをコピペして使った。SRAMを使えているかのテストをし、デバッグ出力を実機に送信するという内容の実験だった。ここに大きな見落としがあって、この実験ではデータをPCから受信していないのでRS-RXの制約が抜けていたのだ。ucfの入れ忘れではなく、100行近いucfファイルに1行抜けがあったのだ。
ここのデバッグは概ね次の要領で行われた。
- 余計に待ってみたり、ラッチを入れたりして確実にデータを受け取る
- シミュレータで正しく動くことを確認する
- ucfがないので実機で正しく動かない
- タイミングのバグを疑う
- 1に戻る
ラッパするだけだったモジュールは、いつしか完全にグニャゲッティと化した。これが後述の full-empty-hack問題を起こす。
First Word Fall Through(2 days)
core generator が生成する同期FIFOには大きく2つのモードがある。Standard FIFOと FWFT FIFOだ。前者はread_enableを掛けると、次にREを掛けるまでFIFOの最後のデータが出力され続ける。後者はFIFOの最後のデータは到着以降常に出力されており、REを掛けるとFIFOが一つ流れて、次のデータが出力されるようになる。感覚としては前者のREは「データを読ませてくれ」のREであり、後者のREは「データを読んだので次を頼む」のREだ。
IOのbufferとしては後者のFIFOの方が良かった。前者だとREを掛けてから1clk待たねば読めないからだ。しかし、夏学期の僕は前者を用いてIO moduleを構成していた。そもそもFWFTモードの存在を知らなかったのである。コアは後者のFIFOを前提して組んでいた。ここの埋め合わせもIOラッパがしなければならない。IOラッパが更に水膨れする。
full-empty-hack(3 days)
元々のIOユニットにはFIFOがついていたので、タイミングを気にすることなくバーストアクセスできるはずだった。しかしFIFOから4byteを読んで1wordのデータをこしらえている以上、それは不可能になった。どうするか。
最適な設計は、 FIFOをbyteではなくword単位のものに変えて、ラッパの外側におくことだろう。しかし、このIOラッパは下手なところを触ると途端に動かなくなった。それに今動いているところを書き直す体力は残っていなかった。そこで、FIFOから出てくるfull,emptyを誤魔化そうという発想に至った。ラッパで作業している最中はfullやemptyを立てておき、コア側からのアクセスを遠慮してもらう。自分がもはや正気で無いのはわかっていたが、一刻も早くIOの実装を終わらせたかった。
int main(){
puts("hoge");
return 0;
}
を2週間掛けても書けないでいるなんて!
test(1 day)
無心でテストを書いていた。IOを書くためだけに学校に10泊以上していた。たかがIOのために。テストケースが全て動作していることを確認すると、僕はIOフォルダに心の中で chmod 444 した。僕自身は二度とそのディレクトリを覗くことはないはずだ。アクセスごとにfullとemptyが数クロック起ち続けるゴミIOが一つ世に生まれた。
IO revival(3 days)
衝撃の事実。raytracerはword-wise送信をしなかった。全てが無駄だった。
IOの中身も、プログラムローダも、コアも、この頃には闇IOラッパの闇と四つに組んでしまい分離不可能であった。byte-wiseアクセスモードを追加するのに3日要した。
IO再設計
完動した。次にすることは明らかだ。一番下から一番上までIOを再設計する。夏学期のIOは使わない。CarinaのIOラッパは見もしない。一から全部書き直す。前回の反省を踏まえてたっぷり2週間取った。
1日で完成した。
教訓
ダメなときはフルスクラッチしましょう。