Hatena::ブログ(Diary)

スティルハウスの書庫 このページをアンテナに追加 RSSフィード

2014-02-10

ハード素人が32bit CPUをFPGAで自作して動かすまで読んだ本のまとめ

男子たるもの一度は自分でCPUを作ってみたいものだけど、ICでLEDをピカピカさせた程度の経験しかないハード素人な俺だったので、CPUを自作してる東大生などを遠くから見て憧れてるだけだった。しかしおよそ一年前のこと、「MIPSなんて簡単に作れますよ!」とKさん(←FPGAでLispマシンを自作するような人)に言われて、お、おぅ。。そりゃKさんはそうでしょうよ。。あれ、もしかして俺にもできるかな。。? と思った。この一言がなければ32bitのCPUを自作しようなんて考えなかっただろう。

それから一年ちょい、とくに今年の正月休みやFPGA温泉でがっつりがんばって、なんとかMIPS Iサブセットの自作CPUが動いた。これはフィボナッチを計算してるところ。


D


ちなみに、これはこんな感じのフィボナッチのコードをCで書いて、

void main() {
    int i, *r = (int *)0x7f00;
    while (1) {
        for (i = 1; i <= 25; i++) {
            *r = fib(i);
        }
    }
}

int fib(int n) {
    if (n == 1) return 0;
    if (n == 2) return 1;
    return fib(n-2) + fib(n-1);
}

これをgccでMIPSバイナリにクロスコンパイルし、FPGAボードに読み込んで動かしてる。

このCPUは趣味で作ったので、実用性はまったくない。メモリは32KBだしfloatも例外もキャッシュもバスもなくLinuxは動かない。でも、CからコンパイルしたMIPSバイナリを実機で動かすという目標を達成できて感無量である。実装したHDLコードはCPU32という名前で置いといた。そして、ここ一年くらいハードウェアの設計の勉強をしてきた中でこれはとても役に立ったっていう本がいろいろあったので、以下にまとめておきたい。


まずはLチカ、デジタル時計、シリアル通信あたり

一年ほど前になるけど、入門用FPGAボードの定番Terasic DE0を買って、LEDをチカチカさせるたり、デジタル時計を作ったりするところから始めた。



この時期にお世話になったのがこのあたりの本。


FPGA ボードで学ぶ組込みシステム開発入門 ?Altera編?

FPGA ボードで学ぶ組込みシステム開発入門 ?Altera編?


上の本はやたら高いし、Verilog HDL(ハードウェア設計用言語)の解説としてはベストとは言えないけど、Terasic DE0を買ってきてまずLチカさせたいって人にはちょうどいい内容。Lチカできたら、定番であるデジタル時計を書いてカウンタや同期回路の書き方を学び、つづいてMIDIに繋いで音を出したり、PCとシリアル通信したり、、って感じだったのが一年前の年末年始。


D

MIDIキーボードをつないで和音を出す


もっとも、FPGAの学習でまずハードルが高いのは、DE0などのFPGAの実機を1万円くらいで購入して、さらにQuartusなどのベンダーツールが動作する環境を用意するところ。ツールは無償なのだけど、どれもWindowsでしか動かないのがネック。


f:id:kazunori_279:20121218232714p:image:w360

AlteraのFPGA開発ツールQuartus II Web Edition


一方、以下の本ではIcarus VerilogというMacでも動作するオープンソースのツールを使い、ソフトウェア・エンジニア向けにFPGA開発のことはじめが解説されてるので、まずは実機なしでHDLのHello Worldを体験してみたいという人におすすめしたい。



そしてもうひとつ、最近Vengineerさんに教えてもらったのがEDA Playground。ツール等を一切インストールせずにブラウザ上でVerilog HDLのシミュレーターを使いながらの基礎レッスンを進められる。英語が苦にならない人向けだ。


つづいて4bit CPUを作る

つづいては4bit CPUを作ってみた。ここで、神いわゆるゴッドと言えるこの名著にたいへんお世話になった。


CPUの創りかた

CPUの創りかた


