S3MIPSシステム/開発記
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
|
ログイン
]
開始行:
[[S3MIPSシステム]]
*S3MIPSシステム開発記 [#e111e61e]
S3MIPSシステムを開発するまでのことを記してみようと思う。
----
#contents
**第1回 FPGA上で動くプロセッサを作ろう! [#v4e09d83]
FPGA上で動くプロセッサを作る。~
~
最近は、ある程度遊べる性能のFPGAが安価に手に入るようになり、~
誰でも気軽にFPGA上で動くハードウェアを開発できるようになった。~
その例として、FPGA上で動くプロセッサを設計したという例は少なくない。~
~
ハードウェア設計の基礎は、簡単なプロセッサを例に学ぶことがほとんどで、~
会津大学でも、3年次にRISCアーキテクチャで有名なMIPSプロセッサの設計を学ぶ。~
~
~
例年、琉球大学が主催しているLSIデザインコンテストin沖縄という学生向けコンテストがある。~
私たちも今年こそは出場しようと発表された課題を見てみると、その課題は「マイクロプロセッサの設計」であった。~
~
これを期に、FPGA上で動くプロセッサを自分の手で作ろう、と思った。~
もちろん、ただ単にFPGA上で動くだけでは面白くない。~
~
FPGAボード上にあるI/Oデバイスをプロセッサから自由に制御できること、~
割り込みを用いたプログラムを実行できること、~
そして、C言語で記述したプログラムが実行できること、~
この3つを実現できるプロセッサと、そのシステムを開発することに決めた。~
~
ターゲットとなるFPGAボードはAlteraから発売されているDE2ボード。~
携帯で写真を撮ったのが丸分かりだが、気にしてはいけない。
CENTER:&ref(de2_board.jpg);
**第2回 FPGA上でプロセッサが動いた! [#q8ac7a6f]
約3ヶ月弱の開発期間を経て、FPGAボード上でプロセッサが動作した。~
例として作成したのはライツアウトというパズルゲーム(左)と、~
ライフゲームというシミュレーションゲーム(右)である。~
~
詳しい動作について興味がある方は、これをキーワードに検索してみると良い。~
CENTER:&ref(s3mips_lights_out.jpg); &ref(s3mips_lifegame.jpg);
まず、使用したFPGAボードはAlteraから発売されているDE2ボードで、Cyclone II FPGAが搭載されている。~
会津大学の授業の演習で使用されている他、研究室にいくつか準備されているので、今回はこれをターゲットとした。~
~
DE2ボードの魅力は、豊富なI/Oデバイスが提供されていることにある。~
その例を挙げると、セブンセグメントLED、LCDデバイス、ディスプレイ出力、~
コンポジットのビデオ入力、サウンド入出力、2系統のUSB、PS/2接続、シリアルポート、~
イーサネット接続、SDカードリーダー、SRAM、SDRAM、FLASHと、このボード1つで遊び尽くせるほどのI/Oデバイスがある。~
~
この中から、制御するのが簡単そうなものをいくつか選んで、~
I/Oデバイスコントローラを作成し、プロセッサから自由に制御できるシステムを設計した。~
~
~
例えば、ライツアウトはVGAのディスプレイにパネルを出力し、~
キーボード割り込みによってカーソルの操作や反転処理を実現している。~
~
ライフゲームはタイマ割り込みを使用して、永遠に世代の進行を続ける。~
この例は、無限にセルが増殖するグライダーガンというモデルを使ったデモンストレーションである。~
~
2つのプログラムはC言語で記述されている。~
割り込みを用いたプログラムが書きやすいようなAPIを提供しているため、~
多少のC言語の知識があれば、このようなプログラムを簡単に開発することができる。~
~
~
なお、ディスプレイの台に使った天ぷらそばは年越しそばとして、スタッフがおいしく頂いた。
**第3回 C言語のプログラムが動くまで [#h9798862]
どんなアーキテクチャでも、アセンブリ言語でプログラムを書いたことがある方なら、開発の面倒さが分かると思う。~
特にC言語など、高級言語でのプログラミングを覚えた後に、アセンブリ言語を体験するとなおさらである。~
~
そこで、既存のコンパイラ技術の恩恵にあやかって、~
C言語で記述したプログラムをFPGAボード上に実装したプロセッサの上で動かすことができるシステムを目指した。
CENTER:&ref(s3mips_design_flow.png);
ハードウェア設計やコンパイラやアセンブラなどの知識がない人にも、~
気軽に使ってもらえるシステムになるように、デザインフローの自動化を検討した。~
~
プロセッサ部分は一度論理合成してしまえば、動かすプログラムの内容を変更するだけで済む。その作業は10秒もかからない。~
C言語で記述したプログラムからメモリの初期化ファイルを生成し、SOFファイルを更新するまでの一連の流れに必要なコマンドを~
Makefileに記述することで、makeコマンドだけで新しいSOFファイルが生成されるように設計した。~
~
ユーザーが用意するのは動かしたいプログラムだけで済む。~
~
~
C言語を使用するにあたり、既存のコンパイラが使用できるアーキテクチャを踏襲する必要がある。~
私たちがターゲットとしたのはMIPSプロセッサである。~
~
この理由はいくつかあるが、~
クロスコンパイラの入手が簡単なことと、MIPSプロセッサの開発経験があることが大きい。
**第4回 13命令の小さなMIPSプロセッサ [#x00c450e]
まずはパタヘネの愛称で知られる「パターソン&ヘネシー コンピュータの構成と設計」の教科書に従って、~
簡単な命令を持ったMIPSプロセッサを開発した。~
~
この段階で実装した命令は以下の表で示される13命令である。~
|区分|命令|形式|例|意味|
|算術演算|add|R|add $s1, $s2, $s3|$s1=$s2+$s3|
|~|sub|R|sub $s1, $s2, $s3|$s1=$s2-$s3|
|~|addi|I|addi $s1, $s2, 100|$s1=$s2+100|
|論理演算|and|R|and $s1, $s2, $s3|$s1=$s2&$s3|
|~|or|R|or $s1, $s2, $s3|$s1=$s2|$s3|
|~|andi|I|andi $s1, $s2, 100|$s1=$s2&100|
|~|ori|I|ori $s1, $s2, 100|$s1=$s2|100|
|データ転送|lw|I|lw $s1, 100($2)|$s1=memory[$s2+100]|
|~|sw|I|sw $s1, 100($2)|memory[$s2+100]=$s1|
|条件分岐|beq|I|beq $s1, $s2, 25|if($s1==$s2) goto PC+4+100|
|~|slt|R|slt $s1, $s2, $s3|if($s2<$s3) $s1=1 ; else $s1=0|
|~|slti|I|slti $s1, $s2, 100|if($s2<100) $s1=1 ; else $s1=0|
|無条件ジャンプ|j|J|j 2500|goto 10000|
addi, andi, ori, sltiといった即値命令はパタヘネの例では実装されていなかったが、~
これらの命令があれば、簡単にアセンブリプログラムを書けるので実装することにした。~
~
この小さなMIPSプロセッサは13命令しか実行できないが、~
これらの命令を組み合わすと、バブルソートといった簡単なプログラムが実現できる。~
~
会津大学の授業の演習で設計するMIPSプロセッサも、これと同じ命令セットを持っている。~
教育用途に使うのであれば、このくらいでも十分に勉強になる。
**第5回 パイプライン化の検討 [#h48b5a22]
将来的にはパイプラインを用いた構成を目指すが、~
ベースとなるプロセッサの構成を考えるにあたって、複数の選択肢がある。~
シングルサイクル方式、マルチサイクル方式などがそれである。~
~
パイプライン化を前提にするならば、シングルサイクル方式を選ぶのが妥当であるが、~
過去にパイプライン化の経験が既にあるので、この方法は取らないことにした。~
~
~
パイプラインの段数を深くすれば、動作周波数の向上が期待できるが、~
それに伴い、パイプラインレジスタの挿入などによって回路規模が増大する。~
~
さらに、命令間でレジスタの依存関係がパイプラインハザードを引き起こすために、~
フォワーディングやハザード検知ユニットなどが追加で必要になる。~
~
これらの話題はパタヘネでも述べられている通常のパイプラインの考え方である。~
~
~
FPGAボード上で動作させることを考えると、~
プロセッサの動作周波数は速くなくてもそれほど問題にならない。~
ターゲットとするDE2ボードが27MHzと50MHzのクロックを提供していることを考えると、最低限27MHzで動けば良い。~
~
過去の経験から、初期のMIPSプロセッサで採用されていた5段のパイプラインでは、~
考慮すべきパイプラインハザードも少ないわけではなく、設計が簡単ではないのが分かっていた。~
~
その他の諸事情もあったが、過去の経験を踏まえた上で、3段のパイプラインで設計することに決めた。~
~
~
完成したプロセッサの簡単なデータパスを示す。
CENTER:&ref(cpucore_simple_sche.png);
**第6回 MIPS Iに準拠した命令セットの実装 [#wd266d25]
コンパイラが生成するコードを実行するためには、~
そのコンパイラが対応しているアーキテクチャがサポートする全ての命令を実装しなければならない。~
~
MIPSプロセッサの場合は、命令セットがMIPS I、 MIPS II、MIPS III、MIPS IVなどで定義されており、~
現在はMIPS 32/64として定義されているのが最新である。~
~
初期のMIPSプロセッサであるR2000やR3000では、MIPS Iの命令セットが使われている。~
MIPS Iでサポートされる命令は32ビットの基本的な命令群で、~
私たちが実装するプロセッサも、このMIPS Iに準拠した命令セットを実装する。~
~
~
MIPS Iではバイト単位のメモリアクセスをサポートしているが、~
私たちのプロセッサではメモリアクセスの簡略化のため、~
ワード単位のメモリアクセスだけをサポートすることとし、バイト単位のアクセスを無効にしている。~
~
このため、C言語で記述されたプログラムではshortやcharといった、ハーフワードやバイトの変数が使用不可能になる。~
これらの変数の型をサポートしなくても、ある程度のプログラムは不自由なく記述できるので、今回は実装を見送った。~
将来的には、拡張することも考えている。(開発を引き継いでくれる研究室の有志求む!)~
~
実装する命令は、以下の通りである。
-シフト演算
--SLL / SRL / SRA / SLLV / SRLV / SRAV
-算術論理演算
--ADD / ADDU / SUB / SUBU / AND / OR / XOR / NOR / SLT / SLTU / ADDI / ADDIU / SLTI / SLTIU / ANDI / ORI / XORI / LUI
-メモリアクセス
--LW / SW
-相対分岐命令
--BEQ / BNE / BLEZ / BGTZ / BLTZ / BGEZ / BLTZAL / BGEZAL
-絶対分岐命令
--J / JAL / JR / JALR
**第7回 I/Oデバイスコントローラを作る [#o3de45cb]
完成したプロセッサだけをFPGAボードに実装しても、~
何の反応もなく、動いているのかどうかも確認できない。~
~
やはり、DE2ボードのI/Oを上手く使って、何らかの結果が返ってくるようでなければ、面白くない。~
~
私たちが開発したのは、プロセッサだけではない。~
より面白い動作ができるように、DE2ボードのI/Oを制御するデバイスコントローラも開発した。~
~
全体の構成は以下のようになっている。
CENTER:&ref(de2_mips_sche.png);
本来、プロセッサがアクセスするメモリ部分は、キャッシュとして実装されるべき部分だったので、~
命令コードの読み込みと、データの読み書き部分で2つのバスが用意されている形になっている。~
~
キャッシュの実装は、FPGAの内部RAMをメモリとして用いる場合、~
ほとんどの場合、1クロックでデータを呼び出せてしまうので、意味がない。~
~
将来的に、外部からプログラムをブートできるような拡張が完成したら、改めてキャッシュを実装したいとは考えている。~
~
~
用意したデバイスコントローラはデータメモリのバスに接続されている。~
デバイスへのアクセスはメモリマップドI/O方式を採用した。~
~
プロセッサはロード命令やストア命令を発行するだけで、これらのデバイスへ簡単にアクセスすることができる。~
これで何かのプログラムで計算した値をセブンセグメントLEDやLCDに表示することができるようになる。
**第8回 メモリマップドI/O方式によるデバイス制御 [#t10ba01a]
メモリマップドI/O方式について簡単に説明する。~
~
この方式ではI/Oデバイスコントローラがプロセッサとメモリを繋ぐバスに接続されている。~
プロセッサがロード命令を実行する際は、以下の図のように全てのモジュールにアドレスを入力する。
CENTER:&ref(memory_map1.png);
I/Oデバイスコントローラは、それぞれのデバイスに割り当てられたメモリアドレスであるかどうかを判定する~
アドレスデコーダを備えており、自分のデバイスに対するアドレスであれば、該当するデータをプロセッサに送信する。~
~
他のモジュールはプロセッサに流すデータはないので、該当モジュールのデータがプロセッサに入力される。~
以下の図は、セブンセグメントLEDにアクセスしたときの例である。
CENTER:&ref(memory_map2.png);
このとき、data_inの信号線は複数の入力線を持つが、それぞれがトライステートバッファで設計されており、~
プロセッサへデータを送信する必要のないときは、ハイインピーダンスの状態にする。~
~
メモリマップと各デバイスに割り当てたワード数は、以下の表のようにした。
|アドレス|デバイス|ワード数|
|0x00000000-0x00003FFF|命令メモリ|4096|
|0x00004000-0x00007FFF|データメモリ|4096|
|0x00008000-0x0000801F|セブンセグメントLED|8|
|0x00008020-0x0000802F|タイマ|4|
|0x00008030-0x0000803F|PS/2 キーボード|4|
|0x00008100-0x0000817F|LCD|32|
|0x00010000-0x00017FFF|キャラクタ・ディスプレイ|8192|
プロセッサがI/Oデバイスにアクセスする際には、これらのアドレス空間へのロード、ストア命令を実行すれば良い。~
C言語でのI/Oデバイスへのアクセスの実現は、ポインタを用いて簡単に記述することができる。
**第9回 Hello Worldを表示させてみた [#ndb1f455]
Hello WolrdをLCDに表示するプログラムを動かしてみる。~
~
通常のCプログラミングで使えるライブラリ類は用意されていないので、~
文字列の表示を行う際に使うprintf関数などは使用できない。~
さらにバイト単位のメモリアクセスをサポートしないためchar型を扱えないので、文字列もint型として扱う必要がある。~
~
LCDに表示するためには、APIで用意されている関数を使用すれば簡単に実現できる。~
LCDの好きな場所に1文字のキャラクタを表示することができる。~
表示するキャラクタはキャラクタコードで指定する必要があるが、~
基本的な文字列はint型でキャストしてあげることで、キャラクタコードを関数に渡すことができる。~
~
LCDに表示するAPIは、LCDのメモリ領域に対してストア命令を実行するような関数である。~
以下ではLCD表示関数が行っている動作を説明する。~
~
0x00008100から0x0000817FまでのアドレスがLCDに割り当てられているので、LCDの先頭に'A'を表示させたければ、
*(int *)0x00008100 = 0x41;
もしくは
*(int *)0x00008100 = (int)'A';
のように記述してやれば良い。~
~
例えば、以下のように"Hello World"を表示させたいときは、1文字単位で各アドレスに値を保持させる。
CENTER:&ref(lcd_display.png);
LCDに割り当てられたアドレスにあるデータは以下の通りになる。
|アドレス|保持する値|キャラクタ|
|0x00008100|0x20|' '|
|0x00008104|0x48|'H'|
|0x00008108|0x65|'e'|
|0x0000810C|0x6C|'l'|
|0x00008110|0x6C|'l'|
|0x00008114|0x6F|'o'|
|0x00008118|0x20|' '|
|0x0000811C|0x57|'W'|
|0x00008120|0x6F|'o'|
|0x00008124|0x72|'r'|
|0x00008128|0x6C|'l'|
|0x0000812C|0x64|'d'|
|0x00008130|0x20|' '|
|0x00008134|0x20|' '|
|...|...|...|
以下の図は、Hello Worldを表示させるプログラムを動作させた例である。~
ただし、上の図とは表示させる場所が異なっている。
CENTER:&ref(hello_world.jpg);
**第10回 割り込みを用いたプログラムの実現 [#kc2e3ef5]
割り込み処理を行うためには、プロセッサに割り込み制御のハードウェアを付加する必要がある。~
MIPSプロセッサでは割り込みを含む例外処理をコプロセッサとして実装している。~
~
割り込み信号を検知したら、現在実行中のプログラムから、割り込み処理用のプログラムに切替える必要がある。~
割り込み実行の様子を以下に示す。
CENTER:&ref(interrupt_flow.png);
割り込みが起きたら、システムが用意した例外ハンドラが実行されるようになっている。~
例外ハンドラと記述しているものの、実装した例外は割り込みだけである。~
~
例外ハンドラは割り込みの原因を調べ、その割り込みに対応した割り込みハンドラを実行する。~
この割り込みハンドラはユーザーが指定した関数をコールする仕組みになっている。~
~
割り込み処理が終われば、プロセッサは割り込みが起きた命令に戻り、プログラムを実行する。~
~
~
例外処理のコプロセッサは、例外が発生したときに実行中の命令を指すプログラムカウンタや~
例外や割り込みを発生したデバイスや、その原因を保持する制御レジスタを持っている。~
~
割り込みに関しては、それぞれの割り込み制御線に対して、許可するか禁止するかを制御できる。~
これらの制御レジスタは直接コプロセッサを扱う命令を用いて操作する。~
~
APIの一部の関数は、こういったコプロセッサ制御命令を含むため、アセンブリプログラム内に記述されている。
**第11回 [#d4ad28de]
終了行:
[[S3MIPSシステム]]
*S3MIPSシステム開発記 [#e111e61e]
S3MIPSシステムを開発するまでのことを記してみようと思う。
----
#contents
**第1回 FPGA上で動くプロセッサを作ろう! [#v4e09d83]
FPGA上で動くプロセッサを作る。~
~
最近は、ある程度遊べる性能のFPGAが安価に手に入るようになり、~
誰でも気軽にFPGA上で動くハードウェアを開発できるようになった。~
その例として、FPGA上で動くプロセッサを設計したという例は少なくない。~
~
ハードウェア設計の基礎は、簡単なプロセッサを例に学ぶことがほとんどで、~
会津大学でも、3年次にRISCアーキテクチャで有名なMIPSプロセッサの設計を学ぶ。~
~
~
例年、琉球大学が主催しているLSIデザインコンテストin沖縄という学生向けコンテストがある。~
私たちも今年こそは出場しようと発表された課題を見てみると、その課題は「マイクロプロセッサの設計」であった。~
~
これを期に、FPGA上で動くプロセッサを自分の手で作ろう、と思った。~
もちろん、ただ単にFPGA上で動くだけでは面白くない。~
~
FPGAボード上にあるI/Oデバイスをプロセッサから自由に制御できること、~
割り込みを用いたプログラムを実行できること、~
そして、C言語で記述したプログラムが実行できること、~
この3つを実現できるプロセッサと、そのシステムを開発することに決めた。~
~
ターゲットとなるFPGAボードはAlteraから発売されているDE2ボード。~
携帯で写真を撮ったのが丸分かりだが、気にしてはいけない。
CENTER:&ref(de2_board.jpg);
**第2回 FPGA上でプロセッサが動いた! [#q8ac7a6f]
約3ヶ月弱の開発期間を経て、FPGAボード上でプロセッサが動作した。~
例として作成したのはライツアウトというパズルゲーム(左)と、~
ライフゲームというシミュレーションゲーム(右)である。~
~
詳しい動作について興味がある方は、これをキーワードに検索してみると良い。~
CENTER:&ref(s3mips_lights_out.jpg); &ref(s3mips_lifegame.jpg);
まず、使用したFPGAボードはAlteraから発売されているDE2ボードで、Cyclone II FPGAが搭載されている。~
会津大学の授業の演習で使用されている他、研究室にいくつか準備されているので、今回はこれをターゲットとした。~
~
DE2ボードの魅力は、豊富なI/Oデバイスが提供されていることにある。~
その例を挙げると、セブンセグメントLED、LCDデバイス、ディスプレイ出力、~
コンポジットのビデオ入力、サウンド入出力、2系統のUSB、PS/2接続、シリアルポート、~
イーサネット接続、SDカードリーダー、SRAM、SDRAM、FLASHと、このボード1つで遊び尽くせるほどのI/Oデバイスがある。~
~
この中から、制御するのが簡単そうなものをいくつか選んで、~
I/Oデバイスコントローラを作成し、プロセッサから自由に制御できるシステムを設計した。~
~
~
例えば、ライツアウトはVGAのディスプレイにパネルを出力し、~
キーボード割り込みによってカーソルの操作や反転処理を実現している。~
~
ライフゲームはタイマ割り込みを使用して、永遠に世代の進行を続ける。~
この例は、無限にセルが増殖するグライダーガンというモデルを使ったデモンストレーションである。~
~
2つのプログラムはC言語で記述されている。~
割り込みを用いたプログラムが書きやすいようなAPIを提供しているため、~
多少のC言語の知識があれば、このようなプログラムを簡単に開発することができる。~
~
~
なお、ディスプレイの台に使った天ぷらそばは年越しそばとして、スタッフがおいしく頂いた。
**第3回 C言語のプログラムが動くまで [#h9798862]
どんなアーキテクチャでも、アセンブリ言語でプログラムを書いたことがある方なら、開発の面倒さが分かると思う。~
特にC言語など、高級言語でのプログラミングを覚えた後に、アセンブリ言語を体験するとなおさらである。~
~
そこで、既存のコンパイラ技術の恩恵にあやかって、~
C言語で記述したプログラムをFPGAボード上に実装したプロセッサの上で動かすことができるシステムを目指した。
CENTER:&ref(s3mips_design_flow.png);
ハードウェア設計やコンパイラやアセンブラなどの知識がない人にも、~
気軽に使ってもらえるシステムになるように、デザインフローの自動化を検討した。~
~
プロセッサ部分は一度論理合成してしまえば、動かすプログラムの内容を変更するだけで済む。その作業は10秒もかからない。~
C言語で記述したプログラムからメモリの初期化ファイルを生成し、SOFファイルを更新するまでの一連の流れに必要なコマンドを~
Makefileに記述することで、makeコマンドだけで新しいSOFファイルが生成されるように設計した。~
~
ユーザーが用意するのは動かしたいプログラムだけで済む。~
~
~
C言語を使用するにあたり、既存のコンパイラが使用できるアーキテクチャを踏襲する必要がある。~
私たちがターゲットとしたのはMIPSプロセッサである。~
~
この理由はいくつかあるが、~
クロスコンパイラの入手が簡単なことと、MIPSプロセッサの開発経験があることが大きい。
**第4回 13命令の小さなMIPSプロセッサ [#x00c450e]
まずはパタヘネの愛称で知られる「パターソン&ヘネシー コンピュータの構成と設計」の教科書に従って、~
簡単な命令を持ったMIPSプロセッサを開発した。~
~
この段階で実装した命令は以下の表で示される13命令である。~
|区分|命令|形式|例|意味|
|算術演算|add|R|add $s1, $s2, $s3|$s1=$s2+$s3|
|~|sub|R|sub $s1, $s2, $s3|$s1=$s2-$s3|
|~|addi|I|addi $s1, $s2, 100|$s1=$s2+100|
|論理演算|and|R|and $s1, $s2, $s3|$s1=$s2&$s3|
|~|or|R|or $s1, $s2, $s3|$s1=$s2|$s3|
|~|andi|I|andi $s1, $s2, 100|$s1=$s2&100|
|~|ori|I|ori $s1, $s2, 100|$s1=$s2|100|
|データ転送|lw|I|lw $s1, 100($2)|$s1=memory[$s2+100]|
|~|sw|I|sw $s1, 100($2)|memory[$s2+100]=$s1|
|条件分岐|beq|I|beq $s1, $s2, 25|if($s1==$s2) goto PC+4+100|
|~|slt|R|slt $s1, $s2, $s3|if($s2<$s3) $s1=1 ; else $s1=0|
|~|slti|I|slti $s1, $s2, 100|if($s2<100) $s1=1 ; else $s1=0|
|無条件ジャンプ|j|J|j 2500|goto 10000|
addi, andi, ori, sltiといった即値命令はパタヘネの例では実装されていなかったが、~
これらの命令があれば、簡単にアセンブリプログラムを書けるので実装することにした。~
~
この小さなMIPSプロセッサは13命令しか実行できないが、~
これらの命令を組み合わすと、バブルソートといった簡単なプログラムが実現できる。~
~
会津大学の授業の演習で設計するMIPSプロセッサも、これと同じ命令セットを持っている。~
教育用途に使うのであれば、このくらいでも十分に勉強になる。
**第5回 パイプライン化の検討 [#h48b5a22]
将来的にはパイプラインを用いた構成を目指すが、~
ベースとなるプロセッサの構成を考えるにあたって、複数の選択肢がある。~
シングルサイクル方式、マルチサイクル方式などがそれである。~
~
パイプライン化を前提にするならば、シングルサイクル方式を選ぶのが妥当であるが、~
過去にパイプライン化の経験が既にあるので、この方法は取らないことにした。~
~
~
パイプラインの段数を深くすれば、動作周波数の向上が期待できるが、~
それに伴い、パイプラインレジスタの挿入などによって回路規模が増大する。~
~
さらに、命令間でレジスタの依存関係がパイプラインハザードを引き起こすために、~
フォワーディングやハザード検知ユニットなどが追加で必要になる。~
~
これらの話題はパタヘネでも述べられている通常のパイプラインの考え方である。~
~
~
FPGAボード上で動作させることを考えると、~
プロセッサの動作周波数は速くなくてもそれほど問題にならない。~
ターゲットとするDE2ボードが27MHzと50MHzのクロックを提供していることを考えると、最低限27MHzで動けば良い。~
~
過去の経験から、初期のMIPSプロセッサで採用されていた5段のパイプラインでは、~
考慮すべきパイプラインハザードも少ないわけではなく、設計が簡単ではないのが分かっていた。~
~
その他の諸事情もあったが、過去の経験を踏まえた上で、3段のパイプラインで設計することに決めた。~
~
~
完成したプロセッサの簡単なデータパスを示す。
CENTER:&ref(cpucore_simple_sche.png);
**第6回 MIPS Iに準拠した命令セットの実装 [#wd266d25]
コンパイラが生成するコードを実行するためには、~
そのコンパイラが対応しているアーキテクチャがサポートする全ての命令を実装しなければならない。~
~
MIPSプロセッサの場合は、命令セットがMIPS I、 MIPS II、MIPS III、MIPS IVなどで定義されており、~
現在はMIPS 32/64として定義されているのが最新である。~
~
初期のMIPSプロセッサであるR2000やR3000では、MIPS Iの命令セットが使われている。~
MIPS Iでサポートされる命令は32ビットの基本的な命令群で、~
私たちが実装するプロセッサも、このMIPS Iに準拠した命令セットを実装する。~
~
~
MIPS Iではバイト単位のメモリアクセスをサポートしているが、~
私たちのプロセッサではメモリアクセスの簡略化のため、~
ワード単位のメモリアクセスだけをサポートすることとし、バイト単位のアクセスを無効にしている。~
~
このため、C言語で記述されたプログラムではshortやcharといった、ハーフワードやバイトの変数が使用不可能になる。~
これらの変数の型をサポートしなくても、ある程度のプログラムは不自由なく記述できるので、今回は実装を見送った。~
将来的には、拡張することも考えている。(開発を引き継いでくれる研究室の有志求む!)~
~
実装する命令は、以下の通りである。
-シフト演算
--SLL / SRL / SRA / SLLV / SRLV / SRAV
-算術論理演算
--ADD / ADDU / SUB / SUBU / AND / OR / XOR / NOR / SLT / SLTU / ADDI / ADDIU / SLTI / SLTIU / ANDI / ORI / XORI / LUI
-メモリアクセス
--LW / SW
-相対分岐命令
--BEQ / BNE / BLEZ / BGTZ / BLTZ / BGEZ / BLTZAL / BGEZAL
-絶対分岐命令
--J / JAL / JR / JALR
**第7回 I/Oデバイスコントローラを作る [#o3de45cb]
完成したプロセッサだけをFPGAボードに実装しても、~
何の反応もなく、動いているのかどうかも確認できない。~
~
やはり、DE2ボードのI/Oを上手く使って、何らかの結果が返ってくるようでなければ、面白くない。~
~
私たちが開発したのは、プロセッサだけではない。~
より面白い動作ができるように、DE2ボードのI/Oを制御するデバイスコントローラも開発した。~
~
全体の構成は以下のようになっている。
CENTER:&ref(de2_mips_sche.png);
本来、プロセッサがアクセスするメモリ部分は、キャッシュとして実装されるべき部分だったので、~
命令コードの読み込みと、データの読み書き部分で2つのバスが用意されている形になっている。~
~
キャッシュの実装は、FPGAの内部RAMをメモリとして用いる場合、~
ほとんどの場合、1クロックでデータを呼び出せてしまうので、意味がない。~
~
将来的に、外部からプログラムをブートできるような拡張が完成したら、改めてキャッシュを実装したいとは考えている。~
~
~
用意したデバイスコントローラはデータメモリのバスに接続されている。~
デバイスへのアクセスはメモリマップドI/O方式を採用した。~
~
プロセッサはロード命令やストア命令を発行するだけで、これらのデバイスへ簡単にアクセスすることができる。~
これで何かのプログラムで計算した値をセブンセグメントLEDやLCDに表示することができるようになる。
**第8回 メモリマップドI/O方式によるデバイス制御 [#t10ba01a]
メモリマップドI/O方式について簡単に説明する。~
~
この方式ではI/Oデバイスコントローラがプロセッサとメモリを繋ぐバスに接続されている。~
プロセッサがロード命令を実行する際は、以下の図のように全てのモジュールにアドレスを入力する。
CENTER:&ref(memory_map1.png);
I/Oデバイスコントローラは、それぞれのデバイスに割り当てられたメモリアドレスであるかどうかを判定する~
アドレスデコーダを備えており、自分のデバイスに対するアドレスであれば、該当するデータをプロセッサに送信する。~
~
他のモジュールはプロセッサに流すデータはないので、該当モジュールのデータがプロセッサに入力される。~
以下の図は、セブンセグメントLEDにアクセスしたときの例である。
CENTER:&ref(memory_map2.png);
このとき、data_inの信号線は複数の入力線を持つが、それぞれがトライステートバッファで設計されており、~
プロセッサへデータを送信する必要のないときは、ハイインピーダンスの状態にする。~
~
メモリマップと各デバイスに割り当てたワード数は、以下の表のようにした。
|アドレス|デバイス|ワード数|
|0x00000000-0x00003FFF|命令メモリ|4096|
|0x00004000-0x00007FFF|データメモリ|4096|
|0x00008000-0x0000801F|セブンセグメントLED|8|
|0x00008020-0x0000802F|タイマ|4|
|0x00008030-0x0000803F|PS/2 キーボード|4|
|0x00008100-0x0000817F|LCD|32|
|0x00010000-0x00017FFF|キャラクタ・ディスプレイ|8192|
プロセッサがI/Oデバイスにアクセスする際には、これらのアドレス空間へのロード、ストア命令を実行すれば良い。~
C言語でのI/Oデバイスへのアクセスの実現は、ポインタを用いて簡単に記述することができる。
**第9回 Hello Worldを表示させてみた [#ndb1f455]
Hello WolrdをLCDに表示するプログラムを動かしてみる。~
~
通常のCプログラミングで使えるライブラリ類は用意されていないので、~
文字列の表示を行う際に使うprintf関数などは使用できない。~
さらにバイト単位のメモリアクセスをサポートしないためchar型を扱えないので、文字列もint型として扱う必要がある。~
~
LCDに表示するためには、APIで用意されている関数を使用すれば簡単に実現できる。~
LCDの好きな場所に1文字のキャラクタを表示することができる。~
表示するキャラクタはキャラクタコードで指定する必要があるが、~
基本的な文字列はint型でキャストしてあげることで、キャラクタコードを関数に渡すことができる。~
~
LCDに表示するAPIは、LCDのメモリ領域に対してストア命令を実行するような関数である。~
以下ではLCD表示関数が行っている動作を説明する。~
~
0x00008100から0x0000817FまでのアドレスがLCDに割り当てられているので、LCDの先頭に'A'を表示させたければ、
*(int *)0x00008100 = 0x41;
もしくは
*(int *)0x00008100 = (int)'A';
のように記述してやれば良い。~
~
例えば、以下のように"Hello World"を表示させたいときは、1文字単位で各アドレスに値を保持させる。
CENTER:&ref(lcd_display.png);
LCDに割り当てられたアドレスにあるデータは以下の通りになる。
|アドレス|保持する値|キャラクタ|
|0x00008100|0x20|' '|
|0x00008104|0x48|'H'|
|0x00008108|0x65|'e'|
|0x0000810C|0x6C|'l'|
|0x00008110|0x6C|'l'|
|0x00008114|0x6F|'o'|
|0x00008118|0x20|' '|
|0x0000811C|0x57|'W'|
|0x00008120|0x6F|'o'|
|0x00008124|0x72|'r'|
|0x00008128|0x6C|'l'|
|0x0000812C|0x64|'d'|
|0x00008130|0x20|' '|
|0x00008134|0x20|' '|
|...|...|...|
以下の図は、Hello Worldを表示させるプログラムを動作させた例である。~
ただし、上の図とは表示させる場所が異なっている。
CENTER:&ref(hello_world.jpg);
**第10回 割り込みを用いたプログラムの実現 [#kc2e3ef5]
割り込み処理を行うためには、プロセッサに割り込み制御のハードウェアを付加する必要がある。~
MIPSプロセッサでは割り込みを含む例外処理をコプロセッサとして実装している。~
~
割り込み信号を検知したら、現在実行中のプログラムから、割り込み処理用のプログラムに切替える必要がある。~
割り込み実行の様子を以下に示す。
CENTER:&ref(interrupt_flow.png);
割り込みが起きたら、システムが用意した例外ハンドラが実行されるようになっている。~
例外ハンドラと記述しているものの、実装した例外は割り込みだけである。~
~
例外ハンドラは割り込みの原因を調べ、その割り込みに対応した割り込みハンドラを実行する。~
この割り込みハンドラはユーザーが指定した関数をコールする仕組みになっている。~
~
割り込み処理が終われば、プロセッサは割り込みが起きた命令に戻り、プログラムを実行する。~
~
~
例外処理のコプロセッサは、例外が発生したときに実行中の命令を指すプログラムカウンタや~
例外や割り込みを発生したデバイスや、その原因を保持する制御レジスタを持っている。~
~
割り込みに関しては、それぞれの割り込み制御線に対して、許可するか禁止するかを制御できる。~
これらの制御レジスタは直接コプロセッサを扱う命令を用いて操作する。~
~
APIの一部の関数は、こういったコプロセッサ制御命令を含むため、アセンブリプログラム内に記述されている。
**第11回 [#d4ad28de]
ページ名: