Verilog-HDL教程.docx
VerilogHDL教程提纲:第一节Verilog简介第二节HDL入门指南第三节Verilog语言要素第四节Verilog中的表达式第五节门级电路模型化第六节Verilog编码技术第七节设计练习进阶(10个设计例子和分析)第一节Verilog简介VerilOgHDL是一种硬件描述语言,用于从算法级、门级到开关级的多种抽象设计层次的数字系统建模。被建模的数字系统对象的复杂性可以介于简单的门和完整的电子数字系统之间。数字系统能够按层次描述,并可在相同描述中显式地进行时序建模。VerilogHDL语言具有下述描述能力:设计的行为特性、设计的数据流特性、设计的结构组成以及包含响应监控和设计验证方面的时延和波形产生机制。所有这些都使用同一种建模语言。止匕外,VerilogHDL语言提供了编程语言接口,通过该接口可以在模拟、验证期间从设计外部访问设计,包括模拟的具体控制和运行。VeriIOgHDL语言不仅定义了语法,而且对每个语法结构都定义了清晰的模拟、仿真语义。因此,用这种语言编写的模型能够使用VerilOg仿真器进行验证。语言从C编程语言中继承了多种操作符和结构。VerilOgHDL提供了扩展的建模能力,其中许多扩展最初很难理解。但是,VeriIOgHDL语言的核心子集非常易于学习和使用,这对大多数建模应用来说已经足够。当然,完整的硬件描述语言足以对从最复杂的芯片到完整的电子系统进行描述。历史:VerilogHDL语言最初是于1983年由GatewayDesignAutomation公司为其模拟器产品开发的硬件建模语言。那时它只是一种专用语言。由于他们的模拟、仿真器产品的广泛使用,VerilogHDL作为一种便于使用且实用的语言逐渐为众多设计者所接受。在一次努力增加语言普及性的活动中,VerilogHDL语言于1990年被推向公众领域。OPenVerilogInternational(OVI)是促进Verilog发展的国际性组织。1992年,OVl决定致力于推广VeriIogoVl标准成为IEEE标准。这一努力最后获得成功,Verilog语言于1995年成为IEEE标准,称为IEEEStd1364-1995o完整的标准在Verilog硬件描述语言参考手册中有详细描述。主要能力:下面列出的是Verilog硬件描述语言的主要能力:*基本逻辑门,例如and>or和nand等都内置在语言中。* 用户定义原语(UDP)创建的灵活性。用户定义的原语既可以是组合逻辑原语,也可以是时序逻辑原语。* 开关级基本结构模型,例如PmoS和nmos等也被内置在语言中。* 提供显式语言结构指定设计中的端口到端口的时延及路径时延和设计的时序检查。* 可采用三种不同方式或混合方式对设计建模。这些方式包括:行为描述方式一使用过程化结构建模;数据流方式一使用连续赋值语句方式建模;结构化方式一使用门和模块实例语句描述建模。*VerilogHDL中有两类数据类型:线网数据类型和寄存器数据类型。线网类型表示构件间的物理连线,而寄存器类型表示抽象的数据存储元件。* 能够描述层次设计,可使用模块实例结构描述任何层次。* 设计的规模可以是任意的;语言不对设计的规模(大小)施加任何限制。* VerilogHDL不再是某些公司的专有语言而是IEEE标准。*人和机器都可阅读VeriIOg语言,因此它可作为EDA的工具和设计者之间的交互语言。*VerilogHDL语言的描述能力能够通过使用编程语言接口(PLI)机制进一步扩展。PLl是允许外部函数访问VerilOg模块内信息、允许设计者与模拟器交互的例程集合。* 设计能够在多个层次上加以描述,从开关级、门级、寄存器传送级(RTL)到算法级,包括进程和队列级。* 能够使用内置开关级原语在开关级对设计完整建模。* 同一语言可用于生成模拟激励和指定测试的验证约束条件,例如输入值的指定。* VerilogHDL能够监控模拟验证的执行,即模拟验证执行过程中设计的值能够被监控和显示。这些值也能够用于与期望值比较,在不匹配的情况下,打印报告消息。* 在行为级描述中,VerilOgHDL不仅能够在RTL级上进行设计描述,而且能够在体系结构级描述及其算法级行为上进行设计描述。* 能够使用门和模块实例化语句在结构级进行结构描述。* VerilogHDL的混合方式建模能力,即在一个设计中每个模块均可以在不同设计层次上建模。* VerilogHDL还具有内置逻辑函数,例如&(按位与)和(按位或)。* 高级编程语言结构,例如条件语句、情况语句和循环语句,语言中都可以使用。* 可以显式地对并发和定时进行建模。* 提供强有力的文件读写能力。* 语言在特定情况下是非确定性的,即在不同的模拟器上模型可以产生不同的结果;例如,事件队列上的事件顺序在标准中没有定义。习题1 .VerilogHDL是在哪一年首次被IEEE标准化的?2 .VerilogHDL支持哪三种基本描述方式?3 .可以使用VeriIogHDL描述一个设计的时序吗?4 .语言中的什么特性能够用于描述参数化设计?5 .能够使用VerilOgHDL编写测试验证程序吗?6 .VerilogHDL是由哪个公司最先开发的?7 .VerilogHDL中的两类主要数据类型什么?8 .UDP代表什么?9 .写出两个开关级基本门的名称。10 .写出两个基本逻辑门的名称。第二节VeriIogHDL入门指南本章提供VerilogHDL语言的速成指南。模块是VeriIOg的基本描述单位,用于描述某个设计的功能或结构及其与其他模块通信的外部端口。一个设计的结构可使用开关级原语、门级原语和用户定义的原语方式描述;设计的数据流行为使用连续赋值语句进行描述;时序行为使用过程结构描述。一个模块可以在另一个模块中调用。一个模块的基本语法如下:modulemodule_name(portjist);Declarations:reg,wire,parameter,input,output,inout,function,task,.Statements:InitialstatementAlwaysstatementModuleinstantiationGateinstantiationUDPinstantiationContinuousassignmentendmodule模块的定义从关键字module开始,到关键字endmodule结束,每条VerilogHDL语句以做为结束(块语句、编译向导、endmodule等少数除外)。一个完整的Verilog模块由以下五个部分组成:1 .模块定义行:modulemodule_name(portjist);2 .说明部分用于定义不同的项,例如模块描述中使用的寄存器和参数。语句定义设计的功能和结构。说明部分和语句可以散布在模块中的任何地方;但是变量、寄存器、线网和参数等的说明部分必须在使用前出现。为了使模块描述清晰和具有良好的可读性,最好将所有的说明部分放在语句前。说明部分包括:寄存器,线网,参数:reg,wire,parameter端口类型说明行:input,output,inout函数、任务:function,task,等3 .描述体部分:这是一个模块最重要的部分,在这里描述模块的行为和功能,子模块的调用和连接,逻辑门的调用,用户自定义部件的调用,初始态赋值,always块,连续赋值语句等等。4 .结束行,以endmodule结束,注意后面没有分号了。以下为建模一个半加器电路的模块的简单实例。moduleHalfAdder(A,B,Sum,Carry);inputA,B;outputSum,Carry;assign#2Sum=AB;assign#3Carry=A&B;endmodule模块的名字是HalfAdder。模块有4个端口:两个输入端口A和B,两个输出端口SUm和Carryo由于没有定义端口的位数,所有端口大小都为1位;同时,由于没有各端口的数据类型说明,这四个端口都是线网数据类型。模块包含两条描述半加器数据流行为的连续赋值语句。从这种意义上讲,这些语句在模块中出现的顺序无关紧要,这些语句是并发的。每条语句的执行顺序依赖于发生在变量A和B上的事件。在模块中,可用下述方式描述一个设计:1)数据流方式;2)行为方式;3)结构方式;4)上述描述方式的混合。下面几节通过实例讲述这些设计描述方式。不过有必要首先对VerilOgHDL的时延作简要介绍。2.2 时延VerilogHDL模型中的所有时延都根据时间单位定义。下面是带时延的连续赋值语句实例。时间单位是由timescale定义的,timescale将在后面讲述。assign#2Sum=AB;#2指2个时间单位。使用编译指令将时间单位与物理时间相关联。这样的编译器指令需在模块描述前定义,如下所示:、timescaleIns/100ps此语句说明时延时间单位为InS并且时间精度为I(X)PS(时间精度是指所有的时延必须被限定在0.1ns内)。如果此编译器指令所在的模块包含上面的连续赋值语句,#2代表2nso如果没有这样的编译器指令,VerilogHDL模拟器会指定一个缺省时间单位。IEEEVerilogHDL标准中没有规定缺省时间单位。2.3 数据流描述方式用数据流描述方式对一个设计建模的最基本的机制就是使用连续赋值语句。在连续赋值语句中,某个值被指派给线网变量。连续赋值语句的语法为:assigndelayLHS_net=RHS_expression;右边表达式使用的操作数无论何时发生变化,右边表达式都重新计算,并且在指定的时延后变化值被赋予左边表达式的线网变量。时延定义了右边表达式操作数变化与赋值给左边表达式之间的持续时间。如果没有定义时延值,缺省时延为0。下面的例子显示了使用数据流描述方式对2-4解码器电路的建模的实例模型。'timescalelnsInsmoduleDecoder2x4(A,B,EN,Z);inputA,B,EN;output0:3Z;wireAbar,Bbar;assign#1Abar=A;/语句loassign#1Bbar=B;/语句2oassign#2Z0=(Abar&Bbar&EN);/语句3oassign#2Zl=(Abar&B&EN);/语句40assign#2Z2=(A&Bbar&EN);/语句5。assign#2Z3=(A&B&EN);/语句6。endmodule以反引号“'”开始的第一条语句是编译器指令,编译器指令、timescale将模块中所有时延的单位设置为1ns,时间精度为1ns。例如,在连续赋值语句中时延值#1和#2分别对应时延InS和2ns。模块Decoder2x4有3个输入端口和1个4位输出端口。线网类型说明了两个连线型变量Abar和Bbar(连线类型是线网类型的一种)。止匕外,模块包含6个连续赋值语句。当EN在第5ns变化时,语句3、4、5和6执行。这是因为EN是这些连续赋值语句中右边表达式的操作数。Z在第7ns时被赋予新值0。当A在第15ns变化时,语句1、5和6执行。执行语句5和6不影响Z0和Zl的取值。执行语句5导致Z2值在第17ns变为Oo执行语句1导致Abar在第16ns被重新赋值。由于Abar的改变,反过来又导致Z0值在第18ns变为Io请注意连续赋值语句是如何对电路的数据流行为建模的;这种建模方式是隐式而非显式的建模方式。止匕外,连续赋值语句是并发执行的,也就是说各语句的执行顺序与其在描述中出现的顺序无关。2.4 行为描述方式设计的行为功能使用下述过程语句结构描述:Dinitial语句:此语句只执行一次。2)always语句:此语句总是循环执行,或者说此语句重复执行。只有寄存器类型数据能够在这两种语句中被赋值。寄存器类型数据在被赋新值前保持原有值不变。所有的初始化语句和always语句在0时刻并发执行。下例为always语句对1位全加器电路建模的示例。moduleFA_Seq(A,B,Cin,Sum,Cout);inputA,B,Cin;outputSum,Cout;regSum,Cout;regTl,T2,T3;always(AorBorCin)beginSum=(AaB)aCiii;Tl=A&Cin;T2=B&Cin;T3=A&B;Cout=(TlT2)T3;endendmodule模块FA_Seq有三个输入和两个输出。由于SUm、CoUt、TKT2和T3在always语句中被赋值,它们被说明为reg类型(reg是寄存器数据类型的一种)。always语句中有一个与事件控制(紧跟在字符后面的表达式)。相关联的顺序过程(begin-end对)。这意味着只要A、B或Cin上发生事件,即A、B或Cin之一的值发生变化,顺序过程就执行。在顺序过程中的语句顺序执行,并且在顺序过程执行结束后被挂起。顺序过程执行完成后,always语句再次等待A、B或Cin上发生的事件。在顺序过程中出现的语句是过程赋值模块化的实例。模块化过程赋值在下一条语句执行前完成执行。过程赋值可以有一个可选的时延。时延可以细分为两种类型:1)语句间时延:这是时延语句执行的时延。2)语句内时延:这是右边表达式数值计算与左边表达式赋值间的时延。下面是语句间时延的示例:Sum=(AaB)aCiii;#4Tl=A&Cin;在第二条语句中的时延规定赋值延迟4个时间单位执行。就是说,在第一条语句执行后等待4个时间单位,然后执行第二条语句。下面是语句内时延的示例。Sum=#3(AB)Cin;这个赋值中的时延意味着首先计算右边表达式的值,等待3个时间单位,然后赋值给Sum0如果在过程赋值中未定义时延,缺省值为0时延,也就是说,赋值立即发生。这种形式以及在always语句中指定语句的其他形式将在第8章中详细讨论。下面是initial语句的示例:'timescaleIns/InsmoduleTest(Pop,Pid);outputPop,Pid;regPop,Pid;initialbeginPop=0;/语句IoPid=O;/语句2。Pop=#51;/语句30Pid=#31;/语句40Pop=#6O;/语句5oPid=#2O;/语句6oendendmoduleinitial语句包含一个顺序过程。这一顺序过程在OnS时开始执行,并且在顺序过程中所有语句全部执行完毕后,initial语句永远挂起。这一顺序过程包含带有定义语句内时延的分组过程赋值的实例。语句1和2在0ns时执行。第三条语句也在0时刻执行,导致Pop在第5ns时被赋值。语句4在第5ns执行,并且Pid在第8ns被赋值。同样,Pop在14ns被赋值0,Pid在第16ns被赋值0。第6条语句执行后,initial语句永远被挂起。2.5 结构化描述形式在VerilogHDL中可使用如下方式描述结构:1)内置门原语(在门级);2)开关级原语(在晶体管级);3)用户定义的原语(在门级);4)模块实例(创建层次结构)。通过使用线网来相互连接。下面的结构描述形式使用内置门原语描述的全加器电路实例。moduleFA_Str(A,B,Cin,Sum,Cout);inputA,B,Cin;outputSum,Cout;wireSl,Tl,T2,T3;xorXl(SI,A,B),X2(Sum,SI,Cin);andAl(T3,A,B),A2(T2,B,Cin),A3(Tl,A,Cin),orOl(Cout,Tl,T2,T3);endmodule在这一实例中,模块包含门的实例语句,也就是说包含内置门xor、and和Or的实例语句。门实例由线网类型变量SI、TKT2和T3互连。由于没有指定的顺序,门实例语句可以以任何顺序出现;图中显示了纯结构;xonand和Or是内置门原语;XI、X2、AI等是实例名称。紧跟在每个门后的信号列表是它的互连;列表中的第一个是门输出,余下的是输入。例如,Sl与xor门实例Xl的输出连接,而A和B与实例Xl的输入连接。4位全加器可以使用4个1位全加器模块描述。下面是4位全加器的结构描述形式。moduleFourBitFA(FA,FB,FCin,FSum,FCout);parameterSIZE=4;inputSIZE:1FA,FB;outputSIZE:1FSuminputFCin;inputFCout;wire1:SIZE1FTemp;FA_StrFA1(.A(FA1),.B(FB1),.Cin(FCin),.Sum(FSuml),.Cout(FTemp2),FA2(.A(FA2),.B(FB2),.Cin(FTempl),.Sum(FSum2),.Cout(FTemp2),FA3(FA3,FB3,FTemp2,FSum3,FTemp3,FA4(FA4,FB4,FTemp3,FSum4,FCout);endmodule在这一实例中,模块实例用于建模4位全加器。在模块实例语句中,端口可以与名称或位置关联。前两个实例FAI和FA2使用命名关联方式,也就是说,端口的名称和它连接的线网被显式描述(每一个的形式都为“.port_name(net_name)o最后两个实例语句,实例FA3和FA4使用位置关联方式将端口与线网关联。这里关联的顺序很重要,例如,在实例FA4中,第一个FA4与FA_Str的端口A连接,第二个FB4与FA_Str的端口B连接,余下的由此类推。2.6 混合设计描述方式在模块中,结构的和行为的结构可以自由混合。也就是说,模块描述中可以包含实例化的门、模块实例化语句、连续赋值语句以及always语句和initial语句的混合。它们之间可以相互包含。来自always语句和initial语句(切记只有寄存器类型数据可以在这两种语句中赋值)的值能够驱动门或开关,而来自于门或连续赋值语句(只能驱动线网)的值能够反过来用于触发always语句和initial语句。下面是混合设计方式的1位全加器实例。moduleFA_Mix(A,B,Cin,Sum,Cout);inputA,B,Cin;outputSum,Cout;regCout;regTl,T2,T3;wireSI;xorXl(Sl,A,B);/门实例语句。always(AorBorCin)begin/always语句。Tl=A&Cin;T2=B&Cin;T3=A&B;Cout=(TlT2)T3;endassignSum=SlCin;/连续赋值语句。endmodule只要A或B上有事件发生,门实例语句即被执行。只要A、B或Cin上有事件发生,就执行always语句,并且只要Sl或Cin上有事件发生,就执行连续赋值语句。2.7 设计模拟VerilOgHDL不仅提供描述设计的能力,而且提供对激励、控制、存储响应和设计验证的建模能力。激励和控制可用初始化语句产生。验证运行过程中的响应可以作为“变化时保存”或作为选通的数据存储。最后,设计验证可以通过在初始化语句中写入相应的语句自动与期望的响应值比较完成。下面是测试模块Top的例子。该例子测试2.3节中讲到的FA_Seq模块。'timescalelnsInsmoduleTop;/一个模块可以有一个空的端口列表。regPA,PB,PCi;wirePCo,PSum;/正在测试的实例化模块:FA_SeqF1(PA,PB,PCi,PSum,PCo);/定位。initialbegin:ONLY_ONCEreg3:0Pal;/需要4位,Pal才能取值8。for(Pal=0;Pal<8;Pal=Pal+1)beginPA,PB,PCi=Pal;#5Sdisplay(TA,PB,PCi=%b%b%b,5PA,PB,PCi,“:PCo,PSUm=%b%b”,PCo,PSum);endendendmodule在测试模块描述中使用位置关联方式将模块实例语句中的信号与模块中的端口相连接。也就是说,PA连接到模块FA_Seq的端口A,PB连接到模块FA_Seq的端口B,依此类推。注意初始化语句中使用了一个for循环语句,在PA、PB和PCi上产生波形。for循环中的第一条赋值语句用于表示合并的目标。自右向左,右端各相应的位赋给左端的参数。初始化语句还包含有一个预先定义好的系统任务。系统任务$display将输入以特定的格式打印输出。系统任务$display调用中的时延控制规定$display任务在5个时间单位后执行。这5个时间单位基本上代表了逻辑处理时间。即是输入向量的加载至观察到模块在测试条件下输出之间的延迟时间。这一模型中还有另外一个细微差别。Pal在初始化语句内被局部定义。为完成这一功能,初始化语句中的顺序过程(begin-end)必须标记。在这种情况下,0NLY_0NCE是顺序过程标记。如果在顺序过程内没有局部声明的变量,就不需要该标记。下面是测试模块产生的输出。PA,PB,PCi=000:PCo,PSum=00PA,PB,PCi=OOl:PCo,PSum=OlPA,PB,PCi=OlO:PCo,PSum=OlPA,PB,PCi=011:PCo,PSum=10PA,PB,PCi=100:PCo,PSum=OlPA,PB,PCi=101:PCo,PSum=10PA,PB,PCi=110:PCo,PSum=10PA,PB,PCi=111:PCo,PSum=11验证与非门交叉连接构成的RS-FF模块的测试模块如下例所示。'timescale10nslnsmoduleRS_FF(Q,Qbar,R,S);outputQ,Qbar;inputR,S;nand#1(Q,R,Qbar);nand#1(Qbar,S,Q,);在门实例语句中,实例名称是可选的。endmodulemoduleTest;regTS,TR;wireTQ,TQb;测试模块的实例语句:RS_FFNSTA(.Q(TQ),.S(TS),.R(TR),.Qbar(TQb);/采用端口名相关联的连接方式。/加载激励:initialbegin:TR=O;TS=O;# 5TS=1;# 5TS=0;TR=1;# 5TS=1;TR=O;# 5TS=O;# 5TR=1;end/输出显示:initialSmonitor(11Attime%t,n,$time,11TR=%b,TS=%b,TQ=%b,TQb=%b11,TR,TS,TQ,TQb);endmoduleRS_FF模块描述了设计的结构。在门实例语句中使用门时延;例如,第一个实例语句中的门时延为1个时间单位。该门时延意味着如果R或Qbar假定在T时刻变化,Q将在T+1时刻获得计算结果值。模块Test是一个测试模块。测试模块中的RS-FF用实例语句说明其端口用端口名关联方式连接。在这一模块中有两条初始化语句。第一个初始化语句只简单地产生TS和TR上的波形。这一初始化语句包含带有语句间时延的程序块过程赋值语句。第二条初始化语句调用系统任务$monitor。这一系统任务调用的功能是只要参数表中指定的变量值发生变化就打印指定的字符串。下面是测试模块产生的输出。请注意、timescale指令在时延上的影响。Attime0,TR=O,TS=O,TQ=x,TQb=XAttime10,TR=O,TS=O,TQ=I,TQb=1Attime50,TR=O,TS=I,TQ=I,TQb=1Attime60,TR=O,TS=I9TQ=I9TQb=0Attime100,TR=I9TS=O,TQ=I,TQb=0Attime110,TR=I,TS=O,TQ=I,TQb=1Attime120,TR=I9TS=O,TQ=O,TQb=1Attime150,TR=O,TS=I9TQ=O,TQb=1Attime160,TR=O,TS=I,TQ=I,TQb=1Attime170,TR=O,TS=I,TQ=I,TQb=0Attime200,TR=O,TS=O,TQ=I,TQb=0Attime210,TR=O,TS=O,TQ=I,TQb=1Attime250,TR=I,TS=O,TQ=I,TQb=1Attime260,TR=I,TS=O,TQ=O,TQb=1习题1 .在数据流描述方式中使用什么语句描述一个设计?2 .使用、timescale编译器指令的目的是什么?举出一个实例。3 .在过程赋值语句中可以定义哪两种时延?请举例详细说明。4 .initial语句与always语句的关键区别是什么?5 .为2.3节中描述的模块Decode2x4编写一个测试验证程序。6 .列出你在VerilogHDL模型中使用的两类赋值语句。7 .在顺序过程中何时需要定义标记?8 .找出下面连续赋值语句的错误。assignReset=#2WriteBus;第三节Verilog语言要素本章介绍VerilogHDL的基本要素,包括标识符、注释、数值、编译程序指令、系统任务和系统函数。另外,本章还介绍了Verilog硬件描述语言中的两种数据类型。3.1 标识符VerilOgHDL中的标识符(identifier)可以是任意一组字母、数字、$符号和_(下划线)符号的组合,但标识符的第一个字符必须是字母或者下划线。另外,标识符是区分大小写的。以下是标识符的几个例子:CountCOUNT/CoUnt不同。_R1_D2R56_68FIVES转义标识符(escapedidentifier)可以在一条标识符中包含任何可打印字符。转义标识符以(反斜线)符号开头,以空白结尾(空白可以是一个空格、一个制表字符或换行符)。下面例举了几个转义标识符:7400、*QXOutGate与OutGate相同。最后这个例子解释了在一条转义标识符中,反斜线和结束空格并不是转义标识符的一部分。也就是说,标识符0utGate和标识符OUtGate恒等。VerilOgHDL定义了一系列保留字,叫做关键词,它仅用于某些上下文中。注意只有小写的关键词才是保留字。例如,标识符always(这是个关键词)与标识符ALWAYS(非关键词)是不同的。另外,转义标识符与关键词并不完全相同。标识符'initial与标识符initial(这是个关键词)不同。注意这一约定与那些转义标识符不同。3.2 注释在VerilogHDL中有两种形式的注释。/*第一种形式:可以扩展至多行*/第二种形式:在本行结束。3.3 格式VeriIOgHDL区分大小写。也就是说大小写不同的标识符是不同的。止匕外,VerilogHDL是自由格式的,即结构可以跨越多行编写,也可以在一行内编写。白空(新行、制表符和空格)没有特殊意义。下面通过实例解释说明。initialbeginTop=3,b001;#2Top=3,bll;end和下面的指令一样:initialbeginTop=3,b001;#2ToP=3'011;end3.4 系统任务和函数以$字符开始的标识符表示系统任务或系统函数。VeriIOgHDL提供了一系列的系统功能调用,任务型的功能调用称之为系统任务(SyStemtask),函数型的调用称之为系统函数(Systemfunction)o系统任务提供了一种封装行为的机制。这种机制可在设计的不同部分被调用。任务可以返回0个或多个值。系统函数除只能返回一个值以外与任务相同。此外,函数在。时刻执行,即不允许延迟,而任务可以带有延迟。一般可以统称为系统函数。VerilogHDL中的系统任务和系统函数是面向模拟的、嵌入到VerilogHdl语句中的模拟系统功能调用。这一部分与相关的模拟器直接相关,不同的模拟器,支持的系统函数可能会有所不同,但是大多数系统函数都是支持的。下面介绍最基本的、最常用的系统任务和系统函数。系统任务和系统函数可以分成以下几类:1 .输出控制类系统函数:模拟过程的状态信息以及模拟结果的输出都必须按一定的格式进行表示,Verilog所提供的输出控制类系统函数的目的就是完成对输出量的格式控制。属于这一类的有:$display,$Write,$nIinitOr等。2 .模拟时标类系统函数:Verilog中有一组与模拟时间定标相关的系统函数,比如$timeSrealtime等。3 .进程控制类系统任务:这一类系统任务用于对模拟进程控制,有$输位11,$StOP等。4 .文件读写类系统任务:用于控制对数据文件读写方式,如$起出110111。5 .其他类:比如随机数产生系统函数$random。3.4.1 Sdisplay和$Write调用格式为:$display(“格式控制输出和字符串”,输出变量名表);$Write(“格式控制输出和字符串L输出变量名表);输出变量名表就是指要输出的变量,各变量之间用逗号相隔。格式控制输出内容包括需要输出的普通字符和对输出变量显示方式控制的格式说明符,格式说明符和变量需要一一对应。$display和$Write的区别是前者输出结束后自动换行,后者不会。格式控制符用于对变量的格式进行控制,指定变量按照一定的格式输出。格式说明符输出格式%h或%H以十六进制的格式输出%d或%D以十进制的格式输出%o或0以八进制的格式输出%b或%B以二进制的格式输出%c或%C以ASCn字符形式输出%s或%S以字符串方式输出%v或%V输出连线型数据的驱动强度%t或%T输出模拟系统所使用的时间单位%m或%M输出所在模块的分级名%e或%E将实型量以指数方式显示%f或%F将实型量以浮点方式显示%g或%G将实型量以上面两种种较短的方式显示(1)控制字符“h、d、o、b”用于对整型量数据的输出控制。对于有位宽定义的量,输出的宽度将由位宽和输出的进制格式两方面决定。如果数据的前面有很多个O前导,可以在控制字符前加0,比如0b,这样一个数据为OOlO的就显示为IO0通常情况需要每一个变量都需要一个控制字符对应,如果缺省,$display函数将按十进制方式显示,$displayh代表缺省态为十六进制,$displayo代表缺省态为八进制,Sdisplayb代表缺省态为二进制。在数据中,可能会有某些位是不定态X或者高阻态z,如果用二进制方式显示,每一位都将显示出来,如果对于八进制或者十六进制,它们的一位相当于二进制的三位或者四位,如果这几位都是X,贝U八、十六进制的相应位也为X,如果这几位不全是X只是个别位是X,贝U八、十六进制的相应位为X。对于高阻Z规则相同。但是对于十进制的表示时,由于没有相互对应的位,所以把十进制数当作一个整体对待,规则相同,如果全部为X或者z,则十进制为X或者z,如果部分为X或者z,则十进制为X或者Z,但是对于既有X又有Z的时候,没有规定统一的标准。(2)控制字符“c、s”这两个把变量转化成字符或者字符串进行输出。对于c(或者C),如果变量的位宽大于8为,则只取最低8位,输出它的ASCn字符;如果变量低于8位,则高位补Oo对于s(或者S),如果变量位宽小于8位,则高位补0并输出它的ASCII字符,如果变量宽度大于8位,则从低位开始每8位输出对应的ASCII字符,一直到剩余高端部分全部为。时停止。(3)控制字符“v”这个控制字符只能用于一位宽的连线型变量,用于输出它的驱动强度。Verilog中定义了8级驱动强度,定义及缩写表示如下:缩写符号强度名称强度等级SuSuperdrive7StStrongdriver6PuPulldriver5LaLargecapacitor4WeWeakdriver3MeMediundriver2SmSmallcapacitor1HiHighimpedance0在信号的逻辑状态表示的时候,还有几个缩写形式,如下表所示:0逻辑01逻辑1X不定态Z(WJ阻态L逻辑。或者高阻态H逻辑1或者高阻态(4)控制字符“t、m”这两个都不需要有相应的输出变量与之对应,因为他们反映的是模拟系统或者模块本身的信息。t给出了系统运行模拟程序所用的模拟时间以什么为单位。m给出当前所在模块的名称。需要说明的是,它显示的名称是分级名,也就是模块被调用时的调用名,另外,除了模块外,任务、函数、有名块,都构成一个新的层次并将在分级名中出现。(5)控制字符%、f、g”这三个是专门为实型量的输出而设置的,对它们的定义完全和C语言中的相应定义。3.4.2 系统任务$111OnitOrSdisplay与$Write一样,同属于输出控制类,它的调用形式可以有以下三种:$monitor(“格式控制输出和字符串、输出变量名表);Smonitoron;Smonitoroff;以上第一种的格式和上面的$display完全一致,不同点是,Sdisplay每调用一次执行一次,$mOnitOr则一旦被调用,就会随着对输出变量名表中的每一个变量检测,如果发现其中任何一个变量在模拟过程中发生了变化,就会按中的格式,产生一次输出。为了明确输出的信息究竟在模拟过程中的什么时刻产生的,通常情况下$monitor的输出中会用到一个系统函数$出求,如:Smonitor($timesignall=%bsignal2=%b,signall,signal2);对$行111。的返回值也可以进行格式控制,如:Smonitor("dsignall=%bsignal2=%b”,$time,signal1,signal2);由于$monitor一旦被调用后就会启动一个后台进程,因而不可能在有循环性质的表达中出现,如always过程块或者其他高级程序循环语句,在实际应用中,Smonitor通常位于initial过程块的最开始处,保证从一开始就实时地检测所关心的变量的变化状态。3.4.3 系统函数$出证和$realtime$山加和$g1出比属于模拟时标类系统函数,对这两个函数调用,将返回从模拟程序开始执行到被调用时刻的时间,不同之处在于$time返回的是64位整数,而$起如而。返回的是一个实型数。例"tim