HDLBits 系列(7)对for循环以及generate for的各种实践

目录

抛砖引玉

累加模型

纹波进位加法器

写在最后


抛砖引玉

本节内容主要讲解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

 

HDLBits 系列(7)对for循环以及generate for的各种实践_第1张图片

纹波进位加法器

所谓的波纹进位加法器,是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个模块,可见上述代码的结构层次:

HDLBits 系列(7)对for循环以及generate for的各种实践_第2张图片

生成的网表文件:

HDLBits 系列(7)对for循环以及generate for的各种实践_第3张图片

局部RTL原理图:

HDLBits 系列(7)对for循环以及generate for的各种实践_第4张图片

这些都是力证。

写在最后

在今年(2019)的秋招一开始,我就建立了一个微信群,在CSDN发布了一条博文,召集全国各地的同行朋友们共同加入,共同讨论秋招求职笔试,面试经验,目前已经有300多人加入,各位才华横溢,让我大开眼界。

到今天11月份,从西北地区最早结束到其他各地陆续结束,但是我们曾开玩笑说,本群继续召集下一届同行,作为先行者的我们也会对你们给予应有的帮助,欢迎加入!

由于人数较多,所以加我的时候务必备注:CSDN.

我的微信号是:ljs521615

 

 

你可能感兴趣的:(#,HDLBits)