《逻辑与计算机设计基础(原书第5版)》——2.9 硬件描述语言—VHDL

简介: 本节书摘来自华章计算机《逻辑与计算机设计基础(原书第5版)》一书中的第2章,第2.9节,作者:(美)M.莫里斯·马诺(M. Morris Mano)著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

2.9 硬件描述语言—VHDL

由于硬件描述语言用来描述和设计硬件,故在使用该语言编程时,应牢记底层的硬件实现,特别是当你的设计将用来综合时。例如,如果忽略将要生成的硬件,那么你可能会用低效的硬件描述语言设计出一个大且复杂的门级结构,而实际上只需少量门的简单结构即可实现。出于这种原因,我们开始重点讲述用VHDL语言详细地描述硬件,然后再进行更抽象的高层次的描述。
本章所选的实例用于说明VHDL是一个很好地描述数字电路的可选方法。首先,我们采用结构化的描述方法,用VHDL而不是原理图对图2-27中的二位大于比较器电路进行描述。这个例子介绍了VHDL的许多基本概念。image
然后,我们采用高层次的行为描述方式设计这个电路,以进一步介绍VHDL的基本概念。
例2-16 二位大于比较器电路的VHDL结构描述
图2-28给出了图2-27中二位大于比较器电路的VHDL描述。这个实例可以用来说明VHDL的许多常见特性和电路的结构描述。

image

