第二部分设计和验证部分第9章VerilogHDL模型的不同抽象级别第10章如何编写和验证简单的纯组合逻辑模块第11章复杂数字系统的构成第12章同步状态机的原理、结构和设计第13章设计可综合的状态机的指导原则第14章深入理解阻塞和非阻塞赋值的不同第15章较复杂时序逻辑电路设计实践第16章复杂时序逻辑电路设计实践第17章简化的RISC_CPU设计第18章虚拟器件/接口、IP和基于平台的设计方法及其在大型数字系统设计中的作用第9章VerilogHDL模型的不同抽象级别概述由初级篇中可知,Verilog模型可以是实际电路中不同级别的抽象。所谓不同的抽象级别,实际上是指同一个物理电路,可以在不同的层次上用Verilog语言来描述它。如果只从行为和功能的角度来描述某一电路模块,就称为行为模块;如果从电路结构的角度来描述该电路模块,就称为结构模块。抽象的级别和它们对应的模块类型常可以分为以下5种,即Verilog浯法支持数字电路系统的5种不同描述方法:(1)系统级(system);(2)算法级(algorithmic);(3)RTL级(Register-Transfer-Level);(4)门级(gate-level);(5)开关级(switch-level)。系统级、算法级和RTL级是属于行为级的。门级是属于结构级的。对于数字系统的逻辑设计工程师而言,熟练地掌握门级、RTL级,算法级、系统级是非常重要的。而对于电路基本部件(如与或非门、缓冲器、驱动器等)库的设计者而言,则需要掌握用户自定义源语元件(UDP)和开关级的描述。9.1门级结构描述一个逻辑电路是由许多逻辑门和开关所组成,因此用基本逻辑门的模型来描述逻辑电路结构是最直观的。VerilogHDL提供了一些描述门类型的关键宇,可以用于门级结构建模。9.1.1与非门、或门和反向器及其说明语法VerilogHDL中有关门类型的关键字共有26个,在本教材中只介绍最基本的8个。有关其他的门类型关键字,读者可以通过语法篇:Verilog硬件描述语言参考手册,在设计的实践中逐步掌握。下面列出了8个基本的门类型关键字和它们所表示的门的类型:and——与门;nand——与非门;nor——或非门;or——或门;xor——异或门;xnor——异或非门;buf——缓冲器;not——非门。门与开关的说明语法可以用标准的声明语句格式和一个简单的实例引用加以说明。门声明语句的格式如下:门的类型[驱动能力延时]门实例1[,门实例2,…,门实例n];门的类型是门声明语句所必须的,它可以是VerilogHDL语法规定的26种门类型中的任意一种。驱动能力和延时是可选项,可根据不同的情况选不同的值或不选。门实例1是在本模块中引用的第一个这种类型的门的名称及其端口定义,而门实例n是引用的第n个这种类型的门的名称及其端口定义。有关驱动能力的选项在以后的章节里再详细加以介绍。下面用一个具体的例子来说明门类型的引用:nand#10nd1(a,data,clock,clear);该例说明在模块中使用了一个名为nd1的与非门(nand),输入为data、clock和clear,输出为a,输出与输入的延时为10个单位时间。Verilog语法支持的基本逻辑部件其行为是由该基本逻辑部件的原语(Primitive)提供的,原语部件和本讲中1.3节介绍的UDP没有本质上的差别。Verilog编译或解释器能正确地处理有关原语部件的语法现象。9.1.2用门级结构描述D触发器例9.1是用VerilogHDL语言描述的D型主从触发器模块,通过这个例子,可以学习门级结构建模的基本方法。【例9.1】用基本逻辑单元组成触发器。moduleflop(data,clock,clear,q,qb);inputdata,clock,clear;outputq,qb;nand#10nd1(a,data,clock,clear),//注意结束时用逗号,最后才用分号nd2(b,ndata,clock),//表示nd1到nd8都是nand(与非门)nd4(d,c,b,clear),nd5(e,c,nclock),nd6(f,d,nclock),nd8(qb,q,f,clear);nand#9nd3(c,a,d),nd7(q,e,qb);not#10iv1(ndata,data),iv2(nclock,clock);endmodule注意:可综合代码中不能出现“#d”延时控制语句!在这个VerilogHDL结构描述的模块中,flop定义了模块名,设计上层模块时可以用模块名(flop)调用这个模块;module,input,output,endmodule等都是关键字;nand和not分别表示与非门和反相器,在Verilog语法中有这两个基本逻辑单元的行为,它们由原语(Primitive)描述,这是一种类似真值表的描述(见本讲1.3节用户定义的原语UDP);#10和#9分别表示10个和9个单位时间的延时;nd1,nd2,…,nd8,iv1,iv2分别为图2.1.1中的各个基本部件。图9.1D型主从触发器的电路结构图9.1.3由已经设计成的模块构成更高一层的模块如果已经编制了一个模块,如1.1.2节中的flop,可以在另外的模块中引用这个模块。引用的方法与门类型的实例引用非常类似,只需在前面写上已编的模块名,紧跟着写上本模块引用的实例名,按顺序写上实例的端口名即可,也可以用已编模块的端口名按对应的原则逐一填入,见下面的两条语句:(1)flopflop_d(d1,clk,clrb,q,qn);(2)flopflop_d(.clock(clk),.q(q),.clear(clrb),.qb(qn),.data(d1));这两条语句都表示实例flop_d引用已编模块flop。从中可以看出引用时flop_d的端口信号与flop的端口对应有两种不同的表示方法。模块的端口名可以按序排列也可以不必按序排列。如果模块的端口名按序排列,只需按序列出实例的端口名(见语句1)。如果模块的端口名不按序排列,则实例的端口信号和被引用模块的端口信号必须一一列出(见语句2)。例9.2引用了9.1.2节中已设计的模块flop,用它构成一个4位寄存器。【例9.2】用触发器组成带清零端的4位寄存器。`include“flop.v”modulehardreg(d,clk,clrb,q);Inputclk,clrb;input[3:0]d;output[3:0]q;flopf1(d[0],clk,clrb,q[0],),//注意结束时用逗号,最后才用分号f2(d[1],clk,clrb,q[1],),//表示f1到f4都是flopf3(d[2],clk,clrb,q[2],),f4(d[3],clk,clrb,q[3],);endmodule在上面这个结构描述的模块中,hardreg定义了模块名;f1,f2,f3,f4分别为图2.1.2中的各个基本部件,而其后面括号中的参数分别为图2.1.2中各基本部件的输入、输出信号。请注意当f1~f4实例引用已编模块flop时,由于不需要flop端口中的qb口,故在引用时把它省去,但逗号仍需要保留。图9.24位寄存器电路结构图9.2VerilogHDL的行为描述建模对于上面两个例子,还可以用比较抽象Veritog描述方法来建立模型。【例9.3】用行为描述的方法来描述带清零端的4位寄存器。modulehardreg(d,clk,clrb,q);inputclk,clrb;input[3:0]d;output[3:0]q;reg[3:0]q;always@(posedgeclkorposedgeclrb)beginif(clrb)q=0;elseq=d;endendmodule例9.3的行为和例9.2的功能是完全一致的,实际上它们是同一物理电路的两种不同的表示方法。如果有一种工具能自动地把例9.3的描述转换为例9.2,再细化为由4个例9.1组成的结构,这样就把比较抽象的行为描述具体化为门级电路的描述。而门级描述表示的是电路结构,它是电路布线的依据。设计的目的就是产生行为和功能准确的电路结构。电路结构看起来相当复杂,难以理解,而行为的描述比较直观。我们可以用比较直观的行为描述来开始设计过程,通过Verilog语言的仿真测试验证其正确后,就完成了第一步设计工作。然后用一种工具把行为模块自动转化为门级结构,再次经过Verilog语言的仿真测试验证其正确后,便完成了前端的逻辑设计。接下去可以进行后端制造的准备工作,这样做大大提高了设计的效率和准确性。这就是用Verilog语言设计复杂逻辑电路的基本思路。这种能把行为级的Verilog模块自动转换为门级结构的工具叫综合器(SynthesisTool)。9.2.1仅用于产生仿真测试信号的verilogHDL行为描述建模为了对已设计的模块进行检验,往往需要产生一系列信号,输入到已设计的模块,并检查已设计模块的输出,看它们是否符合设计要求。这就要求编写测试模块,也称做测试文件,常用带.tf扩展名的文件来描述测试模块,也可以用带.V扩展名的文件来描述测试模块。下面的VerilogHDL行为描述模型用于产生时钟信号,以验证电路功能。其输出的仿真信号共有2个,分别是时钟clk和复位信号reset。初始状态时,clk置为低电平,reset为高电平。reset信号输出一个复位信号之后,维持在高电平。这一功能可利用下面的语句来实现:initialbeginreset=1;//初始状态clk=0:#3reset=0;#5reset=1;end以后每隔5个时间单位,时钟就翻转一次,这一功能可利用下面的语句来实现:always#5clk=~clk;从而该模块所产生的时钟周期为10个时间单位。完整的源程序如下:modulegen_clk(clk,reset);outputclk;outputreset;regclk,reset;initialbeginreset=1;//initialstateclk=0;#3reset=0;#5reset=1;endalways#5clk=~clk;endmodule再举一个简单的例子,即编制9.1.3节中完成的设计(即hardreg模块)的测试文件。这个测试文件不仅要包括时钟信号(clock)、数据(data[3:0])、清零信号(clearb)的变化,还须引用4位寄存器(hardreg)模块,以观测各种组合信号输入到该4位寄存器(hardreg)模块后,它的输出(q[3:0])的变化。这个测试文件完整的源程序如下:`include“flop.v”`include“hardreg.v”//仿真时需要包含文件“hardreg.v”和“flop.v”/*如果仿真环境可以把有关的文件安排在一个项目中,只要底层模块经过编译,并记录在编译的库中,可以不用包含文件。*/modulehardreg_top;//顶层模块,没有输入和输出的端口regclock,clearb;//为产生测试用的时钟和清零信号需要寄存器reg[3:0]data;//为产生测试用数据需要用寄存器wire[3:0]qout;//为观察Q输出信号需要从模块实例端口中引出线`definestim#100data=4’b//宏定义stim,可使源程序简洁eventend_first_pass;//定义事件end_first_passhardregreg_4bit(.d(data),.clk(clock),.clrb(clearb),.q(qout));/*把本模块中产生的测试信号data,clock,clearb输入实例reg_4bit以观察输出信号qout。实例reg_4bit实际上是已经设计好的模块hardreg。实例引用的hardreg模块,根据包含文件的不同,可以是表示行为的模块也可以是表示结构的模块。*/initialbeginclock=0;clearb=1;endalways#50clock=~cloc