Verilogでミニプロセッサを実装してみた
この記事はCAMPHORアドベントカレンダー22日目の記事です.
こんには,びいのです.普段は研究室でVerilogを書いていて,その勉強がてら小さいプロセッサ(RISC-VのI命令,R命令)を実装してみました.FPGA上で動くことを想定しています.
【想定する読者】
【やったこと】
Q:RISC-Vってなに?
https://riscv.org/specifications/
で仕様が定義されていて,誰でもこの仕様に基づいて無料で開発を行えます.
IntelとかARMのプロセッサはライセンス料が高いので,オープンソースで開発が行えるというのは革命的.
すばらしいですね.
ミニCPUの全体像
教科書に書いてそうなCPUのアーキテクチャをそのまま参考にしてつくりました.
今回はI命令とR命令のみ実装するので,データメモリは無いです.ジャンプ命令も簡単そうだったので実装しました.
おおざっぱな理解をしてもらうために図を置いときます(参考文献3より引用).データメモリは今回無いことに注意.
じゃあ,Verilogでどうやって書いたのか紹介していきます
なお,今回実装したもののソースコードはオープンに使って良いものとしてgithubにあげておきます.
プログラムカウンタ
プログラムカウンタを32ビットレジスタとして用意しておきます.毎サイクルごとに4バイトずつ増えていき,命令メモリから次の命令を取り出してくれます.
reg [31:0] pc; // pc is 0 at start initial begin pc <= 32'd0; end /// always always @(posedge clk) begin if(pc==`PC_LIMIT) pc <= 32'd0; else if(optype==`OP_JAL) pc <= pc + jal_offset <<2; else pc <= pc + 4; end
命令メモリ
実装する 命令が入っているメモリですね. 実装したものはFPGAで動かすことを想定しているので,FPGAのブロックRAM(BRAM)を使うつもりです. なので自分で実装することは何もないですね.楽ちんですね.
シミュレーションするときにはこのメモリの中に命令をいれなければいけないのですが,これは後述...
ALU
加算,減算,AND演算など,プロセッサの機能のメインとなる場所です. I命令,R命令それぞれでの動作を記述していたら長くなっちゃったので割愛.詳しくはgithubみてね.
レジスタファイル
演算結果を格納するレジスタ群です. レジスタの値を読み出す機能と,データの値をレジスタに書き込む機能が必要です.
module Register(readRegister1,readRegister2,writeRegister,writeData,readData1,readData2,clk,writeEnable);
// input and output
input [4:0] readRegister1,readRegister2,writeRegister;
input [31:0] writeData;
input writeEnable,clk;
output [31:0] readData1,readData2;
// 32 set of 32-bit registers
reg [31:0] registers [31:0];
// initialize memory to zero
integer i;
initial begin
for(i=0;i<32;i=i+1)
registers[i] = 0;
end
assign readData1 = registers[readRegister1];
assign readData2 = registers[readRegister2];
// write data to register on clk
always @(posedge clk) begin
if(writeEnable==1'b1 && writeRegister != 0)
registers[writeRegister] = writeData;
end
endmodule
ソースコードのコンパイル
ちゃんとプロセッサが動いているか確認するために命令メモリに0,1で書かれた命令を入れなきゃいけないんですが,いちいち0,1入れるのはとてもめんどくさい.
そこでテスト用のアセンブリを自分で書いてみて,アセンブリをコンパイルして出てきたバイナリを命令メモリにぶち込んでチェックしたいと思った.
そこで神のタイミングでトランジスタ技術12月号がFPGAでRISC-Vを実装する内容だったので,めちゃくちゃ参考になりました.(トラ技が特集してたから今回実装したわけじゃないよ!プロセッサの中身もトラ技の実装見ないで書いてるよ!)
詳しくはトラ技を読んでね....というのが手っ取り早い回答なんですが,それもつまらないので,少しだけ解説します.
1,RISC-Vのクロスコンパイラ,ツール群を準備
[https://github.com/riscv/riscv-gnu-toolchain:embed:cite]
これがアセンブリをRISC-Vで動くバイナリにするためのツール群になります.
git clone --recursive で取ってきて,ビルドします.
2,自分で書いたアセンブリをビルドする環境を整える
poyo-vのソフトウェアツールを使わせてもらいました.
[https://www.tartetrat.site/poyo-v/:embed:cite]
poyo-v/software/ 以下でc言語をrisc-v用にクロスコンパイルするMakefileがあるので,それをいじってアセンブリをコンパイルするようにしました.
最適化で追加した命令が消されないように,gccオプションを -O0にするなど,少し変更を加えて自分のアセンブリでも無事にコンパイルされるようになりました.
リンカスクリプトを見てみると,命令メモリの中で最初の命令は32Kiバイトから始まっているようである.プログラムカウンタの初期値もこの値に変更した.
.text .globl main main: addi x1,x1,1 addi x2,x2,2
みたいなコードを用意して,
Makefileを実行して出てきた
code.hex,data.hexをそれぞれ命令メモリ,データメモリに入れれば実行してくれるはず.
さあ,シミュレーションだ!
シミュレーションの結果,I命令,R命令が機能していることを確認した.実験は成功だ!
今後やりたいこと
今回はプロセッサの本当に基礎的な部分だけの実装だったんで,他の部分にも手をつけていく.
メモリロード/ストア命令,乗算器,除算器の追加
パイプライン化,アウトオブオーダー化
OSサポート命令の追加
感想
正直クロスコンパイラ関係で知らないことが多かったので,そこで時間を取られてた.
しかし,objdump,リトルエンディアン,リンカスクリプトについて自分の手を動かしながら理解できたのは良かった.
みんなも自作プロセッサ,やってみよう!
参考文献
1,RISC-V specification
https://riscv.org/specifications/
2,トランジスタ技術 2019年12月号
https://toragi.cqpub.co.jp/tabid/887/Default.aspx
3, プロセッサの中身の図はこの論文から引用
Joseph, Michael & Ravi, Selvaraj. (2016). FPGA Implementation for Low Power Self Testable MIPS processor.
4,poyo-v github
https://github.com/ourfool/poyo-v
5,riscv-gnu-toolchain
わいの実験用LaTeXテンプレートとおすすめリンク集
昨日大学の実験科目が全て終わった。
無事に実験の嵐をくぐりぬけた身としては後輩に少しでも実験レポートが書きやすくなるような情報を記しておこう。
実験レポートはLaTeXで書いてます。
自分が使っていたLaTeXの実験用のテンプレを置いておくので、LaTeX使っている人は参考にしてね。
LaTeX使っていない人は興味のきっかけになればいいかな。
\newcommandを使ってコマンドをいくつか定義しておいた。
式を文中に表示させたいときは
\eI{a = b}
みたいなかんじ
式を文の外に表示させたいときには
\eO{a = b}
画像を表示させたいときは
graphics
というフォルダを作成してそこに画像をいれた後
\fig[画像の横幅を指定]{ファイルの名前}{キャプション}{ラベル}
例:
\fig[width = 14cm]{hoge.png}{hogeのイメージ}{fig:hoge}
みたいなかんじ。
最後にLaTeX文章を作成するにあたってのリンクを置いておくよ
自作言語を自作コンパイラでコンパイルして自作CPUで自作OSを動かしてみたい
はい。タイトルオチです。
とっても長い時間がかかりそうな、長期的な目標のお話です。
その前に、ざっくりとコンピュータの解説をしていきます。
計算機についての知識がある方は後半まで読み飛ばしてね。
パソコンはどうやって動いているか
まず、CPUあたりのお話から。パソコンの内部にはCPUという部品があります。CPUはよくパソコンにとっての脳と言われています。
しかし、CPUは人間の脳のように思考しているわけではありません。
パソコンは機械の一つですね。機械ということは電気で動いている。
コンセントを挿せば電子レンジが動き、電池があれば電卓が動くのと同じようなことです。
つまり、CPUもとより機械は電気しか扱うことができません。
具体的に言うと、CPUにとってわかるのは電気があるかないか(電圧が高いか低いか)。0か1かということだけです。
この0か1を伝えていくことで足し算、引き算などを行っているのがCPUです。
(0や1を伝えていく回路を論理回路といいます)
CPUに0と1が並んだものを渡せば、CPUが計算をしてくれるということですね。
ということは、「0と1が並んだもの」はCPUに対する命令と捉えることができます。
じゃあ、パソコンを動かしたいのならたくさんの命令(プログラム)をCPUに伝えていけばいいということになります。
ここで発生するのが、非常にプログラムが書きにくいという問題です。
コンパイラの必要性
プログラムを書くときに毎回0と1を並べなければならない。とても面倒で生産性が低いですよね。
ここで人類が思いついた手法が、「人間にとってより読みやすいようにプログラムを変換する」ということです。
0と1の羅列は、CPUが何をするかという命令を英語で記述した言語に変換されます。この言語をアセンブリ言語といい、アセンブリ言語から0と1に変換するソフトをアセンブラといいます。
その変換された言語は、さらに人間にとって読みやすい言語になるように変換されていきます。このように変換されたものを高級言語といいます。
このように人間が読みやすいものに変換するソフトをコンパイラといいます。
プログラムを書く準備はできた。これでたくさんソフトをつくることができます。
しかしソフトがたくさんあるとまた問題が起きます。
パソコンは情報を記憶することができます。とあるソフトが動くために情報を記憶した部分を他のソフトが勝手に書き替えたらどうなるでしょう。
勝手に情報が変わっていると、動くはずのソフトも動かない。
それぞれがやりたいことを好き勝手しているとろくに動かないのです。
これらのソフトをまとめて管理するものが必要になってきます。
OSの役割
OSはたくさんのソフトをまとめて管理するソフトです。
OSは情報を記憶する部分(メモリ)のどこが空いているかを常に把握しています。
また、OSはソフトの同時起動を可能にしています。例えばブラウザでネットサーフィンをしながらワードで文章を書けるようなこともOSが可能にしています。
ソフトを大量に扱うにはOSは欠かせないんです。
ざっくりで抜け落ちているところもありますが、これで0と1の世界からみなさんが使っている環境の話まで戻ってくることができました。
ここでやっと本題。
僕の目標は以上のことをすべて自分で作り上げることです。
やりたいこと
最初のCPUからOSまで、すべて自分で作ってみたいというロマンが僕にはある。
今のところの展望は、
自作CPU(自作アーキテクチャ)はFPGAという、論理回路を自分でつくることができる機器を使う。
コンパイラについては
自作アセンブラを作成する。
自作コンパイラを使って自作高級言語からアセンブリ言語まで変換できるようにする。
という流れになりそう。
とても長い時間がかかりそうだけど、のんびり取り組んでいきます。
仮想CentOS上にWebサーバーをつくってみた
どうも、最近ダンスのしすぎで腰を痛めたびいのです。
みんなもダンスのしすぎには注意な。
本題は、自分のマシンの中に仮想CentOSをつくり、Webサーバーとするまでやってみたことです。
動機:Cloud9とか、WebのIDEがあって誰でも簡単に開発できるようになってきたなあと思い、実際にサーバーをつくるとどれぐらい手間がかかるのかやってみた。
自機について:Windows 10/CPU は i3/メモリは8GB
1,仮想CentOSの用意
参考にしたのは以下のサイト。
サイト①
サイト②
仮想化ソフトウェアには「VMware Workstation Player」を使用。
仮想化するOSはCentOS
https://www.centos.org/download/
からISOイメージファイルをダウンロードする。
Minimal ISO を選んでダウンロード。
サイトのやり方だとCentOSのベース環境でいろいろ選べるんだけど、Minimal ISOをダウンロードしてしまったので、最小限のインストールしかなかった
お次はネットワーク設定。
仮想環境のネットワークについては以下のサイトがわかりやすくておすすめ。
https://qiita.com/Higemal/items/b8124b047a3d0393e697
ホストOSであるWindowsのIPアドレスと同じセグメントのIPを割り振って固定IPとしました。
あとはサイト①の通りにソフトを入れていく。
LinuxはUbuntuとラズパイしかやってこなかったのでyumは新鮮でした(小並)
apacheをサーバーのソフトとして、無事Windowsからテストページを表示することに成功!
もしWebを開発するなら
Windowsでコードを書く
↓
CentOSにコードを送る
↓
WIndowsをクライアントとしてテスト
という流れになるのかなと予想。
じゃあgitでssh接続で共有できたら楽だなあと思い、githubをssh接続で使えるようにしました。
Connecting to GitHub with SSH - User Documentation
Windows での鍵生成と登録はすぐできたが、CentOS上で鍵を生成したあとに公開鍵をgithubに登録するところで、CentOS上でコピーが使えないやん!と思い
xclipとかいろいろ試してみたが、どれもコピーできるところまでたどり着けず、結局VMwareのファイル共有機能を使って公開鍵をWindowsに移した
なんとかCentOS上でもgithubのsshが使えるようになり、一安心。
得たもの
●Webサーバーの基本的な知識
●仮想環境の扱い方。特にネットワーク関連。
●Linuxの扱い方。
これからWebの勉強(フロントエンドとか)やっていくかと聞かれたら、今あんまりモチベが無いのでやらないかもしれない。
それよりはFPGAでプロセッサをつくることのほうが楽しそう。これについてはまた後日。
さらなる下準備
SQLiteの進捗
1,文字コード変換
nfk -g poke.csv
>SHIFT-JIS
と出たので、UTFに変換。
これでUTFのcsvファイルができたのでインポートできる。
(H.Mさんに教えてもらいました。ありがとうございます。)
2,インポート
> sqlite3 test.db
sqlite >> .separator , //区切りを,に設定
sqlite >> .import hoge.csv POKE //POKEというテーブルに保存
sqlite >> select * from POKE
ですべてのデータが出ることを確認!
しかし、新しい問題:データの検索がうまくいかない
たとえば、リザードンのデータが欲しいとき
select * from POKE where name = "リザードン"
とすると、検索結果が出ない。(何もヒットしない)結果に。
いろいろ調べた結果、データ型を確認してみると
>> .schema
それぞれのデータ型がみんなtextになっていた!
これはまずいので、データ型変換方法を調べ、やってみる。
まずは、もう一つテーブルを作成
create table temp(
id integer,
name text,
......
attack integer);
そして、既存のテーブルの内容を移す
>> insert into temp select * from POKE;
これで自分のやりたいような検索が可能になった!
無事にC#でも動作を確認。
ポケモンのデータを読み取って満足したところで、
わざのデータをデータベースにする必要があることに気づく。
そして、このcsvは自分でつくるしかないのか...
これはWebからデータを取り出していくしかない。
3,スクレイピング
Pythonでやってみよう。
このサイトで基礎をやったあと、少しコードを変えることで技名を取得することに成功。
データベースとの闘い
前々からポケモンの対戦ツールをつくりたいと思っていました。
せっかくC#勉強したし、つくってみるかと思い、計画を立ててみる。
必要な準備は、
であった。今日は1のデータベースに慣れるところからはじまる。
1-1,SQLiteを使ってみる。
C# にSQLiteを入れてサンプルコードを走らせてみるも、何をしているのか全然わからない。
当方、DBの知識は皆無なのである。
1-2,Progateでデータベースの基礎をやる
こんなときはProgateに頼るに限る。
ド基礎のところを学べたので、データベースNoobの自分にはちょうどいいものでした。
1-3,csvをインポートしてみる。
Ubuntuにsqlite3をinstallして、csvを読み込むところからスタート。
.import コマンドでポケモンの種族値データが入ったcsvを読み込んでtableにするところまではできた。
しかし、select * from table
をしてtableの中身をみてみると、日本語がすべて文字化けしている。
まじか・・・
というわけで、文字化けを対処する必要がでてくる。
1-4,文字化け対処
文字コードを知るために、
sudo apt-get install nkf
でnkfをインストール。
どの文字コードが原因で文字化けしているのかわからなくなったところで、今日はおしまい。
結果:安定のProgate
WindowsユーザーでもiPhoneアプリ(iOSアプリ)を快適につくりたいと思った
備忘録程度のメモ書き
でも自分のiPhoneでアプリをつくりたい。いろいろ試してみました。
案1,Microsoftによるクロスプラットフォームアプリ開発:Xamarin
Visual Stidioに開発環境をインストール。
Xamarin Live PlayerがiPhoneのストアに見つからず困惑。
どうやらTestFlightとかいう試験段階のアプリを公開するアプリを通して自iPhoneに入れれるみたい。Microsoft嫌われすぎワロタ。
2019/1/24 追記
TestFlightでの公開もできなくなったみたい。現在Xamarin Live PlayerはGoogle Play にしか対応できていない。
実際に自機にHello,worldを表示させることに成功したが、何か違う感が筆者を襲う。
調べた限りでは、実機ではデバッグテストしかできず、アプリとして常駐させることはできない(?)
(アプリ常駐の方法あれば教えて)
わしは、スタンドアローンアプリをつくりたいんや.....
ということで案2へ
案2,Pythonista3
自由度も高い。iPhoneの機能をほとんど利用できる。スタンドアローンアプリもつくれるということでこれを使おうと決意。(1200円したけど、Macを買うのに比べると格段に安いので購入を決意)
使っているなかで気づいた点:コーディングの速度が悪すぎる。
フリックでプログラム書くの大変すぎ!予測変換あるといってもキーボードの入力には勝てないでしょ。
ということでキーボードは別入力にしたい。
キーボード案1:Bluetoothキーボードをつくる。
キーボード案2:PCのキーボードを使えないか
結論としては案2を採用
「WifiKeyboard」というアプリを採用。
このアプリは案2をそのままやってくれます。
勢いで有料版を買ってしまった。
これで開発はできるが、いちいちiPhoneを見るのめんどいな・・・
ということで検索「iPhone pc 画面」
apowermirrorというツールを発見。
これをpcとiphone両方に入れて、動かしてみる。
あれ、動かない。。。
でもusb接続しているときは成功するときがあるぞ。いろいろtryしてみる。
try wifi周波数を5GHzから2.5GHzにする
result ワイヤレス接続成功
なんでやねん。。。
try 5GHzのときiPhone設定を自動ログインにする
result 5GHzでも無事に接続完了!
やっとの思いでiPhoneの画面をpcに表示できた。
このツールはツイキャスにも使えそうやな。
と思いつつ、なんとかpc内で表示させることができた。
今後の課題。
iPhoneミラーリング画面がでかすぎる。ミラーリング画面サイズ調整できるツールが欲しい。
pythonista3でairPlay機能使えるみたいだし、ミラーリングのところは自作アプリをつくってみたいと思う。