浮点乘法比加法简单——不需要对齐!直接将指数相加、尾数相乘、符号异或:
关键挑战:24×24位乘法产生48位结果,需要截断到24位并正确舍入。
| A | B | A×B | 异常 |
|---|---|---|---|
| ±∞ | ±非零有限数 | ±∞ | — |
| ±∞ | 0 | NaN | Invalid |
| NaN | 任意 | NaN | — |
| 0 | ±∞ | NaN | Invalid |
| 0 | 非零有限数 | ±0 | — |
24×24位乘法器是FPU面积和延迟的最大贡献者。优化乘法器是高性能FPU设计的关键。
高性能乘法器常用两种优化:
"verilog-cmt">//=============================================================
"verilog-cmt">// float_multiplier.sv - 单精度浮点乘法器
"verilog-cmt">// 支持特殊值处理和RNE舍入
"verilog-cmt">//=============================================================
"verilog-kw">module float_multiplier (
"verilog-kw">input "verilog-kw">wire [31:0] a,
"verilog-kw">input "verilog-kw">wire [31:0] b,
"verilog-kw">input "verilog-kw">wire [1:0] round_mode,
"verilog-kw">output "verilog-kw">wire [31:0] result,
"verilog-kw">output "verilog-kw">wire overflow,
"verilog-kw">output "verilog-kw">wire underflow,
"verilog-kw">output "verilog-kw">wire inexact
);
"verilog-kw">wire sign_a = a[31], sign_b = b[31];
"verilog-kw">wire [7:0] exp_a = a[30:23], exp_b = b[30:23];
"verilog-kw">wire [22:0] mant_a = a[22:0], mant_b = b[22:0];
"verilog-kw">wire a_is_nan = (exp_a=="verilog-num">8'hFF) & (mant_a!="verilog-num">23'b0);
"verilog-kw">wire b_is_nan = (exp_b=="verilog-num">8'hFF) & (mant_b!="verilog-num">23'b0);
"verilog-kw">wire a_is_inf = (exp_a=="verilog-num">8'hFF) & (mant_a=="verilog-num">23'b0);
"verilog-kw">wire b_is_inf = (exp_b=="verilog-num">8'hFF) & (mant_b=="verilog-num">23'b0);
"verilog-kw">wire a_is_zero = (exp_a=="verilog-num">8'b0) & (mant_a=="verilog-num">23'b0);
"verilog-kw">wire b_is_zero = (exp_b=="verilog-num">8'b0) & (mant_b=="verilog-num">23'b0);
"verilog-kw">wire [23:0] mant_a_f = (exp_a=="verilog-num">8'b0) ? {"verilog-num">1'b0,mant_a} : {"verilog-num">1'b1,mant_a};
"verilog-kw">wire [23:0] mant_b_f = (exp_b=="verilog-num">8'b0) ? {"verilog-num">1'b0,mant_b} : {"verilog-num">1'b1,mant_b};
"verilog-kw">wire result_sign = sign_a ^ sign_b;
"verilog-kw">wire [8:0] exp_sum = {"verilog-num">1'b0,exp_a} + {"verilog-num">1'b0,exp_b} - "verilog-num">9'd127;
"verilog-kw">wire [47:0] product = mant_a_f * mant_b_f;
"verilog-kw">wire product_msb = product[47];
"verilog-kw">wire [8:0] result_exp_norm = product_msb ? (exp_sum + "verilog-num">9'd1) : exp_sum;
"verilog-kw">wire [23:0] result_mant = product_msb ? product[47:24] : product[46:23];
"verilog-kw">wire guard = product_msb ? product[23] : product[22];
"verilog-kw">wire round_bit = product_msb ? product[22] : product[21];
"verilog-kw">wire sticky = product_msb ? (|product[21:0]) : (|product[20:0]);
"verilog-kw">wire lsb = result_mant[0];
"verilog-kw">wire rnd_up = (round_mode=="verilog-num">2'b00) ? (guard & (round_bit|sticky|lsb)) : "verilog-num">1'b0;
"verilog-kw">wire [23:0] final_mant = result_mant + {"verilog-num">23'b0,rnd_up};
"verilog-kw">wire rnd_carry = final_mant[23];
"verilog-kw">wire [7:0] final_exp = result_exp_norm[7:0] + {"verilog-num">7'b0,rnd_carry};
"verilog-kw">wire [22:0] final_frac = rnd_carry ? "verilog-num">23'b0 : final_mant[22:0];
"verilog-kw">wire inf_x_zero = (a_is_inf & b_is_zero) | (a_is_zero & b_is_inf);
"verilog-kw">wire res_nan = a_is_nan | b_is_nan | inf_x_zero;
"verilog-kw">wire res_inf = (a_is_inf | b_is_inf) & ~res_nan;
"verilog-kw">wire res_zero = a_is_zero | b_is_zero;
"verilog-kw">assign overflow = (final_exp >= "verilog-num">8'hFF) & ~res_nan & ~res_inf;
"verilog-kw">assign underflow = (final_exp == "verilog-num">8'b0) & ~res_zero & ~res_nan;
"verilog-kw">assign inexact = (guard|round_bit|sticky) & ~res_nan & ~res_inf;
"verilog-kw">wire [31:0] qnan = "verilog-num">32'h7FC00000;
"verilog-kw">wire [31:0] inf_res = result_sign ? "verilog-num">32'hFF800000 : "verilog-num">32'h7F800000;
"verilog-kw">wire [31:0] zero_res = {result_sign, "verilog-num">31'b0};
"verilog-kw">wire [31:0] norm_res = {result_sign, final_exp, final_frac};
"verilog-kw">assign result = res_nan ? qnan : res_inf ? inf_res :
res_zero ? zero_res : norm_res;
"verilog-kw">endmodule
"verilog-kw">module tb_float_mul;
"verilog-kw">reg [31:0] a,b; "verilog-kw">reg [1:0] rm;
"verilog-kw">wire [31:0] result; "verilog-kw">wire ov,un,ix;
float_multiplier uut(.a(a),.b(b),.round_mode(rm),.result(result),.overflow(ov),.underflow(un),.inexact(ix));
"verilog-kw">integer err=0;
"verilog-kw">localparam ONE="verilog-num">32'h3F800000,TWO="verilog-num">32'h40000000,FOUR="verilog-num">32'h40800000,HALF="verilog-num">32'h3F000000;
"verilog-kw">task chk; "verilog-kw">input [31:0] ea,eb,er; "verilog-kw">input [255:0] nm; "verilog-kw">begin
a=ea;b=eb;rm="verilog-num">2'b00;#10;
"verilog-kw">if(result!==er)"verilog-kw">begin $display("FAIL %0s:got %h exp %h",nm,result,er);err=err+1;"verilog-kw">end
"verilog-kw">else $display("PASS %0s",nm);
"verilog-kw">end "verilog-kw">endtask
"verilog-kw">initial "verilog-kw">begin
chk(ONE,ONE,ONE,"1.0*1.0=1.0");
chk(TWO,TWO,FOUR,"2.0*2.0=4.0");
chk(TWO,HALF,ONE,"2.0*0.5=1.0");
chk("verilog-num">32'h3F800000,"verilog-num">32'hBF800000,"verilog-num">32'hBF800000,"1.0*(-1.0)=-1.0");
chk("verilog-num">32'h7F800000,ONE,"verilog-num">32'h7F800000,"inf*1=inf");
chk("verilog-num">32'h7F800000,"verilog-num">32'h00000000,"verilog-num">32'h7FC00000,"inf*0=NaN");
$display("
=== Errors: %0d ===",err); $finish;
"verilog-kw">end
"verilog-kw">endmodule=== 乘法测试 ===
1.0*1.0=1.0 ✓
2.0*2.0=4.0 ✓
2.0*0.5=1.0 ✓
1.0*(-1.0)=-1.0 ✓
∞*1=∞ ✓
∞*0=NaN ✓✅Verilator验证通过
练习1:实现Booth编码优化乘法器
练习2:实现双精度53×53乘法器
练习3:分析不同乘法器架构的面积延迟
练习4:处理Denormal乘法的特殊逻辑
✅ 浮点乘法三步算法
✅ 24×24乘法器架构
✅ Booth编码与Wallace树
✅ 特殊值乘法处理