LZC(leading zeros count)在浮点加法器设计中应用广泛。本文借助优先级编码器的原理设计了一个48bits的LZC电路。
优先级编码器的原理参考了:优先编码器 Priority Encoder-CSDN博客
直接上代码:
module LZC_cascade #(
parameter N = 8
) (
input [N-1: 0]Q1 ,
input [N-1: 0]Q0 ,
input vld1,
input vld0,
output [N : 0]Q ,
output vld
);
assign Q[N] = vld1 ;
assign Q[N-1:0] = vld1 ? Q1[N-1:0]: Q0[N-1:0];
assign vld = vld1 | vld0 ;
endmodule
module LZC_48bits (
input [ 47: 0]D ,
output vld ,
output [ 5: 0]leading_zeros
);
wire [4*6 -1:0]PEnc8_x6 ;
wire [5*3 -1:0]PEnc16_x3;
wire [6*2 -1:0]PEnc32_0,PEnc32_1 ;
wire [6 :0]PEnc48_0 ;
genvar i ;
function [3:0]PEnc_8bits; //Priority Encoder: {vld,Q[2:0]}
input [7:0]D;
reg vld1;
begin
vld1 = |D[7:4];
PEnc_8bits[0] = vld1 ? D[7] | (~D[6] & D[5]) : D[3] | (~D[2] & D[1]) ;
PEnc_8bits[1] = vld1 ? D[7] | D[6] : D[3] | D[2] ;
PEnc_8bits[2] = vld1 ;
PEnc_8bits[3] = vld1 | |D[3:0] ;
end
endfunction
generate
for(i=0;i<6;i=i+1) begin: GEN0
assign PEnc8_x6[i*4+3:i*4] = PEnc_8bits(D[i*8+7:i*8]);
end
endgenerate
generate
for(i=0;i<3;i=i+1) begin: GEN1
LZC_cascade #(
.N(3)
)u_lzc16 (
.Q1 ( PEnc8_x6[i*8+6:i*8+4] ),
.Q0 ( PEnc8_x6[i*8+2:i*8+0] ),
.vld1( PEnc8_x6[i*8+7] ),
.vld0( PEnc8_x6[i*8+3] ),
.Q ( PEnc16_x3[ i*5+3:i*5+0] ),
.vld ( PEnc16_x3[ i*5+4] )
);
end
endgenerate
LZC_cascade #(
.N(4)
)u_lzc32 (
.Q1 ( PEnc16_x3[8: 5] ),
.Q0 ( PEnc16_x3[3: 0] ),
.vld1( PEnc16_x3[9] ),
.vld0( PEnc16_x3[4] ),
.Q ( PEnc32_0[ 4: 0] ),
.vld ( PEnc32_0[ 5 ] )
);
assign PEnc32_1 = {PEnc16_x3[14],1'b0,PEnc16_x3[13:10]};
LZC_cascade #(
.N(5)
)u_lzc48 (
.Q1 ( PEnc32_1[4: 0] ),
.Q0 ( PEnc32_0[4: 0] ),
.vld1( PEnc32_1[5] ),
.vld0( PEnc32_0[5] ),
.Q ( PEnc48_0[5: 0] ),
.vld ( PEnc48_0[6 ] )
);
assign vld = PEnc48_0[6] ;
assign leading_zeros = {~PEnc32_1[5]&~PEnc32_0[4],PEnc48_0[4],~PEnc48_0[3:0]};
endmodule
Testbench文件如下:
module TB_LDC;
reg clk,rst_n;
reg [15:0]cnt;
reg [47:0]D ;
wire en ;
reg en_g;
integer fl ;
wire vld ;
wire [ 5: 0]leading_zeros;
always #12.5 clk = ~clk;
initial begin
clk = 0;
rst_n = 0;
#80 rst_n = 1;
fl = $fopen("bf16_result.txt","w");
$fdisplay(fl," D vld leading_zeros");
wait(cnt == 100);
$fclose(fl);
#5 $stop;
end
always @(negedge rst_n or posedge clk)
if(!rst_n) begin
cnt <= 'd0;
en_g <= 'd0;
end else begin
cnt <= cnt + 1'b1;
en_g <= en ;
end
assign en = (cnt > 'd35) && (cnt < 'd48);
always @(posedge clk or negedge rst_n)
if(!rst_n)
D <= 48'd0 ;
else if(en) begin
D <= 48'h93ab_5af1_10a5 >> ($random%48) ;
end
always @(posedge clk)
if(en_g) begin
$fdisplay(fl,"%012h %d %d", D, vld, leading_zeros);
end
LZC_48bits
DUT(
.D ( D ),
.vld ( vld ),
.leading_zeros( leading_zeros )
);
endmodule
测试波形:
打印结果:
D vld leading_zeros
0000093ab5af 1 20
000000000000 0 47
000000000000 0 47
000000000000 0 47
000000000004 1 45
000000049d5a 1 29
000000000000 0 47
000000000000 0 47
0000000049d5 1 33
00049d5ad788 1 13
024ead6bc442 1 6
000000049d5a 1 29
可见,本设计正确实现了48位前导零计数功能。