两条短线“--”和行末之间的语句称为注释(comment),图2-28中的描述一开始是两行注释,用以说明该程序的功能以及与图2-27的关系。为了便于说明该描述,在每行的右边采用注释标注了行号。作为一种语言,VHDL有其语法规则,它准确地描述了可以使用的合法结构。这个实例将介绍VHDL语法的一些内容,特别要注意描述中分号、逗号与冒号的用法。
首先,我们跳过第3、4行,将注意力集中到整个结构上。第6行声明了一个实体(entity),这是VHDL设计中的一个基本单元。像对原理图中的一个逻辑符号一样,在VHDL中我们需要对设计命名,定义其输入/输出端口,这些是实体声明(entity declar-ation)的职能。entity和is是VHDL中的关键词。用粗体标示的关键词有特殊的含义,不能用来命名实体、输入/输出端口或者信号。语句entity comparator_greater_than_structural is声明了一个名为comparator_greater_than_structural的设计。VHDL大小写不敏感(例如,用相同字母的大写或小写命名的名字和关键词不能区分)。COMPARATOR_greater_than_Structural和comparator_Greater_than_structural以及comparator_greater_than_Structural是相同的。
接下来,从第7~9行的端口声明(port declaration)用来定义输入和输出端口,就像在原理图中对逻辑符号所做的那样。对于这个设计实例,它有二个输入信号:A和B。这些信号通过模式in指定为输入端口。同样,A_greater_than_B通过模式out指定为输出端口。VHDL是一种强类型语言,所以输入和输出信号的数据类型必须事先声明。在此例中,输出信号的类型为std_logic(标准逻辑类型(standard logic))。类型声明指定了输入输出信号的值以及对这些信号可能执行的操作。标准逻辑类型有9个值,其中包括常用的二进制值0和1以及两个附加值X和U。X表示未知值,U表示未初始化。我们选择使用标准逻辑,因为一般的仿真工具都用到这些值。
输入A和B说明了VHDL的另一个概念,即std_logic_vector(标准逻辑向量)。两个输入中的每一个都是二位宽,因此把它们定义为std_logic_vector,而不是独立的std_logic信号。我们使用下标来对向量寻址。由于A包含两个编号为0和1的输入信号,1是最高有效位(最左边),故A的下标是由1降至0。这个向量的成员是A(1)和A(0)。同样,B包含两个编号为1和0的输入信号,故它的下标也是由1降至0。从第32行开始,注意std_logic_vector类型的信号是如何通过指定信号名与用括号括起的下标来引用的。如果希望向量的下标由小到大显示,那么在VHDL中可采用另一种不同的标记方法。例如,signal N:std_logic_vector(0 to 3)定义了信号N的第一位(最左边)为N(0),最后一位(最右边)为N(3)。也可以引用子向量(例如,N(1 to 2),表示引用N的中间两个信号N(1)和N(2))。
为了使用std_logic和std_logic_vector类型,有必要对该类型的值和操作进行定义。为方便起见,我们可以采用一个由预编译的VHDL代码组成的程序包(package)来完成预定义。包一般存放在称为库(library)的目录中,而库可被一些或所有用户共享。对于std_logic,基本包是ieee.std_logic_1164,这个包定义了std_logic与std_ulogic类型的值和基本的逻辑操作。为了使用std_logic,我们在第3行调用了包含包的ieee库,在第4行调用了ieee.std_logic_1164.all包,表示我们会用到ieee库中ieee.std_logic_1164包内的所有定义。另外,lcdf_vhdl库包含了func_prims包,该包用VHDL语言描述了基本的逻辑门、锁存器和触发器,我们通过all调用该包中的所有内容。lcdf_vhdl库的ASCII码格式可从本书的配套网站上下载。注意,第3、4行语句后紧跟着实体部分。如果另一个实体也将用到std_logic类型和fun_prims中的元件,那么库和使用语句必须重复放在实体声明之前。
实体声明以关键词end结束,其后紧跟实体名。到目前为止,对于这个电路我们已经讨论了与原理图中逻辑符号等效的VHDL描述
结构化描述 接下来,我们要描述电路的功能。实体功能的描述称作实体的结构体(architecture),因此第12行声明了实体comparator_greater_than_structural的结构体structural。以下将介绍结构体的详细语法。在此实例中,根据图2-27的电路图,我们采用与原理图等价的结构化描述(structural description)方式来设计电路。
首先,在第15~29行声明了我们将在描述中要用到的门类型。由于我们采用门来实现电路,所以声明了一个反相器NOT1,一个二输入与门AND2,一个三输入与门AND3和一个三输入或门OR3作为组件(component)。这些门的VHDL描述包含在包func_prims中,包func_prims包含了这些门的实体与结构体。组件声明中的名字与端口声明必须与其对应的实体完全一致。对于NOT1,端口指定的输入名为in1和输出名为out1。对于AND2,其组件声明部分中输入名为in1和in2,输出名为out1。类似地,对于AND3和OR3,其组件声明部分中输入名为in1、in2和in3,输出名为out1。
接下来,在根据电路图确定这些门的相互连接之前,我们需要对电路中的所有节点进行命名。输入和输出已经命名了。图2-27中的内部节点是两个反相器的输出以及三个与门的输出,这些输出节点声明为std_logic类型的信号。not_B1和not_B0是两个反相器的输出信号,and0_out、and1_out和and2_out是三个与门的输出信号。同样,端口中声明的所有输入和输出都是信号。在VHDL中有信号和变量。变量的赋值是立即有效的。相反,信号的赋值不即刻有效,它在未来的某个时间被赋值。这个时间可以是物理时间,例如当前时间之后的2 ns,也可以是增量时间(delta time),如一个信号在当前时间上加上一个增量时间后被赋值。增量时间可以看作一个无穷小的时间量。信号赋值的时间延迟对典型的数字模拟器的内部操作来说是必不可少的,当然,基于门延时可使电路仿真结果更接近实际。但为简单起见,我们通常是验证电路功能的正确性,而不是其性能或者延时问题。对于这样的功能仿真,将时延默认为增量时间是最容易的。因此,在电路的VHDL描述中不涉及时延,但在测试程序中可能出现。
在内部信号的声明之后,以关键词begin开始结构体的主体部分。这个电路的描述由两个反相器、一个二输入与门、两个三输入与门和一个三输入或门组成。第32行给出了第一个反相器的标号为inv_0,指示了这个反相器是NOT1组件。接着是端口映射(port map),将反相器的输入与输出端口映射到相连接的信号上。信号间的映射通过符号=>关联,符号左边是门的端口,右边是所连接的信号。例如,反相器inv_0的输入是B(0),输出是not_B0。
从第33~37行给出了剩下的5个门以及与它们的输入输出端口相连的信号。这5个门使用了另外一种方法来映射逻辑门的端口。这种方法没有显式地给出元件的输入输出名称,而是假定在端口映射中连接的信号顺序与引用的元件的端口顺序一致。这样我们可以按元件端口的顺序列举信号,从而隐式地指定信号之间的连接。例如在33行,B(1)连接到输入,not_B1连接到输出。结构体以关键词end加其结构名structural结束。 ■
数据流描述法 数据流描述法是根据功能而不是结构来描述电路的,它由并发赋值语句或与之等价的语句组成。只要语句右边的一个值改变,并发赋值语句就并发(也就是并行)执行。例如,任何时候一个布尔表达式右边的某个值发生变化时,其左边的信号就会被赋值。例2-17举例说明由布尔表达式组成的数据流描述的使用方法。
例2-17 二位大于比较器电路的VHDL数据流描述
图2-29给出了图2-27中二位大于比较器电路的VHDL数据流描述。这个例子用来说明由布尔表达式组成的数据流描述方法。该程序中的库、包的使用及实体声明部分与图2-28中的相同,故在此不再重复。数据流描述从第15行开始,信号B0_n与B1_n分别通过对输入信号B(0)和B(1)进行not操作实现赋值。在第17行,B1_n和A(1)组合通过and运算得到and0_out。信号and1_out、and2_out和A_greater_than_B在第18~20行中,采用类似方法得到,A_greater_than_B使用了or运算。大家可以看到,数据流描述比图2-28中的结构描述要简单得多。