この本、前半まるっきりアナログな話だったり、FPGAどころかバラのTTL ICでCPUを組んだりと色々おかしい本(褒め言葉)なのだけど、しかしこれを繰り返し読みながら同じ設計の4bit CPUをHDLで書いていく作業を通じて、はぁ〜つまりCPUってこういうことなんだな!と目からうろこな体験ができた。とりわけ、著者が「迷ったらここに戻ってきてください」と記した1bitフリップフロップのページ、これが真髄だなぁと思うことしばし。自分でHDLで書いた4bit CPUをDE0で動かし、本書の巻末にあるラーメンタイマーのプログラムが動いたときは嬉しかった。。My first CPU!


この時期にお世話になった他の本は、このあたり。

Microprocessor Design Using Verilog HDL

Microprocessor Design Using Verilog HDL


上の本は、ベテランのハード設計者がVerilog HDLでZ80をまるごと実装してみたらどうなるか? っていう趣旨の本(英語)。こちらも、本格的な8bit CPUをHDLでガリガリ書くためのコーディングスタイルやプラクティス、テスト方法、そして設計手法(まずはステートマシンを表計算で設計する)を紹介してて、なるほどプロはこんなふうに仕事するのか〜と感心。

岸本さんの本はHDLで8bit CPUを作るもので、4bit CPUが動いた後に読むのに適した内容。例えばCPUの各コンポーネントをHDLで書くとどうなるか? テストベンチはどう書くか?ってイメージを掴むのに役に立った。


Verilog HDLの基礎、シミュレーション、そして検証技法のお勉強

しかしこの辺りで、どうもVerilog HDLのお勉強でカベにつきあたった。例えば代入の構文に「=」(ブロッキング代入)と「<=」(ノンブロッキング代入)という2種類があるのだけど、すべての演算が同時並列で進むデジタル回路なのにブロッキングとかノンブロッキングってどういうこと? ってしばらく理解できなかった。

答えを言うと、Verilog HDLはそもそも回路合成用の言語じゃなくて「回路シミュレーターのふるまいを記述するための言語」として生まれたものであり、ブロッキングとかノンブロッキングとはシミュレータの逐次処理のふるまいを指定するもの、なのだ。つまり、HDLをきちんと理解するには、シミュレーターの使い方やそれがどう動作しながらデジタル回路の動きを模倣してるのかを意識する必要がある、、ってハリー先生に教えてもらった。

4bit CPUを作る前あたりまでは、ほとんどシミュレーターを使わずに済ませていた。回路をLSIに焼き付けるASICとは違い、FPGAは自分で書いたコードをすぐに実機で試せるし、デバッグしたかったらSignalTapやChipScopeと呼ばれるロジック・アナライザを使えばある程度は信号を追えるからだ。よって、Verilog HDLのシミュレーター用言語としての使われ方も知る由もなかった。実のところ、Verilog HDLには回路合成とシミュレーションという2つの用途(セマンティクス)が存在し、しかも計算パラダイムもいろいろ混在してるので、ある段階になるとそれらの違いを意識しないといけない。

Altera FPGAの場合、本格的なシミュレーターとしてModelSimが無償で提供されている。このModelSimの使い方をこの本で勉強した。


図解 ModelSim実習  ゼロからわかるディジタル回路シミュレーション

図解 ModelSim実習 ゼロからわかるディジタル回路シミュレーション


ModelSimを使い始めて気づいたけど、シミュレーターでHDLを書いたほうがQuartus上で直接コーディングするよりもコンパイルが全然速くて生産効率がまるっきり違う。それに、制約の多いSignalTapに縛られることなく、すべての信号の状態をタイミング・チャート上で眺めつつデバッグできる。シミュレーターであらかたのバグを取っておけば、実機のみで出るバグはあまり多くない。ModelSimまじおすすめ。これ以降、ハード設計の時間の8割はModelSim上でのコーディング&デバッグ作業になった。飛行機乗ってて死ぬほどヒマな時とかにもHDL書ける。ひと通り書いたら、最後にQuartusでビルドして実機テスト&デバッグ、、という流れ。


f:id:kazunori_279:20140209195247p:image

ModelSimでシミュレーションしてるところ


