【FPGA】for循环求取二进制1的个数的方法与差别
测试二进制值
reg [15 : 0] data_test;initial begindata_test = 16'b1100_0011_0101_1010;repeat (90) @(posedge clk);data_test = 16'b0100_0000_1011_1000;
end方法一:
数组类型,在always块中用非阻塞式赋值语句
reg [4 : 0] bit_cnt [15 : 0];
always @(posedge clk) begin : bit_cnt_blockinteger i;if (!rst_n) beginfor (i = 0 ; i < 16 ; i = i + 1)bit_cnt[i] <= 5'd0;endelse beginfor (i = 0 ; i < 16 ; i = i + 1) beginif (i == 0)bit_cnt[i] <= data_test[i];else bit_cnt[i] <= bit_cnt[i - 1] + data_test[i];endend
end
wire [4 : 0] w_bit_cnt [15 : 0];
genvar i1;
generate for (i1 = 0 ; i1 < 16 ; i1 = i1 + 1)assign w_bit_cnt[i1] = bit_cnt[i1];
endgenerate
测试结果

每一个时钟周期计算一位,需要16个时钟周期才能计算完成,数组类型可以看到运算过程。运算正确✔
方法二:
数组类型,在always块中用阻塞式赋值语句
reg [4 : 0] bit_cnt1 [15 : 0];
always @(posedge clk) begin : bit_cnt_block1integer i;if (!rst_n) beginfor (i = 0 ; i < 16 ; i = i + 1)bit_cnt1[i] = 5'd0;endelse beginfor (i = 0 ; i < 16 ; i = i + 1) beginif (i == 0)bit_cnt1[i] = data_test[i];else bit_cnt1[i] = bit_cnt1[i - 1] + data_test[i];endend
end
wire [4 : 0] w_bit_cnt1 [15 : 0];
genvar i2;
generate for (i2 = 0 ; i2 < 16 ; i2 = i2 + 1)assign w_bit_cnt1[i2] = bit_cnt1[i2];
endgenerate测试结果

一个时钟周期内即可计算完成,数组类型可以看到运算过程。运算正确✔
方法三:
单寄存器类型,always块中用非阻塞式赋值语句
reg [4 : 0] bit_cnt2;
always @(posedge clk) begin : bit_cnt_block2integer i;if (!rst_n)bit_cnt2 <= 5'd0;else beginfor (i = 0 ; i < 16 ; i = i + 1)bit_cnt2 <= bit_cnt2 + data_test[i];end
end
测试结果

由于是非阻塞式赋值语句,所以把for循环展开,其实只执行最后一次循环体,也就是每次累加第16位的值(data_test[15]),所以这个结果是错误的❌。绝对不能这样使用!
方法四:
单寄存器类型,always块中用阻塞式赋值语句
reg [4 : 0] bit_cnt3;
always @(posedge clk) begin : bit_cnt_block3integer i;if (!rst_n)bit_cnt3 = 5'd0;else beginbit_cnt3 = 'd0;for (i = 0 ; i < 16 ; i = i + 1)bit_cnt3 = bit_cnt3 + data_test[i];end
end测试结果

一个时钟周期内即可计算完成,由于是单寄存器,所以只能获得最后的求和结果,看不到中间过程。运算正确✔。
方法二、四对比:

完整tb代码
reg [15 : 0] data_test;initial begindata_test = 16'b1100_0011_0101_1010;repeat (90) @(posedge clk);data_test = 16'b0100_0000_1011_1000;
endreg [4 : 0] bit_cnt [15 : 0];
always @(posedge clk) begin : bit_cnt_blockinteger i;if (!rst_n) beginfor (i = 0 ; i < 16 ; i = i + 1)bit_cnt[i] <= 5'd0;endelse beginfor (i = 0 ; i < 16 ; i = i + 1) beginif (i == 0)bit_cnt[i] <= data_test[i];else bit_cnt[i] <= bit_cnt[i - 1] + data_test[i];endend
end
wire [4 : 0] w_bit_cnt [15 : 0];
genvar i1;
generate for (i1 = 0 ; i1 < 16 ; i1 = i1 + 1)assign w_bit_cnt[i1] = bit_cnt[i1];
endgeneratereg [4 : 0] bit_cnt1 [15 : 0];
always @(posedge clk) begin : bit_cnt_block1integer i;if (!rst_n) beginfor (i = 0 ; i < 16 ; i = i + 1)bit_cnt1[i] = 5'd0;endelse beginfor (i = 0 ; i < 16 ; i = i + 1) beginif (i == 0)bit_cnt1[i] = data_test[i];else bit_cnt1[i] = bit_cnt1[i - 1] + data_test[i];endend
end
wire [4 : 0] w_bit_cnt1 [15 : 0];
genvar i2;
generate for (i2 = 0 ; i2 < 16 ; i2 = i2 + 1)assign w_bit_cnt1[i2] = bit_cnt1[i2];
endgeneratereg [4 : 0] bit_cnt2;
always @(posedge clk) begin : bit_cnt_block2integer i;if (!rst_n)bit_cnt2 <= 5'd0;else beginfor (i = 0 ; i < 16 ; i = i + 1)bit_cnt2 <= bit_cnt2 + data_test[i];end
endreg [4 : 0] bit_cnt3;
always @(posedge clk) begin : bit_cnt_block3integer i;if (!rst_n)bit_cnt3 = 5'd0;else beginbit_cnt3 = 'd0;for (i = 0 ; i < 16 ; i = i + 1)bit_cnt3 = bit_cnt3 + data_test[i];end
end