image

赋值语句执行的顺序与这些语句在模型描述中出现的顺序无关,但与赋值语句右边信号变化的顺序有关。因此,如果将图2-29中的赋值语句按其他顺序重写,例如把第15行与第20行调换,程序的行为是完全一样的。 ■
行为描述 使用并发赋值语句的数据流模型可以认为是行为描述,因为它们描述了电路的功能而不是它的结构。正如我们将在第4章介绍的那样,VHDL还提供使用在过程中按顺序执行的赋值语句来描述行为的方法,这种方法被称为算法模型化。但即使是使用并发赋值语句的数据流模型,VHDL也能够提供比逻辑级更为抽象的电路描述。
例2-18 使用when-else的二位大于比较器的VHDL描述
在图2-30中,我们使用when-else语句而不是根据电路结构得到的类似布尔方程的语句来描述多路复用器。这种电路模型使用电路所期望的数学运算而不是布尔逻辑,来描述电路的行为(例如,当A大于B时输出为1,否则为0)。只要A或者B发生变化,when后的条件将重新计算并进行相应的赋值。 ■
例2-19 使用with-select的二位大于比较器的VHDL描述
with-select是when-else的一个变种,用该语句描述的模型见图2-31。在表达式中,决策变量位于with与select之间。由表达式的值来选择赋值,表达式的值位于when的后面,每一对表达式值和赋值用逗号分开。在这个例子中,A是一个信号,它的取值决定了分配给A_greater_than_B的值。对于这个例子,A用于选择B的一个函数当作合适的输出。当A=“00”时,0赋给输出,因为对于B的所有组合函数为0。当A=“01”,输出只在B=“00”时为1,这是两位B的或非函数。当A=“10”,输出在B(1)为0时等于1,在B(1)为1时等于0,因此赋值函数是B(1)的非。当A=“11”时,输出除B=“11”时均等于1,它是两位B的与非函数。最后,当A是其他值时(when others),输出赋值为‘X’。这里的others代表没有指定的标准逻辑组合,如A的一位既不是0也不是1,比如是U。

image

这个例子对于这个特定的电路来说显得有点不自然,结果是没有像以前的方法那样直观。但是,这个例子介绍了一种非常有用的,用一组条件选择多个函数的方法。我们将在后面的章节中看到使用这类方法的电路的例子,特别是在有关多路复用器的第3章和有关寄存器传输的第6章。

image

