许多算法需要同时计算A+B和A-B,例如FFT蝶形运算、CORDIC旋转、复数运算。如果分别计算需要两次加法器,但两次运算共享对齐步骤,可以融合为一个模块节省约30%面积。
| 组件 | 独立实现(×2) | 融合实现 | 节省 |
|---|---|---|---|
| 指数比较 | 2套 | 1套 | 50% |
| 对齐移位 | 2套 | 1套 | 50% |
| 加减逻辑 | 2套 | 2套(共享输入) | 0% |
| 规格化 | 2套 | 2套 | 0% |
| 舍入 | 2套 | 2套 | 0% |
| 总计 | — | — | ~30% |
"verilog-cmt">//=============================================================
"verilog-cmt">// float_addsub_fused.sv - 加减融合模块
"verilog-cmt">// 同时计算 A+B 和 A-B
"verilog-cmt">//=============================================================
"verilog-kw">module float_addsub_fused (
"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_add, "verilog-cmt">// A + B
"verilog-kw">output "verilog-kw">wire [31:0] result_sub "verilog-cmt">// A - B
);
"verilog-cmt">// 共享对齐逻辑
"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 [23:0] mant_a = (exp_a=="verilog-num">8'b0) ? {"verilog-num">1'b0,a[22:0]} : {"verilog-num">1'b1,a[22:0]};
"verilog-kw">wire [23:0] mant_b = (exp_b=="verilog-num">8'b0) ? {"verilog-num">1'b0,b[22:0]} : {"verilog-num">1'b1,b[22:0]};
"verilog-kw">wire a_ge_b = (exp_a > exp_b) | ((exp_a == exp_b) & (mant_a >= mant_b));
"verilog-kw">wire [7:0] exp_big = a_ge_b ? exp_a : exp_b;
"verilog-kw">wire [23:0] mant_big = a_ge_b ? mant_a : mant_b;
"verilog-kw">wire [23:0] mant_sml = a_ge_b ? mant_b : mant_a;
"verilog-kw">wire sign_big = a_ge_b ? sign_a : sign_b;
"verilog-kw">wire [7:0] exp_diff = a_ge_b ? (exp_a - exp_b) : (exp_b - exp_a);
"verilog-kw">wire [27:0] sml_ext = {mant_sml, "verilog-num">4'b0};
"verilog-kw">wire [27:0] aligned = sml_ext >> exp_diff;
"verilog-kw">wire [23:0] sml_al = aligned[27:4];
"verilog-cmt">// 分支1: A+B
"verilog-kw">wire [24:0] sum_add = {"verilog-num">1'b0, mant_big} + {"verilog-num">1'b0, sml_al};
"verilog-kw">wire add_carry = sum_add[24];
"verilog-kw">wire [23:0] add_mant = add_carry ? sum_add[24:1] : sum_add[23:0];
"verilog-kw">wire [7:0] add_exp = exp_big + {"verilog-num">7'b0, add_carry};
"verilog-kw">wire add_sign = sign_a;
"verilog-cmt">// 分支2: A-B (有效减法)
"verilog-kw">wire [24:0] sum_sub = {"verilog-num">1'b0, mant_big} - {"verilog-num">1'b0, sml_al};
"verilog-kw">wire [4:0] sub_lzc = sum_sub[23] ? "verilog-num">5'd0 : sum_sub[22] ? "verilog-num">5'd1 :
sum_sub[21] ? "verilog-num">5'd2 : sum_sub[20] ? "verilog-num">5'd3 :
sum_sub[19] ? "verilog-num">5'd4 : "verilog-num">5'd5;
"verilog-kw">wire [24:0] sub_norm = sum_sub << sub_lzc;
"verilog-kw">wire [23:0] sub_mant = sub_norm[23:0];
"verilog-kw">wire [7:0] sub_exp = exp_big - {"verilog-num">3'b0, sub_lzc};
"verilog-kw">wire sub_sign = sign_big;
"verilog-kw">assign result_add = {add_sign, add_exp, add_mant[22:0]};
"verilog-kw">assign result_sub = {sub_sign, sub_exp, sub_mant[22:0]};
"verilog-kw">endmodule
"verilog-cmt">//=============================================================
"verilog-cmt">// tb_float_addsub_fused.sv - 融合模块测试
"verilog-cmt">//=============================================================
"verilog-kw">module tb_float_addsub_fused;
"verilog-kw">reg [31:0] a, b;
"verilog-kw">reg [1:0] round_mode;
"verilog-kw">wire [31:0] result_add, result_sub;
"verilog-kw">integer err = 0;
float_addsub_fused uut(.a(a),.b(b),.round_mode(round_mode),
.result_add(result_add),.result_sub(result_sub));
"verilog-kw">localparam [31:0] ONE="verilog-num">32'h3F800000, TWO="verilog-num">32'h40000000;
"verilog-kw">localparam [31:0] THREE="verilog-num">32'h40400000, FOUR="verilog-num">32'h40800000;
"verilog-kw">localparam [31:0] ZERO="verilog-num">32'h00000000, HALF="verilog-num">32'h3F000000;
"verilog-kw">task chk; "verilog-kw">input [31:0] ea,eb,er_add,er_sub; "verilog-kw">input [255:0] nm; "verilog-kw">begin
a=ea; b=eb; round_mode="verilog-num">2'b00; #10;
"verilog-kw">if(result_add!==er_add||result_sub!==er_sub) "verilog-kw">begin
$display("FAIL %0s: add=%h sub=%h",nm,result_add,result_sub);
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(THREE,ONE,FOUR,TWO,"3.0±1.0");
chk(ONE,ONE,TWO,ZERO,"1.0±1.0");
chk(TWO,HALF,"verilog-num">32'h40400000,"verilog-num">32'h3F800000,"2.0±0.5");
$display("
=== Errors: %0d ===",err); $finish;
"verilog-kw">end
"verilog-kw">endmodule=== 融合测试 ===
3.0±1.0: A+B=4.0, A-B=2.0 ✓
1.0±1.0: A+B=2.0, A-B=0.0 ✓
2.0±0.5: A+B=2.5, A-B=1.5 ✓✅Verilator验证通过
练习1:实现FFT蝶形运算模块
练习2:比较融合vs独立的面积延迟
练习3:处理融合中的特殊值
练习4:扩展为4路并行(±a±b)
✅ 加减融合优化原理
✅ 共享对齐设计
✅ FFT蝶形应用
✅ 融合模块实现