题目
用verilog实现,不断寻找序列中的第一个1,并输出其index,当寻找完毕后输出结束信号。(LSB为例)
分析
- 数字IC秋招手撕代码(七)找序列中的第一个1
在之前手撕代码专题的内容中已经分析过如何利用二分法,快速地找到数组或者序列中的第一个‘1’。
在本文中,将在此基础上设计一个,能够检测数组中多个‘1’的索引,并在检测结束后,触发done信号。
此外,还针对本文设计进行仿真与综合,希望给有类似需求的朋友们更多的参考。
代码
module find_one(
clk,
rst_n,
din_vld,
din,
idx,
idx_vld,
idx_rdy,
done
);
parameter DATA_WIDTH = 8;
localparam IDX_LEN = log2(DATA_WIDTH);
input clk;
input rst_n;
input din_vld;
input [DATA_WIDTH-1:0] din;
output [IDX_LEN-1:0] idx;
output idx_vld;
input idx_rdy;
output done;
reg [DATA_WIDTH-1:0] data;
wire [3:0] tmp0;
wire [1:0] tmp1;
wire [IDX_LEN-1:0] idx_tmp;
reg [IDX_LEN-1:0] idx;
reg din_vld_dly;
reg idx_vld;
reg done;
wire done_tmp;
reg cal_flag; //0 indicate not run, 1indicate already run
reg idx_rdy_dly;
//===========================================
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
data[DATA_WIDTH-1:0] <= {(DATA_WIDTH){1'b0}};
else if(din_vld)
data[DATA_WIDTH-1:0] <= din[DATA_WIDTH-1:0];
else if(idx_rdy & idx_vld)
data[DATA_WIDTH-1:0] <= data[DATA_WIDTH-1:0] ^ {{(DATA_WIDTH-1){1'b0}},1'b1} << idx[IDX_LEN-1:0];
end
assign idx_tmp[2] = ~(|data[3:0]);
assign tmp0 = idx_tmp[2] ? data[7:4] : data[3:0];
assign idx_tmp[1] = ~(|tmp3[1:0]);
assign tmp1 = idx_tmp[1] ? tmp0[3:2] : tmp0[1:0];
assign idx_tmp[0] = ~tmp1[0];
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cal_flag <= 1'b0;
else if(done_tmp)
cal_flag <= 1'b0;
else if(din_vld)
cal_flag <= 1'b1;
end
assign done_tmp = cal_flag & (~(|data[DATA_WIDTH-1:0]));
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
done <= 1'b0;
else
done <= done_tmp;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
din_vld_dly <= 1'b0;
else
din_vld_dly <= din_vld;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
idx_rdy_dly <= 1'b0;
else
idx_rdy_dly <= idx_rdy;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
idx_vld <= 1'b0;
else if(done_tmp | idx_rdy)
idx_vld <= 1'b0;
else if(din_vld_dly | (idx_rdy_dly & !done))
idx_vld <= 1'b1;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
idx[IDX_LEN-1:0] <= {(IDX_LEN){1'b0}};
else
idx[IDX_LEN-1:0] <= idx_tmp[IDX_LEN-1:0];
end
endmodule
对上述代码进行仿真,输入0x2c,在索引为2、3、5存在‘1’,仿真波形与理论一致。
- 为了方便上层模块的使用,使用握手信号(valid,ready)来处理何时进行下一次检测;
- 输入信号有效采用脉冲信号来触发模块内部寄存器的采样;
- 为了使output有更优timing,对idx,done信号都采用DFF输出。
综合结果
为了得知设计可以处理多大数组的序列,本文在TSMC12nm工艺下对设计进行了综合。
时序约束设置了:
- 主频500MHz;
- input/output delay 0.9ns
- clock uncertainty 0.43ns
首先对位宽为8-bits的情况进行综合,可以看出模块关键路径的裕量还有0.55ns。
面积为32.24um^2,转换为gata是56个门
然后对位宽为64-bits的情况进行综合,模块关键路径的裕量还有0.32ns。
面积为158.83um^2,转换为gata是288个门。
- 本文所设计的带有握手信号的找1模块,在64-bits位宽以下的情况,能满足500MHz的应用,且仍有15%的裕量。
搜索关注公众号【IC墨鱼仔】,获取我的更多IC干货分享!