FSUB.S命令
from マルチサイクル RISC-V CPU を作成したい
FADD.S 命令をちょっといじって FSUB.S 命令にする。
A + B を、A + (-B) にすることで減算にできる。
code:diff
diff --git a/rtl/cpu.sv b/rtl/cpu.sv
index bf27ad6..345e023 100644
--- a/rtl/cpu.sv
+++ b/rtl/cpu.sv
@@ -90,6 +90,7 @@ module cpu(
logic 1:0 alu_in1_src;
logic alu_in2_src;
logic 3:0 alu_op;
+ logic 3:0 fpu_op;
logic dc_mem_to_reg;
logic branch;
logic jump;
@@ -106,6 +107,7 @@ module cpu(
.aluIn1Src(alu_in1_src),
.aluIn2Src(alu_in2_src),
.aluOp(alu_op),
+ .fpuOp(fpu_op),
.memToReg(dc_mem_to_reg),
.branch(branch),
.jump(jump),
@@ -152,12 +154,10 @@ module cpu(
// FPU
//-------------------------------------
- logic 3:0 fpu_op;
logic 31:0 fpu_in1, fpu_in2, fpu_result;
logic fpu_in1_stb, fpu_in2_stb, fpu_result_ack;
logic fpu_in1_ack, fpu_in2_ack, fpu_result_stb;
- assign fpu_op = 4'b0000; // fadd
assign fpu_in1 = rf_read_data1;
assign fpu_in2 = rf_read_data2;
@@ -330,6 +330,7 @@ module decoder(
output logic 1:0 aluIn1Src,
output logic aluIn2Src,
output logic 3:0 aluOp,
+ output logic 3:0 fpuOp,
output logic memToReg,
output logic branch,
output logic jump,
@@ -428,6 +429,12 @@ module decoder(
assign fpu = (opCode === 7'b1010011) ? 1'b1 : 1'b0; // FPU を使う命令(RV32F R-type)
+ assign fpuOp = (funct7 === 7'b0000000) ? 4'b0000 : // fadd
+ (funct7 === 7'b0000100) ? 4'b0001 : // fsub
+ (funct7 === 7'b0001000) ? 4'b0010 : // fmul
+ (funct7 === 7'b0001100) ? 4'b0011 // fdiv
+ : 4'bxxxx;
+
// always @(*) begin
// $display("opCode %b", opCode);
// $display("funct7 %b", funct7);
diff --git a/rtl/fpu_controller.sv b/rtl/fpu_controller.sv
index 7980f77..4be027a 100644
--- a/rtl/fpu_controller.sv
+++ b/rtl/fpu_controller.sv
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// FPU Controller
//
-// code | operation
+// op | operation
// -----|----------
// 0000 | fadd
// 0001 | fsub
@@ -25,21 +25,31 @@ module fpu_controller(
output out_stb,
input out_ack
);
+
+ //------------------------------------------------------------------------------
// 入力セレクタ
- assign adder_in1_stb = (op === 4'b0000) ? in1_stb : 1'b0;
- assign adder_in2_stb = (op === 4'b0000) ? in2_stb : 1'b0;
- assign adder_out_ack = (op === 4'b0000) ? out_ack : 1'b0;
+ //------------------------------------------------------------------------------
+
+ // fsub の場合は、in2 の最上位ビットにある符号を反転して加算を行う
+ assign adder_in2 = (op === 4'b0001) ? {~in231, in230:0} : in2;
+ assign adder_in1_stb = (op === 4'b0000 || op === 4'b0001) ? in1_stb : 1'b0;
+ 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 in1_ack = (op === 4'b0000) ? adder_in1_ack : 1'bx;
- assign in2_ack = (op === 4'b0000) ? adder_in2_ack : 1'bx;
- assign out_stb = (op === 4'b0000) ? adder_out_stb : 1'bx;
- assign out = (op === 4'b0000) ? adder_out : 32'bx;
+ //------------------------------------------------------------------------------
+
+ 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;
//------------------------------------------------------------------------------
// Floating-point Adder
//------------------------------------------------------------------------------
+ logic 31:0 adder_in2;
logic adder_in1_stb; // in1 が有効になったらアサートする
logic adder_in2_stb; // in2 が有効になったらアサートする
logic adder_in1_ack; // 受け手側で in1 の読み込みが終わったらアサートされる
@@ -54,7 +64,7 @@ module fpu_controller(
.input_a(in1),
.input_a_stb(adder_in1_stb),
.input_a_ack(adder_in1_ack),
- .input_b(in2),
+ .input_b(adder_in2),
.input_b_stb(adder_in2_stb),
.input_b_ack(adder_in2_ack),
.output_z(adder_out),
diff --git a/rtl/test_program/fp.sv b/rtl/test_program/fp.sv
index fddcd92..8d5924a 100644
--- a/rtl/test_program/fp.sv
+++ b/rtl/test_program/fp.sv
@@ -6,20 +6,28 @@
// FLW と FSW のテスト
instructions0 = flw(5, 0, 32'h100); // f5 = Mx0+0x100
-instructions1 = fsw(0, 5, 32'h104); // M0x104 = f5
-instructions2 = flw(6, 0, 32'h104); // f6 = M0x104
-instructions3 = fsw(0, 6, 32'h108); // M0x108 = f6
+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 のテスト
instructions4 = flw(5, 0, 32'h100); // f5 = M0x100
-instructions5 = flw(6, 0, 32'h100); // f6 = M0x100
+instructions5 = flw(6, 0, 32'h104); // f6 = M0x104
instructions6 = fadd_s(7, 5, 6); // f7 = f5 + f6
-instructions7 = fsw(0, 7, 32'h10c); // M0x10c = f7
+instructions7 = fsw(0, 7, 32'h118); // M0x118 = f7
-instructions8 = jal(0, 0); // 無限ループ
+// FSUB.S のテスト
+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); // 無限ループ
// テスト用の浮動小数点数データ
instructions64 = 32'h3f800000; // M0x100 = 1.0
+instructions65 = 32'h40000000; // M0x104 = 2.0
+instructions66 = 32'h40400000; // M0x108 = 3.0
/**
@@ -58,36 +66,48 @@ reset_n = 1;
// 実行が終わった頃合いを見て、メモリの内容を確認
mem_monitor_on = 1;
mem_monitor_valid_reg = 1;
-mem_monitor_addr_reg = 32'h104;
+mem_monitor_addr_reg = 32'h110;
mem_monitor_wstrb_reg = 4'b0000;
#10;
wait(mem_ready);
assert(
mem_rdata === 32'h3f800000
-) $display("PASSED"); else $display("FAILED: %d", mem_rdata);
+) $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'h108;
+mem_monitor_addr_reg = 32'h114;
mem_monitor_wstrb_reg = 4'b0000;
#10;
wait(mem_ready);
assert(
mem_rdata === 32'h3f800000
-) $display("PASSED"); else $display("FAILED: %d", mem_rdata);
+) $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'h10c;
+mem_monitor_addr_reg = 32'h118;
mem_monitor_wstrb_reg = 4'b0000;
#10;
wait(mem_ready);
assert(
- mem_rdata === 32'h40000000
-) $display("PASSED"); else $display("FAILED: %d", mem_rdata);
+ 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;
+#10;
+wait(mem_ready);
+assert(
+ mem_rdata === 32'h3f800000
+) $display("PASSED"); else $display("FAILED: %h", mem_rdata);
mem_monitor_valid_reg = 0;
#10;