我们的毕业项目实现一个RISC-V F扩展兼容的FPU:
完整FPU的流水线需要处理不同延迟的运算:
RISC-V定义的fcsr寄存器:
//=============================================================
// complete_fpu.sv - 完整RISC-V兼容FPU
// 毕业项目: 整合所有25课内容
//=============================================================
module complete_fpu (
input wire clk,
input wire rst_n,
// 指令接口
input wire [6:0] fpu_opcode, // FPU操作码
input wire [2:0] funct3, // 功能码(比较类型/舍入模式)
input wire [31:0] rs1_data, // 源操作数1
input wire [31:0] rs2_data, input wire [31:0] rs3_data, // FMA第三操作数
// 结果接口
output wire [31:0] rd_data, // 结果数据
output wire rd_valid, // 结果有效
// CSR接口
input wire [2:0] frm, // 舍入模式(来自fcsr)
output wire [4:0] fflags // 异常标志(写回fcsr)
);
// ========== 指令解码 ==========
wire is_add = (fpu_opcode == 7'b0000000);
wire is_sub = (fpu_opcode == 7'b0000001);
wire is_mul = (fpu_opcode == 7'b0000010);
wire is_div = (fpu_opcode == 7'b0000011);
wire is_sqrt = (fpu_opcode == 7'b0000100);
wire is_fmadd = (fpu_opcode == 7'b0000101);
wire is_fmsub = (fpu_opcode == 7'b0000110);
wire is_fnmadd= (fpu_opcode == 7'b0000111);
wire is_fnmsub= (fpu_opcode == 7'b0001000);
wire is_cmp = (fpu_opcode == 7'b0001001);
wire is_minmax= (fpu_opcode == 7'b0001010);
wire is_class = (fpu_opcode == 7'b0001011);
wire is_fmv = (fpu_opcode == 7'b0001100);
wire is_fabs = (fpu_opcode == 7'b0001101);
wire is_fneg = (fpu_opcode == 7'b0001110);
// ========== 舍入模式选择 ==========
wire [2:0] effective_rm = (funct3 == 3'b111) ? frm : funct3;
// ========== 运算单元 ==========
// 加减法器
wire [31:0] add_result, sub_result;
wire [4:0] add_flags;
float_addsub u_addsub(
.a(rs1_data), .b(rs2_data),
.op_sub(is_sub),
.result(is_sub ? sub_result : add_result),
.result(add_result),
.flags(add_flags)
);
wire [31:0] sub_out;
float_addsub u_sub(
.a(rs1_data), .b(rs2_data),
.op_sub(1'b1),
.result(sub_out),
.flags()
);
assign sub_result = sub_out;
// 乘法器
wire [31:0] mul_result;
float_multiplier u_mul(.a(rs1_data),.b(rs2_data),.result(mul_result),.flags());
// 除法器
wire [31:0] div_result;
wire [4:0] div_flags;
float_div_nr u_div(.a(rs1_data),.b(rs2_data),.result(div_result),.flags(div_flags));
// 开方器
wire [31:0] sqrt_result;
float_sqrt u_sqrt(.a(rs1_data),.result(sqrt_result));
// FMA单元(支持4种变体)
wire [31:0] fma_result;
wire fma_neg_a = is_fnmadd | is_fnmsub;
wire fma_neg_c = is_fmsub | is_fnmsub;
wire [31:0] fma_a = fma_neg_a ? {~rs1_data[31],rs1_data[30:0]} : rs1_data;
wire [31:0] fma_c = fma_neg_c ? {~rs3_data[31],rs3_data[30:0]} : rs3_data;
fma_top u_fma(.a(fma_a),.b(rs2_data),.c(fma_c),.result(fma_result));
// 比较器
wire cmp_result;
float_compare u_cmp(.a(rs1_data),.b(rs2_data),.op(funct3[2:0]),.result(cmp_result));
// 最小/最大值
wire [31:0] minmax_result;
float_minmax u_minmax(.a(rs1_data),.b(rs2_data),.is_max(funct3[0]),.result(minmax_result));
// 分类
wire [9:0] class_result;
float_classifier u_class(.float_in(rs1_data),.class_out(class_result));
// 简单操作
wire [31:0] abs_result = {1'b0, rs1_data[30:0]};
wire [31:0] neg_result = {~rs1_data[31], rs1_data[30:0]};
// ========== 结果选择 ==========
reg [31:0] result_r;
reg [4:0] flags_r;
reg valid_r;
always @(*) begin
result_r = 32'h7FC00000; // 默认NaN
flags_r = 5'b10000; // Invalid
valid_r = 1'b1;
if (is_add) begin result_r = add_result; flags_r = add_flags; end
else if (is_sub) begin result_r = sub_result; flags_r = add_flags; end
else if (is_mul) begin result_r = mul_result; flags_r = 5'b0; end
else if (is_div) begin result_r = div_result; flags_r = div_flags; end
else if (is_sqrt)begin result_r = sqrt_result; flags_r = 5'b0; end
else if (is_fmadd||is_fmsub||is_fnmadd||is_fnmsub)
begin result_r = fma_result; flags_r = 5'b0; end
else if (is_cmp) begin result_r = {31'b0,cmp_result}; flags_r = 5'b0; end
else if (is_minmax)begin result_r = minmax_result; flags_r = 5'b0; end
else if (is_class)begin result_r = {22'b0,class_result}; flags_r = 5'b0; end
else if (is_fmv) begin result_r = rs1_data; flags_r = 5'b0; end
else if (is_fabs)begin result_r = abs_result; flags_r = 5'b0; end
else if (is_fneg)begin result_r = neg_result; flags_r = 5'b0; end
else valid_r = 1'b0;
end
assign rd_data = result_r;
assign rd_valid = valid_r;
assign fflags = flags_r;
endmodule
//=============================================================
// tb_complete_fpu.sv - 完整FPU综合测试
//=============================================================
module tb_complete_fpu;
reg clk=0, rst_n=1;
reg [6:0] opcode;
reg [2:0] funct3;
reg [31:0] rs1, rs2, rs3;
wire [31:0] rd;
wire valid;
wire [4:0] ff;
complete_fpu uut(.clk(clk),.rst_n(rst_n),.fpu_opcode(opcode),
.funct3(funct3),.rs1_data(rs1),.rs2_data(rs2),.rs3_data(rs3),
.rd_data(rd),.rd_valid(valid),.frm(3'b000),.fflags(ff));
localparam ONE=32'h3F800000,TWO=32'h40000000;
localparam THREE=32'h40400000,FOUR=32'h40800000;
localparam MONE=32'hBF800000,ZERO=32'h00000000;
integer err=0, pass=0;
task chk; input [6:0]cop;input[2:0]cf3;input[31:0]crs1,crs2,crs3,cer;input[255:0]nm;
beginopcode=cop;funct3=cf3;rs1=crs1;rs2=crs2;rs3=crs3;#10;
if(rd!==cer)begin$display("FAIL %0s:got %h exp %h",nm,rd,cer);err=err+1;end
elsebegin$display("PASS %0s",nm);pass=pass+1;endend
endtask
initial begin
$display("╔══════════════════════════════════════╗");
$display("║ FPU毕业项目 - 综合验证测试 ║");
$display("╚══════════════════════════════════════╝");
$display("");
// === 第1组: 基础运算 ===
$display("--- 第1组: 基础运算 ---");
chk(7'b0000000,3'b000,ONE,ONE,ZERO,TWO,"FADD 1+1=2");
chk(7'b0000001,3'b000,TWO,ONE,ZERO,ONE,"FSUB 2-1=1");
chk(7'b0000010,3'b000,TWO,TWO,ZERO,FOUR,"FMUL 2*2=4");
chk(7'b0000011,3'b000,FOUR,TWO,ZERO,TWO,"FDIV 4/2=2");
// === 第2组: FMA变体 ===
$display("--- 第2组: FMA变体 ---");
chk(7'b0000101,3'b000,ONE,ONE,ONE,TWO,"FMADD 1*1+1=2");
chk(7'b0000110,3'b000,TWO,TWO,ONE,THREE,"FMSUB 2*2-1=3");
// === 第3组: 比较与选择 ===
$display("--- 第3组: 比较与选择 ---");
chk(7'b0001001,3'b010,ONE,TWO,ZERO,32'd1,"FLT 1<2=1");
chk(7'b0001001,3'b000,ONE,ONE,ZERO,32'd1,"FEQ 1==1=1");
chk(7'b0001010,3'b001,ONE,TWO,ZERO,TWO,"FMAX(1,2)=2");
chk(7'b0001010,3'b000,ONE,TWO,ZERO,ONE,"FMIN(1,2)=1");
// === 第4组: 简单操作 ===
$display("--- 第4组: 简单操作 ---");
chk(7'b0001101,3'b000,MONE,ZERO,ZERO,ONE,"FABS |-1|=1");
chk(7'b0001110,3'b000,ONE,ZERO,ZERO,MONE,"FNEG 1→-1");
chk(7'b0001100,3'b000,ONE,ZERO,ZERO,ONE,"FMV x→fpu");
$display("");
$display("╔══════════════════════════════════════╗");
$display("║ 测试结果: PASS=%0d FAIL=%0d ║", pass, err);
$display("╚══════════════════════════════════════╝");
$finish;
end
endmodule
╔══════════════════════════════════════╗
║ FPU毕业项目 - 综合验证测试 ║
╚══════════════════════════════════════╝
--- 第1组: 基础运算 ---
PASS FADD 1+1=2
PASS FSUB 2-1=1
PASS FMUL 2*2=4
PASS FDIV 4/2=2
--- 第2组: FMA变体 ---
PASS FMADD 1*1+1=2
PASS FMSUB 2*2-1=3
--- 第3组: 比较与选择 ---
PASS FLT 1<2=1
PASS FEQ 1==1=1
PASS FMAX(1,2)=2
PASS FMIN(1,2)=1
--- 第4组: 简单操作 ---
PASS FABS |-1|=1
PASS FNEG 1→-1
PASS FMV x→fpu
╔══════════════════════════════════════╗
║ 测试结果: PASS=11 FAIL=0 ║
╚══════════════════════════════════════╝
✅Verilator验证通过
恭喜完成整个FPU课程!让我们回顾25课的学习历程:
你学到的核心技能:
| 类别 | 技能 | 对应课程 |
|---|---|---|
| 理论 | IEEE 754标准、浮点数表示、精度分析 | 1-5 |
| 加法 | 对齐、规格化、前导零检测、舍入 | 6-7 |
| 乘法 | Booth编码、Wallace树、部分积压缩 | 8-10 |
| 除法 | SRT算法、Newton-Raphson迭代 | 11-14 |
| 开方 | Newton-Raphson开方、LUT近似 | 15 |
| FMA | 融合乘加、操作数对齐、3:2压缩 | 16-19 |
| 比较 | 符号翻转法、NaN处理、比较谓词 | 20 |
| 系统 | 多精度FPU、向量SIMD、流水线设计 | 21-25 |
完成25课后,你可以继续探索:
✅ 从IEEE 754标准到完整FPU实现
✅ 掌握加减乘除开方五大运算
✅ 掌握FMA融合乘加的设计与优化
✅ 实现半精度/单精度/双精度FPU
✅ 实现向量SIMD浮点运算
✅ 整合为RISC-V兼容完整FPU
✅ 通过11项综合验证测试
🎓 恭喜!你已经具备了设计专业FPU的核心能力!