PLD(可编程逻辑器件)出现后,需要有一种设计切入点(Design Entry)将设计者的意图表现出来,并最终在具体的器件上实现。早期主要有两种设计方式:一种是采取画原理图的方式,就像PLD出现之前将分散的TTL(Transistor-Transistor Logic)芯片组合成电路板一样进行设计,这种方式只是将电路板变成了一块芯片而已;还有一种设计方式是用逻辑方程式来表现设计者意图,先将多条方程式语句组成的文件经过编译器编译后产生相应文件,再由专用工具写到PLD中,从而实现各种逻辑功能。
随着PLD技术的发展,开发工具的功能已十分强大。目前设计输入方式在形式上仍有原理图输入方式、状态机输入方式和HDL输入方式,由于HDL输入方式具有其他方式无可比拟的系列优点,因此在FPGA设计过程中几乎均采用这种方式,其他输入方式很少使用。HDL输入方式,即采用编程语言进行设计输入的方式,主要有以下几方面的优点。
(1)HDL没有固定的目标器件,在进行设计时不需要考虑器件的具体结构。不同厂商生产的PLD虽然功能相似,但内部结构上毕竟有不同之处,若采用原理图输入方式,则需要对具体器件的结构、功能部件有一定的了解,从而增加了设计的难度。
(2)HDL设计通用性、兼容性好,十分便于移植。在大多数情况下,用HDL进行设计几乎不需要进行任何修改就可以在各种设计环境、PLD之间编译实现,这给项目的升级开发、程序复用、程序交流、程序维护带来了很大的便利。
(3)由于HDL在设计之时不需要考虑硬件结构,不需要考虑布局布线等问题,只需要结合仿真软件对设计结果进行仿真即可得到满意的结果,因此大大降低了设计的复杂度和难度。
目前的HDL较多,主要有VHDL(VHSIC Hardware Description Language,其中的VHSIC是Very High Speed Integrated Circuit的缩写,超高速集成电路硬件描述语言)、Verilog HDL、AHDL、SystemC、HandelC、System Verilog、System VHDL等,其中主流工具语言为VHDL和Verilog HDL。
VHDL和Verilog HDL各有优势。VHDL语法严谨,虽然在描述具体设计时感觉较为烦琐,但正因为其严谨使得语法的编译纠错能力较强;Verilog HDL语法宽松,因其宽松导致描述具体设计时容易产生问题。例如,VHDL会在编译过程中检查信号的位宽问题,而Verilog HDL不会检查位宽问题。虽然两种语言的结构及形式不同,但编程设计的思路是一样的,读者在掌握了其中一种语言后,很容易读懂其他HDL。由于目前Verilog HDL在国内应用更为广泛,本书所有FPGA实例均采用Verilog HDL进行设计。
1.Verilog HDL简介
Verilog HDL是在1983年由GDA(GateWay Design Automation)公司的Phil Moorby首创的。Phil Moorby后来成为Verilog-XL的主要设计者和Cadence公司(Cadence Design System)的第一个合伙人。1984—1985年,Phil Moorby设计出了第一个关于Verilog-XL的仿真器。1986年,他对Verilog HDL的发展又做出了一个巨大贡献:提出了用于快速门级仿真的XL算法。
随着Verilog-XL算法的成功,Verilog HDL得到迅速发展。1989年,Cadence公司收购了GDA公司,Verilog HDL成为Cadence公司的私有财产。1990年,Cadence公司决定公开Verilog HDL,于是成立了OVI(Open Verilog International)组织来负责Verilog HDL语言的发展。基于Verilog HDL的优越性,IEEE于1995年制定了Verilog HDL语言的IEEE标准,即Verilog HDL 1364—1995。随着Verilog HDL语言的不断完善和发展,先后制定了IEEE 1364—2001、IEEE 1364—2005两个标准。
Verilog HDL是一种用于数字逻辑电路设计的语言,用Verilog HDL描述的电路设计就是该电路的Verilog HDL模型。Verilog HDL既是一种行为描述语言,也是一种结构描述语言。也就是说,既可以用电路的功能描述,也可以用器件和它们之间的连接来建立所设计电路的Verilog HDL模型。Verilog HDL模型可以是实际电路的不同级别的抽象,这些抽象的级别和它们对应的模型类型共有以下几种。
系统级(System):用高级语言实现设计模块的外部性能模型。
算法级(Algorithm):用高级语言实现设计算法的模型。
RTL级(Register Transfer Level):描述数据在寄存器之间流动,以及如何处理这些数据的模型。
门级(Switch-Level):描述器件中三极管、存储节点和它们之间连接的模型。
一个复杂电路系统的完整Verilog HDL模型是由若干个Verilog HDL模块构成的,每个模块又可以由若干个子模块构成,其中有些模块需要综合成具体电路,而有些模块只是生成激励信号源且不需要生成具体电路,这些不需要生成具体电路的模块,可以仅从语法角度进行设计,设计更加灵活。利用Verilog HDL模型所提供的这种功能可以构造一个模块间的清晰层次结构,从而描述极其复杂的大型设计,并对所做设计的逻辑进行严格的验证。
作为一种结构描述和行为描述的语言,Verilog HDL的语法结构非常适合算法级和RTL级的模型设计。这种行为描述的语言具有以下功能。
可描述顺序执行或并行执行的程序结构。
可用延时表达式或事件表达式来明确控制过程的启动时间。
可通过命名的事件来触发其他过程中的激活行为或停止行为。
提供了条件、if-else、case、循环程序结构。
提供了可带参数且非零延迟时间的任务(Task)程序结构。
提供了可定义新的操作符的函数(Function)结构。
提供了用于建立表达式的算术运算符、逻辑运算符和位运算符。
作为一种结构描述的语言,Verilog HDL也非常适合门级和开关级的模型设计,因其结构化的特点使它具有以下功能。
提供了一套完整的组合型原语(Primitive)。
提供了双向通路和电路器件的原语。
可建立MOS器件的电荷分享和电荷衰减的动态模型。
Verilog HDL语言的构造性语句可以精确地建立信号的模型,是因为在Verilog HDL语言中,提供了延迟和输出强度的原语来建立精确程度很高的信号模型。信号值可以有不同的强度,可以通过设计宽范围的模糊值来降低不确定条件的影响。
作为一种高级的硬件描述编程语言,Verilog HDL有着类似C语言的风格,其中有许多语句,如if语句、case语句等,与C语言中的对应语句十分相似。需要特别说明的是,虽然Verilog HDL的一些语法与C语言类似,但Verilog HDL本质上是描述硬件的“并行”语言,而C语言本质上是“顺序”语言,两者在设计思想上有本质的区别。关于Verilog HDL的详细学习方法可参考《零基础学FPGA设计——理解硬件编程思想》。
Verilog HDL是一套完整的语言,有严密的语法体系。但用于FPGA电路设计的常用语法只有很少的几条,完成特定功能电路设计的核心在于工程师的设计思想。下面介绍在本书的编写过程中,需要用到的几条Verilog HDL的基本语法,以及几条简单的代码设计规则。
2.Verilog HDL程序结构
Verilog HDL的基本设计单元是module(模块)。一个模块由两部分组成,一部分描述接口,另一部分描述逻辑功能,即定义输入是如何影响输出的。下面是一段完整的Verilog HDL程序代码。
在上面的例子中,加粗字体为Verilog HDL的关键字。完整的Verilog HDL设计文件以module开始,以endmodule结束。第1~3行声明了模块名为mdesign的模块,其中第2行声明了模块的两个输入信号a、b,第3行声明了模块的两个输出信号c、d;第4行表示信号c为a和b相或的运算结果;第5行表示信号d为a和b相与的运算结果。
以上就是设计一个简单的Verilog HDL程序模块所需的全部内容。从这个例子可以看出,Verilog HDL结构完全嵌在声明语句module和endmodule之间。每个Verilog HDL程序都包括三个主要部分:端口定义、内部信号声明和功能定义。
(1)端口定义:模块的端口声明了模块的输入/输出接口,其格式如下。
其中,N为输入端口的位宽,如信号为单比特信号,则不写位宽说明;M为输出端口信号的位宽,如信号为单比特信号,则不写位宽说明。需要注意的是,端口声明中最后一个信号名后为右括号“)”,并以分号“;”结束。
(2)内部信号声明:在模块内用到的wire和reg信号的声明,其格式如下。
(3)功能定义:模块中最重要的部分就是逻辑的功能定义部分。有三种方法可以在模块中产生逻辑,即用assign声明语句、例化模块和用always块。下面分别是这三种方法实现逻辑功能定义的例子。
如果用Verilog HDL程序模块实现一定的功能,那么首先应该清楚哪些是同时发生的,哪些是顺序发生的。上面三个例子分别采用了assign声明语句、例化模块和always块。这三个例子描述的逻辑功能是同时执行的,也就是说,如果把这三个例子写到一个Verilog HDL程序模块文件中,它们的次序不会影响逻辑实现的功能。这三个例子是同时执行的,也就是并发的。
请注意,两个或多个always块是同时执行的,但是模块内部的语句一般是顺序执行的。看一下always块内的语句,你就会明白它是如何实现功能的。if…else…if必须顺序执行,否则其功能就没有任何意义。如果else语句在if语句之前执行,功能就不符合要求了。为了能实现上述描述的功能,always块内部的语句将按照书写的顺序执行。
完整的Verilog HDL语法包括信号位宽,信号的加、减、乘、除运算,参数调用,激励文件的编写等。本书主要讨论采用FPGA进行数字滤波器设计,由于读者已经具备一定的FPGA设计知识,本书不再详细介绍完整的Verilog HDL语法。但是,为了明确“语法是次要的,思想才是关键”的思想,本书在编写过程中,会尽量采用简单明了的语法,所有可综合成电路的FPGA程序(不含仿真测试激励文件代码)实例应遵循以下几条简单的设计原则。
(1)所有wire、reg信号在使用之前,均需要进行声明。
(2)所有在always块内被赋值的信号均声明为reg类型,否则声明为wire类型。
(3)所有在always块内的赋值均采用非阻塞赋值语句“<=”,否则使用阻塞赋值语句“=”。
(4)仅使用加、减、比较运算符,一律不直接使用移位、乘、除、开方、指数运算符。
(5)如果需要实现乘、除运算,那么一律通过调用IP核的方式实现。
(6)主要使用if/else、case等简单的语句,尽量减少复杂语句的使用。