目录
抛砖引玉
累加模型
纹波进位加法器
写在最后
本节内容主要讲解for和generate for的用法,这两个用法,之前也有写过:
Verilog中关于for与generate for用法和区别的一点愚见
先练习一个小题目:
给定100位输入向量 in[99:0],请反转其位顺序。
使用generate for的做法:
module top_module(
input [99:0] in,
output [99:0] out
);
genvar i;
generate
for(i = 0;i <= 99; i = i + 1) begin: bit_verse
assign out[i] = in[99-i];
end
endgenerate
endmodule
需要注意的是,上面那个for循环,必须要有一个名字。
使用for 循环的做法:
module top_module(
input [99:0] in,
output reg [99:0] out
);
always@(*) begin: bit_reverse
integer i;
for(i = 0;i <= 99; i = i + 1) begin
out[i] = in[99-i];
end
end
endmodule
代入HDLBits中验证,包括代入你自己的编译器中,也一样,二者均可。
但仅仅对于这个组合逻辑的实现,使用for循环更为的方便,generate for当然也可以用,但是更常用语模块的例化。
最后说一句,上面for循环的用法,理论上可以写的标标准准,但是如果改变一下某些定义的位置,以及去除always块的取名也不是不可以。
下面这样写也行:
integer i,提前定义就好,也不必给每个always块命名。
module top_module(
input [99:0] in,
output [99:0] out
);
integer i;
reg [99:0] out;
always@(*) begin
for(i = 0;i <= 99; i = i + 1) begin
out[i] = in[99-i];
end
end
endmodule
HDLBits上将此累加设计称之为“population count”,其实也只不过是一个累加模型罢了,给一个255位 的输入,然后统计bit为1的个数。
当然我们可以使用循环语句来解决这个问题,如下是我的答案:
module top_module(
input [254:0] in,
output reg [7:0] out );
integer i;
always@(*) begin
out = 0;
for(i = 0; i <= 254; i = i + 1)begin
if(in[i] == 1)
out = out + 1;
else ;
end
end
endmodule
所谓的波纹进位加法器,是ripple-carry adder的直译,前一级的Cout作为后一级的进位输入。
我们可以通过generate for语法来例化一位全加器来设计波纹进位加法器。
这里先不进行例化,直接设计一个波纹进位加法器:
module top_module(
input [99:0] a, b,
input cin,
output [99:0] cout,
output [99:0] sum );
assign sum[0] = a[0]^b[0]^cin;
assign cout[0] = a[0]&b[0] + (a[0]&cin)^(b[0]&cin);
genvar i;
generate
for(i = 1; i <= 99; i = i + 1)begin: ripple_carry
assign sum[i] = a[i] ^ b[i] ^ cout[i -1];
assign cout[i] = a[i] & b[i] + (a[i] & cout[i-1])^(b[i] & cout[i -1]);
end
endgenerate
endmodule
其实,上面的每一次加法都可以用一位全加器来替换。
如下,如果设计一个一位全加器:
module full_adder1(
input a, b, cin,
output cout, sum );
//assign sum = a ^ b ^ cin;
//assign cout = a&b + (cin&a)^(cin&b);
wire [1:0] mid;
assign mid = a + b + cin;
assign cout = mid[1];
assign sum = mid[0];
endmodule
设计方法有两种,上面代码注释掉的为一种,未注释掉的为另一种,只不过抽象级别不一样罢了,结果都是一样的。
然后我们例化这个全加器得到最终的电路设计为:
module top_module(
input [99:0] a, b,
input cin,
output [99:0] cout,
output [99:0] sum );
full_adder1 inst0(
.a(a[0]),
.b(b[0]),
.cin(cin),
.cout(cout[0]),
.sum(sum[0])
);
genvar i;
generate
for(i = 1; i <= 99; i = i + 1)begin: ripple_carry
full_adder1 inst1(
.a(a[i]),
.b(b[i]),
.cin(cout[i-1]),
.cout(cout[i]),
.sum(sum[i])
);
end
endgenerate
endmodule
generate for的实质是将例化的模块展开成for循环中的i个模块,可见上述代码的结构层次:
生成的网表文件:
局部RTL原理图:
这些都是力证。
在今年(2019)的秋招一开始,我就建立了一个微信群,在CSDN发布了一条博文,召集全国各地的同行朋友们共同加入,共同讨论秋招求职笔试,面试经验,目前已经有300多人加入,各位才华横溢,让我大开眼界。
到今天11月份,从西北地区最早结束到其他各地陆续结束,但是我们曾开玩笑说,本群继续召集下一届同行,作为先行者的我们也会对你们给予应有的帮助,欢迎加入!
由于人数较多,所以加我的时候务必备注:CSDN.
我的微信号是:ljs521615