一:模块的组成和例化
-
在了解模块的例化这一操作前,我们先需要理解硬件描述语言中模块到底是什么。硬件描述语言的宗旨是用代码去描述电路的功能,而再复杂的电路都是由一块一块简单的电路组成的,硬件描述过程也是如此。程序员通常先从最底层的基础模块开始书写代码,然后逐层地在更高地层级中对低一层级的模块进行调用(可以想象一下把已经封装好的已知内部逻辑和输入输出端口的芯片一片一片地插在电路板上,这些芯片也就是“模块”)。当然,在更高一级的电路中,不仅包含有低层级的模块(即实例化建模),还会有当下电路中的数据流建模(多以assign连续赋值语句出现)和行为级建模(以always语句等形式出现)。
-
模块的实例化是一种非常高效的电路调用方法。如:
(1)描述一个4位相加的加法器,就可以用4个一位全加器进行实例化来实现;
(2)描述一个16位BCD加法器,就可以用四个四位BCD全加器实例化来实现;
更加详细抽象的例子就不加赘述,总之,模块的实例化无论是在verilog还是在vhdl中都是一种相当高效的电路描述方式。 -
例化的操作方法在实际电路中又是什么样的呢?
在第一段中我们通过一种比较通俗的方法来理解例化的过程。实际上,例化是指通过硬件描述语言来实现模块端口或者是线网间的映射关系。
实例化的两种方法
以以下一段已经給出模块的代码作为引例:
/*四位加法器模块*/
module BCD_4bit(A,B,cin,cout,sum);
input [3:0]A,B;
input cin;
output cout;
output [3:0]sum;
reg [4:0]middle;//用于存放中间计算结果
reg cout;
reg [3:0]sum;
always @(A,B,cin) begin
middle=A+B+cin;
if (middle>9)
{
cout,sum}=middle+6;
else
{
cout,sum}=middle;
end
endmodule
观察上面这段代码可以发现,在不具体了解代码功能(也就是内特性)的时候,我们依旧可以通过观察知道其外特性(也就是端口特性),可以发现:这个电路模块有三个输入端口和两个输出端口,并且其各自的端口名已经在模块内部定义(关于BCD四位加法器的代码原理不再详述,笔者会在文末附件中作简单的解释),那么在使用到这个模块的电路时就需要为这些内部端口与外部进行列连接,以笔者这次碰到的题目(题目传送门:HDLBits中16位BCD加法器)为例。题目:使用已写好的四位BCD加法器来实现16位加法器。
- 分析:整个16位BCD加法器的外特性为:
input [15:0] a, b,
input cin,
output cout,
output [15:0] sum );
先看最低的四位BCD加法器输入,它们的组成除了两个被加数的低四位A[3:0]和B[3:0]以外,还有一个一位的进位输入cin,而它们的加法结果输出经过要调用的***第一个4位BCD加法器(也就是第一个BCD_4bit)*** 的逻辑运算后,输出构成了sum[3:0]的结果,同时还有一个一位进位输出"cout"(此处加双引号的目的是cout此时作为内部端口名出现)。根据我们对加法器的理解,低位的进位输出就是高位的进位输入(也就是下一个4位BCD加法器的进位输入端)。但这时我们还需要申请线网变量矢量reg来存放进位输入和输出进位位的中间变量,此时观察可以发现,由于只需要四个四位BCD加法器模块就可以构成16位BCD加法器,装载输入输出进位位的 中间变量矢量宽度为3 即可,因为最后一位的内部端口(“cout”)就是整个16位加法器电路模块的进位输出cout。