ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

verilog-统计n位数据中1的个数

2022-03-02 10:35:27  阅读:276  来源: 互联网

标签:din clk 32 个数 cnt 计数器 verilog rst 统计


引言

最近在看数字IC面经,遇见一个很有趣的题目:输入一个32位的数据,判断数据中0/1的个数,如果1比0多则下一个时钟周期输出一个标志信号。

我一开始的思路是要在一个时钟周期内完成计算,应该是要用生成循环语句generate,但是平时的项目中几乎没用过这个语句,实在是不熟悉,并且如何用组合逻辑在一拍内完成计算也没想清楚。

后来在网上搜索到一个很不错的思路,现整理如下:

设计思路

首先要有一个计数器来进行1的累加,计数器的位宽取决于输入数据的位宽,比如输入一个32位的数据,那么最多是32个1,因此位宽为5。这里需要注意如果是输入一个10位的数据,那么应该在计数器设计上留有余量,即设置一个4位的计数器。核心原则就是cnt_width =  ceil(log2data_width)。

接着进行计算,将输入数据第一位与第二位相加,结果存在第一个计数器中。再是将第一个计数器与第三位相加,结果存在第二个计数器中。以此类推,最后第32位与第30个计数器相加,结果存在第31个计数器中。这里我们可以声明一个(data_width-1)x(cnt_width)位宽的计数器,在本例中就是31x5=155,所以最终计算的1的数目的大小存在cnt[154:150]里。

最后再用一个时序逻辑进行判断来输出标志信号即可。

RTL代码

 1 module cal1num(
 2     input         wire            clk,
 3     input         wire             rst,
 4     input         wire     [31:0]    din,
 5     output         reg                flag
 6     );
 7 
 8 parameter     data_len = 32;
 9 parameter      data_wid = 5;
10 
11 wire        [(data_len-1)*data_wid-1:0]            cnt;
12 
13 
14 generate
15     genvar i;
16     for(i=0;i<data_len-1;i=i+1)begin:get_1_num
17         if (i==0) begin
18             assign cnt[data_wid*(i+1)-1 -: data_wid] = din[i] + din[i+1];
19         end
20         else begin
21             assign cnt[data_wid*(i+1)-1 -: data_wid] = cnt[data_wid*(i)-1 -: data_wid] + din[i+1]; 
22         end
23     end
24 endgenerate
25 
26 always @(posedge clk) begin
27     if (rst==1'b1) begin
28         // reset
29         flag <= 1'b0;
30     end
31     else if (cnt[(data_len-1)*data_wid-1 -: data_wid]>16) begin
32         flag <= 1'b1;
33     end
34     else begin
35         flag <= 1'b0;
36     end
37 end
38 
39 endmodule

tips:

 这里还有个比较独特的书写方式:

 关于[-:]和[+:]的含义,比如cnt[7-:1],意思就是从第8位往下减1位也就是cnt[7:6],cnt[7+:1],意思就是加1位,等价于cnt[7:8]

个人认为这种书写方式也是很清晰的,只需要根据冒号后面的数字大小就能确定位宽,有时候按照普通的写法没这么清晰,有时候还需要计算一下。因此也是值得借鉴学习的。

 

测试代码

 

`timescale 1ns/1ps
module tb_cal1num();

reg     clk;
reg        rst;
reg [31:0]    din;
wire     flag;

initial begin
    clk=0;
    rst=1;
    din=0;
end

always #10 clk = ~clk;

initial begin
    #100;
    rst=0;
    #11
    din=32'hffff00ff;
    #20
    din=0;
    #10
    din=32'hff000000;
end

//inst cal1num
    cal1num inst_cal1num (
            .clk  (clk),
            .rst  (rst),
            .din (din),
            .flag (flag)
        );


endmodule

仿真结果

由图可以看出输入ffff00ff时cnt高5位结果是24,标志信号在下一个时钟上升沿来临时拉高,而输入是ff000000时,1的数目只有8个,因此标志信号不会拉高。

参考资源

https://wenku.baidu.com/view/1bafd4b2657d27284b73f242336c1eb91a373390.html

https://blog.csdn.net/feiliantong/article/details/107782129

标签:din,clk,32,个数,cnt,计数器,verilog,rst,统计
来源: https://www.cnblogs.com/Achilles7/p/15953874.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有