《电子系统集成设计导论》课件第7章_第1页
《电子系统集成设计导论》课件第7章_第2页
《电子系统集成设计导论》课件第7章_第3页
《电子系统集成设计导论》课件第7章_第4页
《电子系统集成设计导论》课件第7章_第5页
已阅读5页,还剩265页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

7.1VerilogHDL概要7.2VerilogHDL基础知识7.3逻辑门及延迟模型7.4数据流风格描述7.5行为风格描述7.6结构风格描述7.7编译仿真辅助技术7.8VerilogHDL调试与测试7.9VerilogHDL与VHDL的对比7.10课程设计练习7.11VerilogHDL扩展与支撑技术第7章VerilogHDL系统设计语言

7.1VerilogHDL概要

VerilogHDL(简称Verilog)是一种通用的硬件电路设计高级语言,设计师用它来进行数字系统与电路的设计。它最初由GDA(GatewayDesignAutomation)公司的PhilMoorby于1983年创建。之后GDA公司并入Cadence公司,Verilog遂成为Cadence公司的专利技术。其出色的门级快速仿真工具Verilog-XL迅速获得成功,为Verilog的广泛应用奠定了基础。

(1)从1990年开始,经过OVI(OpenVerilogInternational)VerilogHDL研究开发计划的推动,Verilog于1995年被正式确定为IEEEStd1364-1995标准。

(2)2001年9月公布了Verilog标准的新版本IEEEStd1364-2001。2001版本主要在行为描述、ASIC底层、外围环境接口三个方面进行了改进。在本书后面的附录2中给出了IEEE-1364-2001版本新增的保留关键字和按类别不同的句法汇总修订。

(3)国际标准化部门于2002年又推出了IEEEStd1364.1-2002,它是一个关于寄存器转移级综合方面的附属标准。

(4)经过OSCI(OpenSystemCinitiative,SystemC开放促进会)的努力,于2005年将SystemC确定为IEEE1666标准,可以免费下载。

(5)2006年,公布了Verilog2001的修订版IEEEStd1364-2005,详见参考文献《IEEEStandardforVerilogHardwareDescriptionLanguage2005及附录2》。同年,SystemVerilog也被确定为IEEEStd1800-2005标准,全面包容Verilog,所编同样功能的代码,其行数约为Verilog的1/2~1/5。目前,这两个IEEE-2005标准之间是一致和兼容的。根据计划安排,2008年要将IEEE-1364整合进IEEE-1800标准之中。7.1.1VerilogHDL的特点

1.语法结构简单,易学实用

VerilogHDL语言与C语言很接近,易学易用。借助于本书前面的VHDL基础,学习VerilogHDL就显得比较容易。目前,Verilog在国外,尤其是美国和欧洲得到广泛的应用。与VHDL一样,VerilogHDL支持系统与电路设计创建描述(输入归档、交流修改)、设计模拟仿真(验证、时序分析、调试联试,这方面Verilog尤其擅长)、设计综合(有底层库的强力支撑)、设计测试(故障覆盖、测试代码生成ATPG)等贯穿产品研制全程四个方面的功能。

2.具有丰富的底层器件资源和ASIC厂商支持

VerilogHDL便于开展自底向上的设计,因为它的一个显著特点是具有丰富的底层器件资源支持。方便的内建基元和用户定义基元适于采用模块化、结构化设计;特别是与底层门级开关电路打交道较多的设计比较优化;综合成EDIF格式电路结构化网表的效率较高。现在许多ASIC制造厂商将其作为设计制造间签发(Sign-Off)的工具。

3.支持行为、结构、数据流三种风格描述,具有较好的可综合性

VerilogHDL支持行为、结构两种类型风格描述,数据流采用类似于行为风格的描述,但是对应于寄存器转移一级(RTL)的结构。一个模块内允许行为风格和结构风格相互连接。VerilogHDL在综合,特别在RTL级的综合方面具有明显的优势。然而,Verilog在系统级接近顶层的抽象设计能力较弱,而且还有许多是不可综合的。设计前期可以多用些行为描述与仿真,设计后期再用结构手法以便综合。目前出现的SystemVerilog弥补了这方面的不足。

4.面向Top-Down设计的机制

VerilogHDL以模块(Module)设计手法为主,由大小不同的模块直接嵌套形成层次结构化设计体系。凭借丰富的函数和任务等复用手段,高层设计可以方便地进行行为风格描述和仿真。这些都是设计师采用自上而下设计策略的基础。

5.丰富的编译调试手段和EDA厂商支持

与EDA关系密切的VerilogHDL,本身就具有丰富的编译调试手段,大量实用的编译预处理宏命令、系统函数和任务,使得编译、仿真、综合的交互性较好。

6.提供与其他语言和开发环境间强大的接口能力

VerilogHDL提供编程语言接口(PLI)、Verilog接口例程(VPI)、ACC(Access,访问接口)、标准延迟格式(SDF)等,使得外围可扩展能力非常强。7.1.2VerilogHDL模块

1.模块句法结构

模块设计在句法中又被总称为模块声明(module_

declaration),其基本格式如下:

module

module_identifier[(list_of_ports)];//模块命名并列出端口名

/*以下是关于模块项声明(module_item_declarations)段*/

input_declaration|output_…|inout_…

|reg_…|net_…|parameter_…|integer_…

|function_…|task_…|event_…|…

/*以下是模块项(module_items)描述段*/

initial_construct

|always_construct

|module_instantiation

|gate_instantiation

|udp_instantiation

|continuous­_assign

|parameter_override

|specify_block

endmodule

2.模块中的项语句结构

VerilogHDL程序由模块组成,每个模块都是安排在module和endmodule两个关键字之间。每个模块功能明确,模块间可以实现从底层到顶层层次化的模块嵌套调用。

模块内的基本架构主要是由两大段项语句组成:①相关的项声明(module_item_declarations)段;②其他实质性项描述语句(module_items)段。项声明对模块中用到的各种数据、端口、函数、任务等加以声明,项描述语句则用来描述电路的功能或结构。有三类项描述语句可用来设计模块,即行为构件、持续赋值、实例生成。此外,还有参数重置、规定块两类项描述语句。

除了endmodule之外,每个项声明和项描述语句的最后必须有分号。Verilog允许一行写几个语句;也可以一个语句占有几行。

3.端口定义和模块项声明

在模块名后面紧接着定义端口的圆括号中,对模块的输入输出端口进行定义。

然后,在项声明段中给出端口模式的声明。端口可以是input、output、inout三种模式,均需要在这里明确声明。reg不能做为input或inout端口。

端口定义及端口I/O模式声明的格式为

module模块名[(口1,口2,口3,…)];//圆括号中给出端口定义

input

口2,口3,…;//在项声明段给出端口模式声明

output

口1,…;

inout…;

…;在模块项声明段module_item_declarations的部分,还要对模块内部所用其他项进行声明。一方面要对模块中用到的各种数据类型加以声明,包括参数(parameter)、线网(net)、寄存器(reg)、整数(integer)、实数(real)、时间(time)等;另一方面要对公用子程序,包括函数(function)、任务(task),以及事件(event)等加以声明。

4.模块项描述段和层次

在模块声明段之后的项描述段,给出模块输入输出关系的描述;给出模块功能及结构描述。包括描述行为的构件类(initial_construct;always_construct等)、描述结构的实例生成(module_instantiation;gate_instantiation;udp_instantiation)、描述数据流的独立持续赋值(continuous_assign)等语句。下面先用设计简例分别大致加以介绍。

Verilog实质性的设计嵌套,实现起来非常简单。与VHDL不同的是,Verilog的模块中可以调用(实例生成)其他模块,但不能声明其他模块。调用时采用名称相关和位置相关两种手法,如7.1.3中例3所示。另外,还可以采用层次化名称法引用其他模块内部的标识符。7.1.3VerilogHDL设计简例

为了对采用VerilogHDL语言设计尽早有一个感性认识,这里举出几种风格的典型设计简例。通过分析并与VHDL比较,有助于深入理解后面更为复杂的设计。

1.例1——与或非门设计

/*如图7-1所示给出数据流描述的结构*/

