引言
最近在看数字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