FPGAで32bit RISC-V CPUを作った話

## はじめに

皆さん、CPUを作ってみたいと思ったことはありませんか？
自分はあります。
CPUをFPGAを用いて実装するという実験がある学科もあります（東京大学理学部情報科学科のCPU実験などが一部では有名です）が、自分の所属している計数工学科ではそのような実験はありません。
院試が終わった後、一か月弱時間があったためCPUを作ってみることにしました。

## 今回作ったCPUの概要
命令セット:だいたいRISC-V RV32imf（権限に関する命令は実装していない）
整数命令5段パイプライン（RISCの基本的なパイプラインを踏襲）
浮動小数点ユニット : 浮動小数点レジスタを別に用意しており、9段パイプライン
シリアル通信可能
レジスタフォワーディング実装
FPGA評価ボード(DE0-lite)で動作（動作周波数は50MHzほど）

## 用意するもの

### FPGAとは？
AND OR NOTと呼ばれるような論理ゲートを大量に用意して、それらを組み合わせることが出来れば、任意の計算が出来ることが知られています（チューリング完全と呼ばれます）。自由に繋げることが出来る大量の論理ゲートを備えた素子があれば好きな計算を実装できそうです。そのような大量の論理ゲートを用意してそれらを繋ぐような素子があって、FPGAと呼ばれます。今回のFPGAでCPUを実装するという試みは、チューリング完全なシステムを用いて万能チューリングマシンを実装するというお遊びな訳です。

FPGAはAlteraとxilinxという二つのメーカーがメジャーです。今回用いたDE10-Liteという評価ボードには、MAX10というAlteraのFPGAが載っています。
東大の情報学科で行われているCPU実験ではxilinx製の数十万円するFPGAを用いているようですが、今回使用したものは学生ならば55ドルで購入できてお財布にも優しいです。壊してもまた買えばいいので非常に気軽に扱うことが出来ます。

### UART
何かしらのインターフェースを持たないとCPUを作っても使い道がありません。今回はひとまずシリアル通信を実装することにしました。[USBからの変換モジュール](http://akizukidenshi.com/catalog/g/gK-01977/)は秋月電子などで購入できます。
シリアル通信の細かい規格は良く分かっていませんが、今回のチップはRS-232という規格に対応しているようだったので、グーグル先生にプロトコルを教えてもらい、雰囲気で送受信するモジュールを書いたら動きました。

### 教科書
今回CPUを実装するという事で「コンピュータの構成と設計」（通称パタヘネ）という有名な教科書を一通り眺めました。英語版しか手元になかったこともあり大体しか読んでいませんが、簡単なCPUのデータフローの図や、基本的なRISCプロセッサの高速化手法などが載っており非常に参考になります。今までは命令セットの例としてMIPSが用いられていましたが、最新版にはRISC-V版もあります。（大した違いはないと思いますが）
今回、回路を書く言語としてverilogを選択したのでverilogの書き方を学ぶ必要があります。verilogはC言語の構文を基に作られた言語ですが、構文の制約が緩いため良くないコードを書いてもコンパイルが出来てしまいます。「LSI設計の基本 RTL設計スタイルガイド Verilog HDL編」という本の前半部分が非常に参考になりました。


## 実装手順
RISC-Vの[規格書](https://riscv.org/specifications/)を手元に用意して、その命令を順番に実装していくことになります。
今回の自分の実装手順としては、
整数演算->ジャンプ->条件分岐->load store->（ここでフィボナッチ数列の計算が出来るようになる)
->7セグIO->UART IO
->ハーバードアーキテクチャからフォンノイマンアーキテクチャへの変更（命令用のメモリとデータ用のメモリを共有するようにする）
->プログラムローダのソフトウェア実装（UARTを用いてプログラムを外から流しこむことが出来るようになる）
->レジスタフォワーディングの実装
->パイプライン段数を4段から5段にする
->パイプラインハザードをソフトウェア側で回避しなくても問題なく動くようにする
->FPUの実装
->gccのクロスコンパイラを用意
->gccが出力した対応していない命令を順番に実装していく

という手順でした。アセンブラも自作した為、CPUの実装と並行してアセンブラの実装も進めました。途中でパイプライン段数を変えるなどの仕様変更を行うのは非常にめんどくさいので最初からちゃんと考えておいた方が良いでしょう。全ての計算が並行に進む為、どのように現状の回路が動いているのか把握するコストが非常に高く、仕様変更の結果コアがうまく動かなくなった場合復帰困難です。
折角なので設計を考えているときの謎のお絵描きの画像を置いておきます。
![CPU-13 (4).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251724/ba84bd67-385a-b91b-0236-29c842e13275.jpeg)


## 実際の動作
マンデルブロ集合

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">夏休みに作った自作CPUでマンデルブロ集合を描画している様子です<a href="https://t.co/oa187tNjEi">https://t.co/oa187tNjEi</a></p>&mdash; トマボウ (@28tomabou) <a href="https://twitter.com/28tomabou/status/1186988424718237697?ref_src=twsrc%5Etfw">October 23, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

Brainf*ckインタプリタ

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">自作CPU上のbrainf*ckインタプリタでHello world<a href="https://t.co/ifthL6mPJl">https://t.co/ifthL6mPJl</a></p>&mdash; トマボウ (@28tomabou) <a href="https://twitter.com/28tomabou/status/1186988700451758080?ref_src=twsrc%5Etfw">October 23, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

これはチューリング完全なシステム（FPGA）上に実装した万能チューリングマシン（CPU）上でチューニング完全なシステム（brainf*ck)をシミュレートしています。面白いですね。

## 感想と反省点
* CPUアーキテクチャに対する理解が非常に深まった。
* RISC-Vの規格書は非常に分かりやすく、不合理な命令はほとんどないため、RISC-Vベースで作っていくと特に困ったことはなく基本的なCPUが実装できた。
* gccなどがRISC-Vに対応している為、コンパイラを用意しなくても大丈夫なのは一人でやるうえでは気楽であった。
* 55ドルのFPGAでも論理ゲートの数としてはシンプルなRISC-Vのチップを実装するのには十分である。しかしオンチップメモリの容量は非常に小さいためまともなプログラムを動かす為には外部DRAMとの通信を実装する必要がある。
* 最初からパイプラインを実装するのは止めた方が良い。一度シンプルなコアを実装してハマりどころが分かったうえで対処するべきである。
* RTLシミュレーションは非常に大事であるのでRTLシミュレーションをちゃんとやった方が良い（quartusのコンパイルは非常に時間がかかるため、RTLシミュレーションツールでコンパイルを行うと非常に手早くデバックが出来る）
* しかし今回用いた浮動小数点演算のIPは上手くRTLシミュレーションが出来なかった。仕方がないのでFPUのデバッグは目力で行った。
* コアのシミュレーターを書かなかったため、アセンブラのデバッグが非常に面倒であった。シミュレーターは書いた方が良い。


## 今後の展望
時間が出来たら外部DRAMを使用できるようにしたいです。権限まわりを実装して簡単な自作OSを動かしたり、自作コンパイラを動かすことが出来たら非常に楽しそうです。

githubリポジトリは[こちら](https://github.com/tomabou/cpu_core)です

皆さんも是非自作CPUを作ってみてください！