FSGNJ.S命令とFSGNJN.S命令
rs1の値にrs2の符号を差し込む謎の命令。この命令を使って疑似命令 fmv や fneg が実装されるみたい。
fsgnj.s (Floating-point Sign Inject, Single-Precision)
f[rd] = {f{rs2][31], f[rs1][30:0]}
fsgnjn.s (Floating-point Sign Inject-Negate, Single-Precision)
f[rd] = {~f[rs2][31], f[rs1][30:0]}
雑に実装。ひとまずこんなもんでええやろ。
code:diff
diff --git a/rtl/cpu.sv b/rtl/cpu.sv
index 4be8dd2..297a55a 100644
--- a/rtl/cpu.sv
+++ b/rtl/cpu.sv
@@ -436,13 +436,15 @@ 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'b1101000) ? 4'b0100 : // fcvt.s.w (int to float)
- (funct7 === 7'b1100000) ? 4'b0101 : // fcvt.w.s (float to int)
- (funct7 === 7'b0000100) ? 4'b0001 : // fsub
- (funct7 === 7'b0001000) ? 4'b0010 : // fmul
- (funct7 === 7'b0001100) ? 4'b0011 // fdiv
- : 4'bxxxx;
+ assign fpuOp = (funct7 === 7'b0000000) ? 4'b0000 : // fadd
+ (funct7 === 7'b1101000) ? 4'b0100 : // fcvt.s.w (int to float)
+ (funct7 === 7'b1100000) ? 4'b0101 : // fcvt.w.s (float to int)
+ (funct7 === 7'b0010000 && funct3 === 3'b000) ? 4'b0110 : // fsgnj
+ (funct7 === 7'b0010000 && funct3 === 3'b001) ? 4'b0111 : // fsgnjn
+ (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);
diff --git a/rtl/fpu_controller.sv b/rtl/fpu_controller.sv
index d024148..a482456 100644
--- a/rtl/fpu_controller.sv
+++ b/rtl/fpu_controller.sv
@@ -9,9 +9,11 @@
// 0011 | fdiv
// 0100 | fcvt.s.w (int to float)
// 0101 | fcvt.w.s (float to int)
-// 0110 | feq
-// 0111 | flt
-// 1000 | fle
+// 0110 | fsgnj
+// 0111 | fsgnjn
+// 1000 | feq
+// 1001 | flt
+// 1010 | fle
//------------------------------------------------------------------------------
module fpu_controller(
@@ -57,24 +59,32 @@ module fpu_controller(
assign in1_ack = (op === 4'b0000 || op === 4'b0001) ? adder_in1_ack :
(op === 4'b0100) ? int2float_in1_ack :
(op === 4'b0101) ? float2int_in1_ack :
+ (op === 4'b0110) ? fsgnj_in1_ack :
+ (op === 4'b0111) ? fsgnjn_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'b0100) ? int2float_in1_ack :
(op === 4'b0101) ? float2int_in1_ack :
+ (op === 4'b0110) ? fsgnj_in2_ack :
+ (op === 4'b0111) ? fsgnjn_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'b0100) ? int2float_out_stb :
(op === 4'b0101) ? float2int_out_stb :
+ (op === 4'b0110) ? fsgnj_out_stb :
+ (op === 4'b0111) ? fsgnjn_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'b0100) ? int2float_out :
(op === 4'b0101) ? float2int_out :
+ (op === 4'b0110) ? fsgnj_out :
+ (op === 4'b0111) ? fsgnjn_out :
(op === 4'b0010) ? multiplier_out :
(op === 4'b0011) ? divider_out
: 32'bx;
@@ -200,4 +210,32 @@ module fpu_controller(
.output_z_ack(float2int_out_ack)
);
+ //------------------------------------------------------------------------------
+ // 符号インジェクト
+ //------------------------------------------------------------------------------
+
+ // fsgnj: 「in2 の符号部 + in1 の指数部 + in1 の仮数部」を返す
+ logic fsgnj_in1_ack;
+ logic fsgnj_in2_ack;
+ logic fsgnj_out_stb;
+
+ // 常にアサートでもいいかな?
+ assign fsgnj_in1_ack = 1'b1;
+ assign fsgnj_in2_ack = 1'b1;
+ assign fsgnj_out_stb = 1'b1;
+
+ // fsgnjn: 「in2 の符号部の反転 + in1 の指数部 + in1 の仮数部」を返す
+ logic fsgnjn_in1_ack;
+ logic fsgnjn_in2_ack;
+ logic fsgnjn_out_stb;
+
+ // 常にアサートでもいいかな?
+ assign fsgnjn_in1_ack = 1'b1;
+ assign fsgnjn_in2_ack = 1'b1;
+ assign fsgnjn_out_stb = 1'b1;
+
endmodule
diff --git a/rtl/test_program/fp.sv b/rtl/test_program/fp.sv
index a397741..88bcedf 100644
--- a/rtl/test_program/fp.sv
+++ b/rtl/test_program/fp.sv
@@ -41,7 +41,17 @@ instructions22 = sw(0, 6, 32'h12c); // M0x12c = x6 instructions23 = fcvt_s_w(7, 6); // f7 = (float)x6 instructions24 = fsw(0, 7, 32'h130); // M0x130 = f7 -instructions25 = jal(0, 0); // 無限ループ +// FSGNJ系のテスト
+// f5 = 3.0
+// f6 = fsgnj(f6, f5, f5) // f6 = f5
+// f7 = fsgnjn(f7, f5, f5) // f7 = -f5
+instructions25 = flw(5, 0, 32'h108); // f5 = 3.0 +instructions26 = fsgnj_s(6, 5, 5); // f6 = f5 +instructions27 = fsw(0, 6, 32'h134); // M0x134 = f6 +instructions28 = fsgnjn_s(7, 5, 5); // f7 = -f5 +instructions29 = fsw(0, 7, 32'h138); // M0x138 = f7 +
+instructions30 = jal(0, 0); // 無限ループ // テスト用の浮動小数点数データ
instructions64 = 32'h3f800000; // M0x100 = 1.0 @@ -80,7 +90,7 @@ reset_n = 0;
reset_n = 1;
-#5000;
+#10000;
// 実行が終わった頃合いを見て、メモリの内容を確認
mem_monitor_on = 1;
@@ -181,3 +191,27 @@ 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'h134;
+mem_monitor_wstrb_reg = 4'b0000;
+#10;
+wait(mem_ready);
+assert(
+ mem_rdata === 32'h40400000 // 3.0
+) $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'h138;
+mem_monitor_wstrb_reg = 4'b0000;
+#10;
+wait(mem_ready);
+assert(
+ mem_rdata === 32'hc0400000 // -3.0
+) $display("PASSED"); else $display("FAILED: %h", mem_rdata);
+mem_monitor_valid_reg = 0;
+#10;