作ったもの東大の情報科学科では3年の秋学期にCPU実験という、自分たちでCPU、コンパイラ、シミュレーターを作ってレイトレーシングを動かすことが単位要件の名物実験があります。僕らの班では12月初旬に単位要件を満たすCPUは出来ていたので、2/20にあった成果報告会までの間にIwashi班という自作CPU上でlinuxを動かすことを目標とした余興班を作ってこのエントリのタイトルにあるような結果に終わったのでその報告をしたいと思います。後輩の進捗を覗きに来たISの先輩その他面白いと思ってくれた界隈の人CPU実験でははじめにFPGAとコンテストサーバーを渡されてレイトレをしろと言われるだけで基本的には何も教えてはくれないので学生は先輩のブログなどを読んで情報を収集します。自分達も先輩のブログに助けられたので今度は後輩が参考になるようなブログを書きたいと思います。私の班でIwashi班の元となった班が6班で、メンバーは僕(コア)、maane123(コンパイラ)、mdj982(シミュレーター)とあと一人最終的に失踪してしまったしかく係*1で構成されていました。Iwashi班のメンバー*2は僕(コア書いた、linuxのデバドラ書いた、シェル書いた、発案したり人々に仕事振ったりした)、kcz146(CでフルスクラッチでOS書いた、QEMUに追加命令実装した)、mdj982(シミュレーター書いたりデバッグ手伝ってもらったり色々)、hikalium(QEMUのバグ直した、カーネルパニックさせた)です。Adelie(6班1stアーキ)のソースコードがここ、Iwacpu(班横断2ndアーキ)のソースコードがここです。できたこととできなかったことコアでlinux動かすのはできなかったQEMU、linuxを移植してQEMU上でlinuxが起動してカーネルパニックしてるところが見れた自作OSがコア上で動いた!シェルが動いている動画(バックで話しているのでとてもうるさい):youtu.beコンテキストスイッチしている動画:youtu.be技術的な詳細ISA僕らの班ではISAはriscvのものを元にした。理由は私が将来性を感じて好きだったから(当時)。dayにも行ったりなどもしてriscvについてはかなり知見を深めたので今ではいいところと悪いところが見えてきた。よかったところ他の班はMIPSやPPCを元にしていたが、それよりはずっとマシだったと思う。MIPSやPPCは良くも悪くも古いので、なんでこんな仕様にしたんだ・・・という仕様が沢山ありそれが嫌だったので自分たちで修正しました・・というような班が多かった。その点、riscvは反省を元に作られているので単純かつ必要十分で仕様に対して怒りが湧くことはほぼなかった。おすすめできるISAである。riscvに関する書籍は限られているためFPGAマガジンのRISCV特集という本がとても役に立った。コンパイラとシミュレーターにRV32Iの仕様書を渡してこれでいくからよろしく!と言ったら大体形にはなる。仕様はここに書いてある。ISAは良いが・・・・。全体的に理想論すぎるという印象を受けている。riscvはバークレーが「オープンソースならぬオープンISAを作ることによって企業の興隆にソフトウェア資源が依存するのをやめよう」というモチベーションで始められたもので、バークレーはMIPSの開発元でもありアーキテクチャ関係ではとても強い大学なので流石にしっかりしているが、アーキテクチャの仕様というのはISAだけではないだろう。riscvはISA以外の仕様はほぼないので実装任せな部分が非常に大きく、結局実装任せじゃないか・・という気持ちになった。バークレーのOBが作ったベンチャーのSiFiveという会社がriscv実装のチップを提供していて、こことバークレーくらいしか諸々のソフトウェア資源のメンテナンスをしていない。riscv-linuxなど。wrapperなども32bitがunsupportedなどととても発展途上である。ISAが綺麗でも環境が整備されて使われなければなんの意味もないので本当に頑張ってほしい。結論riscvのISAは、自分で実装するのはおすすめだ。実際riscvのFounderであるKrste*3も、中小企業で小さいCPUを作らなければならなくなったら是非riscvを使って欲しいと言っていた。その需要は現に僕が使ったのであると思う。チップの性能はISAでは決まるものではないしIntelなどのCPUを量産するような大企業にとってはriscvを採用するアドバンテージが何一つないので普及するかはかなり疑問である。memoryという5段階に加えてfloatingやuartもあるのでstoleも付けた。細かくステートで分けるのは良かったと思う。実装も難しくないし愚直に実装しても300Mz余裕で出たので結果的に結構早くなる。詳細はコードを見て欲しい、結構コメントも書いてあるので読みやすいと思う。pointIPコアが使えるので楽勝である。ISAのところでも書いたが、浮動小数点関係の命令はFLW,FSW,FADDS,FSUBS,FMULS,FDIVS,FSQRTS,FEQS,FLES,FSGNJXS,FMVSX,FCVTWS,FCVTSWを実装した。MMIOや夏学期に実装するオレオレuartを使う手もあるが正直全然おすすめしない。僕らの班はuartliteを使った。uartよりは若干単純なのでとりあえず動かしたい班にはとてもいいと思うが、僕らは最終的にOSを動かしたくてDRAMも使いたかったのでDRAMを使うモチベーションがある人はuartを使うと二度手間にならなくていいと思う。rate上げても大丈夫なこと確認する、としっかりやったほうが後々無限にバグらせることがなくて良いと思う。自作OS/Shellの仕様タイムラインのセクションでも順を追って詳しく話しているので2月のところを読んで欲しいが、まとめると以下のようになる。動機Linuxは冷静に考えてこの数日で無理なので、小さいOSを動かしたい。OSの本質の1つとして、タイマ割り込みからのコンテキストスイッチによるマルチタスクがあるので、ここを実装すれば、OSを動かせたことになる。(たぶん)やることノイマン型。命令メモリ・データメモリをわけず、1つのメモリを共有する。デュアルポートにしようと思うシミュレータとコアに、MMUによる仮想アドレス→物理アドレス変換を実装する。シミュレータとコアに、雑タイマ割り込みを実装する。Kernelを実装する。実装方針1ページは4096byte。32ページによる仮想アドレス空間。仮想メモリアドレスは0x20000未満。よって、下12bitがページ内オフセット、それ以外がページ番号を指す。32個のページが、物理アドレスのどこから始まるかを表す。MMUによる仮想アドレス機能を有効/無効にする。無効のときは、メモリアドレスは、そのまま物理アドレスを表す。タイマ割り込みハンドラの関数アドレス(物理アドレス)を格納する。タイマ割り込み時は、MMUを無効に設定しつつ、この関数に飛ぶ。タイマ割り込みハンドラから戻るべき先を格納する。常に仮想アドレスが入っている。コアにもシミュレータにもあるって言ってた。MMUが有効である間、一命令実行する毎にインクリメントされる。これが一定数(1000くらい?)になったとき、タイマ割り込み動作を行う。10’b1111111111ごとに初期化する。上述したとおり、仮想アドレスがあったとき、Offsetは下12bit。Offsetにアクセスする。MMUが無効であるなら、それはそのまま物理アドレスである。タイマ割り込みの挙動コア・シミュレータは、命令を実行するたびに、「MMUが有効であるならば、カウンタレジスタをインクリメントする」をする。)以上のとき、次に示すタイマ割り込みを行う。ないときは、普通に次の命令に進める。Registerの内容にセットiretの挙動MMUを有効化する。Kernelの実装コンテキストスイッチをする。