もうひとつ避けて通れないのが、検証手法のお勉強。ハード開発の世界は、テストファーストどころか、開発コストの7〜8割が検証に費やされたりする。徹底した検証作業を専業とする検証エンジニアの方もとっても多い。ちょっとバグると数億円が飛んでしまうASICとは違い、FPGAではその場でどんどんバグを直せるのだけど、それでもハードウェアはソフトウェアよりもケタ違いに並列性が高く、どれだけいろいろなパターンと組み合わせでテストしても完全なバグの洗い出しは難しそうである。入門用のごく簡単なHDLを書いてても、検証コードをひととおり書いてテストを通しておかないと、なんだかまったくコードを書けた気がしないのだ。

そうしたハードウェア設計での検証の基本は、この本で勉強した。


Verilog HDL&VHDLテストベンチ記述の初歩 (DESIGN WAVE MOOK)

Verilog HDL&VHDLテストベンチ記述の初歩 (DESIGN WAVE MOOK)


検証のあたりを勉強すると、Verilog HDLの構文のかなりの割合がテストを書くためにあるんだな〜と分かってきた。もっとも、今回のCPUでは個々の命令実行の検証をHDLで記述してるとものすごく手間がかかるので、代わりに各命令を実行してその後のレジスタ状態をチェックするテストケースをMIPSアセンブラで書き、さらっと通しで流す程度である。CPUの検証を仕事できちっとやるのはものすごく大変そうだ。。

シミュレーション用言語としてのVerilog HDLの使い方、そしてシミュレーターがそれをどう解釈して実行するかの詳細については、あまりよい日本語の本がなさそうなのだけど、YouTubeにあるVerilog Lectureシリーズのビデオで丁寧に解説されている。英語だけど、リスニング教材としてもちょうどいいと思う。


D


ただし、このビデオの後半に出てくるタイミング検証用のいくつかの構文は、今のFPGA開発ではほとんど使われてないらしい。

それと、HDLの書き方に関して最近おすすめされたのはこの本。



Verilog HDLはシンタックスがゆるいので、きちんとしたコードを書くには一定のプラクティスやコーディングスタイルに添って書くことが重要、、と皆さんによく言われる。この本はそのあたりを網羅した本としてnatsutanさんに紹介していただいたので、じっくり読んでみたい。


いよいよMIPSを書く

そんな感じのハード設計修行をだらだらとやりつつ、今年の正月休みからいよいよ本格的に32bit CPUを書き始めた。ここでも、神いわゆるゴッド本の存在によってすっごく助けられた。皆さんご存知のパタヘネ。。ではなく、この本である。



現代のコンピューター・アーキテクチャの教科書といえばパターソン&ヘネシーであるが、上記の本はパタヘネをもっともっと分かりやすくして、しかも実際に動くCPUを作るために必要になりそうな領域をひととおり網羅してて、かつHDLによる実装例まで載せてくれている、至れり尽くせりの本だ。この本をブログで紹介されていたnatsutanさんに改めて感謝。これを読みながら自分でHDLを書いてMIPS命令を一個づつ実装して、あれこの命令ってどうやって実装するの? とつまづいたらこの本を読み直して、、という正月を過ごした。

もちろん、教科書であるパタヘネもぜひ手元に置いておきたい。



パタヘネを買ったのは10年か15年以上前のことで、本棚で永劫の眠りについていたのだけど、まさか今になってこのパタヘネをバサッと自炊して電車の中のiPadで繰り返し読むことになろうとは、本との関わりとは不思議なものだ。

実はMIPSを作り始める前に、ARMの方がいまどきっぽくない? と思ってARMのアーキテクチャを調べてたのだけど、なかなかに複雑な部分(命令エンコーディングとか)もあったり初期アーキテクチャに基づく教科書や資料の豊富さではMIPSにかなわないので、断念してオーソドックスなMIPSで行くことにした。でも、以下のARM本はARMアーキテクチャを知る上でとても参考になった。


ARMで学ぶ アセンブリ言語入門

ARMで学ぶ アセンブリ言語入門


自分で実装してみると、MIPSの命令セットや命令エンコーディングがそのまんま素直に回路設計に落とせるようになってるところが結構感動した。なーるほど、コレはここがラクになるからこういう設計になってるんだね、という感じで。

