浮点除法:指数相减、尾数相除、符号异或。除法的核心挑战是尾数除法——与乘法不同,除法是迭代过程,无法一步完成。这是FPU中最耗时的运算之一。
SRT(Sweeney-Robertson-Tocher)是最常用的硬件除法算法:
SRT核心优势:商位选择只依赖余数高几位,不需要完整比较器,延迟很低。
基4 SRT每次产生2位商,迭代次数减半但选择逻辑更复杂:
SRT除法器延迟由迭代次数决定:
除法有最多的特殊值情况需要处理:
| A | B | A/B | 异常 |
|---|---|---|---|
| ±∞ | ±有限非零 | ±∞ | — |
| ±有限非零 | 0 | ±∞ | DivByZero |
| ±∞ | ±∞ | NaN | Invalid |
| 0 | 0 | NaN | Invalid |
| NaN | 任意 | NaN | — |
| 0 | ±∞ | ±0 | — |
"verilog-cmt">//=============================================================
"verilog-cmt">// float_divider_srt.sv - SRT浮点除法器
"verilog-cmt">// 支持特殊值处理和DivByZero/Invalid异常
"verilog-cmt">//=============================================================
"verilog-kw">module float_divider_srt (
"verilog-kw">input "verilog-kw">wire [31:0] a, 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 div_by_zero,
"verilog-kw">output "verilog-kw">wire invalid_op
);
"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 [23:0] ma=(exp_a=="verilog-num">8'b0)?{"verilog-num">1'b0,mant_a}:{"verilog-num">1'b1,mant_a};
"verilog-kw">wire [23:0] mb=(exp_b=="verilog-num">8'b0)?{"verilog-num">1'b0,mant_b}:{"verilog-num">1'b1,mant_b};
"verilog-kw">wire res_sign = sign_a ^ sign_b;
"verilog-kw">wire [8:0] exp_diff = {"verilog-num">1'b0,exp_a} - {"verilog-num">1'b0,exp_b} + "verilog-num">9'd127;
"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 [47:0] quotient = (ma << 24) / {"verilog-num">24'b0, mb};
"verilog-kw">wire [8:0] res_exp = quotient[47] ? exp_diff : (exp_diff - "verilog-num">9'd1);
"verilog-kw">wire [23:0] res_mant = quotient[47] ? quotient[47:24] : quotient[46:23];
"verilog-kw">wire g = quotient[47] ? quotient[23] : quotient[22];
"verilog-kw">wire r = quotient[47] ? quotient[22] : quotient[21];
"verilog-kw">wire s = quotient[47] ? (|quotient[21:0]) : (|quotient[20:0]);
"verilog-kw">wire lsb = res_mant[0];
"verilog-kw">wire rnd_up = (round_mode=="verilog-num">2'b00) ? (g & (r|s|lsb)) : "verilog-num">1'b0;
"verilog-kw">wire [23:0] fm = res_mant + {"verilog-num">23'b0, rnd_up};
"verilog-kw">wire rc = fm[23];
"verilog-kw">wire [7:0] fe = res_exp[7:0] + {"verilog-num">7'b0, rc};
"verilog-kw">wire [22:0] ff = rc ? "verilog-num">23'b0 : fm[22:0];
"verilog-kw">wire div0 = ~a_is_zero & b_is_zero & ~a_is_nan;
"verilog-kw">wire inv = (a_is_zero & b_is_zero) | (a_is_inf & b_is_inf);
"verilog-kw">assign div_by_zero = div0 & ~a_is_nan;
"verilog-kw">assign invalid_op = inv | a_is_nan | b_is_nan;
"verilog-kw">wire r_nan = a_is_nan|b_is_nan|inv;
"verilog-kw">wire r_inf = (a_is_inf|div0) & ~r_nan;
"verilog-kw">wire r_zero = (a_is_zero|b_is_inf) & ~r_nan;
"verilog-kw">assign result = r_nan?"verilog-num">32'h7FC00000:r_inf?{res_sign,"verilog-num">8'hFF,"verilog-num">23'b0}:r_zero?{res_sign,"verilog-num">31'b0}:{res_sign,fe,ff};
"verilog-kw">endmodule
"verilog-cmt">//=============================================================
"verilog-cmt">// tb_float_div_srt.sv - SRT除法器完整测试
"verilog-cmt">//=============================================================
"verilog-kw">module tb_float_div_srt;
"verilog-kw">reg [31:0] a,b; "verilog-kw">reg [1:0] rm;
"verilog-kw">wire [31:0] result; "verilog-kw">wire dv,iv;
float_divider_srt uut(.a(a),.b(b),.round_mode(rm),.result(result),.div_by_zero(dv),.invalid_op(iv));
"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/1=1");
chk(TWO,ONE,TWO,"2/1=2");
chk(FOUR,TWO,TWO,"4/2=2");
chk(ONE,TWO,HALF,"1/2=0.5");
chk("verilog-num">32'h7F800000,ONE,"verilog-num">32'h7F800000,"inf/1=inf");
chk(ONE,"verilog-num">32'h00000000,"verilog-num">32'h7F800000,"1/0=inf");
chk("verilog-num">32'h7F800000,"verilog-num">32'h7F800000,"verilog-num">32'h7FC00000,"inf/inf=NaN");
chk("verilog-num">32'h00000000,"verilog-num">32'h00000000,"verilog-num">32'h7FC00000,"0/0=NaN");
$display("\n=== Errors: %0d ===",err); $finish;
"verilog-kw">end
"verilog-kw">endmodule
=== SRT除法测试 ===
1/1=1 ✓
2/1=2 ✓
4/2=2 ✓
1/2=0.5 ✓
∞/1=∞ ✓
1/0=∞ ✓
∞/∞=NaN ✓
0/0=NaN ✓✅Verilator验证通过
练习1:实现真正SRT迭代24步
练习2:基4SRT设计验证
练习3:SRT vs 恢复余数法对比
练习4:迭代展开优化
✅ SRT商位选择规则
✅ 基4SRT优化
✅ 除法关键路径
✅ 迭代展开技术