Download pdf - Verilog-HDL Tutorial (8)

Transcript
Page 1: Verilog-HDL Tutorial (8)

1

Verilog-HDL 講習会DE0編(8) 順序回路記述(3)

~コンパクトな乗算器~

3, July, 2013 鹿児島大学 中原 啓貴

Page 2: Verilog-HDL Tutorial (8)

2

2進数の乗算 (例: 18 x 21 = 378)

1 0 0 1 0 1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 1 0 0 1 0

1 0 1 1 1 1 0 1 0

× 18 21

256+64+32+16+8+2=378

各列毎に加算

乗数=1 → 被乗数 乗数=0 → 0ベクトル

Page 3: Verilog-HDL Tutorial (8)

3

LUTを使った直接表現

LUT数が 入力ビット数nに 対して 指数関数的に 爆発してしまう

Page 4: Verilog-HDL Tutorial (8)

4

順序回路を使う •  乗数の各桁(ビット)に応じて ‒  0のとき, 途中の結果を左シフト ‒  1のとき, 被乗数を途中の結果に加算して左シフト

1 0 0 1 0 1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 1 0 0 1 0

1 0 1 1 1 1 0 1 0

× 18 21

各列毎に加算

乗数=1 → 被乗数 乗数=0 → 0ベクトル

よく見ると, 被乗数を左シフトしながら加算すれば良い 000010010 000100100 001001000 010010000 100100000

Page 5: Verilog-HDL Tutorial (8)

5

アルゴリズム 1.  途中結果を記憶するレジスタTEMPを初期化. TEMP <= 0; 2.  乗数Bのi番目のビットbi (i=0,1,2,...)に対して 1.  bi==0のとき, TEMP <= TEMP; 2.  bi==1のとき, TEMP <= TEMP + A; // A は被乗数

3.  A <= A << 1; とし, 全ての桁の計算が終わるまで2. を繰返す 4.  全ての桁の計算が終われば, RESULT に TEMPを格納.

1 0 0 1 0 1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 1 0 0 1 0

1 0 1 1 1 1 0 1 0

× 18 21

各列毎に加算

乗数=1 → 被乗数 乗数=0 → 0ベクトル

Page 6: Verilog-HDL Tutorial (8)

6

状態遷移図

Inital Q1

Reset R_A <= 0; R_B <= 0; TEMP <= 0; RESULT <= 0;

NONE if (R_B[0] == 1'b0) TEMP <= 10'b0; else TEMP <= R_A; R_A <= R_A << 1;

Q2

NONE R_A <= A; R_B <= B; TEMP <= 0;

NONE if (R_B[1] == 1'b0) TEMP <= TEMP; else TEMP <= TEMP +R_A; R_A <= R_A << 1;

Q3

NONE if (R_B[2] == 1'b0) TEMP <= TEMP; else TEMP <= TEMP +R_A; R_A <= R_A << 1;

Q4 Q5

NONE if (R_B[3] == 1'b0) TEMP <= TEMP; else TEMP <= TEMP +R_A; R_A <= R_A << 1;

NONE if (R_B[4] == 1'b0) RESULT <= TEMP; else RESULT <= TEMP +R_A;

Page 7: Verilog-HDL Tutorial (8)

7

DE0ボードに合わせて 信号線名を変更

Inital Q1

Reset R_A <= 0; R_B <= 0; TEMP <= 0; LEDG <= 0;

NONE if (R_B[0] == 1'b0) TEMP <= 10'b0; else TEMP <= R_A; R_A <= R_A << 1;

Q2

NONE R_A <= {5'b0,SW[4:0]}; R_B <= SW[9:5]; TEMP <= 0;

NONE if (R_B[1] == 1'b0) TEMP <= TEMP; else TEMP <= TEMP +R_A; R_A <= R_A << 1;

Q3

NONE if (R_B[2] == 1'b0) TEMP <= TEMP; else TEMP <= TEMP +R_A; R_A <= R_A << 1;

Q4 Q5 NONE if (R_B[3] == 1'b0) TEMP <= TEMP; else TEMP <= TEMP +R_A; R_A <= R_A << 1;

NONE if (R_B[4] == 1'b0) LEDG <= TEMP; else LEDG <= TEMP +R_A;

•  A -> SW[4:0], B -> SW[9:5], R_AとR_Bでそれぞれ保持 •  RESULT -> LEDG[9:0] (5ビットx5ビットの乗算は高々10ビット)

Page 8: Verilog-HDL Tutorial (8)

8

状態符号を割当て •  A -> SW[4:0], B -> SW[9:5], R_AとR_Bでそれぞれ保持 •  OUT -> LEDG[9:0] (5ビットx5ビットの乗算は高々10ビット)

000 001

Reset R_A <= 0; R_B <= 0; TEMP <= 0; LEDG <= 0;

NONE if (R_B[0] == 1'b0) TEMP <= 10'b0; else TEMP <= R_A; R_A <= R_A << 1;

010

NONE R_A <= {5'b0,SW[4:0]}; R_B <= SW[9:5]; TEMP <= 0;

NONE if (R_B[1] == 1'b0) TEMP <= TEMP; else TEMP <= TEMP +R_A; R_A <= R_A << 1;

011

NONE if (R_B[2] == 1'b0) TEMP <= TEMP; else TEMP <= TEMP +R_A; R_A <= R_A << 1;

100 101 NONE if (R_B[3] == 1'b0) TEMP <= TEMP; else TEMP <= TEMP +R_A; R_A <= R_A << 1;

NONE if (R_B[4] == 1'b0) LEDG <= TEMP; else LEDG <= TEMP +R_A;

Page 9: Verilog-HDL Tutorial (8)

9

注意

000 001 010

NONE if (R_B[1] == 1'b0) LEDG <= LEDG; else LEDG <= LEDG +R_A; R_A <= R_A << 1;

011

100 101 NONE if (R_B[3] == 1'b0) LEDG <= LEDG; else TEMP <= TEMP +R_A; R_A <= R_A << 1;

•  異なるビット幅の信号を接続する時は, ビット幅を合わせる!

SW[4:0] (5ビット)

R_A (10ビット)

5'b0 つまり 0 0 0 0 0

Reset R_A <= 0; R_B <= 0; TEMP <= 0; LEDG <= 0;

NONE if (R_B[0] == 1'b0) TEMP <= 10'b0; else TEMP <= R_A; R_A <= R_A << 1;

NONE R_A <= {5'b0,SW[4:0]}; R_B <= SW[9:5]; TEMP <= 0;

NONE if (R_B[4] == 1'b0) LEDG <= TEMP; else LEDG <= TEMP +R_A;

Page 10: Verilog-HDL Tutorial (8)

10

•  ピン配置が面倒くさいので、デフォルトのプロジェクトを読み込みましょう! (DE0に限った事ではないが、Terasic製品はサンプルCD-ROMの プロジェクトを改変するのが楽でお勧め)

DE0付属のCD-ROM ”Demonstrations”内の "DE0_Top"フォルダの ファイル全てを C:¥verilog¥DE0_tutorial_7_1¥ 内にコピー

Page 11: Verilog-HDL Tutorial (8)

DE0_TOP.qpfをダブルクリックしてQuartus IIを起動

11

Pin Plannerを開いてみると ピン配置が終わっている!

Page 12: Verilog-HDL Tutorial (8)

Verilog-HDLを入力

12

ダブルクリック Verilog-HDLの テンプレートが 表示されるので コードを入力

コード入力したら保存を忘れずに!

Page 13: Verilog-HDL Tutorial (8)

13

記述するVerilog-HDL

Page 14: Verilog-HDL Tutorial (8)

14

記述するテストベンチ

リセット信号と 入力値を記述

クロックを記述

Page 15: Verilog-HDL Tutorial (8)

15

シミュレーションで動作確認 •  デフォルトでは入出力信号のみ表示 ‒ 回路内部の信号(特にレジスタ)がわからない

Page 16: Verilog-HDL Tutorial (8)

16

内部信号の表示

乗算回路の インスタンス名 「i1」を選択 (テストベンチ自動 生成で勝手に命名される) 内部信号が

リストアップされます

simタブをクリック

Page 17: Verilog-HDL Tutorial (8)

17

観測する信号の追加

追加したい信号を選択し、 右クリック->「Add Wave」を 選択

Page 18: Verilog-HDL Tutorial (8)

18

シミュレーションの再実行

Console に「restart」と入力し, 出現するウインドウの「OK」を選択 シミュレーションが初期化(波形がクリア)

「run 400ps」と入力し, #400時間シミュレーションをスタート

Page 19: Verilog-HDL Tutorial (8)

19

シミュレーション結果を確認 •  状態が000のときに出力値(18x21=378)が得られているか確認

リセット中は 初期値が出る

リセット後は 21x18を計算. 状態000で 出力値を得る.

Page 20: Verilog-HDL Tutorial (8)

FPGA上で動作させる •  Compilation を行い, DE0ボード上に実現

20

1 0 1 0 1 21

1 0 0 1 0 18

378 0 1 0 1 1 1 1 0 1 0

Page 21: Verilog-HDL Tutorial (8)

21

まとめ •  今回学習したこと ‒ アルゴリズムから状態遷移図を作成 ‒ 状態遷移図からVerilog-HDLを記述 ‒ 内部信号のシミュレーション • 信号の追加 • シミュレーションの再実行

Page 22: Verilog-HDL Tutorial (8)

22

課題 (今回は非常に難しい)

•  Page 6の状態遷移図の状態を併合し, 簡単化しなさい ‒  R_B[0] を変数 idx で指定できれば, 大幅に簡単化できる (つまりC言語の配列を使う)

•  簡単化した状態遷移図をVerilog-HDLで記述せよ ‒  C言語の配列は直接実現できないので, マルチプレクサ(選択回路)を使う. つまり, if( R_B[idx]== 1'b0) をFunction文を使ったマルチプレクサからの信号 mux_out に置き換える. if( mux_out == 1'b0) ... assign mux_out = mux_6( R_B, idx); function mux_6; input [5:0]R_B; input [2:0]idx; ... endfunction

•  6ビットの割り算回路を順序回路で設計せよ. 動作確認はシミュレーションで行え.