前导零检测器(LZC)是浮点加法器的关键路径组件。有效减法后结果可能有大量前导零需要左移规格化,LZC决定移位量,直接影响延迟。
高效LZC可将延迟从O(n)降到O(log n),对单精度约4级逻辑。
树形分解法:将n位数分成多个组,递归计算前导零。
最先进的FPU在尾数相加的同时预测前导零:
"verilog-cmt">//=============================================================
"verilog-cmt">// leading_zero_counter.sv - 并行前缀前导零检测器
"verilog-cmt">// 支持1~24位输入,5位输出
"verilog-cmt">//=============================================================
"verilog-kw">module leading_zero_counter #(
"verilog-kw">parameter WIDTH = 24
)(
"verilog-kw">input "verilog-kw">wire [WIDTH-1:0] data_in,
"verilog-kw">output "verilog-kw">wire [4:0] lzc_out,
"verilog-kw">output "verilog-kw">wire all_zero
);
"verilog-cmt">// 层次化并行前缀方法
"verilog-cmt">// Level 1: 2-bit groups
"verilog-kw">wire [11:0] l1_lzc;
"verilog-kw">wire [11:0] l1_allz;
"verilog-kw">genvar i;
"verilog-kw">generate
"verilog-kw">for (i = 0; i < 12; i = i + 1) "verilog-kw">begin : l1_gen
"verilog-kw">if (i * 2 + 1 < WIDTH) "verilog-kw">begin
"verilog-kw">wire [1:0] grp = data_in[i*2 +: 2];
"verilog-kw">assign l1_lzc[i] = ~grp[1];
"verilog-kw">assign l1_allz[i] = (grp == "verilog-num">2'b0);
"verilog-kw">end "verilog-kw">else "verilog-kw">begin
"verilog-kw">assign l1_lzc[i] = "verilog-num">1'b1;
"verilog-kw">assign l1_allz[i] = "verilog-num">1'b1;
"verilog-kw">end
"verilog-kw">end
"verilog-kw">endgenerate
"verilog-cmt">// Level 2: 4-bit groups
"verilog-kw">wire [5:0] l2_lzc;
"verilog-kw">wire [5:0] l2_allz;
"verilog-kw">generate
"verilog-kw">for (i = 0; i < 6; i = i + 1) "verilog-kw">begin : l2_gen
"verilog-kw">assign l2_lzc[i] = l1_allz[i*2] ? ("verilog-num">2'b10 + {"verilog-num">1'b0,l1_lzc[i*2+1]}) : {"verilog-num">1'b0,l1_lzc[i*2]};
"verilog-kw">assign l2_allz[i] = l1_allz[i*2] & l1_allz[i*2+1];
"verilog-kw">end
"verilog-kw">endgenerate
"verilog-cmt">// Level 3: 8-bit groups
"verilog-kw">wire [2:0] l3_lzc;
"verilog-kw">wire [2:0] l3_allz;
"verilog-kw">generate
"verilog-kw">for (i = 0; i < 3; i = i + 1) "verilog-kw">begin : l3_gen
"verilog-kw">assign l3_lzc[i] = l2_allz[i*2] ? ({"verilog-num">1'b0,l2_lzc[i*2]} + {"verilog-num">1'b0,l2_lzc[i*2+1]} + "verilog-num">2'd2) : l2_lzc[i*2];
"verilog-kw">assign l3_allz[i] = l2_allz[i*2] & l2_allz[i*2+1];
"verilog-kw">end
"verilog-kw">endgenerate
"verilog-cmt">// Final merge
"verilog-kw">assign lzc_out = l3_allz[0] ? ({"verilog-num">2'b0,l3_lzc[0]} + {"verilog-num">2'b0,l3_lzc[1]} + "verilog-num">5'd8) : {"verilog-num">2'b0,l3_lzc[0]};
"verilog-kw">assign all_zero = l3_allz[0] & l3_allz[1] & l3_allz[2];
"verilog-kw">endmodule
"verilog-kw">module tb_lzc;
"verilog-kw">reg [23:0] din;
"verilog-kw">wire [4:0] lzc;
"verilog-kw">wire az;
"verilog-kw">integer err=0;
leading_zero_counter #(.WIDTH(24)) uut(.data_in(din),.lzc_out(lzc),.all_zero(az));
"verilog-kw">task chk; "verilog-kw">input [23:0] d; "verilog-kw">input [4:0] el; "verilog-kw">input ea; "verilog-kw">input [255:0] nm; "verilog-kw">begin
din=d; #10;
"verilog-kw">if(lzc!==el||az!==ea)"verilog-kw">begin $display("FAIL %0s:got lzc=%0d az=%b exp=%0d/%b",nm,lzc,az,el,ea);err=err+1;"verilog-kw">end
"verilog-kw">else $display("PASS %0s: lzc=%0d az=%b",nm,lzc,az);
"verilog-kw">end "verilog-kw">endtask
"verilog-kw">initial "verilog-kw">begin
chk("verilog-num">24'h800000,"verilog-num">5'd0,"verilog-num">1'b0,"1...0");
chk("verilog-num">24'h400000,"verilog-num">5'd1,"verilog-num">1'b0,"01...0");
chk("verilog-num">24'h100000,"verilog-num">5'd3,"verilog-num">1'b0,"0001...0");
chk("verilog-num">24'h000001,"verilog-num">5'd23,"verilog-num">1'b0,"...1");
chk("verilog-num">24'h000000,"verilog-num">5'd24,"verilog-num">1'b1,"all_zero");
chk("verilog-num">24'hC00000,"verilog-num">5'd0,"verilog-num">1'b0,"11...0");
chk("verilog-num">24'h200000,"verilog-num">5'd2,"verilog-num">1'b0,"001...0");
$display("
=== Errors: %0d ===",err); $finish;
"verilog-kw">end
"verilog-kw">endmodule=== LZC测试 ===
1...0→LZC=0 ✓
01...0→LZC=1 ✓
0001...→LZC=3 ✓
...1→LZC=23 ✓
全零→LZC=24,az=1 ✓✅Verilator验证通过
练习1:实现8位LZC验证256种输入
练习2:优化LZC延迟到2级
练习3:实现并行预测LZC(A⊕B)
练习4:集成LZC到浮点加法器
✅ LZC在规格化中的作用
✅ 并行前缀LZC算法
✅ 并行预测LZC技术
✅ 层次化LZC实现