数字IC秋招手撕代码(八)找序列中的第一个1—升级篇

数字IC秋招手撕代码(八)找序列中的第一个1—升级篇



题目

用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干货分享!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值