3、Verilog Language-Modules:Hierarchy

本文详细介绍了VHDL和Verilog在数字电路设计中的模块连接方法,包括按位置和按名称连接端口,以及多层次模块实例化。通过实例展示了如何创建32位加法器、移位寄存器、进位选择加法器和加减法器。同时,探讨了加法器的优化,如进位选择加法器减少延迟的设计思想。
摘要由CSDN通过智能技术生成

Module - HDLBits链接

下列提供的代码答案不唯一!


目录

1、Modules

2、Connecting ports by position

3、Connecting ports by name

4、Three modules

5、Modules and vectors

6、Adder1

7、Adder2

8、Carry-select adder

9、Adder-subtractor


1、Modules

下图显示了一个非常简单的电路及其子模块。在这个练习中,创建模块mod_a的一个实例,然后将模块的三个引脚(in1、in2和out)连接到top_module的三个端口(连接a、b和out)。

只要使用的所有模块都属于同一个项目(这样编译器就知道在哪里找到模块),就可以通过在模块内部实例化一个模块来创建模块的层次结构。一个模块的代码不能在另一个模块的主体中编写(不同模块的代码不是嵌套的)。

有两种常用的方法将wire连接到端口,按位置或按名称连接

按位置将导线连接到端口的语法应该很熟悉,因为它使用了类似c的语法。当实例化一个模块时,端口根据模块的声明从左到右连接。例如:


mod_a instance1 (wa, wb, wc);


这将实例化一个mod_a类型的模块,并给它一个实例名“instance1”,然后将信号wa(在新模块外部)连接到新模块的第一个端口(in1), wb连接到第二个端口(in2), wc连接到第三个端口(out)。该语法的一个缺点是,如果模块的端口列表发生变化,则需要找到并修改模块的所有实例,以匹配新模块。

按名称将wire连接到模块的端口,即使端口列表发生变化,连接线也可以保持正确连接。但是,这种语法更加冗长。


mod_a instance2(.out(wc), .in1(wa), .in2(wb));


上面的代码实例化了一个名为“instance2”的mod_a类型的模块,然后将信号wa(在模块外部)连接到名为in1的端口,将wb连接到名为in2的端口,将wc连接到名为out的端口。注意,这里端口的排序是如何无关紧要的,因为连接将连接到正确的名称,而不管它在子模块的端口列表中的位置。

 代码:

module top_module ( input a, input b, output out );
    mod_a(
        .in1(a),
        .in2(b),
        .out(out)
    );

endmodule

2、Connecting ports by position

这个问题类似于上述。一个名为mod_a的模块,它有2个输出和4个输入。必须按位置顺序将6个端口连接到顶级模块的端口out1、out2、a、b、c和d。


按下列模板::

mod_a ( output, output, input, input, input, input );

 代码:

module top_module ( 
    input a, 
    input b, 
    input c,
    input d,
    output out1,
    output out2
);
    mod_a(out1, out2, a, b, c, d);
endmodule

3、Connecting ports by name

一个名为mod_a的模块,它有2个输出和4个输入,按某种顺序。必须按名称将这6个端口连接到top_module的端口。

 按下列模板:

mod_a ( output out1, output out2, input in1, input in2, input in3, input in4);

 代码:

module top_module ( 
    input a, 
    input b, 
    input c,
    input d,
    output out1,
    output out2
);
    mod_a(
        .out1(out1),
        .out2(out2),
        .in1(a),
        .in2(b),
        .in3(c),
        .in4(d)
    );

endmodule

4、Three modules

提供一个模块my_dff,它有两个输入和一个输出(相当于一个D触发器)。将它们链接在一起,形成长度为3的移位寄存器。

 代码:

module top_module ( input clk, input d, output q );
    
    wire q_1;
    wire q_2;
    
    my_dff u_my_dff_1(
        .clk(clk),
        .d(d),
        .q(q_1)
    );
    my_dff u_my_dff_2(
    	.clk(clk),
        .d(q_1),
        .q(q_2)
    );
	my_dff u_my_dff_3(
        .clk(clk),
        .d(q_2),
        .q(q)
    );
endmodule

5、Modules and vectors


模块端口不再是单一的引脚,我们现在有了以向量作为端口的模块。

一个模块my_dff8,它有两个输入和一个输出(实现了一组8个D触发器)。将三个链接在一起,形成一个长度为3的8位宽移位寄存器。另外,创建一个4选1的多路器,根据sel[1:0]选择输出内容:输入d处的值,在第一个、第二个或第三个d触发器之后。

 按下列模板:

my_dff8 ( input clk, input [7:0] d, output [7:0] q );

 

代码:

module top_module ( 
    input clk, 
    input [7:0] d, 
    input [1:0] sel, 
    output [7:0] q 
);
    wire [7:0] q1;
    wire [7:0] q2;
    wire [7:0] q3;
    
    my_dff8 u_my_dff8_1(
        .clk(clk),
        .d(d),
        .q(q1)
    );
    my_dff8 u_my_dff8_2(
        .clk(clk),
        .d(q1),
        .q(q2)
    );
	my_dff8 u_my_dff8_3(
        .clk(clk),
        .d(q2),
        .q(q3)
    );
    
    always@(*)
        begin
            case(sel)
                2'b00 : q = d;
                2'b01 : q = q1;
                2'b10 : q = q2;
                2'b11 : q = q3;
            endcase
        end
endmodule

6、Adder1

