SFLで作るPICO-16プロセッサ/第3回
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
|
ログイン
]
開始行:
[[SFLで作るPICO-16プロセッサ]]
*命令フェッチ回路の設計 [#pa338f5d]
プロセッサが実行する命令を格納するメモリである命令メモリと、~
命令メモリのアドレスを保持するプログラムカウンタを組み合わせて、命令メモリに保存されているデータを順次出力していく回路を設計します。
プログラムカウンタのインクリメントには、前回設計したALUを使ってみましょう。
**コンテンツ [#ee92de2e]
#contents
*仕様 [#ab285b48]
今回設計する回路の仕様は2つに分けて説明します。
**命令メモリ [#l77c86b8]
まずは、命令コードを格納させるROMである命令メモリを設計します。
CENTER:&ref(inst_memory.png);
***入出力 [#k2425f8b]
-入力
--読み出しアドレス(8ビット)
-出力
--命令コード(16ビット)
***内部メモリ領域 [#uc422621]
[[レジスタファイルの設計>SFLで作るPICO-16プロセッサ/第2回]]では、記憶領域としてレジスタを使用しました。~
今回は、より大きな記憶領域を扱うため、配列のような記述ができる[[メモリ領域宣言>#ba712d77]]を用いて内部メモリ領域を定義します。
-256ワード(1ワードは16ビット)
--アドレス指定は8ビットで行う。
--メモリ領域の名前はarrayとする。
***機能 [#cd7dae85]
-読み出し
--8ビットの読み出しアドレスを使って、メモリ領域からデータを読み込む。
**全体 [#q0d4b707]
命令メモリにプログラムカウンタとALUを接続して、メモリの内容を順次出力する回路を設計します。
CENTER:&ref(inst_fetch.png);
***入出力 [#a7b41246]
入力信号はありません。
-出力
--読み出した命令データ(16ビット)
***内部レジスタ [#a77910f2]
-プログラムカウンタ(16ビット)
--リセット時に0に初期化する。
***サブモジュール [#g822a6da]
-ALU
--[[第1回>SFLで作るPICO-16プロセッサ/第1回]]で設計したALU。
-命令メモリ
--サブモジュールの名前はimemとする。
***機能 [#g0cc9f09]
-プログラムカウンタのインクリメント
--ALUのADD機能を使用してプログラムカウンタをインクリメント(+1)する。
-メモリ内容の読み出し
--プログラムカウンタを命令メモリのアドレスとして、命令メモリからのデータを出力する。
*実装 [#v58f12cc]
実装も2つに分けて説明します。
**命令メモリ [#q94fc33e]
ファイル名はinst_memory.sfl及び、inst_memory.hとします。
***ヘッダ [#ce29860a]
declare inst_memory {
input adrs<8>;
output out<16>;
instrin read;
instr_arg read(adrs);
}
***モジュール [#mec84dfa]
今回は詳細なスケルトンを用意しません。以下の手順に従って記述してください。
module inst_memory {
/* 1. 入出力信号、制御入出力信号を記述 */
/* 2. 内部メモリ領域宣言 */
/* 3. 制御入力に対する動作を記述 */
}
**全体 [#r2b29c54]
ファイル名はinst_fetch.sfl及び、inst_fetch.hとします。
***ヘッダ [#o30f1ab0]
declare inst_fetch {
output mem_data<16>;
instrin inc_pc;
instrin read;
}
***モジュール [#rf0e2735]
命令メモリ同様に詳細なスケルトンは用意しません。以下の手順に従って記述してください。
/* 1. サブモジュールとして使用するモジュールのヘッダをインクルード */
module inst_fetch {
/* 2. 入出力信号、制御入出力信号を記述 */
/* 3. レジスタ宣言 */
/* 4. サブモジュール宣言 */
/* 5. 制御入力に対する動作を記述 */
}
[[ヘッダファイルのインクルード>#gdaa2eaf]]と[[サブモジュール>#ka1493fc]]を参考にしてください。
*論理シミュレーション [#ifbf4309]
回路が正しく動作しているかどうかを確認します。
+&ref(ex03.tar.gz);をダウンロードする。~
~
解凍方法)
% tar zxvf ex03.tar.gz
+inst_memory.h、inst_memory.sfl、inst_fetch.h、inst_fetch.sflを作成し、ex03ディレクトリに入れる。
--inst_memory.hは、[[ここ>#ce29860a]]から内容をコピーする。
--inst_memory.sflは、[[ここ>#mec84dfa]]から内容をコピーして、記述を完成させる。
--inst_fetch.hは、[[ここ>#o30f1ab0]]から内容をコピーする。
--inst_fetch.sflは、[[ここ>#rf0e2735]]から内容をコピーして、記述を完成させる。
+[[第1回>SFLで作るPICO-16プロセッサ/第1回]]で作成したalu.h、alu.sflをex03ディレクトリにコピーする。
+シミュレーションを行う。
--シミュレーションには次のコマンドを使います。
% make
もしくは、
% make sim
--シミュレーションの結果はsim.logに出力されます。正しく動作していると&ref(sim.log.txt);のようになります。
--余裕があればテストベンチを自由に改変してみましょう。
+波形を観察する。
--波形ビューワの起動には次のコマンドを使います。
% make wave
--
+ファイルをクリーンする。
--ファイルのクリーンには次のコマンドを使います。
% make clean
--シミュレーションや波形ビューワで生成されたファイルのサイズが大きいときもあるので、全て終わったら余計なファイルを削除しておきましょう。
**シミュレーション結果 [#id672fb0]
正しく動作していれば、次のような結果が出ます。
|ステップ|出力|
|0|0000|
|1|1111|
|2|2222|
|3|3333|
|4|4444|
|5|5555|
|6|6666|
|7|7777|
**テストベンチ [#a841f14b]
今回のテストベンチで使っているtaskは全部で4つあります。
-set_memory_data~
メモリに初期値をセットします。データの中身はmemory_data.memに定義されています。initialize内で呼び出されています。~
~
使用例)
set_memory_data;
-initialize~
リセット処理及びメモリの初期化を行います。テストベンチの最初に一度だけ使用します。~
~
使用例)
initialize;
-inc_pc~
プログラムカウンタをインクリメントします。~
~
使用例)
inc_pc;
-display_out~
プログラムカウンタで示されるアドレスを使って命令メモリからデータを出力します。~
~
使用例)
display_out;
*ヒントと豆知識 [#xc58c50a]
ここでは、今回の演習に関わる豆知識やヒントを紹介します。
**メモリ領域宣言 [#ba712d77]
SFLでは大きな記憶領域を扱うため、配列のような記述ができるメモリ領域宣言が用意されています。~
例えば、8ビットの記憶領域を1024個用意したい場合は以下のように記述できます。
mem array[1024]<8>;
このとき、1024は2の10乗で表現できるため、読み出しアドレスは10ビット必要になります。
メモリ領域の読み書きはレジスタと同様に扱うことが出来ます。
-読み出し
out = array[adrs];
-書き込み
array[adrs] := in;
**ヘッダファイルのインクルード [#gdaa2eaf]
他のモジュールをサブモジュールとして使用する場合、そのモジュールのdeclare宣言を記述する必要があります。~
今回はヘッダファイルとしてdeclareの記述をしているので、ヘッダファイルをインクルードしましょう。
インクルード文は以下のように記述します。
%i "[ヘッダファイルへのパス]"
%i "./submodule.h"
**サブモジュール [#ka1493fc]
サブモジュールを宣言するときは、インスタンス名(サブモジュールに付ける名前)をつける必要があります。~
例として、以下のようにサブモジュールの宣言ができます。
alu alu1, alu2, alu3;
regfile rf1, rf2, rf3;
サブモジュールの使い方は[サブモジュール名].[制御信号]([引数/入力信号]).[出力信号]という書き方で、制御信号に対しての出力を得ることができます。
~
例えば、inaとinbを入力して、ALUでANDを行い結果を出力する場合、
alu_and_result = alu1.AND(ina, inb).out;
の様に記述することで使用することができます。
また、
par {
alu1.AND(ina, inb);
alu_and_result = alu1.out;
}
と記述しても、parで書かれたブロックの中は全て1クロック(並列に)で動作するため、同じ意味を持ちます。
**memファイルの書き方 [#e85c728a]
今回用意したmemory_data.memファイルは、以下のような内容が記述されています。
@0000 0000
@0001 1111
@0002 2222
...
これは@で指定するのがメモリのアドレス、続く2つ目のデータがそのアドレスが指すメモリに書き込む値になっています。
簡単に編集することができるので、試してみるといいでしょう。
終了行:
[[SFLで作るPICO-16プロセッサ]]
*命令フェッチ回路の設計 [#pa338f5d]
プロセッサが実行する命令を格納するメモリである命令メモリと、~
命令メモリのアドレスを保持するプログラムカウンタを組み合わせて、命令メモリに保存されているデータを順次出力していく回路を設計します。
プログラムカウンタのインクリメントには、前回設計したALUを使ってみましょう。
**コンテンツ [#ee92de2e]
#contents
*仕様 [#ab285b48]
今回設計する回路の仕様は2つに分けて説明します。
**命令メモリ [#l77c86b8]
まずは、命令コードを格納させるROMである命令メモリを設計します。
CENTER:&ref(inst_memory.png);
***入出力 [#k2425f8b]
-入力
--読み出しアドレス(8ビット)
-出力
--命令コード(16ビット)
***内部メモリ領域 [#uc422621]
[[レジスタファイルの設計>SFLで作るPICO-16プロセッサ/第2回]]では、記憶領域としてレジスタを使用しました。~
今回は、より大きな記憶領域を扱うため、配列のような記述ができる[[メモリ領域宣言>#ba712d77]]を用いて内部メモリ領域を定義します。
-256ワード(1ワードは16ビット)
--アドレス指定は8ビットで行う。
--メモリ領域の名前はarrayとする。
***機能 [#cd7dae85]
-読み出し
--8ビットの読み出しアドレスを使って、メモリ領域からデータを読み込む。
**全体 [#q0d4b707]
命令メモリにプログラムカウンタとALUを接続して、メモリの内容を順次出力する回路を設計します。
CENTER:&ref(inst_fetch.png);
***入出力 [#a7b41246]
入力信号はありません。
-出力
--読み出した命令データ(16ビット)
***内部レジスタ [#a77910f2]
-プログラムカウンタ(16ビット)
--リセット時に0に初期化する。
***サブモジュール [#g822a6da]
-ALU
--[[第1回>SFLで作るPICO-16プロセッサ/第1回]]で設計したALU。
-命令メモリ
--サブモジュールの名前はimemとする。
***機能 [#g0cc9f09]
-プログラムカウンタのインクリメント
--ALUのADD機能を使用してプログラムカウンタをインクリメント(+1)する。
-メモリ内容の読み出し
--プログラムカウンタを命令メモリのアドレスとして、命令メモリからのデータを出力する。
*実装 [#v58f12cc]
実装も2つに分けて説明します。
**命令メモリ [#q94fc33e]
ファイル名はinst_memory.sfl及び、inst_memory.hとします。
***ヘッダ [#ce29860a]
declare inst_memory {
input adrs<8>;
output out<16>;
instrin read;
instr_arg read(adrs);
}
***モジュール [#mec84dfa]
今回は詳細なスケルトンを用意しません。以下の手順に従って記述してください。
module inst_memory {
/* 1. 入出力信号、制御入出力信号を記述 */
/* 2. 内部メモリ領域宣言 */
/* 3. 制御入力に対する動作を記述 */
}
**全体 [#r2b29c54]
ファイル名はinst_fetch.sfl及び、inst_fetch.hとします。
***ヘッダ [#o30f1ab0]
declare inst_fetch {
output mem_data<16>;
instrin inc_pc;
instrin read;
}
***モジュール [#rf0e2735]
命令メモリ同様に詳細なスケルトンは用意しません。以下の手順に従って記述してください。
/* 1. サブモジュールとして使用するモジュールのヘッダをインクルード */
module inst_fetch {
/* 2. 入出力信号、制御入出力信号を記述 */
/* 3. レジスタ宣言 */
/* 4. サブモジュール宣言 */
/* 5. 制御入力に対する動作を記述 */
}
[[ヘッダファイルのインクルード>#gdaa2eaf]]と[[サブモジュール>#ka1493fc]]を参考にしてください。
*論理シミュレーション [#ifbf4309]
回路が正しく動作しているかどうかを確認します。
+&ref(ex03.tar.gz);をダウンロードする。~
~
解凍方法)
% tar zxvf ex03.tar.gz
+inst_memory.h、inst_memory.sfl、inst_fetch.h、inst_fetch.sflを作成し、ex03ディレクトリに入れる。
--inst_memory.hは、[[ここ>#ce29860a]]から内容をコピーする。
--inst_memory.sflは、[[ここ>#mec84dfa]]から内容をコピーして、記述を完成させる。
--inst_fetch.hは、[[ここ>#o30f1ab0]]から内容をコピーする。
--inst_fetch.sflは、[[ここ>#rf0e2735]]から内容をコピーして、記述を完成させる。
+[[第1回>SFLで作るPICO-16プロセッサ/第1回]]で作成したalu.h、alu.sflをex03ディレクトリにコピーする。
+シミュレーションを行う。
--シミュレーションには次のコマンドを使います。
% make
もしくは、
% make sim
--シミュレーションの結果はsim.logに出力されます。正しく動作していると&ref(sim.log.txt);のようになります。
--余裕があればテストベンチを自由に改変してみましょう。
+波形を観察する。
--波形ビューワの起動には次のコマンドを使います。
% make wave
--
+ファイルをクリーンする。
--ファイルのクリーンには次のコマンドを使います。
% make clean
--シミュレーションや波形ビューワで生成されたファイルのサイズが大きいときもあるので、全て終わったら余計なファイルを削除しておきましょう。
**シミュレーション結果 [#id672fb0]
正しく動作していれば、次のような結果が出ます。
|ステップ|出力|
|0|0000|
|1|1111|
|2|2222|
|3|3333|
|4|4444|
|5|5555|
|6|6666|
|7|7777|
**テストベンチ [#a841f14b]
今回のテストベンチで使っているtaskは全部で4つあります。
-set_memory_data~
メモリに初期値をセットします。データの中身はmemory_data.memに定義されています。initialize内で呼び出されています。~
~
使用例)
set_memory_data;
-initialize~
リセット処理及びメモリの初期化を行います。テストベンチの最初に一度だけ使用します。~
~
使用例)
initialize;
-inc_pc~
プログラムカウンタをインクリメントします。~
~
使用例)
inc_pc;
-display_out~
プログラムカウンタで示されるアドレスを使って命令メモリからデータを出力します。~
~
使用例)
display_out;
*ヒントと豆知識 [#xc58c50a]
ここでは、今回の演習に関わる豆知識やヒントを紹介します。
**メモリ領域宣言 [#ba712d77]
SFLでは大きな記憶領域を扱うため、配列のような記述ができるメモリ領域宣言が用意されています。~
例えば、8ビットの記憶領域を1024個用意したい場合は以下のように記述できます。
mem array[1024]<8>;
このとき、1024は2の10乗で表現できるため、読み出しアドレスは10ビット必要になります。
メモリ領域の読み書きはレジスタと同様に扱うことが出来ます。
-読み出し
out = array[adrs];
-書き込み
array[adrs] := in;
**ヘッダファイルのインクルード [#gdaa2eaf]
他のモジュールをサブモジュールとして使用する場合、そのモジュールのdeclare宣言を記述する必要があります。~
今回はヘッダファイルとしてdeclareの記述をしているので、ヘッダファイルをインクルードしましょう。
インクルード文は以下のように記述します。
%i "[ヘッダファイルへのパス]"
%i "./submodule.h"
**サブモジュール [#ka1493fc]
サブモジュールを宣言するときは、インスタンス名(サブモジュールに付ける名前)をつける必要があります。~
例として、以下のようにサブモジュールの宣言ができます。
alu alu1, alu2, alu3;
regfile rf1, rf2, rf3;
サブモジュールの使い方は[サブモジュール名].[制御信号]([引数/入力信号]).[出力信号]という書き方で、制御信号に対しての出力を得ることができます。
~
例えば、inaとinbを入力して、ALUでANDを行い結果を出力する場合、
alu_and_result = alu1.AND(ina, inb).out;
の様に記述することで使用することができます。
また、
par {
alu1.AND(ina, inb);
alu_and_result = alu1.out;
}
と記述しても、parで書かれたブロックの中は全て1クロック(並列に)で動作するため、同じ意味を持ちます。
**memファイルの書き方 [#e85c728a]
今回用意したmemory_data.memファイルは、以下のような内容が記述されています。
@0000 0000
@0001 1111
@0002 2222
...
これは@で指定するのがメモリのアドレス、続く2つ目のデータがそのアドレスが指すメモリに書き込む値になっています。
簡単に編集することができるので、試してみるといいでしょう。
ページ名: