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

2.10 硬件描述语言—Verilog

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

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

两条斜线“//”和行末之间的语句称为注释,图2-33中的描述一开始是两行注释。对于比一行还长的注释,也可以选用“/*”来标明:
《逻辑与计算机设计基础(原书第5版)》——2.10 硬件描述语言—Verilog

为了便于说明Verilog描述,在每行的右边采用注释标注了行号。作为一种语言,Verilog有其语法规则,它准确地描述了可以使用的合法结构。这个实例将介绍Verilog语法的一些内容,特别要注意描述中逗号与分号的用法。逗号“,”通常用来分隔一个列表中的各个元素,而分号“;”则用来结束一个Verilog语句。
从第3行开始声明模块(module),这是Verilog设计中的一个基本单元。剩余的行对模块进行了定义,直到第15行以endmodule结束,注意在endmodule后面没有分号。像对原理图中的一个逻辑符号一样,我们需要对设计命名,定义其输入/输出端口,这些是第3行模块语句(module statement)和其后的输入和输出声明(input and output declaration)的职能。module、input和output是Verilog中的关键词。用粗体标示的关键词有特殊的含义,不能用来命名模块、输入、输出或者信号线。语句module comparator_greater_than_structural声明了一个名为comparator_greater_than_structural的设计或设计的一部分。另外,Verilog中的名字对大小写敏感(例如,用相同字母的大写或小写命名的名字是不同的)。COMPARATOR_greater_than_Structural、Comparator_greater_than_structural和comparator_grea-ter_than_Structural都是不同的名字。
正如我们在原理图中对逻辑符号所做的那样,我们要在模块语句中对比较器的输入和输出命名。接下来,用输入声明(input declaration)定义模块语句中的哪些名字是输入。对于这个设计例子,有两个输入信号A和B。事实上,这些输入是用关键字input来指定的。同样,用输出声明(output declaration)定义输出。信号A_greater_than_B用关键字output定义为输出。
Verilog中的输入和输出以及其他二进制信号类型可以取4个值中的某一个值。0和1是两个明显的值,另外再加上表示未知值的x和在三态逻辑输出中表示高阻的z。Verilog还有强度值,当它们与已给的4个值组合时可以提供120种可能的信号状态。强度值在电子电路模型中使用,因此这里对其不予考虑。
输入A和B还可说明Verilog关于向量的概念。在第4行,A和B被指定为叫做向量(vector)的多位的线,而不是一位的线。向量中的位用一个范围内的整数来命名,这个范围通过给出最大值和最小值来确定。给定这两个值我们就可以确定向量的宽度和每一位的名字。“input [1:0] A,B”这一行说明A和B都是一个两位宽的向量,最高有效位(最左边)命名为1,最低有效位(最右边)命名为0。A由A[1]和A[0]组成。一旦向量被声明,则整个向量或向量的一部分就可以被引用。例如,A代表两位的A,A[1]代表A的最高有效位。从第8行、第9行,一直到第12行,用这种引用方式说明门实例的输出和输入。而且,Verilog允许向量的最大索引放在后面。例如,input [0:3] N定义输入端口N作为一个四位向量,这里最高有效位(最左边)编号为0,最低有效位(最右边)编号为3。
结构化描述 接下来,我们要描述电路的功能。在此,我们使用与图2-27中所示原理图等价的结构化描述(structural description)。注意,原理图由门组成。Verilog提供14种基本门作为关键字。当然,我们现在只对其中的8种有兴趣,它们是:buf(缓冲器)、not(非门,也称反相器—译者注)、and(与门)、or(或门)、nand(与非门)、nor(或非门)、xor(异或门)和xnor(异或非门)。buf和not只有一个输入,其他所有门可以有两个及以上任意整数个输入。buf的功能表达式为z=x,x是输入,z是输出。buf是放大电信号的放大器,可以用来驱动大的扇出,或是减少延迟。xor是异或门,nxor是异或非门,它是异或门的非。在这个例子中,我们只用not、and和or三种类型的门,它们如图2-33中的第7~14行所示。
在根据电路网表确定这些门的相互连接之前,我们需要对电路中的所有节点进行命名。输入和输出已经命名了。图2-27中的内部节点是两个反相器的输出以及三个与门的输出。在第6行,这些节点用关键字wire声明为线(wire)。名字B0_n和B1_n是反相器的输出,and0_out、and1_out和and2_out是与门的输出。在Verilog中,wire是默认的节点类型,尤其是input和output端口的默认类型就是wire。
在内部信号声明的后面,电路描述包括两个反相器、一个二输入与门、两个三输入与门和一个三输入或门。语句由一个门类型后面跟着一个相同门类型实例的列表构成,实例之间用逗号分开。每一个实例由门的名字和放在括号里的门输出与输入组成,输入输出之间用逗号分隔,输出放在前面。第一个语句在第7行,门类型为非门(not)。接下来是反相器inv0,它的输出是B0_n,输入是B0。Inv1与inv0类似。第9~14行分别是剩下的4个门以及连接到它们的输出与输入的信号。例如,第12行定义了一个名为and2的三输入与门实例,它的输出是and2_out,输入分别是A[0]、B1_n和B0_n。这个模块用关键字endmodule结束。 ■
数据流描述法 数据流描述法根据功能而不是结构来描述电路,它由并发赋值语句或与之等价的语句组成。只要语句右边的一个值改变,并发赋值语句就并发(即并行)地执行。例如,只要一个布尔表达式右边的某个值发生变化,那么其左边的值就要重新计算。例2-21说明由布尔表达式组成的数据流描述的使用方法。
例2-21二位大于比较器的Verilog数据流描述
图2-34给出了二位大于比较器的Verilog数据流描述。该数据流描述在这里特意使用了由关键字assign后跟一个布尔等式组成的赋值语句。在这样的等式中,我们使用表2-4所示的位布尔运算符。在图2-34的第7行,B1_n用运算符“~”表示为B[1]的非。在第9行,A[1]和B1_n用“&”运算符“与”在一起,并将组合结果赋值给输出and0_out。线and1_out和and2_out用同样的方法在第10行和第11行中进行定义。输出A_greater_than_B在第12行通过对线and0_out、and1_out和and2_out实行或操作“|”进行赋值。

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

