FMUL.S命令とFDIV_S命令
掛け算を追加。
code:diff
diff --git a/Makefile b/Makefile
index 04aef1f..5a99465 100644
--- a/Makefile
+++ b/Makefile
@@ -33,7 +33,7 @@ unit-test:
iverilog -g 2012 -s alu_test rtl/instructions.sv rtl/cpu.sv rtl/alu_test.sv && ./a.out
test:
- iverilog -g 2012 -s cpu_test -I rtl rtl/cpu_test.sv rtl/bram_controller.sv rtl/fpu/adder/adder.v rtl/fpu_controller.sv rtl/cpu.sv && ./a.out
+ iverilog -g 2012 -s cpu_test -I rtl rtl/cpu_test.sv rtl/bram_controller.sv rtl/fpu/adder/adder.v rtl/fpu/multiplier/multiplier.v rtl/fpu_controller.sv rtl/cpu.sv && ./a.out
firmware/firmware.hex:
diff --git a/rtl/fpu_controller.sv b/rtl/fpu_controller.sv
index 4be027a..90082fd 100644
--- a/rtl/fpu_controller.sv
+++ b/rtl/fpu_controller.sv
@@ -36,14 +36,26 @@ module fpu_controller(
assign adder_in2_stb = (op === 4'b0000 || op === 4'b0001) ? in1_stb : 1'b0;
assign adder_out_ack = (op === 4'b0000 || op === 4'b0001) ? out_ack : 1'b0;
+ assign multiplier_in1_stb = (op === 4'b0010) ? in1_stb : 1'b0;
+ assign multiplier_in2_stb = (op === 4'b0010) ? in1_stb : 1'b0;
+ assign multiplier_out_ack = (op === 4'b0010) ? out_ack : 1'b0;
+
//------------------------------------------------------------------------------
// 出力セレクタ
//------------------------------------------------------------------------------
- assign in1_ack = (op === 4'b0000 || op === 4'b0001) ? adder_in1_ack : 1'bx;
- assign in2_ack = (op === 4'b0000 || op === 4'b0001) ? adder_in2_ack : 1'bx;
- assign out_stb = (op === 4'b0000 || op === 4'b0001) ? adder_out_stb : 1'bx;
- assign out = (op === 4'b0000 || op === 4'b0001) ? adder_out : 32'bx;
+ assign in1_ack = (op === 4'b0000 || op === 4'b0001) ? adder_in1_ack :
+ (op === 4'b0010) ? multiplier_in1_ack
+ : 1'bx;
+ assign in2_ack = (op === 4'b0000 || op === 4'b0001) ? adder_in2_ack :
+ (op === 4'b0010) ? multiplier_in2_ack
+ :1'bx;
+ assign out_stb = (op === 4'b0000 || op === 4'b0001) ? adder_out_stb :
+ (op === 4'b0010) ? multiplier_out_stb
+ : 1'bx;
+ assign out = (op === 4'b0000 || op === 4'b0001) ? adder_out :
+ (op === 4'b0010) ? multiplier_out
+ : 32'bx;
//------------------------------------------------------------------------------
// Floating-point Adder
@@ -72,4 +84,31 @@ module fpu_controller(
.output_z_ack(adder_out_ack)
);
+ //------------------------------------------------------------------------------
+ // Floating-point Multiplier
+ //------------------------------------------------------------------------------
+
+ logic multiplier_in1_stb; // in1 が有効になったらアサートする
+ logic multiplier_in2_stb; // in2 が有効になったらアサートする
+ logic multiplier_in1_ack; // 受け手側で in1 の読み込みが終わったらアサートされる
+ logic multiplier_in2_ack; // 受け手側で in2 の読み込みが終わったらアサートされる
+ logic 31:0 multiplier_out; + logic multiplier_out_stb; // 計算結果が out に返ってきたらアサートされる
+ logic multiplier_out_ack; // out の読み込みが終わったらアサートしてあげる
+
+ multiplier multiplier_inst (
+ .clk(clk),
+ .rst(~reset_n),
+ .input_a(in1),
+ .input_a_stb(multiplier_in1_stb),
+ .input_a_ack(multiplier_in1_ack),
+ .input_b(in2),
+ .input_b_stb(multiplier_in2_stb),
+ .input_b_ack(multiplier_in2_ack),
+ .output_z(multiplier_out),
+ .output_z_stb(multiplier_out_stb),
+ .output_z_ack(multiplier_out_ack)
+ );
+
+
endmodule
diff --git a/rtl/instructions.sv b/rtl/instructions.sv
index bebcf87..a4259e5 100644
--- a/rtl/instructions.sv
+++ b/rtl/instructions.sv
@@ -391,8 +391,36 @@ function 31:0 fsub_s( endfunction
// fmul.s
+);
+ fmul_s = {
+ 7'b0001000, // funct7
+ rs2,
+ rs1,
+ 3'b111, // roundMode (既存の出力コードに合わせて 111 を入れておく)
+ rd,
+ 7'b1010011 // opCode
+ };
+endfunction
// fdiv.s
+);
+ fdiv_s = {
+ 7'b0001100, // funct7
+ rs2,
+ rs1,
+ 3'b111, // roundMode (既存の出力コードに合わせて 111 を入れておく)
+ rd,
+ 7'b1010011 // opCode
+ };
+endfunction
// fcvt.s.w
// Floating-point Convert to Single from Word)
diff --git a/rtl/test_program/fp.sv b/rtl/test_program/fp.sv
index 8d5924a..715705a 100644
--- a/rtl/test_program/fp.sv
+++ b/rtl/test_program/fp.sv
@@ -10,19 +10,25 @@ instructions1 = fsw(0, 5, 32'h110); // M0x110 = f5 instructions2 = flw(6, 0, 32'h110); // f6 = M0x110 instructions3 = fsw(0, 6, 32'h114); // M0x114 = f6 -// FADD.S のテスト
+// FADD.S のテスト (1.0 + 2.0)
instructions4 = flw(5, 0, 32'h100); // f5 = M0x100 instructions5 = flw(6, 0, 32'h104); // f6 = M0x104 instructions6 = fadd_s(7, 5, 6); // f7 = f5 + f6 instructions7 = fsw(0, 7, 32'h118); // M0x118 = f7 -// FSUB.S のテスト
+// FSUB.S のテスト (3 - 2)
instructions8 = flw(5, 0, 32'h108); // f5 = M0x108 instructions9 = flw(6, 0, 32'h104); // f6 = M0x104 instructions10 = fsub_s(7, 5, 6); // f7 = f5 + f6 instructions11 = fsw(0, 7, 32'h11c); // M0x11c = f7 -instructions12 = jal(0, 0); // 無限ループ +// FMUL.S のテスト (2.0 * 3.0)
+instructions12 = flw(5, 0, 32'h104); // f5 = M0x108 +instructions13 = flw(6, 0, 32'h108); // f6 = M0x104 +instructions14 = fmul_s(7, 5, 6); // f7 = f5 + f6 +instructions15 = fsw(0, 7, 32'h120); // M0x11c = f7 +
+instructions16 = jal(0, 0); // 無限ループ // テスト用の浮動小数点数データ
instructions64 = 32'h3f800000; // M0x100 = 1.0 @@ -61,7 +67,7 @@ reset_n = 0;
reset_n = 1;
-#2000;
+#3000;
// 実行が終わった頃合いを見て、メモリの内容を確認
mem_monitor_on = 1;
@@ -95,6 +101,9 @@ mem_monitor_wstrb_reg = 4'b0000;
wait(mem_ready);
assert(
+ // 0_00000001_00000000000000000000000 = 2.0
+ // 0_00000010_00000000000000000000000 =
+ // 0_00000011_00000000000000000000000 = 5.0
mem_rdata === 32'h40400000
) $display("PASSED"); else $display("FAILED: %h", mem_rdata);
mem_monitor_valid_reg = 0;
@@ -111,3 +120,15 @@ assert(
) $display("PASSED"); else $display("FAILED: %h", mem_rdata);
mem_monitor_valid_reg = 0;
+
+mem_monitor_on = 1;
+mem_monitor_valid_reg = 1;
+mem_monitor_addr_reg = 32'h120;
+mem_monitor_wstrb_reg = 4'b0000;
+#10;
+wait(mem_ready);
+assert(
+ mem_rdata === 32'h40c00000
+) $display("PASSED"); else $display("FAILED: %h", mem_rdata);
+mem_monitor_valid_reg = 0;
+#10;
割り算を追加。
code:diff
diff --git a/Makefile b/Makefile
index 5a99465..174ce1e 100644
--- a/Makefile
+++ b/Makefile
@@ -33,7 +33,7 @@ unit-test:
iverilog -g 2012 -s alu_test rtl/instructions.sv rtl/cpu.sv rtl/alu_test.sv && ./a.out
test:
- iverilog -g 2012 -s cpu_test -I rtl rtl/cpu_test.sv rtl/bram_controller.sv rtl/fpu/adder/adder.v rtl/fpu/multiplier/multiplier.v rtl/fpu_controller.sv rtl/cpu.sv && ./a.out
+ iverilog -g 2012 -s cpu_test -I rtl rtl/cpu_test.sv rtl/bram_controller.sv rtl/fpu/adder/adder.v rtl/fpu/multiplier/multiplier.v rtl/fpu/divider/divider.v rtl/fpu_controller.sv rtl/cpu.sv && ./a.out
firmware/firmware.hex:
diff --git a/rtl/fpu_controller.sv b/rtl/fpu_controller.sv
index 90082fd..1062a74 100644
--- a/rtl/fpu_controller.sv
+++ b/rtl/fpu_controller.sv
@@ -40,21 +40,30 @@ module fpu_controller(
assign multiplier_in2_stb = (op === 4'b0010) ? in1_stb : 1'b0;
assign multiplier_out_ack = (op === 4'b0010) ? out_ack : 1'b0;
+ assign divider_in1_stb = (op === 4'b0011) ? in1_stb : 1'b0;
+ assign divider_in2_stb = (op === 4'b0011) ? in1_stb : 1'b0;
+ assign divider_out_ack = (op === 4'b0011) ? out_ack : 1'b0;
+
+
//------------------------------------------------------------------------------
// 出力セレクタ
//------------------------------------------------------------------------------
assign in1_ack = (op === 4'b0000 || op === 4'b0001) ? adder_in1_ack :
- (op === 4'b0010) ? multiplier_in1_ack
+ (op === 4'b0010) ? multiplier_in1_ack :
+ (op === 4'b0011) ? divider_in1_ack
: 1'bx;
assign in2_ack = (op === 4'b0000 || op === 4'b0001) ? adder_in2_ack :
- (op === 4'b0010) ? multiplier_in2_ack
+ (op === 4'b0010) ? multiplier_in2_ack :
+ (op === 4'b0011) ? divider_in2_ack
:1'bx;
assign out_stb = (op === 4'b0000 || op === 4'b0001) ? adder_out_stb :
- (op === 4'b0010) ? multiplier_out_stb
+ (op === 4'b0010) ? multiplier_out_stb :
+ (op === 4'b0011) ? divider_out_stb
: 1'bx;
assign out = (op === 4'b0000 || op === 4'b0001) ? adder_out :
- (op === 4'b0010) ? multiplier_out
+ (op === 4'b0010) ? multiplier_out :
+ (op === 4'b0011) ? divider_out
: 32'bx;
//------------------------------------------------------------------------------
@@ -110,5 +119,30 @@ module fpu_controller(
.output_z_ack(multiplier_out_ack)
);
+ //------------------------------------------------------------------------------
+ // Floating-point Divider
+ //------------------------------------------------------------------------------
+
+ logic divider_in1_stb; // in1 が有効になったらアサートする
+ logic divider_in2_stb; // in2 が有効になったらアサートする
+ logic divider_in1_ack; // 受け手側で in1 の読み込みが終わったらアサートされる
+ logic divider_in2_ack; // 受け手側で in2 の読み込みが終わったらアサートされる
+ logic 31:0 divider_out; + logic divider_out_stb; // 計算結果が out に返ってきたらアサートされる
+ logic divider_out_ack; // out の読み込みが終わったらアサートしてあげる
+
+ divider divider_inst (
+ .clk(clk),
+ .rst(~reset_n),
+ .input_a(in1),
+ .input_a_stb(divider_in1_stb),
+ .input_a_ack(divider_in1_ack),
+ .input_b(in2),
+ .input_b_stb(divider_in2_stb),
+ .input_b_ack(divider_in2_ack),
+ .output_z(divider_out),
+ .output_z_stb(divider_out_stb),
+ .output_z_ack(divider_out_ack)
+ );
endmodule
diff --git a/rtl/test_program/fp.sv b/rtl/test_program/fp.sv
index 715705a..15ac258 100644
--- a/rtl/test_program/fp.sv
+++ b/rtl/test_program/fp.sv
@@ -4,11 +4,11 @@
/* instruction0からinstruction63までの命令がメモリに書き込まれる */ -// FLW と FSW のテスト
-instructions0 = flw(5, 0, 32'h100); // f5 = Mx0+0x100 -instructions1 = fsw(0, 5, 32'h110); // M0x110 = f5 -instructions2 = flw(6, 0, 32'h110); // f6 = M0x110 -instructions3 = fsw(0, 6, 32'h114); // M0x114 = f6 +// FDIV.S のテスト
+instructions0 = flw(5, 0, 32'h108); // f5 = 3.0 +instructions1 = flw(6, 0, 32'h104); // f6 = 2.0 +instructions2 = fdiv_s(7, 5, 6); // f7 = f5 / f6 +instructions3 = fsw(0, 7, 32'h110); // M0x110 = f7 // FADD.S のテスト (1.0 + 2.0)
instructions4 = flw(5, 0, 32'h100); // f5 = M0x100 @@ -28,7 +28,13 @@ instructions13 = flw(6, 0, 32'h108); // f6 = M0x104 instructions14 = fmul_s(7, 5, 6); // f7 = f5 + f6 instructions15 = fsw(0, 7, 32'h120); // M0x11c = f7 -instructions16 = jal(0, 0); // 無限ループ +// FLW と FSW のテスト
+instructions16 = flw(5, 0, 32'h100); // f5 = Mx0+0x100 +instructions17 = fsw(0, 5, 32'h124); // M0x110 = f5 +instructions18 = flw(6, 0, 32'h124); // f6 = M0x110 +instructions19 = fsw(0, 6, 32'h128); // M0x114 = f6 +
+instructions20 = jal(0, 0); // 無限ループ // テスト用の浮動小数点数データ
instructions64 = 32'h3f800000; // M0x100 = 1.0 @@ -67,7 +73,7 @@ reset_n = 0;
reset_n = 1;
-#3000;
+#5000;
// 実行が終わった頃合いを見て、メモリの内容を確認
mem_monitor_on = 1;
@@ -77,14 +83,29 @@ mem_monitor_wstrb_reg = 4'b0000;
wait(mem_ready);
assert(
- mem_rdata === 32'h3f800000
+ mem_rdata === 32'h3fc00000 // 1.5
) $display("PASSED"); else $display("FAILED: %h", mem_rdata);
mem_monitor_valid_reg = 0;
mem_monitor_on = 1;
mem_monitor_valid_reg = 1;
-mem_monitor_addr_reg = 32'h114;
+mem_monitor_addr_reg = 32'h118;
+mem_monitor_wstrb_reg = 4'b0000;
+#10;
+wait(mem_ready);
+assert(
+ // 0_00000001_00000000000000000000000 = 2.0
+ // 0_00000010_00000000000000000000000 =
+ // 0_00000011_00000000000000000000000 = 5.0
+ mem_rdata === 32'h40400000
+) $display("PASSED"); else $display("FAILED: %h", mem_rdata);
+mem_monitor_valid_reg = 0;
+#10;
+
+mem_monitor_on = 1;
+mem_monitor_valid_reg = 1;
+mem_monitor_addr_reg = 32'h11c;
mem_monitor_wstrb_reg = 4'b0000;
wait(mem_ready);
@@ -96,22 +117,19 @@ mem_monitor_valid_reg = 0;
mem_monitor_on = 1;
mem_monitor_valid_reg = 1;
-mem_monitor_addr_reg = 32'h118;
+mem_monitor_addr_reg = 32'h120;
mem_monitor_wstrb_reg = 4'b0000;
wait(mem_ready);
assert(
- // 0_00000001_00000000000000000000000 = 2.0
- // 0_00000010_00000000000000000000000 =
- // 0_00000011_00000000000000000000000 = 5.0
- mem_rdata === 32'h40400000
+ mem_rdata === 32'h40c00000
) $display("PASSED"); else $display("FAILED: %h", mem_rdata);
mem_monitor_valid_reg = 0;
mem_monitor_on = 1;
mem_monitor_valid_reg = 1;
-mem_monitor_addr_reg = 32'h11c;
+mem_monitor_addr_reg = 32'h124;
mem_monitor_wstrb_reg = 4'b0000;
wait(mem_ready);
@@ -123,12 +141,12 @@ mem_monitor_valid_reg = 0;
mem_monitor_on = 1;
mem_monitor_valid_reg = 1;
-mem_monitor_addr_reg = 32'h120;
+mem_monitor_addr_reg = 32'h128;
mem_monitor_wstrb_reg = 4'b0000;
wait(mem_ready);
assert(
- mem_rdata === 32'h40c00000
+ mem_rdata === 32'h3f800000
) $display("PASSED"); else $display("FAILED: %h", mem_rdata);
mem_monitor_valid_reg = 0;