注意when-else允许用多个不同的信号来进行决策。例如,一个模型中可以用第一个when将一个信号作为条件,在else部分用另外一个when将另一个不同的信号作为条件,等等。相反,with-select仅允许一个单一的布尔条件(如:要么是第一个信号,要么是第二个信号,但不能是两个信号)。另外,对于典型的综合工具,when-else语句会比with-select语句综合出一个更复杂的逻辑结构,因为when-else依赖于多个条件。 ■
测试程序(测试平台,测试床) 我们在第2.8节已经简要介绍过测试程序是硬件描述语言的一种模型,它的目的是用来测试另外的模型,通常称之为被测设备(DUT),测试时给输入提供激励。更复杂的测试程序还要分析被测设备的输出以保证正确性。图2-32对二位大于比较器电路给出了一个简单的VHDL测试程序。这个测试程序有几个方面与所有测试程序是一样的。第一,实体声明部分没有任何输入或输出端口(第5~6行)。第二,测试程序的结构体为DUT声明了元件(第11~15行),然后对DUT进行实例化(第17行)。结构体还声明了将要连接到DUT的输入与输出信号(第9~10行)。最后,结构体向DUT加载各种输入组合以对其在不同条件下进行测试(第18~29行)。输入值用一个称为tb的进程进行加载,进程是一个按顺序执行的语句块。这个测试程序中的tb进程在模拟开始时启动,给DUT的输入赋值,在两次赋值之间等待10 ns模拟时间,然后以永久等待实现停机。为了简单明了起见,这个例子中的进程仅使用了少量的输入组合,但它确实测试了A与B之间关系的所有三种情况(A<B,A=B和A>B)。在第4章将更详细的介绍进程,那时会讲解大量的可用于进程的顺序语句。
至此,我们完成了组合电路的VHDL介绍。在第3章和第4章我们将用语言的另外一些特点来描述更复杂的电路,从而继续加深对VHDL的了解。

image

相关文章
|
测试技术
《逻辑与计算机设计基础(原书第5版)》——2.10 硬件描述语言—Verilog
本节书摘来自华章计算机《逻辑与计算机设计基础(原书第5版)》一书中的第2章,第2.10节,作者:(美)M.莫里斯·马诺(M. Morris Mano)著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1645 0
|
存储 测试技术
《逻辑与计算机设计基础(原书第5版)》——2.8 硬件描述语言简介
本节书摘来自华章计算机《逻辑与计算机设计基础(原书第5版)》一书中的第2章,第2.8节,作者:(美)M.莫里斯·马诺(M. Morris Mano)著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1530 0
《逻辑与计算机设计基础(原书第5版)》——第3章 3.0组合逻辑电路的设计
本节书摘来自华章计算机《逻辑与计算机设计基础(原书第5版)》一书中的第3章,第3.0节,作者:(美)M.莫里斯·马诺(M. Morris Mano)著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1309 0
《逻辑与计算机设计基础(原书第5版)》——第2章 2.0组合逻辑电路
本节书摘来自华章计算机《逻辑与计算机设计基础(原书第5版)》一书中的第2章,第2.0节,作者:(美)M.莫里斯·马诺(M. Morris Mano)著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1221 0
|
存储 开发工具 异构计算
第三章 硬件描述语言verilog(二) 功能描述-组合逻辑(下)
第三章 硬件描述语言verilog(二) 功能描述-组合逻辑
614 0
第三章 硬件描述语言verilog(二) 功能描述-组合逻辑(下)
|
算法 芯片 计算机视觉
第三章 硬件描述语言verilog(二) 功能描述-组合逻辑(上)
第三章 硬件描述语言verilog(二) 功能描述-组合逻辑
561 0
第三章 硬件描述语言verilog(二) 功能描述-组合逻辑(上)
|
异构计算
第三章 硬件描述语言verilog(二) 功能描述-组合逻辑(中)
第三章 硬件描述语言verilog(二) 功能描述-组合逻辑
201 0
第三章 硬件描述语言verilog(二) 功能描述-组合逻辑(中)
|
存储 算法 C++
《逻辑与计算机设计基础(原书第5版)》——1.2 计算机系统设计的抽象层次
本节书摘来自华章计算机《逻辑与计算机设计基础(原书第5版)》一书中的第1章,第1.2节,作者:(美)M.莫里斯·马诺(M. Morris Mano)著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
2046 0
《逻辑与计算机设计基础(原书第5版)》——3.5 译码
本节书摘来自华章计算机《逻辑与计算机设计基础(原书第5版)》一书中的第3章,第3.5节,作者:(美)M.莫里斯·马诺(M. Morris Mano)著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1711 0