SFLで作るPICO-16プロセッサ/第2回
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
|
ログイン
]
開始行:
[[SFLで作るPICO-16プロセッサ]]
*レジスタファイルの設計 [#pd9b7a0f]
レジスタファイルはALUに入力するデータや計算結果を一時的に保持しておく汎用レジスタの集まりです。~
PICO-16プロセッサのレジスタファイルは16ビットの汎用レジスタを8個の備えています。2つの読み出しポートと1つの書き込みポートを持っています。
**コンテンツ [#h6f0d3f6]
#contents
*仕様 [#a9bb6dbd]
今回設計するレジスタファイルの仕様を確認します。
CENTER:&ref(regfile.png);
**入出力 [#aa91a783]
-入力
--読み出しポート1のレジスタアドレス(3ビット)
--読み出しポート2のレジスタアドレス(3ビット)
--書き込みポートのレジスタアドレス(3ビット)
--書き込みデータ(16ビット)
-出力
--読み出しポート1のデータ(16ビット)
--読み出しポート2のデータ(16ビット)
**内部レジスタ [#ie6ed604]
-8つの汎用レジスタ(16ビット)
--リセット時に0に初期化する。
--名前はr0, r1, r2, r3, ..., r7とする。
--汎用レジスタの指定は3ビットで行う。
|レジスタアドレス|対応するレジスタ|
|000|r0|
|001|r1|
|010|r2|
|011|r3|
|100|r4|
|101|r5|
|110|r6|
|111|r7|
**機能 [#v2323796]
-読み出し1
--読み出しポート1のレジスタアドレスから、汎用レジスタを選択して、その値を読み出しポート1のデータとして出力する。
-読み出し2
--読み出しポート2のレジスタアドレスから、汎用レジスタを選択して、その値を読み出しポート2のデータとして出力する。
-書き込み
--書き込みポートのレジスタアドレスから、汎用レジスタを選択して、書き込みデータをそのレジスタに書き込む。
*実装 [#l6963e84]
ファイル名はregfile.sfl及び、regfile.hとします。
**ヘッダ [#hc078b36]
ヘッダは仕様定義からの情報を用いて書くことができます。入出力、制御入出力、仮引数を定義します。
declare regfile {
input adrs1<3>;
input adrs2<3>;
input adrs3<3>;
input in<16>;
output out1<16>;
output out2<16>;
instrin read1;
instrin read2;
instrin write;
instr_arg read1(adrs1);
instr_arg read2(adrs2);
instr_arg write(adrs3, in);
}
ヘッダは既に完成しているので、regfile.hの内容としてコピーして保存してください。
**モジュール [#i9483f8c]
スケルトンを用意しました。入出力と制御入力は仕様定義やヘッダで既に決まっているので、以下のような記述になります。~
足りない部分は各制御入力に対応する動作なので、正しく動作するように該当部分を記述してください。
module regfile {
input adrs1<3>;
input adrs2<3>;
input adrs3<3>;
input in<16>;
output out1<16>;
output out2<16>;
instrin read1;
instrin read2;
instrin write;
/* ここに内部レジスタを記述する */
instruct read1 /* ここに動作を記述する */
instruct read2 /* ここに動作を記述する */
instruct write /* ここに動作を記述する */
}
レジスタの宣言方法と、条件動作ブロックであるanyの使い方を復習しましょう。
*論理シミュレーション [#n217291a]
回路が正しく動作しているかどうかを確認します。
+&ref(ex02.tar.gz);をダウンロードする。~
~
解凍方法)
% tar zxvf ex02.tar.gz
+regfile.h、regfile.sflを作成し、ex02ディレクトリに入れる。
--regfile.hは、[[ここ>#hc078b36]]から内容をコピーする。
--regfile.sflは、[[ここ>#i9483f8c]]から内容をコピーして、記述を完成させる。
+シミュレーションを行う。
--シミュレーションには次のコマンドを使います。
% make
もしくは、
% make sim
--シミュレーションの結果はsim.logに出力されます。正しく動作していると&ref(sim.log.txt);のようになります。
--余裕があればテストベンチを自由に改変してみましょう。
+波形を観察する。
--波形ビューワの起動には次のコマンドを使います。
% make wave
--
+ファイルをクリーンする。
--ファイルのクリーンには次のコマンドを使います。
% make clean
--シミュレーションや波形ビューワで生成されたファイルのサイズが大きいときもあるので、全て終わったら余計なファイルを削除しておきましょう。
**シミュレーション結果 [#y26a274d]
正しく動作していれば、次のような結果が出ます。
|ステップ|動作|r0|r1|r2|r3|r4|r5|r6|r7|出力1|出力2|
|1|WRITE r0 <= 1111|1111|0000|0000|0000|0000|0000|0000|0000|||
|2|WRITE r1 <= 2222|1111|2222|0000|0000|0000|0000|0000|0000|||
|3|WRITE r2 <= 3333|1111|2222|3333|0000|0000|0000|0000|0000|||
|4|WRITE r3 <= 4444|1111|2222|3333|4444|0000|0000|0000|0000|||
|5|WRITE r4 <= 5555|1111|2222|3333|4444|5555|0000|0000|0000|||
|6|WRITE r5 <= 6666|1111|2222|3333|4444|5555|6666|0000|0000|||
|7|WRITE r6 <= 7777|1111|2222|3333|4444|5555|6666|7777|0000|||
|8|WRITE r7 <= 8888|1111|2222|3333|4444|5555|6666|7777|8888|||
|9|READ r0, r1|1111|2222|3333|4444|5555|6666|7777|8888|1111|2222|
|10|READ r2, r3|1111|2222|3333|4444|5555|6666|7777|8888|3333|4444|
|11|READ r4, r5|1111|2222|3333|4444|5555|6666|7777|8888|5555|6666|
|12|READ r6, r7|1111|2222|3333|4444|5555|6666|7777|8888|7777|8888|
**テストベンチ [#r83a29db]
今回のテストベンチで使っているtaskは全部で4つあります。
-initialize~
リセット処理を行います。テストベンチの最初に一度だけ使用します。~
~
使用例)
initialize;
-display_regs~
8個のレジスタの状態を表示します。write_regの最後で使っています。~
~
使用例)
display_regs;
-write_reg~
指定したレジスタ番号に好きなデータを書き込みます。レジスタ番号とデータを渡します。~
~
使用例)
write_reg(3, 16'h4444);
write_reg(4, 16'h5555);
-read_reg~
指定したレジスタ番号のデータを読み出します。2つのレジスタ番号を渡します。~
~
使用例)
read_reg(0, 1);
read_reg(2, 3);
*ヒントと豆知識 [#s3f23290]
ここでは、今回の演習に関わる豆知識やヒントを紹介します。
**レジスタ宣言 [#p75eef65]
SFLでは3種類のレジスタ宣言方法があります。
-reg~
リセット時に初期化されないレジスタの宣言です。~
~
使用例)
reg hoge<16>;
-reg_wr~
リセット時に0に初期化されるレジスタの宣言です。~
~
使用例)
reg_wr hoge<16>;
-reg_ws~
リセット時に全て1で初期化されるレジスタの宣言です。~
例えば16ビットのレジスタをreg_wsで宣言すると、0xffffのデータで初期化されます。~
~
使用例)
reg_ws hoge<16>;
また、レジスタへの値の代入には専用の演算子である(:=)を使用します。例としては以下のようになります。
hoge := 0x1234;
**条件動作ブロック [#x89e1b69]
入力データによって出力するデータを選択するような動作を実現したい場合は、条件動作ブロックであるany構文を使用します。
マルチプレクサ(複数の入力から出力を選ぶ回路)を例に、サンプルコードを書きます。ここでは4入力1出力のマルチプレクサを例に扱います。
module mux4to1 {
input in1;
input in2;
input in3;
input in4;
input select<2>;
output out;
instrin do;
instruct do any {
select == 0b00 : out = in1;
select == 0b01 : out = in2;
select == 0b10 : out = in3;
select == 0b11 : out = in4;
}
}
ここでselect信号が2ビットなのは、4つの入力を選ぶという制御に必要なビット幅だからです。例えば8入力なら制御は3ビットになります。
また、any構文を使用する上で、条件に該当しなかった場合の動作を定義することも可能です。簡単な例を書くと以下のようになります。
any {
select == 0b00 : out = in1;
select == 0b01 : out = in2;
else : out = in3;
}
終了行:
[[SFLで作るPICO-16プロセッサ]]
*レジスタファイルの設計 [#pd9b7a0f]
レジスタファイルはALUに入力するデータや計算結果を一時的に保持しておく汎用レジスタの集まりです。~
PICO-16プロセッサのレジスタファイルは16ビットの汎用レジスタを8個の備えています。2つの読み出しポートと1つの書き込みポートを持っています。
**コンテンツ [#h6f0d3f6]
#contents
*仕様 [#a9bb6dbd]
今回設計するレジスタファイルの仕様を確認します。
CENTER:&ref(regfile.png);
**入出力 [#aa91a783]
-入力
--読み出しポート1のレジスタアドレス(3ビット)
--読み出しポート2のレジスタアドレス(3ビット)
--書き込みポートのレジスタアドレス(3ビット)
--書き込みデータ(16ビット)
-出力
--読み出しポート1のデータ(16ビット)
--読み出しポート2のデータ(16ビット)
**内部レジスタ [#ie6ed604]
-8つの汎用レジスタ(16ビット)
--リセット時に0に初期化する。
--名前はr0, r1, r2, r3, ..., r7とする。
--汎用レジスタの指定は3ビットで行う。
|レジスタアドレス|対応するレジスタ|
|000|r0|
|001|r1|
|010|r2|
|011|r3|
|100|r4|
|101|r5|
|110|r6|
|111|r7|
**機能 [#v2323796]
-読み出し1
--読み出しポート1のレジスタアドレスから、汎用レジスタを選択して、その値を読み出しポート1のデータとして出力する。
-読み出し2
--読み出しポート2のレジスタアドレスから、汎用レジスタを選択して、その値を読み出しポート2のデータとして出力する。
-書き込み
--書き込みポートのレジスタアドレスから、汎用レジスタを選択して、書き込みデータをそのレジスタに書き込む。
*実装 [#l6963e84]
ファイル名はregfile.sfl及び、regfile.hとします。
**ヘッダ [#hc078b36]
ヘッダは仕様定義からの情報を用いて書くことができます。入出力、制御入出力、仮引数を定義します。
declare regfile {
input adrs1<3>;
input adrs2<3>;
input adrs3<3>;
input in<16>;
output out1<16>;
output out2<16>;
instrin read1;
instrin read2;
instrin write;
instr_arg read1(adrs1);
instr_arg read2(adrs2);
instr_arg write(adrs3, in);
}
ヘッダは既に完成しているので、regfile.hの内容としてコピーして保存してください。
**モジュール [#i9483f8c]
スケルトンを用意しました。入出力と制御入力は仕様定義やヘッダで既に決まっているので、以下のような記述になります。~
足りない部分は各制御入力に対応する動作なので、正しく動作するように該当部分を記述してください。
module regfile {
input adrs1<3>;
input adrs2<3>;
input adrs3<3>;
input in<16>;
output out1<16>;
output out2<16>;
instrin read1;
instrin read2;
instrin write;
/* ここに内部レジスタを記述する */
instruct read1 /* ここに動作を記述する */
instruct read2 /* ここに動作を記述する */
instruct write /* ここに動作を記述する */
}
レジスタの宣言方法と、条件動作ブロックであるanyの使い方を復習しましょう。
*論理シミュレーション [#n217291a]
回路が正しく動作しているかどうかを確認します。
+&ref(ex02.tar.gz);をダウンロードする。~
~
解凍方法)
% tar zxvf ex02.tar.gz
+regfile.h、regfile.sflを作成し、ex02ディレクトリに入れる。
--regfile.hは、[[ここ>#hc078b36]]から内容をコピーする。
--regfile.sflは、[[ここ>#i9483f8c]]から内容をコピーして、記述を完成させる。
+シミュレーションを行う。
--シミュレーションには次のコマンドを使います。
% make
もしくは、
% make sim
--シミュレーションの結果はsim.logに出力されます。正しく動作していると&ref(sim.log.txt);のようになります。
--余裕があればテストベンチを自由に改変してみましょう。
+波形を観察する。
--波形ビューワの起動には次のコマンドを使います。
% make wave
--
+ファイルをクリーンする。
--ファイルのクリーンには次のコマンドを使います。
% make clean
--シミュレーションや波形ビューワで生成されたファイルのサイズが大きいときもあるので、全て終わったら余計なファイルを削除しておきましょう。
**シミュレーション結果 [#y26a274d]
正しく動作していれば、次のような結果が出ます。
|ステップ|動作|r0|r1|r2|r3|r4|r5|r6|r7|出力1|出力2|
|1|WRITE r0 <= 1111|1111|0000|0000|0000|0000|0000|0000|0000|||
|2|WRITE r1 <= 2222|1111|2222|0000|0000|0000|0000|0000|0000|||
|3|WRITE r2 <= 3333|1111|2222|3333|0000|0000|0000|0000|0000|||
|4|WRITE r3 <= 4444|1111|2222|3333|4444|0000|0000|0000|0000|||
|5|WRITE r4 <= 5555|1111|2222|3333|4444|5555|0000|0000|0000|||
|6|WRITE r5 <= 6666|1111|2222|3333|4444|5555|6666|0000|0000|||
|7|WRITE r6 <= 7777|1111|2222|3333|4444|5555|6666|7777|0000|||
|8|WRITE r7 <= 8888|1111|2222|3333|4444|5555|6666|7777|8888|||
|9|READ r0, r1|1111|2222|3333|4444|5555|6666|7777|8888|1111|2222|
|10|READ r2, r3|1111|2222|3333|4444|5555|6666|7777|8888|3333|4444|
|11|READ r4, r5|1111|2222|3333|4444|5555|6666|7777|8888|5555|6666|
|12|READ r6, r7|1111|2222|3333|4444|5555|6666|7777|8888|7777|8888|
**テストベンチ [#r83a29db]
今回のテストベンチで使っているtaskは全部で4つあります。
-initialize~
リセット処理を行います。テストベンチの最初に一度だけ使用します。~
~
使用例)
initialize;
-display_regs~
8個のレジスタの状態を表示します。write_regの最後で使っています。~
~
使用例)
display_regs;
-write_reg~
指定したレジスタ番号に好きなデータを書き込みます。レジスタ番号とデータを渡します。~
~
使用例)
write_reg(3, 16'h4444);
write_reg(4, 16'h5555);
-read_reg~
指定したレジスタ番号のデータを読み出します。2つのレジスタ番号を渡します。~
~
使用例)
read_reg(0, 1);
read_reg(2, 3);
*ヒントと豆知識 [#s3f23290]
ここでは、今回の演習に関わる豆知識やヒントを紹介します。
**レジスタ宣言 [#p75eef65]
SFLでは3種類のレジスタ宣言方法があります。
-reg~
リセット時に初期化されないレジスタの宣言です。~
~
使用例)
reg hoge<16>;
-reg_wr~
リセット時に0に初期化されるレジスタの宣言です。~
~
使用例)
reg_wr hoge<16>;
-reg_ws~
リセット時に全て1で初期化されるレジスタの宣言です。~
例えば16ビットのレジスタをreg_wsで宣言すると、0xffffのデータで初期化されます。~
~
使用例)
reg_ws hoge<16>;
また、レジスタへの値の代入には専用の演算子である(:=)を使用します。例としては以下のようになります。
hoge := 0x1234;
**条件動作ブロック [#x89e1b69]
入力データによって出力するデータを選択するような動作を実現したい場合は、条件動作ブロックであるany構文を使用します。
マルチプレクサ(複数の入力から出力を選ぶ回路)を例に、サンプルコードを書きます。ここでは4入力1出力のマルチプレクサを例に扱います。
module mux4to1 {
input in1;
input in2;
input in3;
input in4;
input select<2>;
output out;
instrin do;
instruct do any {
select == 0b00 : out = in1;
select == 0b01 : out = in2;
select == 0b10 : out = in3;
select == 0b11 : out = in4;
}
}
ここでselect信号が2ビットなのは、4つの入力を選ぶという制御に必要なビット幅だからです。例えば8入力なら制御は3ビットになります。
また、any構文を使用する上で、条件に該当しなかった場合の動作を定義することも可能です。簡単な例を書くと以下のようになります。
any {
select == 0b00 : out = in1;
select == 0b01 : out = in2;
else : out = in3;
}
ページ名: