浮動小数点ユニットの素振り
#自作CPU #RISC-V #FPGA #Verilog
form マルチサイクル RISC-V CPU を作成したい
自作CPUは、整数演算系はだいたい動くようになったので、次は浮動小数点数を計算できるようにしたい。
浮動小数点数計算を行うためのFPUコアは、自作ではなく既存のものを利用する。
https://github.com/dawsonjon/fpu
上記のFPUコアを使って、浮動小数点数計算を練習する。
インストール
https://github.com/dawsonjon/fpu のリポジトリをcloneして、自作CPUの rtl/fpu ディレクトリへコピー。
FPUコア付属のテストベンチを流してみる
code:sh
$ cd rtl/fpu/adder
# テストに使うC++のプログラムをコンパイル
$ cd c_test
$ make test
$ cd ..
$ python run_test.py
ちゃんと動いていそう
浮動小数点加算器を動かしてみる
自分で書いたテストベンチを動かし、波形を眺める。
adder.v の使い方はこんな感じ。
1. input_a と input_b をセットし、input_a_stb と input_b_stb をアサートする。同じタイミングで output_z_ack をデアサートしておく
2. 計算が終わると output_z_stb がアサートされるので、それまで待機
3. output_z から計算結果を取得
4. 計算結果見終わったよを伝えるため、output_z_ack をアサートする。同じタイミングで input_a_stb と input_b_stb をデアサートしておく
code:rtl/fpu/adder/adder_test.sv
`timescale 1ns/1ps
// adder.v のテストベンチ
module adder_test;
reg clk;
reg rst;
reg 31:0 input_a, input_b;
reg input_a_stb, input_b_stb;
logic input_a_ack, input_b_ack;
logic 31:0 output_z;
logic output_z_stb;
reg output_z_ack;
adder adder_inst (
.clk(clk),
.rst(rst),
.input_a(input_a),
.input_a_stb(input_a_stb),
.input_a_ack(input_a_ack),
.input_b(input_b),
.input_b_stb(input_b_stb),
.input_b_ack(input_b_ack),
.output_z(output_z),
.output_z_stb(output_z_stb),
.output_z_ack(output_z_ack)
);
initial begin
clk = 0;
$dumpfile("adder_test.vcd");
$dumpvars(0, adder_test);
// リセット
rst = 1;
#10;
rst = 0;
#10;
//----------------------------------------------------------------------
// 0.0 + 0.0 = 0.0
//----------------------------------------------------------------------
// a と b をセット
input_a = 32'b0_00000000_00000000000000000000000; // a = 0.0
input_b = 32'b0_00000000_00000000000000000000000; // b = 0.0
input_a_stb = 1;
input_b_stb = 1;
output_z_ack = 0; // 入力が受理される前に z_ack をデアサートしておく
// z_stb がアサートされるまで待機
wait(output_z_stb);
// z の出力を確認(z = 0.0)
assert(output_z == 32'h00000000) $display("PASSED"); else $display("FAILED");
// a_stb と b_stb をデアサートしてから、z_ack を返す
input_a_stb = 0;
input_b_stb = 0;
output_z_ack = 1;
#20;
//----------------------------------------------------------------------
// 1.0 + 1.0 = 2.0
//----------------------------------------------------------------------
// a と b をセット
input_a = 32'b0_01111111_00000000000000000000000; // a = 1.0
input_b = 32'b0_01111111_00000000000000000000000; // b = 1.0
input_a_stb = 1;
input_b_stb = 1;
output_z_ack = 0; // 入力が受理される前に z_ack をデアサートしておく
// z_stb がアサートされるまで待機
wait(output_z_stb);
// z の出力を確認(z = 2.0)
assert(output_z == 32'b0_10000000_00000000000000000000000) $display("PASSED"); else $display("FAILED: %b", output_z);
// a_stb と b_stb をデアサートしてから、z_ack を返す
input_a_stb = 0;
input_b_stb = 0;
output_z_ack = 1;
#20;
$finish;
end
// 5ns ごとに clk を反転
always #5
clk <= ~clk;
endmodule
テストベンチを実行。いい感じに動いてるみたい。
code:sh
$ iverilog -s adder_test -g 2012 adder_test.sv adder.v && ./a.out
VCD info: dumpfile adder_test.vcd opened for output.
PASSED
PASSED
出力される波形はこんな感じ。
https://gyazo.com/4188761b4081d706b555e7e5f34fd7a5
参考
気になるFPUコア
FPUコアを使ってみる