`timescale1ns/100ps

/*指定时间单位1ns和精度100ps*/

moduleaoi21(d,a,b,c);

inputa,b,c;

outputd;

assign

#5d=~((a&b)|c);

/*赋值延迟为5ns,按位操作,持续赋值,实现与或非*/

endmodule图7-1与或非门aoi21设计

2.例2——四位加法器设计

/*如图7-2所示为数据流描述的结构*/

moduleFulladder(sum,cout,a,b,cin);

input[3:0]a,b;

inputcin;

outputcout;

output[3:0]sum;

assign{cout,sum}=a+b+cin;//并置后共计五位

endmodule图7-2四位加法器

3.例3——模块调用

采用层次化结构风格,顶层主模块topmd调用底层三态门子模块bomtri实例生成一个bot_ins。如图7-3所示,给出的是一种层次结构。

modulebomtri(out,int,exp1);

outputout;

inputint,exp1;

assignout=exp1?int:‘bz;

/*当条件exp1为真,out=int(输入);当exp1为假,out=’bz(高阻)*/

endmodule

moduletopmd(ou,in,enb);

outputou;

inputin,enb;

bomtribot_ins(ou,in,enb);

/*也可以是bomtribot_ins(.int(in),.exp1(enb),.out(ou))*/

endmodule图7-3层次化设计

4.例4——D触发器设计

如图7-4所示,采用行为风格描述如下:

moduleFlop(q,d,clk,clr,ena);

inputd,clk,clr,ena;

outputq;

regq;

always@(posedgeclkorposedgeclr)

/*@为事件控制符,事件posedge含从某值到1的跳变以及从0到某值的跳变——总共五种(01,x1,z1,0x,0z,但一般不计z1和0z)。negedge与此类似*/

begin

if(clr)q<=0;//<=为非阻塞性赋值

elseif(ena)q<=d;

end

endmodule

注意,上面例4中if_else_if是时序语句,其顺序为if→elseif。图7-4D触发器设计

7.2VerilogHDL基础知识

7.2.1数据及类型

1.标识符和注释

由字母、数字、下划线等组成的一组符号称为标识符(Identifier),在VerilogHDL中用它来表示各种线网、变量、参数或构件的名称,而且大写与小写是不一样的。为了简单起见,建议所给出的第一个字符采用英文字母,其余字符采用英文字母、下划线和数字。例如7.1.3节中例1的模块名称aoi21等。

Verilog用不同的后缀表示不同的文件类型。例如,用*.v表示源程序(有些设计环境采用*.tf表示测试模块)等。这里的*.v也是一种标识符。

Verilog程序中的注释有以下两种。

短注释:参见附录2的句法汇总中综合类关于one_line_comment的句法定义。在每行程序的后边半行,以//开始的文字部分为注释内容。用\n表示注释文字的后面通常跟有一个换行符。

长注释:在程序行之间位于/*…*/之内,允许一行或多行的文字部分,也属于注释内容。

注释的目的是为了阅读方便,并不进入编译。

2.线网形态数据类型

根据Verilog标准的定义,线网(net)类(wire、tri)是一类专门的数据类型。

线网类数据表示各结构化元件之间的物理硬件互连线。它不能存储值,而必须受到驱动器的驱动。当没有驱动器连接到线网类上时,该线网则呈现高阻。

最常用的线网类数据是wire和tri(二者等价。wire表示单个门驱动,tri表示多个门驱动)。ASIC设计中的wire不能存储和保存值,只作传输被持续赋值语句驱动的值,其默认值为z。

未声明的数据默认是net类型,后面将给出它的详细格式。net的默认位数为1,即标量型;而矢量需要显式声明。对此,可以理解为:Verilog隐含的数值类型为标量型线网逻辑类数据。但这里隐含的是四值逻辑,类似于VHDL中的bit量。

下面具体介绍这种数据形态类型。

线网中的wire又被称为连线型线网,用来表示连接单元的硬互连线。承载的是组合逻辑值,通常由单个门驱动或由持续赋值语句驱动。Verilog中的输入、输出默认数据类型为wire(tri型则用来表示多驱动器驱动同一根连线的情况)。

多位wire类型定义语句格式为

wire[n:1]数据名1,数据名2,…,数据名k;(也可以用格式

[n-1:0])例如:

wire[3:0]c,d;

wire上的数据一般用持续赋值的assign语句来赋值。

其他可以归为线网型同类数据的主要有:supply0、supply1(分别表示负、正电源);trireg(需要单独声明)、tri0、tri1、tri(总线输入全1时输出结果为1,输入全0时则输出为0,其余为x)、trior、triand、wor(wired-or线或型线网)、wand(wired-and线与型线网)、wire(可以与tri功能相同)等。其中惟有trireg特殊,它表示线网上挂有电容,可用来描述电荷存储值。电荷强度级别有large、medium(默认强度值)、small。

没有被声明的线网默认为1位线网。对线网类型的限定词有标量scalared、矢量vectored等,默认值为标量。被声明为矢量的线网不允许按位直接运算。线网类可以拥有逻辑值。

3.变量类别数据

在Verilog的新标准中,取消了寄存器(register)一类的提法,以变量代替。与VHDL非常不同,这里的变量包括存储类(reg、memory)、整数类、实数类、时间类等数据。

最常用的存储类数据有寄存器型reg。存储器型memory则是由reg组成的数组,它是Verilog的一种多维数据构成的表征形式。

reg类可以在驱动撤销时仍能保存数据值,但并不总与硬件的寄存器、触发器、锁存器等价。在个别情况下,它也可能是组合逻辑。

1)寄存器(reg)型

寄存器reg用来表示数据记忆单元,通过行为赋值语句可以改变存储的值,reg的默认位数也是1。用reg定义的变量将用在always构件内,常用它代表触发器。在always构件内赋值的每一个变量都必须定义成reg型。

多位reg类型定义语句格式为

reg[n:1]数据名1,数据名2,…,数据名k;//(也可以写成[n-1:0])

例如:

reg[3:0]regc,regd;

r

eg的默认初始值为未定值x。

2)存储器(memory)型

在Verilog中,存储器数据不是一个独立的类型,它是寄存器类型reg派生出来的。通过对reg型数据建立数组来加以定义,用来描述RAM、ROM等存储器电路和reg文件。

存储器类型定义语句格式为

reg[n:1]存储器名[m:1];//(也可以用格式[m-1:0])

其中reg[n:1]表示存储器中宽度为n的一个单元。例如:reg[7:0]mema[255:0];定义了存储器mema,其记忆单元地址范围为从0~255。如果要对存储器中的记忆单元进行读写,必须指定它在存储器中的一个地址。地址值可以用表达式表示,通过计算来获得不同的地址值。不允许对存储器单元的部分位进行直接运算。

3)区间型

区间型变量主要包括integer(整数)、real(实数)、time(时间)、realtime(实时间)等。Verilog主要用区间数值类表示变化的数据,它并不直接对应于真实的硬件。

设计中使用较多的区间类数据是整数(integer)型。采用无符号基数表示整数的标准格式为

位宽'进制数字

其中位宽为用十进制表示的精确位宽常数;整数的进制有二进制(b,B)、八进制(o,O)、十六进制(h,H)、十进制(d,D)四种;数字可以是x,z,数字间可以添加下划线。例如:

4‘b10x0

表示是一个位宽为4的二进制数10x0,其中从低位数起的第二位是未知值。

当表达式只有数字时,意味着采用默认的十进制表示。这时在数字表达式前可以加一减号,表示是负数。

需要指出的是,在Verilog中,整数表示与逻辑集合表示是相通的。一个x或者z,可以被用来表示十六进制数中的四位(或者八进制的三位,二进制的一位)的未知或者高阻状态。

其他的实数(real)型、字符串数值集合等不再介绍。整数、实数、时间量集合都是变量数据类型。

4.参数类数据

VerilogHDL中常见的常数形式是参数(parameter)。参数实质上就是采用parameter格式定义的标识符常数。这样定义的参数在程序正式运行前可以被多次指定、改变和推翻,有点类似于VHDL的类属(generic)。Verilog规定常数在程序运行中不能再改变它的值。

用paramete定义标识符来表示常数,即参数型常数,又称为符号常数。其格式为

parameter参数名1=表达式1,参数名2=表达式2,…,参数名n=表达式n;

例如:

parameterr=1.5,f=2.4;

parametermean_delay=(r+f)/2.0;参数型常数常用来定义延迟和变量宽度。其主要优点是通过参数传递,可以改变被引用模块中已经定义的参数。定义参数的格式为

#(参数1,…,参数n)

模块生成中用#表示参数(例如变量宽度),而延迟控制中也用#给出延迟专用参数,注意不要混淆。

例如,在设计模块Decode(A,F)时定义上升下降延迟参数为parameterr=1,f=1;,它们就成为该参数的默认值。后面允许将默认的参数值再推翻,比如用Decode#(4,0)D1(A1,F1);实例生成D1时,此时,参数值变为r=4,f=0。

与参数定义有关的关键字还有specparam、defparam。

5.逻辑数值集合

VerilogHDL设计中使用最多的是逻辑数值集合,但并不被称作是一种数据类型。逻辑值(0,1,x,z)集合是默认的,不需要说明。逻辑数值集合被用来表示线网、变量和参数的数值。

Verilog标准中规定的二进制逻辑值集合含有四个值——1,0,x,z

(也可以是X、Z,此处大小写一样)。

逻辑值x表示未知值或者未初始化的未定值,未知的逻辑值可能是1,0,或者是一个处于变化中的值。逻辑值z表示一个高阻值。逻辑值?也是表示z|Z。

布尔量的表示也采用逻辑值的集合:用1表示真,0表示假,x表示真假未定,z则无定义。

6.其他广义数据类型

1)用于数据行为特征描述的类

(1)驱动强度类(线网被赋予1或0的强度——strength0、strength1)。

0强度类supply0、strong0、pull0、weak0、highz0。

1强度类supply1、strong1、pull1、weak1、highz1等。

默认值为strong0、strong1。

(2)边沿跳变事件(event)类。

开关级是介于逻辑门和晶体管之间的一个层次,这些强度类数据主要用于开关级建模,包括:

①边沿描述。posedge表示正边沿的01、0x、x1(也可加上z1、0z);negedge表示负边沿的10、1x、x0(也可以加上1z、z0)。

②边沿符号。r、R(狭义上升);f、F(狭义下降);p、P(三种上升);n、N(三种下降)。还有一种是在标准中给出的用*表示边沿的任何变化,等同于(??)。

2)用于结构描述的内建模型类数据

(1)开关模型。

MOS通路晶体管类有nmos、pmos、rnmos、rpmos(nmos、pmos的高阻态版本,在输入输出间有高阻抗存在,使得数据强度衰减)。

CMOS传输门类有cmos、rcmos(以下带r的与上述解释类似)。

无使能控制的双向传输门类有tran、rtran。

有使能控制的双向传输门类有tranif0、tranif1、rtranif1、rtranif0。

(2)上拉、下拉(即电源、地)类:pullup、pulldown。

上述两类数据类型主要用于开关级建模。

(3)基本逻辑门模型。

多(n)个输入端的逻辑门类:and、nand、or、nor、xor、nxor。

多(n)个输出端的逻辑门类:buf、not。

(4)使能控制同相反相三态门类:bufif0、bufif1、notif0、notif1。7.2.2表达式中的操作符

(1)算术操作符:

+-*/%**

上述六种算术操作符分别为加(正)、减(负)、乘、除、求余、指数运算,乘法符号一般被写作*。

当+、-表示正、负时,为一元运算,否则为二元运算。

%为对整型数求余数的模运算。例如,7%3=1,其结果的符号与第一个操作数相同。注意要与系统任务中的%区别开。

在进行算术运算时,如果有一个操作数为x,则结果为x。

(2)布尔逻辑关系:

&&||!

以上符号是三种布尔操作符,分别为逻辑与关系、逻辑或关系、逻辑非关系。

与普通的逻辑运算规则相同,其真值表如表7-1所示。

布尔逻辑运算中的a、b通常是一个表达式。真、假采用逻辑值1、0表示。

对于矢量的布尔逻辑运算规则是:非零矢量整体作为1处理;如果任何一个操作数含有x,则结果为x表示真假未定。

(3)大小关系:

><>=<=

上述四种操作符分别为大于、小于、大于或等于、小于或等于。

在大小关系运算时,如果该关系为真(true),则返回1;如果关系为假(false),则返回0;如果某个操作数的值未定,则该关系为模糊,返回未定值x。

(4)相等关系:

==:等于,是一种简单的相等比较,它只比较逻辑值中的1、0。相等时结果为1,否则为0;如果某操作数含有逻辑值x或z,则结果为x。

!=:不等于,与等于相反。

===:全等于,全面的全等比较,比较逻辑值中全部可能的1、0、x、z,当完全相等时结果为1,否则结果为0。

!==:不全等于,也是比较全部逻辑值,其规则与全等于相反。

两个等于的差别体现在表7-2的真值表中。

===和!==常用于case表达式的判别,所以又被称为“case等式操作符”。

(5)算术逻辑移位:

<<>><<<>>>

这四种操作符分别代表:操作数a逻辑左移n位,记作a<<n;a逻辑右移n位,记作a>>n。逻辑移规定用0填补移出的空位。

例如:

4‘b1001<<1=5’b10010;

a算术左移n位,记作a<<<n;a算术右移n位,记作a>>>n。对于无符号操作数,用0填补移出的空位;对于有符号的操作数a,则补上a的符号位值。其中n作为无符号数处理,当n为未知或高阻时,其结果为未知。

(6)按位运算:

~&|^^~(~^)

上述五种操作符分别为按位取反、按位与、按位或、按位异或、按位异或非运算。

按位取反~的情况比较简单。例如,一个操作数的情况:

rega=b‘1100;

rega=~rega;//取反后rega变为b'0011。对于两个操作数的情况,操作数各位的取值允许为0、1、x。此时除了正常的0、1运算之外,做了非常简单合理的扩展延伸,解释如下:当两个操作数的数据位数不同时,则在运算前,首先将操作数右端对齐,然后将位数少的操作数高位填0后以使左边也对齐,最后再按位运算。

按位与&的约定是:只有两个对应位均为1时,输出为1;两个中有一个为0时,输出为0;其余情况的输出为x。

按位或 | 的约定是:只要两个对应位中有一个为1,则输出为1;两个同时为0时,输出为0;其余情况的输出为x。按位异或^的约定是:只有两个对应位分别为1、0时,输出为1;两个同时为0或同时为1时,输出为0;其余输出均为x。

按位异或非^~的约定是:只有两个同时为0或1时,输出为1;两个对应位分别为1、0时,输出为0;其余输出均为x。

Verilog可以同时进行多位按位运算,所以在设计模块时可以定义总线级多位并行运算的与门、或门、异或门等。

(7)归约(reduced):

&|~&~|^~^(^~)

归约操作符只对单个操作数进行自身各位间的与、或、与非、或非、异或、异或非等单一递推缩减运算,最后结果是一位二进制数。

归约运算的步骤是:先将操作数的第0位和第1位进行与、或、异或等运算;中间结果再与第2位进行同样的运算……以此类推,直到变成一位数为止。例如:

reg[3:0]B;regC;C=&B;

则相当于

C=((B[0]&B[1])&B[2])&B[3];

(8)并置:

{}

它把两个或多个线网、变量的若干位拼接起来。例如:

{a,b[3:0],w,3'b101}

(9)条件表达式:

如图7-5所示,对于表中最后的条件选择表达式,语法解释如下:

exp1?expt:expf

其中exp1、expt、expf均为表达式。上式表示当条件exp1为真时选择expt。当条件exp1为假时选择expf。当exp1为模糊值x、z时,将表达式expt、expf分别加以计算,并按位运算,然后根据下面的规则给出判断结果:对于结果的每一位来说,如果两个表达式均为1,则结果为1;如果两个表达式均为0,则结果为0;否则,结果为x。

由条件选择组成的条件赋值,例如out=enab?a:b可用于持续赋值和一般行为赋值。图7-5条件表达式

(10)优先等级:

Verilog操作符约定的运算顺序与VHDL相似,优先等级如表7-3所示。其中用竖杠与箭头相连表示属于同一个优先级;并置运算的优先级应是最高。

7.3逻辑门及延迟模型

7.3.1内建门与开关基元

Verilog的内建(Built-In)门与开关模型有下述一些基元(Primitive)。

(1)多输入单输出门(出,入1,入2,…,入k):

and,or,xor,nand,nor,xnor

上述每个门有多个输入端(每一种都可以有2~n个),但惟一的一个输出端放在第一个端位置。

(2)多输出单输入门(出1,出2,…,出k,入):

buf,not

上述每个门可以有多个输出端,但一个输入端放在最后一个端位置。

(3)三态门(单入多出):

bufif0,bufif1,notif0,notif1

(4)上拉、下拉(即接地、接电源,可多点):

pullup,pulldown

(5) MOS开关(即通路晶体管和传输门):

nmos,pmos,rnmos,rpmos,cmos,rcmos

(6)双向开关(双向传输门):

tran,tranif0,tranif1,rtran,rtranif0,rtranif1

在设计模块时可以使用它们,同时可以显式定义逻辑值强度和门延迟,如图7-6所示。例如:图7-6模块Primit设计前面两个门用的是强0、强1,门延迟为2.2ns。第三个门Nand_3没有显式声明,用的是默认驱动强度值——也是强0、强1,但门延迟为0。

上拉电阻举例:

pulluppup(pwr);

这里单端上拉器件的实例名为pup,它将惟一的实例输出端pwr置为高电平。在pup之前还可以给出强度,后面还可以同时列出多个上拉器件。7.3.2用户定义基元——UDP

UDP是一种由用户自己定义的库基元(User-DefinedPrimitives)。它也是源文件的一种,是用户根据自己的需要而建立的基本逻辑门模型,具体格式参见附录2中的udp_declaration。在udp_port_list中的第一个为惟一的标量输出端。它不能是矢量型vertor数据,不能是inout模式。在body部分,有组合电路和时序逻辑两类体格式,但都是采用Verilog约定的真值表格式定义和解释。输入端可以是多个(编写非UDP的正常模块时不受上述限制)。

下面以设计半加器本级和的用户定义基元Adder为例,介绍比较简单的组合电路UDP设计。至于半加器的另一个本级进位

Carry,也可以如法炮制。注意,在定义UDP输出时,可以采用0、1、x,但不允许采用z,如果输入端中出现z,则作为x处理。

除了组合电路UDP之外,还有时序逻辑UDP。下面给出的例子是时序逻辑(sequential_body)UDP设计。UDP的调用步骤与内建基元的调用句法相同。在调用这两种基元时,可以有实元名称,也可以没有实元名称。

时序电路中又分电平有效(锁存器)和边沿有效(触发器)两种。定义时序电路也是用列表形式完成,只是表内的格式有所区别。这里举一个正边沿触发的D触发器UDP定义为例来加以阐明。注:VerilogUDP真值表定义中的格式(ab)表示从a电平到b电平。用?表示不必关心的任意值。用(??)表示无关的任意转换。UDP中的?可能是0、1、x。与以前介绍过的?不同,在Verilog条件选择表达式中用?表示选择真假;在逻辑类数值集合中用?表示z。此外,UDP真值表中还用b|B表示是0或者1。7.3.3线网延迟和门延迟

Verilog中有许多定义线网和门延迟的详细规定,主要用于结构和数据流描述。延迟种类有四种:上升(Pd,to_1:从0、x、z到1);下降(Nd,to_0:从1、x、z到0);浮空(Zd,to_z);其他to_x。Verilog中采用#作为延迟(Delay)控制符。

上升、下降、浮空(从1、0到z)都是一种事件变化表征。书写延迟的完整格式示例如下:

#(0.2:0.3:0.4,0.3:0.4:0.5,0.1:0.2:0.3);

该式中按顺序给出上升、下降、浮空的最小、典型、最大值。

此外,规定to_x的延迟取(上升、下降、浮空)之中的最小值。

1.线网延迟

下面举例阐明线网延迟的设计。

设计时可以用#来指定线网的线延迟,例如:

wire#(1.1:1.3:1.7)a_delay;

这句程序给出线网a_delay被驱动源驱动时的线延迟,括号内的三个值分别表示线延迟参数中的最小延迟、典型延迟、最大延迟。

#(1.1:1.3:1.7)assignq=a;

表示的是驱动源赋值阶段的延迟。但是,下述是一种容易误解的写法:

wire#(1.1:1.3:1.7)a_delay=a;

在这种情况下,凡有驱动器出现的是指驱动源a的赋值延迟而不是a_delay的线延迟。

总之,驱动源的赋值延迟加上线延迟才是线网的实际驱动阶段总延迟。

2.门延迟(同样适用于UDP的延迟)

表示门延迟的方式与表示线网线延迟的方式是一样的。这里表示的延迟类别有三种:#(Pd,Nd,Zd),它们是上升延迟(Pd)、下降延迟(Nd)、浮空(即Turnoff;又称Float)延迟(Zd)。有些门,例如与非门等,只有前两种延迟。对其中某一种延迟,还可以用#(a1:a2:a3)分别表示其最小值、典型值、最大值。如果这时只有a1,则不区分最小值、典型值、最大值。举例阐明如下:

nand#3.0nd01(c,a,b);//上升、下降均为单一门延迟,即3.0ns

nand#(2.6:3.0:3.4)nd02(d,a,b);//单一门延迟中的最小值,典型值,最大值

nand#(2.8:3.2:3.4,2.6:2.8:2.9)nd03(e,a,b);

/*上升、下降两种,每种各三个可能取值。这里的最小,典型,最大值算是一套值*/

3.引脚延迟

规定(Specify)块是Verilog延迟表征的重要组成部分。在Specify块中,可以进行延迟参数声明、模块的路径延迟声明和系统时序校验。在编写Specify块时,一般首先用specparam定义延迟参数,再定义路径及其延迟。一般黑体字,包括这里的specparam是Verilog的保留字,凡由specparam开头的语句就是专门用来定义延迟参数的语句。

在Specify块(specify…endspecify)中,可以规定模块内不同引脚间(Pin-to-Pin)的路径延迟,符号为*>以及=>。

x*>y表示所谓的全路径,则x的每一位与后面的y都有路径相通。全路径类似于时钟一类的全局信号线,从一个输入端到所有的输出端都有线连接路径,它们之间的路径延迟均需计算。

例如:

specify

(a,b*>c,d)=10;

endspecify

表示a到c、d的延迟为10,b到c、d的延迟也为10。

x=>y表示所谓的并行路径,要求x、y的位数相等。并行路径类似于并行总线,是指前面引脚和后面引脚是成对出现的,相当于计算从并行输入端到并行输出端的路径延迟。

注意,Verilog中默认的延迟模型也是惯性延迟。所谓“上升”延迟是指输出端的上升边,对其他有关下降等含义的解释与此类似。

7.4数据流风格描述

Verilog的一种常用手法是数据流风格。从形式上看它也是一种对电路行为的描述,但实质上它对应于RTL一级的结构模型,是一种容易被综合的准结构类表征。数据流风格常用于描述数据通路中简单组合元件的逻辑电路设计。它采用行为过程外的独立持续赋值语句,即assign语句描述。驱动强度和延迟值信息也被嵌套在持续赋值语句之中。

持续赋值(continuous_assign)语句类似于VHDL中的并发信号赋值,其格式为

assign[驱动强度][#延迟值]线网标识符=表达式{,线网标识符=表达式};它所表达的动作是:在行为风格的构件(过程)之外采用assign语句对一个或多个线网持续赋值。它与门基元类似,只能对线网类数据进行赋值。线网结构非常重要,它对应的就是物理互连线。由于线网是默认的,所以实现连接比较方便。在电路仿真中,一旦表达式中的一个值发生变化,就要重新计算表达式,并将结果赋给被驱动的标识符。

它没有保持的概念,需要不停地持续赋值才行。它完全类似于实际硬件中的一个逻辑门驱动一条实际互连线的真实情况。“持续”的含义可以理解为右边的“风吹草动”直接联动到左边。例如:

assignpwr_on=1;

下面以8位数值比较器为例阐明:

moduleMgCp(A,B,AgtB,AeqB,AltB,C);

parameterBus=8;

parameterEQ_Dl=5,LT_Dl=8,GT_Dl=8;

input[1:Bus]A,B,C;

outputAgtB,AeqB,AltB;

assign#EQ_DlAeqB=A==B;

assign#GT_DlAgtB=A>B;

assign#LT_DlAltB=A<B,C=A+B;

endmodule持续赋值语句之间是并发的,每一句都是各自根据条件自行其是,与书写的先后顺序无关。

线网的延迟一般采用惯性延迟模型,即小于线延迟的输入端电平变化在输出端将被忽略。

注意,持续赋值、过程内第一类force-release形式的持续赋值语句左端的数据类型为net,而一般的行为赋值语句(包括阻塞和非阻塞赋值)和过程内assign-deassign、另一类force-release形式的持续赋值语句左端的数据类型则为reg。但需要提醒的是,对于赋值语句右端的数据类型则没有太多的限制。此外,一个模块中数据流还允许和其他风格混合编写。

7.5行为风格描述

Verilog中行为风格的概念与VHDL相类似,但是许多地方比较简化,设计师用其来描述那些比较复杂的组合电路和时序逻辑。下面首先介绍构件、块、赋值、时序、程控的概念要点。

直接采用initial和always两种构件(Construct,见附录2IEEE-1364标准句法汇总中的行为语句部分)进行设计。构件,又称过程,主要由时序控制、程序控制语句和赋值语句组成。

•Verilog中的task、function的定义(声明)是两种比构件低一级的公用子程序,它们定义的格式与构件类似。在两类子程序调用中,任务调用是一种专门的语句,而函数调用则是一个表达式。

Verilog的构件中可以有begin_end格式的串行块,也可以有fork_join格式的并行块。

赋值语句,就是将由操作符加操作数组成表达式的值赋给赋值符号左边的线网和变量。行为构件过程中的赋值语句类别有两种:一般行为赋值和(行为)过程内持续赋值。在构件的initial和always构件内的一般赋值称为行为赋值(或称过程内一般赋值),其符号左边必须是寄存器一类的变量类型,但是它仍然适用于描述比较复杂的组合逻辑;而过程内持续赋值则是在构件内的强制性准持续赋值。

一般的行为赋值也分为两种:阻塞(Blocking)和非阻塞(Non-blocking)赋值。

无疑,构件中需要延迟和事件等时序控制,此外,也需要分支、循环、等待、禁止等程序控制,这就是Verilog的程序控制语句。

在Verilog的两种构件、两种子程序、两种块结构框架下,根据要求将时序控制前缀、赋值语句和程序控制语句相组合去处理各种数据,就可以构建出异彩纷呈的行为描述,下面分别加以介绍。7.5.1构件过程、子程序与块语句

1.初始化(initial)构件过程

initial构件在整个仿真期间只被执行一次。一个模块中使用initial构件的次数不受限制,所出现的位置也没有约定和限制。实际上,在真正做逻辑综合时,所有initial构件都将被忽略。

初始化构件过程的格式为

initial一般语句

上面格式中的一般语句(Statement)可以是赋值语句、带有过程内时序控制前缀的一般语句、程序控制语句(含if、case、loop、wait、disable等语句)、事件创建语句、块(含串行、并行块)语句、任务调用(或者系统任务调用)语句等。这些一般语句基本上都是允许嵌套的。

initial通常用来完成初始化。例如初始化寄存器和存储器:

initial

begin

areg=0;

for(index=0;index<size;index=index+1)

memory[index]=0;

end

注意,initial也可以用于程序的结束,因为它也是一次性的。

2.总是(always)构件过程

always构件可以理解成一个“while(true)”循环执行机制。它常用于描述时序逻辑电路。需要强调的是,两个或更多的always构件间是并发执行的。always构件不断反复循环被执行,直到仿真结束。一个模块中使用always构件的次数不受限制。

always构件的格式为

always一般语句

与initial构件一样,这里的一般语句也可以是赋值语句、带有过程内时序控制前缀的一般语句、程序控制语句(含if、case、loop、wait、disable等语句)、事件创建语句、块(含串行、并行块)语句、任务调用语句、系统任务调用语句等。例如产生时钟变量和不断计数:

(1) always#20areg=~areg;

//#20是指20个时间单位

(2) always@(posedgeareg)

//@表示当…事件

begin

count=count+1;

end

(3) always#5cun=(cun!=25)?(cun+1):5;需要提醒的是:由于多个always构件间是并发的,一定要将赋值延迟设计恰当。要与赋值的先后顺序配合好,以防止出现不希望的数据滑动。

为了能够有效地综合,应事先确认always中所描述的状态机是由惟一的时钟所触发。

always构件中可以同时包含串行块begin_end和并行块fork_join。

3.任务(task)子程序及调用

task和function都是一种公用的子程序定义性描述,任务和函数只能在模块项声明中定义,然后可以在initial或always构件中多次被调用。利用任务和函数完成大程序的化简和层次分解。

任务可以启动其他任务和函数;任务可以包含时序控制;任务可以定义自己的仿真时间单位;任务可以有多个任何类型的输入量(或者没有输入量);任务返回值通过输出端口给出,如下面例子所示;任务可以返回,也可以不返回输出值。任务定义的格式为

task

任务名;//无端口列表

输入输出端口声明

数据类型声明

一般语句

endtask

任务定义中的一般语句可以嵌入在串行块和并行块结构中,允许展开成多个一般语句。

任务调用(enable)可以在always和initial构件中使用,它的格式为

任务名[(表达式1,表达式2,…,表达式n)];下面给出任务设计及应用举例——完成8位数的高位和低位的交换:

moduleHas_Task;

parameterMAXBITS=8;

taskReverse_Bits;//任务定义

input[MAXBITS-1:0]Din;//端口声明先后有序

output[MAXBITS-1:0]Dout;

integerk;

begin

for(k=0;k<MAXBITS;k=k+1)

Dout[MAXBITS-1-k]=Din[k];

end

endtask

reg[MAXBITS-1:0]Reg_X,New_Reg;//为了任务调用的声明

Reverse_Bits(Reg_X,New_Reg);//此时参数的顺序必须与定义时相一致

endmodule

4.函数(function)子程序及调用

函数至少有一个输入参量值;函数也必须而且只能返回一个输出函数值;定义函数时必须至少用一条赋值语句为函数输出寄存器赋结果值;函数不能包含时序控制;函数只能和主程序共用一个仿真时间单位;函数无法启动任务。在原程序中被调用的函数起到表达式的作用。函数常用来对组合逻辑建模。函数定义的格式为

function[返回输出值的类型和范围]函数名;

输入端口声明

数据类型声明

一般语句

endfunction

函数定义中的一般语句可以嵌入在串行块和并行块结构中,允许展开成多个一般语句。注意,函数定义中不能出现时序控制,即延迟#、事件@等标识符,也不能包括wait语句。

格式中的[返回输出值的类型和范围],给出对以(函数名)命名的输出寄存器的声明;如果返回值声明默认,则默认该函数为一位数寄存器。

函数调用(call)是一个表达式,它的格式为

函数名(输入表达式1,输入表达式2,…,输入表达式n);函数设计及应用举例——完成8位数的高位和低位的交换:

moduleFunction_Example;

parameterMAXBITS=8;

function[MAXBITS-1:0]Reverse_Bits; //函数定义

input[MAXBITS-1:0]Din; //端口声明先后有序,输出则勿须声明

integerk;

begin

for(k=0;k<MAXBITS;k=k+1)

Reverse_Bits[MAXBITS-1-k]=Din[k];

end

endfunction

reg[MAXBITS-1:0]Reg_X,New_Reg; //为了函数调用的声明

New_reg=Reverse_Bits(Reg_X); //多参数时顺序必须与定义时相一致

endmodule

5.串行块(seq_block)语句

在行为描述的构件中主要有两种块语句:串行块(seq_block)语句和并行块(par_block)语句。块内由许多语句构成一个总的统一块语句。

在串行块内的begin和end(起始和结束)之间的语句按顺序执行,每条语句的延迟时间是相对于前一条语句的仿真时间而言的。整个块的最初起始时间是块内第一个语句开始被执行的时间;整个块的最后结束时间是块内最后一条语句执行结束的时间。串行块语句的格式为

begin[:块名]

[块内声明]

一般语句1

一般语句2

一般语句n

end

格式中的[块内声明],可以是多种数据类型声明,包括integer、real、reg、parameter等。举例:

begin

areg=breg;

creg=breg;

end

串行语句可以出现在initial和always构件中;串行块可以嵌套。串行块中的延迟采用的是相对延迟。

6.并行块(par_block)语句

在并行块fork_join(分叉和汇合)内的语句同时开始、并行执行,每条语句的延迟量是相对于程序进入到块内的仿真时间而言,相互间是独立的。当执行完按绝对仿真时间排在最后的语句(不一定是写在最后的语句)之后,或者程序执行了一条禁止disable语句之后,程序就从块语句跳出。整个块的最初起始时间对于块内的所有语句都是相同的,即程序流进入该块的时间;块结束时间是块内按绝对仿真时间排在最后的一条语句执行结束的时间。只有该块结束之后,跟在该块后面的语句才得以执行。fork_join块内的语句不必按顺序给出。并行块语句的格式为

fork[:块名]

[块内声明]

一般语句1

一般语句2

一般语句n

join

格式中的[块内声明]可以是多种数据类型声明,包括integer、real、reg、parameter、time、event等。举例:

fork

#50r=‘h35; //无位宽的十六进制数

#100r=’hE2;

#150r=‘h00;

#200r=’hF7;

#250->end_wave; //创建事件end_wave用的event_trigger语句

join

并行块内的延迟采用的是绝对延迟。

串行块中可以嵌套并行块,并行块中可以嵌套串行块。在设计ASIC时,要慎用fork_join语句,因为难于硬件实现。7.5.2行为风格中的赋值语句

行为风格中的赋值语句有两类:构件过程内的一般赋值(包括阻塞和非阻塞赋值);构件过程内的持续赋值(包括assign-deassign和force-deforce两种形式的赋值)。

1.一般赋值语句

行为风格中的一般赋值语句,只能实现对reg类型变量数据的赋值。

=、<=分别为阻塞和非阻塞赋值符号(注意,不要将非阻塞赋值符号<=与小于等于符号<=混淆)。

1)阻塞式(Blocking)赋值

这是一种立即赋值,可以理解为排他性赋值。例如,a=b;使得a立即获得值b。位于赋值关系式右侧(RHS)的值或任何表达式按照定时要求更新位于左侧(LHS)的寄存器或存储器的值,并且保持该值直到另一个赋值语句启动。

例如:

always@(c)y=a;赋值语句当事件c出现时立即改变y(reg)的值,并将保持下去,其默认初始值为x。此时,允许把wire上的值赋给reg。

又如:

begin

a=#2b;

c=#3a;

end

2)非阻塞式(Non-blocking)赋值

类似VHDL的信号赋值,它只对寄存器类型变量赋值,是在构件过程结束后的统一时刻才真正赋值。这类非阻塞赋值语句将根据构件规定的时序控制条件,同步同时并发地执行。例如,某一模块中有一个always@(c)a<=b;语句,则a不能立即获得值b。需要和其他同类语句一起,等到条件c为真时同时赋值。大型数字系统行为中所有的记忆单元一般都是由相同时钟边沿同步并发控制地变化,非阻塞赋值就是与这种实际情况相对应。

非阻塞赋值中的延迟是绝对延迟,从某一时刻起始统一计时。除了并行块和非阻塞赋值外,其他均取相对延迟,即一句与一句之间的相对延迟值。构件中的非阻塞赋值间是并发的,句法没有规定它们的顺序。如同VHDL一样,语法规定赋值符号右边表达式中要代入变量的原值。例如,下面表达式中的变量a。

begin

a<=#2b;

c<=#3a;

end

2.持续赋值语句

Verilog中过程内持续赋值语句(ProceduralContinuousAssignment)是在构件内采用assign-deassign或force-release形式的强制性赋值语句。它们具有持续赋值的特征,也被称为准持续赋值。不过,这里给出的赋值只在一段时间内有效。assign-deassign只对reg赋值,force-release可以对reg或net赋值。描述一个带异步置位和异步复位端的D触发器电路,可以加入assign-deassign。举例:

always@(reset_orset_)//低电平有效

if(!reset_)assignq=0;

elseif(!set_)assignq=1;

else

deassignq;

/*上边的deassign解赋值语句,使得强制赋值方式取消。寄存器q可以再赋它值,例如接着执行下述赋值语句*/

always@(posedgeclock)q=d; … 在过程内持续赋值句法中,assign-deassign对应于一些异步操作。有学者认为其风格怪异,主张尽量少用。

与上述assign-deassign形式对称的还有force-release形式。两种形式的共同点是:右端表达式中操作数的任何变化都会导致强制执行赋值语句,这正是准持续的含义。它们的不同点是:assign-deassign用于寄存器reg赋值;而force-release除了可以对reg赋值外,还可以用于行为描述中对线网net赋值。force-release主要用于仿真调试。7.5.3过程内语句中的时序控制

VerilogHDL过程内语句(procedural_timing_control_statement)拥有时序控制的前缀。这样,用时序控制来给出仿真器时间的推进方式,在仿真中对发生时刻(用前缀符号#来表征)和事件次序(用前缀符号@来表征)实施控制。

时序控制分为门级时序模型和行为时序模型两种。数据流和结构对应门级时序;行为风格对应行为时序。与7.3.3节中介绍过的门级时序模型相类似,这里的行为时序控制除了延迟控制之外,还有事件控制。一般设计中,可以让延迟控制和事件控制共同起时序控制作用。

1)延迟控制

延迟控制采用符号#,少了上升、下降、高阻的区别。其格式有两种:

#

延迟值

#

(最小延迟:典型延迟:最大延迟)

#6表示有6个时间单位延迟,其在语句中共有两种写法。举例:

(1) x=#3y;//它等价于下列内插延迟

begin

hold=y;

#3;

x=hold;

end

(2) #3x=y;//它等价于

begin

#3;

x=y;

end

Verilog的数据流和结构风格中,对于门延迟也是采用延迟控制描述。

2)事件控制

事件(Event)的含义与VHDL相似,主要指任何值的变化,即边沿跳变,用得较多的有posedge表示正边沿;negedge表示负边沿。正边沿描述有01、0x、x1三种;负边沿描述有10、1x、x0三种(z也参与变化,但一般不考虑z)。

事件名就是事件标识符,它是对事件进行的专门标识。例如变量ae可以产生值的变化,就可以将ae单独命名为事件名,以表示“它的值发生了变化”这件事。用event声明来定义具体的事件名,形如:

eventae;

事件控制的格式为

@事件名或

@(事件表达式)

@(事件表达式or

事件表达式)

事件表达式可以写成单个或两个操作数之间的运算。操作数可以是具体的数、标识符或者表达式。例如,表示一直要等到事件ae发生这一条件的到来:

@ae注意下面二者的区别:

@事件名;一般语句

/*上面等价于两句,如果出现在begin_end块中在句法上就是对的。是要等待事件发生后执行一个空语句,一般语句才执行*/

@事件名一般语句//是指当事件出现时刻,就执行一般语句

#延迟量

->事件名;

上式表示在左边的延迟条件下,将创建右边的事件。形如:

#5->ae;这时从功能上它可以等效于:

#5

begin

ae=0;

#0a

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论