赋值语句执行的顺序与这些语句在模型描述中出现的顺序无关,但与赋值语句右边信号变化的顺序有关。因此,如果将图2-34中的赋值语句以不同顺序重写,例如把第7行与第12行调换,程序的行为完全是一样的。 ■
行为描述 使用并发赋值语句的数据流模型可以认为是行为描述,因为它们描述了电路的功能而不是它的结构。正如我们将在第4章介绍的那样,Verilog还提供使用在进程中按顺序执行的赋值语句来描述行为的方法,这种方法被称为算法模型化。但即使是使用并发赋值语句的数据流模型,Verilog也能够提供比逻辑级更为高级的电路描述。
例2-22 使用条件操作的二位大于比较器的Verilog描述
图2-35中的描述在第6行用条件操作符“?:”实现了电路的功能。如果“?”前面括号内的逻辑值为真,则“:”前面的值赋给目标信号,这里就是信号A_greater_than_B;如果逻辑值为假,则“:”后面的值赋给目标信号。值“1’b1”表示一个常量,第1个1表示常量包含一位,“’b”代表常量用二进制表示,后面的1给出常量的值。在这个例子中,如果条件A>B为真,则A_greater_ than_B赋值为“1’b1”,否则A_greater_than_B赋值为“1’b0”。

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

例2-23 二位大于电路的Verilog行为模型
图2-36给出了使用条件运算的另外一种数据流描述,它是扩展使用条件运算的一个例子。逻辑相等操作用“=”表示。假设我们考虑A= 2'b00的情况。“2'b00”代表一个常量,“2”表示这个常量包含2位,“b”说明常量用二进制表示,“00”给出常量的值。因此,如果向量A等于00,则表达式的值为真,否则为假。如果表达式为真,则A_greater_than_B赋值为“1'b0”。如果表达式为假,则下一个包含“?”的表达式将进行计算,等等。在这个例子中,为了计算一个条件,必须将这个条件所有原来的值设置为假。如果没有一个计算出来的值是真的,以使我们作出决策,则将缺省值“1'bx”赋给A_greater_than_B。我们曾经讲过,缺省值x代表不知道。

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

这个例子对于这个特定的电路来说显得有点不自然,没有像以前的方法那样直观。但是,这个例子介绍了一种非常有用的,用一组条件选择多个函数的方法。我们将在后面的章节中看到使用这类方法的一些电路的例子,特别是在有关多路复用器的第3章和有关寄存器传输的第6章。 ■
例2-24 二位大于电路的Verilog行为描述
作为二位大于电路的最后一个例子,图2-37在比布尔等式高得多的抽象层次上描述了这个电路的行为。这个描述简单地使用一种带“>”数学运算的赋值语句实现了所期望的功能。 ■

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

测试程序(测试平台,测试床) 我们在第2.8节已经简要介绍过测试程序是硬件描述语言的一种模型,它的目的是用来测试另外的模型,通常称之为被测设备(DUT),测试时给输入提供激励。更复杂的测试程序还要分析被测设备的输出以保证正确性。图2-38对二位大于比较器电路给出了一个简单的Verilog测试程序。这个测试程序有几个方面与所有测试程序是一样的。第一,模块声明部分没有任何输入或输出端口(第2行)。第二,测试程序声明了要连接到DUT输入与输出的寄存器(变量)(第3~4行),并对DUT进行实例化(第5行)。最后,测试程序向DUT加载各种输入组合以对其在不同条件下进行测试(第6~16行)。输入值用一个过程来进行加载,过程是一个按顺序执行的语句块。因为A和B在过程中当作变量赋值,而不是连续地赋值,所以A和B必须声明为reg类型而不是wire类型(第3行)。测试程序中的这个过程在模拟开始时进行initial(第6行),给DUT的输入赋值,在两次赋值之间等待10个时间单位的模拟时间。在Verilog中,延迟用一个数字符号(#)后跟一个数字组成。为了简单明了起见,这个例子中的过程仅使用了少量的输入组合,但它确实测试了A与B之间关系的所有三种情况(A<B,A=B和A>B)。在第4章将更详细地介绍过程,那时会讲解大量的可用于过程的顺序语句。

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

至此,我们完成了组合电路的Verilog介绍。在第3章和第4章我们将用语言的另外一些特点来描述更复杂的电路,从而继续加深对Verilog的了解。

上一篇:C# using Sendkey function to send a key to another application


下一篇:移动开发在路上-- IOS移动开发系列 多线程三