// arithmetic operations
  always_comb begin
    case (cpath[`CP_ALU_CTRL])
      `R_sll:     result = rt_or_imm << inst[`I_SHFT];
      `R_srl:     result = rt_or_imm >> inst[`I_SHFT];
      `R_sra:     result = $signed(rt_or_imm) >>> inst[`I_SHFT];
      `R_sllv:    result = rt_or_imm << rs[4:0];
      `R_srlv:    result = rt_or_imm >> rs[4:0];
      `R_srav:    result = $signed(rt_or_imm) >>> rs[4:0];
      `R_jr:      result = {rs, 32'b0 };        // jump to [rs]
      `R_jalr:    result = {rs, (pc + 32'd8) }; // jump to [rs], $ra = PC + 8 (incl. delay slot)
      `R_mfhi:    result = hilo_q[63:32];
      `R_mthi:    result = {rs, hilo_q[31:0]};
    ...

ALUまわりのHDLコード


一方で、まだパイプライン実装まではたどり着いてないし、例外(システムコールやトラップ)、キャッシュ、バス、MMUといった現代のCPUに不可欠なコンポーネントはどれも実装できていないしできる気がしないので、これを仕事で設計してしかもきっちり検証されている方々との間の超えられないカベを改めて認識。

ちなみに、もし自作MIPSで例外、キャッシュ、MMUなどOSカーネルとのやりとりのあたりをきっちり実装したかったら、この本がさらなる神本となるであろう。



MIPSとLinuxカーネルとの間の、まー低レベルもいいとこの詳細を話を解説した本だ。しかし、俺の力量ではこの領域には達せないだろうなぁ。。


MIPS GNUツールチェイン、ハード&ソフト連携、SoC

その他、今回はMIPS版のGNUツールチェインを使ってCコードからアセンブラを生成、そしてELFファイルからバイナリを引っ張ってきてMIPS用マシンコードを生成したので、バイナリまわりのツールの使い方を以下の本でお勉強した。


Binary Hacks ―ハッカー秘伝のテクニック100選

Binary Hacks ―ハッカー秘伝のテクニック100選


この著者の方々のお名前はどこかで見たことがある気がするぞ。。objdumpやreadelf等のバイナリいじりのためのツールはこれまでまったく触れる機会がなかったし、ELFファイルの構成やアセンブラのマクロの意味、関数呼び出し時のレジスタの使い方、スタックポインタやフレームポインタの動きとか、これを機にいろいろ学べた。

そして今後は、CPU上のソフトウェアとFPGA上のハード間の連携手法をお勉強していきたい。そうしたSoC (System on Chip)の世界ではどんな感じでシステムを設計するのか詳細に解説してるのは、栗元さんのこの本。



CPUで動くソフトウェアとFPGAで動くハードウェアの両方を自作して、それらをバスでつないでSoCを構成する、、という我々が目指すべき世界の詳細が記されているのだけど、今の俺のレベルではまだ手が届いていない。

それともう一冊、Alteraのバスまわりを勉強するためにFPGA技術のVol. 5のおさふねさんの連載をとっても読んでみたいものの、残念ながら在庫切れ。。とりあえずVol. 6は入手したのでこれから読むところ。


CPU自作はおもしろい

というわけで、振り返るとなかなかに密度の濃いお勉強コースであった。途中、長い放置期間もあったので、実質かかった時間は週末×3〜4か月くらいだろうか。ソフトウェア・エンジニアのCPU自作は楽しいなーという話。FPGAに興味のあるソフト屋さんは3/10のFPGAエクストリーム・コンピューティング第5回に来るといいよ!

bengelbengel 2014/02/11 03:33 参考になります!

spinutespinute 2016/02/13 12:30 今年の3月にパタヘネARG版が出るそうですよ!
http://store.elsevier.com/product.jsp?locale=en_JP&isbn=9780128017333

spinutespinute 2016/02/13 12:30 (ARMです)

kazunori_279kazunori_279 2016/02/28 05:01 おお!これはおもしろそう。ありがとうございます!

はてなユーザーのみコメントできます。はてなへログインもしくは新規登録をおこなってください。

トラックバック - http://d.hatena.ne.jp/kazunori_279/20140210/1391989012