一个模块add16,它执行16位加法。实例化其中两个来创建一个32位加法器。一个add16模块计算相加结果的下16位,而第二个add16模块在接收到第一个加法器的执行结果后,计算结果的上16位。32位加法器不需要处理输入或输出,但是内部模块需要处理才能正确运行。(换句话说,add16模块执行16位a + b + cin,而该模块执行32位a + b)。

 按下列模板:

add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );

如下图所示将模块连接在一起。

 代码:

module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire cout_lo;
    wire [15:0] sum_lo;
    wire [15:0] sum_hi;
    wire cout;
    wire cin_lo;
    
    add16 add16_lo(
        .a({a[15:0]}),
        .b({b[15:0]}),
        .cin(cin_lo),
        .sum(sum_lo),
        .cout(cout_lo)
    );
    add16 add16_hi(
        .a({a[31:16]}),
        .b({b[31:16]}),
        .cin(cout_lo),
        .sum(sum_hi),
        .cout(cout)
    );
    assign sum = {sum_hi, sum_lo};

endmodule

7、Adder2

在这个练习中,将创建一个具有两层层次结构的电路。top_module将实例化add16的两个副本(提供),每个副本将实例化add1的16个副本(必须编写)。因此,必须编写两个模块:top_module和add1。提供一个模块add16,它执行16位加法您必须实例化其中两个来创建一个32位加法器。一个add16模块计算加法结果的下16位,而第二个add16模块计算加法结果的上16位。

综上所述,本次设计共有三个模块:

top_module——顶层模块

add16——一个16位加法器模块

add1——1位完全加法器模块

 按下列模板:

add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );

add1 ( input a, input b, input cin, output sum, output cout );

 代码:

module top_module (
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);//
	wire cin_lo ;
    wire cout_lo;
    wire cout;
    wire [15:0] sum_lo;
    wire [15:0] sum_hi;
    
    
    add16 add16_lo(
        .a({a[15:0]}),
        .b({b[15:0]}),
        .cin(cin_lo),
        .sum(sum_lo),
        .cout(cout_lo)
    );
    
    add16 add16_hi(
        .a({a[31:16]}),
        .b({b[31:16]}),
        .cin(cout_lo),
        .sum(sum_hi),
        .cout(cout)
    );
    
    assign sum={sum_hi,sum_lo};
endmodule

module add1 ( input a, input b, input cin,   output sum, output cout );

// Full adder module here
	assign sum = a ^ b ^ cin;
    assign cout = (a ^ b) & cin | a & b;
endmodule

8、Carry-select adder

前面进位加法器的有一个缺点,是加法器计算进位的延迟在最坏的情况下是相当慢的,在第一阶段加法器完成之前,第二阶段加法器不能开始计算它的进位。这使得加法器变慢。改进之一是进位选择加法器,如下图所示。第一阶段加法器与之前相同,但我们复制了第二阶段加法器,一个假设进位=0,一个假设进位=1,然后使用快速2选1多路选择器来选择哪个结果是正确的。

在本练习中,提供与上一个模块add16,该模块将两个带进位的16位数字相加,并生成一个带进位的16位和。


 按下列模板:

add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );

 代码:

module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
	wire cin1=0;
    wire cin2=1;
    wire [15:0] sum1,sum2,sum3,sum4;
    wire cout1,cout2,cout3;
    
    add16 add16_1(
        .a({a[15:0]}),
        .b({b[15:0]}),
        .cin(cin1),
        .sum(sum1),
        .cout(cout1)
    );
    
    add16 add16_2(
        .a({a[31:16]}),
        .b({b[31:16]}),
        .cin(cin1),
        .sum(sum2),
        .cout(cout2)
    );
    
    add16 add16_3(
        .a({a[31:16]}),
        .b({b[31:16]}),
        .cin(cin2),
        .sum(sum3),
        .cout(cout3)
    );
    
    always@(a or b)
        begin
            if(cout1==0)  sum4=sum2;
            else sum4 = sum3;
        end
    assign sum = {sum4,sum1};
/*
    //也可以这样
    always@(a or b)begin
	if(cout1 == 0)	
		sum = {sum2, sum1};
	else    
		sum = {sum3, sum1};

end
*/
endmodule

9、Adder-subtractor

加-减法器可以由加法器构建,可选地对其中一个输入取反,这相当于将输入取反,然后加1。最终的结果是一个可以进行(a + b + 0)和(a + ~b + 1)两种操作的电路。如果想要更详细的电路工作原理的解释,请参阅维基百科。
构建下图的加-减法器。 按下列模板:

add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );

当sub为1时,使用32位宽的异或门来反转b输入。

 代码:

module top_module(
    input [31:0] a,
    input [31:0] b,
    input sub,
    output [31:0] sum
);

wire cout1, cout2;
wire [15:0] b_lo;
wire [15:0] b_hi;
wire [15:0] sum_lo;
wire [15:0] sum_hi;

always@(a or b or sub)begin
	if(sub == 0)begin
		b_lo = b[15:0];
		b_hi = b[31:16];
	end 
	else begin
        //取反,程序到这说明sub=1,16位宽都为1与其进行异或运行,0变1,1变0,从而达到取反的效果
		b_lo = {16{sub}} ^ b[15:0];
		b_hi = {16{sub}} ^ b[31:16];
	end
end

add16 u_add16_1(
	.a(a[15:0]),
	.b(b_lo),
	.cin(sub),
	.sum(sum_lo),
	.cout(cout1)
	);

add16 u_add16_2(
	.a(a[31:16]),
	.b(b_hi),
	.cin(cout1),
	.sum(sum_hi),
	.cout(cout2)
	);

assign sum = {sum_hi, sum_lo};

endmodule

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值