2.1 什么是HDL
知识分部网络
2.1.1 HDL及其特点
HDL(Hardware Description Language,硬件描述语言)是一种用文本方式来描述数字电路和数字系统的语言。
设计者利用HDL来描述一个数字系统,首先编写设计文件。然后利用EDA工具进行逻辑综合和仿真,进行功能验证,最后自动生成能在ASIC或FPGA上具体实现的逻辑网表,并对产生的电路进行优化。
数字系统的设计、综合、仿真及验证都可以利用HDL实现,这种综合设计方法已经成为数字系统的主流设计方法,与传统的人工设计电路原理图的方法相比,它采用自顶向下的设计方式,便于设计的早期规划、分工协作、设计功能验证,从而大大缩短了产品开发的周期。
目前最常用的硬件描述语言是VHDL和Verilog HDL,这两种语言都有IEEE(美国电气和电子工程师协会)标准。VHDL是Very High Speed Integrated Circuit HDL的缩写,语法比较烦琐,关键字较长,学习较困难,对电路的行为描述能力较强,但对开关级电路描述能力不强。与VHDL相比,Verilog对底层电路描述能力较强,而行为描述能力较VHDL弱,但它类似于C语言,语法简洁,结构自由,入门较易,可使设计者集中精力在设计工作中,而不必花费太多的时间在语言和语法的学习上,并且用Verilog HDL编辑的程序代码长度只是VHDL的一半,因此现代工业广泛采用Verilog HDL进行电路系统设计。
小资料
VHDL在1985年正式推出,其开发背景源于美国国防高级研究计划局(DARPA)提出的超高速集成电路计划,目的是在各个承担美国国防部订货的集成电路厂商之间建立一个标准的设计数据格式。VHDL于1987年成为IEEE标准(IEEE Standard 1076—1987)。
1983年,GDA(Gateway Design Automation)公司开发了Verilog HDL,最初只设计了一个仿真与验证工具,之后又陆续开发了相关的故障模拟与时序分析工具。1985年Moorby推出了它的第三个商用仿真器Verilog-XL,获得了巨大成功,从而使Verilog HDL得到迅速推广和应用。1989年Cadence Design Systems公司收购了GDA公司,从此对Verilog和Verilog-XL模拟器拥有全部的财产权。1990年Cadence公司公开发表了Verilog HDL。随着技术发展,Cadence公司采取了开放标准的路线,将Verilog转放到公众开放领域OVI(Open Verilog International)组织以促进Verilog HDL语言的发展,1995年Verilog HDL成为IEEE标准,即IEEE Standard 1364—1995,我们通常称这个标准为Verilog 5。随后,人们向IEEE提交了一个改善了原始的Verilog—95标准缺陷的新标准。这一扩展版本成为IEEE 1364—2001标准,也就是Verilog 2001。
2.1.2 Verilog电路模块的一般结构
1.电路建模的概念
用Verilog HDL描述的电路设计称为模块,也就是该电路的Verilog HDL模型。模块描述某个电路的功能或结构以及与其他模块通信的外部接口,是Verilog的基本描述单位。用Verilog语言编写代码来设计一个电路的过程,也就称为对电路建模的过程。
2.Verilog HDL模块的一般结构
用Verilog HDL语言来定义一个电路的模块,必须符合一定的语法结构和基本规则。下面采用任务3中的2输入与非门电路模块nand2_ex1.v来认识Verilog代码的基本结构。
行号 代码 1 // nand2_ex1.v 2 module nand2_ex1( //定义2输入与非门电路模块nand2_ex1 3 a, //模块的外部输入/输出端口列表 4 b, 5 f 6 ); 7 input a,b; //a、b为输入端口 8 output f; //f为输出端口 9 nand inst1 (f,a,b); //调用Verilog内部预定义的门原语nand 10 endmodule
第一行:注释文字。
第26行:用关键字module定义了模块的名字nand2_ex1,其后用圆括号( )列出了模块的所有对外输入/输出端口a、b和f,并且将输入端口a、b列在前面,输出端口f列在后面。
第7行:用关键字input说明端口a、b是输入端口。
第8行:用关键字output说明端口f是输出端口。
第9行:调用了Verilog内部预定义的门级原语nand来说明输入/输出信号之间的逻辑关系。
第10行:用关键字endmodule来结束电路模块nand2_ex1的定义。
可以看出,用Verilog HDL描述一个电路模块必须做以下两件事情:
第一:模块声明和端口类型声明。首先定义设计模块,包括给模块命名并确定输入和输出信号线(称为端口,port),也称为模块声明(以上代码的第26行),其次必须对该模块各个端口的输入/输出类型进行声明,即端口类型声明(以上代码的第78行)。
第二:必须确定该模块的实际操作、输入和输出的关系,也称为模块的逻辑功能描述(以上代码的第9行)。
小经验
为了使代码具有可读性好和可维护性高的特点,要求用多行注释符“/*……*/”或单行注释符“//”对代码段或语句做必要的注释说明。例如,模块nand2_ex.v在程序中首先在第1行用单行注释符来注释说明2输入与非门电路模块的Verilog代码名是nand2_ex.v。
注意:注释行不被编译,仅起注释作用。
一般地,我们习惯称所编写的设计内容为“代码”,而不叫“程序”,因为用硬件描述语言表述的是一个物理上存在的电路,本身不是应该被运行的“程序”。但是通常可以把验证代码是否正确的验证代码称之为验证程序,因为这些验证代码是可以运行的,用来检测设计是否正确。
假定,一个通用的Verilog HDL电路模块结构如图2.6所示,下面以该电路为例介绍Verilog代码的一般描述方法。
对电路模块描述的内容都是嵌在关键字module和endmodule之间的,其基本架构如下:
module 模块名(port1,port2,…,portn); 端口声明语句块; 逻辑功能描述语句块; endmodule
图2.6 通用的Verilog模块
(1)模块声明。模块声明包括模块名字和模块输入/输出端口列表,格式如下:
module 模块名(port1,port2,…,portn);
模块声明以关键字module开始,后面紧接着模块名,在圆括号内列出模块的所有输入/输出端口,后面必须加上作为行结束符的分号“;”。
小经验
一般地,EDA工具对中文的支持不是很好,而且EDA设计一般会跨越Windows和Linux平台,所以对于命名需要注意规范形式。一般地,建议使用字母或者下画线开头,整个路径以及文件名、模块名中不要出现空格、中文。此外,项目工程不能保存在根目录下。同时应注意,Verilog语言对字母大小写是敏感的。
模块定义以关键字endmodule结束,此时不须使用行结束符的分号“;”。
(2)端口声明语句块。
完成了模块声明语句后,还必须明确说明模块的端口类型。一个电路模块与外界连接和通信的端口有3种类型,分别是输入端口(input)、输出端口(output)和输入/输出双向端口(inout)。端口类型声明语句格式如下:
input 端口名1,端口名2,……; //声明输入端口 output 端口名1,端口名2,……; //声明输出端口 inout 端口名1,端口名2,……; //声明双向端口
小提示
端口声明语句仍然使用分号“;”表示语句行的结束。
(3)逻辑功能描述语句块。
建模中最重要的部分是正确地描述模块逻辑功能,也就是需要定义f(port1,port2,…,portn)是什么。描述和定义模块逻辑功能的方法通常采用结构描述、数据流描述以及行为描述三种方式,下面分别加以简单介绍。
- 方法一:调用库元件的结构描述方式。在Verilog HDL语言中,可以通过调用原语元件的方式来描述电路的结构,这种方法类似于在电路图输入方式下调用库元件来完成设计。例如,在任务3中,2输入与非门建模时采用的语句:“nand inst1 (f,a,b);”,调用了库原语元件nand,说明了库元件的实例引用名为inst1,将库元件的引脚连接到模块的相应信号端口。
- 方法二:使用连续赋值语句“assign”的数据流描述方式。
对任务3的2输入与非门电路建模也可用如下代码来实现:
由关键字assign引出的是连续赋值语句。连续赋值语句不间断地监视等式右端的变量,每当这些变量中有任何一个发生变化,右端表达式就被重新赋值,并将结果传给等式左端进行输出。这种描述方法简单,只须将逻辑表达式放在关键字assign后面即可。
小知识
assign连续赋值语句的赋值操作符是普通的赋值操作符“=”,通过定义数据信号的“流程”来描述模块,一旦其输入端发生变动,输出端也随之而改变,因此用连续赋值语句描述模块逻辑功能的方式也称为数据流描述方式,一般用于组合电路的逻辑功能描述,它可以看成是行为级模块的一种。
关于assign的具体描述参见2.3节。
- 方法三:使用always过程块的行为描述方式。
任务3的2输入与非门建模时还可采用如下方式:
在上述代码中,关键字always引出的语句称为always过程语句。always过程语句的执行是需要触发条件的,触发条件列在圆括号里,称为敏感信号表达式,如“a or b”,表示当敏感信号a或b(输入端口)发生变化时,逻辑表达式就将随之发生一次变化,执行过程赋值语句“f<=~(a&b);”一次。这里的always具有循环等待的含义,即循环等待敏感信号表达式是否发生变化,一旦发生变化,就执行逻辑表达式一次。
根据以上不同的模块逻辑功能描述方式,我们可以了解到,Verilog HDL程序有三种描述设计的方式:
- 结构描述方式;
- 行为描述方式;
- 数据流描述方式。
小资料
一个电路模块既可以用结构方式建模,也可以用行为描述方式建模,还可以采用数据流方式建模,实际的建模过程往往会综合使用这三种方式来实现。
一个电路系统的Verilog模块,可以采用结构级描述方式进行建模,如任务3中的代码nand2_ex1.v。也可以用行为描述方式的代码风格来建模,如代码nand2_ex2.v和nand2_ex3.v。Verilog模型共有五种不同抽象级别的描述风格。
① 系统级(system-level)。系统级建模方式用Verilog语言来抽象地描述电路的外部性能,目前这种描述方式建立的电路模型不一定能综合出实际的标准门级电路。
② 算法级(algorithm-level)。算法级建模风格是用Verilog语言来构造电路输入/输出的行为算法程序,这种描述方式可读性好,容易理解,但所描述的算法与硬件之间没有明显的对应关系,因此不是所有的算法级描述方式建立的电路模型都能综合出实际的标准门级电路。
③ RTL级(register transfer level)。数据流/寄存器传输级的建模编程通常是处理和控制数据如何在寄存器之间传送,RTL级模型和逻辑电路有着明确对应的关系,一般来说都能综合出实际的硬件电路。
④ 门级(gate-level)。门级建模是结构级描述风格,描述的是逻辑门和逻辑门之间的连接,因此所建立的模型与逻辑电路有明确的对应关系。
⑤ 开关级(switch-level)。开关级模型是建立在底层物理器件基础上的,描述的是器件级的晶体管之间的连接关系。
系统级、算法级和RTL级都属于行为级,门级属于结构级。大多数的电路设计都采用易于用逻辑表达式描述的行为描述方式,而通常只有RTL级这样的行为级描述能够综合出实际的硬件电路,因此行为级的建模通常就是RTL级建模或数据流建模。
2.1.3 基于Verilog的系统设计流程
在1.3节中介绍了电子系统的基本设计方法,包括传统的自底向上(Bottom-Up)和现代的自顶向下(Top-Down)设计方法,我们采用Verilog HDL进行复杂数字逻辑电路和系统的设计过程中,通常将以上两种设计方法结合起来运用。
在定义高层系统结构和系统模块时采用Top-Down设计方法,划分好系统所需要的各个子模块,根据系统性能的总体考虑和指标要求,对高层次模块往往编写一些行为级的代码,进行功能仿真和验证。而在设计实现时使用Bottom-Up的方法,从库元件或数据库中调用已有的单元或采用可综合的行为描述方式来设计底层的子模块,并且进行电路综合、优化,以及功能、性能的仿真和验证;再实现大一些的子模块,最后构建出整个系统。
图2.7 Verilog HDL设计电路的基本流程
硬件描述语言HDL为我们提供了在所希望的层次级别中描述电路的方法。用Verilog HDL设计电路的基本流程如图2.7所示。
小资料
设计验证是在系统设计的过程中,进行包括功能、性能等各种参数指标的仿真,如果在仿真过程中发现问题,就返回设计的输入阶段进行修改,然后再重复各项仿真,直至达到各项系统指标的要求。
对一个系统设计的验证工作通常采用Bottom-Up的方法,即先验证底层模块,保证每个底层模块的正确性后,再验证顶层模块的正确性。
1.电路需求分析
需求分析是进行电路系统设计的起点。工作人员需要对用户提出的功能要求进行分析理解,做出电路系统的整体规划,形成详细的技术指标,确定初步方案。例如,要设计一个数字密码锁,需要考虑供电方式、电路工作频率、开锁方式、设码/解码方式、产品体积、成本、功耗和安装位置,电路实现采用ASIC还是选用哪种FPGA/CPLD器件等。需求分析的结果是否准确将直接影响到后面各阶段的设计过程,并影响到设计结果是否合理和实用。做好电路的需求分析,必定会大大缩短产品开发周期。
2.电路功能设计与逻辑划分
正确地分析了用户的电路需求后,就可以进行逻辑功能的总体设计,设计整个电路的功能、接口和总体结构,考虑功能模块的划分和设计思路,各子模块的接口和时序(包括接口时序和内部信号的时序)等,向项目组成员合理分配子模块设计任务。
3.HDL描述的电路设计
按照电路的功能设计及性能要求,用硬件描述语言来描述各个子模块。
小提示
电路设计也可以按照传统的画电路图的设计方式来完成。但是,当今电路系统的逻辑关系和时序关系往往非常复杂。按照以往传统的画电路图设计方式且没有计算机辅助仿真工具的条件下,开发一个电路系统需要很长的周期。HDL的出现使电路设计的工作效率大幅提高,如今一个成熟的数字电路设计师所做的工作,在早期的20世纪80年代则需要十几个人乃至一个研究所才能完成。因此,要做一个硬件设计师,如果不学会像写程序一样地用HDL来描述电路系统,则很难适应高速发展的信息时代。
4.电路逻辑功能仿真
电路逻辑功能仿真的目的是对所描述的电路功能正确与否进行验证,经过功能仿真找出设计的错误并进行修正,因此功能仿真在整个电路系统的设计过程中具有重要的作用。
电路逻辑功能仿真时并不考虑信号的时间延迟等因素对电路性能的影响,只是验证功能的正确性。
小知识
一般的EDA(Electric Design Automation:电子设计自动化)综合工具都提供了电路逻辑仿真的环境,例如,在任务1、任务2、任务3中都使用了Quartus Ⅱ软件提供的“仿真波形文件”,采用图形方式编辑激励信号,对电路进行功能仿真。仿真还可以使用专门的仿真工具。例如,FPGA设计中最常用的仿真工具是Mentor Graphics公司的产品Modelsim仿真软件。
除了用图形方式编辑激励信号仿真电路功能以外,还可以用HDL编写测试程序。例如,对一个2输入与非门的逻辑仿真编写的测试程序nand2_test.tst如下所示。
/* nand2_test.tst */ timescale 1ns/1ns //将仿真的时间单位设置为1ns,精度为1ns module nand2_ex_test; //定义测试程序模块nand2_ex_test reg a,b; //将被测试模块的输入信号定义为reg寄存器型 wire f; //将被测试模块的输出信号定义为wire线网型 nand2_ex_1 U1 (a,b,f); //说明被测试电路U1为模块nand2_ex_1 initial begin //保留字initial后描述的是仿真波形的变化情 //况,所描述的内容写在begin和end之间 a=1′b0; b=1′b0; //输入信号波形起始状态:a=0,b=0 #100 a=1′b1; //“#100”表示经过100ns的延迟后a=1,b没变 #100 a=1′b0; b=1′b1; //经过第二个100ns的延迟后a=0,b=1 #100 a=1′b1; //经过第三个100ns的延迟后a=1,而b仍为0 #200 $finish; //再经过200ns的延迟后结束仿真 end endmodule
这样的测试程序在仿真软件中要产生出所需的激励波形,并将它加载到电路模块上。仿真软件再控制显示出仿真后产生的输出信息。测试程序也称为验证程序、测试文件、测试模块或顶层模块。
这段测试程序中出现的语句“a=1′b0;”和“b=1′b1;”,其含义分别是将1位位宽的二进制数0和1赋值给寄存器变量a和b。
5.电路逻辑综合
当逻辑仿真验证正确以后,就可以进行逻辑综合,将电路模块的逻辑描述文件根据选定的ASIC类型或FPGA/CPLD器件类型的硬件结构和约束控制条件进行编译、优化和转换,最后获得可以实现的基本门级电路的网表文件。
逻辑综合的目的是决定电路门级结构,寻求时序与面积、功耗与时序的平衡,增强电路的可测试性。
能够完成逻辑综合的工具软件称为逻辑综合器,它借助于计算机强大的计算能力,自动完成逻辑综合的过程,产生优化的电路结构网表,输出.edf文件。
在FPGA/CPLD设计中最著名的逻辑综合工具有三种:Synopsys公司的FPGA Express、FPGA Compiler和FPGA Compiler Ⅱ;Synplicity公司的Synplify和Synplify Pro.;Mentor Graphics公司的Leonardo Spectrum。
专门用于ASIC的综合工具有Synopsys公司的Design Compiler和Behavial Compiler;Synplicity公司的Synplify ASIC;Cadence公司的Synergy。
小提示
不是所有的HDL语句和程序都可以进行逻辑综合,自动产生真实电路。对于HDL的可综合性研究已有十多年的历史,但目前尚未形成国际标准,各厂商的综合器所支持的可综合HDL语法也不相同。因此,为了能转换成标准的门级电路网表,编写HDL程序时必须符合特定的综合器需求的风格。目前所有的逻辑综合器基本上都支持门级结构和RTL(寄存器传输级)结构的HDL程序的综合。
6.电路优化及布局布线
由于各种ASIC和FPGA/CPLD器件的工艺各不相同,因而当用不同厂家的不同器件来实现已通过验证的电路逻辑网表时,不但需要使用该器件类型对应的基本单元库,还必须使用相应的布线延迟模型,才能进行精确的电路优化和布局布线,使设计能与实际电路的情况一致。
基本单元库与布线延迟模型由器件厂家提供,并由EDA工具厂商的工程师将其编入到相应的处理程序中。逻辑电路设计师在进行逻辑综合时只需调用一个说明了工艺器件和约束条件的文件,EDA工具就会自动地根据这一个文件选择相应的库和模型进行准确的处理。
7.电路时序仿真
完成了逻辑综合和电路的优化及布局布线工作后,结合为电路实现所选定的器件类型,还需要考虑信号的延迟对电路进行仿真。由于不同器件的内部时延以及布局、布线方案都会给电路的功能及时延造成很大的影响,因此在设计实现后,对电路进行时延仿真,分析定时关系,估计设计性能非常有必要。
不考虑信号时延等因素的功能仿真称为前仿真,时序仿真称为后仿真。
8.FPGA/CPLD下载或ASIC制造工艺文件产生
完成了电路的设计、仿真验证后,就可以通过EDA工具生成由基本门电路组成的逻辑网表目标文件,再通过开发工具将目标文件下载到FPGA/CPLD芯片中,然后在电路板上进行实际环境的调试。如果电路要在ASIC上实现,则在EDA工具上生成集成电路制造的工艺文件,再将工艺文件送到Foundry开始制造芯片。