背景
在看向量处理器ara源码的时候在sequencer、vmfpu、masku、sldu、addrgen等单元都看到了lzc单元,起初不知道这个缩写的含义,看了模块发现是一个计算头部或尾部1个数的模块trailing zero counter / leading zero counter(也就是第一个1的索引)。比如在masku中,对于mask操作数计算得到尾部0的个数,然后累加来得到vfirst指令所要获得的最低有效元素的index。
我自己用一个简单的for循环写了个LUT用DC综合发现时序差了很多。
32位
面积5287 vs. 4545
时序4.95 vs. 2.40
lzc模块分析
ara的lzc可见 https://github.com/pulp-platform/common_cells/blob/master/src/lzc.sv
我自己看了下这个模块,发现其是用了个二叉树,将待计数的输入作为虚拟"叶子"节点,然后父节点的2个子节点向上报是否有1,并且报告这个1的索引。
综合电路如
我们可以看到对于8位的输入,输出的表达式为{(0+1+2+3)', (0+1+2+3)' ? (4+5)' : (0+1)', (0+1+2+3)' ? (4+5'6)' : (0+1'2)'} ,可以看到就是二分mux,根据一半或的结果来选择哪一半的结果
模仿
然后我根据自己的理解,添加了一个target输入来表示是识别0还是1,参数HIGHEST表示从高到低识别。不过这里很多边界情况没有做处理。
当前节点编号为i,则其子节点的编号为$i\times 2+1$和$i\times 2+2$
module lzc_target #(
parameter int WIDTH = 8,
parameter int HIGHEST = 0
) (
input [WIDTH-1:0] data_i,
input target,
output exit_o,
output [$clog2(WIDTH)-1:0] pos_o
);
localparam LEVELS = $clog2(WIDTH);
localparam N = 2**LEVELS;
localparam N_2 = 2**(LEVELS-1);
logic [N-1:0][LEVELS-1:0] indices;
logic [N-1:0] sel_node;
logic [N-1:0][LEVELS-1:0] index_node;
`define INDEX (2**l-1+i)
for (genvar i = 0; i < WIDTH; i=i+1) begin
assign indices[i] = (LEVELS)'(unsigned'(i));
end
for (genvar l = 0; l < LEVELS; l=l+1) begin
if (l == LEVELS-1) begin: gen_last_level
for (genvar i = 0; i < N_2; i=i+1) begin
assign sel_node[N_2-1+i] = target ? (data_i[i*2] | data_i[i*2+1]) : (data_i[i*2] & data_i[i*2+1]);
if (HIGHEST)
assign index_node[N_2-1+i] = data_i[i*2+1] == target ? indices[i*2+1] : indices[i*2];
else
assign index_node[N_2-1+i] = data_i[i*2] == target ? indices[i*2] : indices[i*2+1];
end
end else begin: gen_each_level
for (genvar i = 0; i < 2**l; i=i+1) begin: gen_each_node
assign sel_node[`INDEX] = target ? (sel_node[`INDEX*2+1] | sel_node[`INDEX*2+2]) : (sel_node[`INDEX*2+1] & sel_node[`INDEX*2+2]);
if (HIGHEST)
assign index_node[`INDEX] = sel_node[`INDEX*2+2] == target ? index_node[`INDEX*2+2] : index_node[`INDEX*2+1];
else
assign index_node[`INDEX] = sel_node[`INDEX*2+1] == target ? index_node[`INDEX*2+1] : index_node[`INDEX*2+2];
end
end
end
assign pos_o = index_node[0];
assign exit_o = sel_node[0] == target;
endmodule
本文由 BWonder 创作,采用 知识共享署名4.0 国际许可协议进行许可。
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。