系统任务和函数_第1页
系统任务和函数_第2页
系统任务和函数_第3页
系统任务和函数_第4页
系统任务和函数_第5页
已阅读5页,还剩77页未读 继续免费阅读

下载本文档

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

文档简介

为了便于设计者对仿真过程进行控制,以及对仿真结果进行分析比较,VerilogHDL提供了大量的系统功能调用,大致可以分成两种:一种是任务型的功能调用,称为系统任务;另一种是函数型的功能调用,称为系统函数。VerilogHDL的系统任务与系统函数是以字符“$”开头的标识符,一般在initial和always过程块中调用系统任务和函数主要区别有两点:系统任务可以没有返回值,或有多个返回值,而系统函数只有一个返回值;系统任务可以带有延迟,而系统函数不允许延迟,在0时刻执行。依据实现功能的不同,可分成以下几类:1)显示任务(displaytask)2)文件输入/输出任务(FileI/Otask)3)时间标度任务(timescaletask)4)模拟控制任务(simulationcontroltask)5)时序验证任务(timingchecktask)6)PLA建模任务(PLAmodelingtask)7)随机建模任务(stochasticmodelingtask)8)实数变换函数(conversionfunctionsforreal)9)概率分布函数(probabilisticdistributionfunction)显示系统任务用于信息显示和输出。这些系统任务进一步分为:•显示和写入任务•探测监控任务•连续监控任务$display与$write都属于显示类系统任务调用形式$display(“格式控制字符串”,输出变量名表项);$write(“格式控制字符串”,输出变量名表项);输出变量名表项就是指要输出的变量,各变量名之间以逗号相隔;格式控制字符串的内容包括两部分:需要与输出变量一起在输出时一并显示的普通字符;对输出变量显示形式进行控制的格式说明符。格式相同区别:$display任务具有自动换行的功能下面以$display任务为例进行详细说明。$display可以用来输出字符串、表达式及变量值,其语法格式与C语言中的printf函数相同,可表示如下:$display(<format_specifiers>,signal,signal,……);其中,<format_specifiers>用来指定输出格式。表7.1给出了各种不同的输出格式。普通字符,即需要原样输出的字符。其中一些特殊的字符可以通过表2中的转换序列来输出。下面表中的字符形式用于格式字符串参数中,用来显示特殊的字符

【例7.9】$display任务的例子。$display("HelloDrBlair");……output:HelloDrBlair$display($time)//目前的仿真时间……output:460counter=4'b10;$display("Thecountis%b",counter);……output:Thecountis0010在$display和$write的参数列表中,其“输出表列”是需要输出的一些数据,可以是表达式,下面举例说明例7-10moduledisp;initialbegin$display("\\\t%%\n\"\123");endendmodule输出结果为\%"S”从上面的这个例子中可以看到一些特殊字符的输出形式(八进制数123就是字符S)moduledisp;reg[31:0]rval;pulldown(pd);initialbeginrval=101;$display("rval=%hhex%ddecimal",rval,rval);$display("rval=%ootal%bbinary",rval,rval);$display("rvalhas%casciicharactervalue",rval);$display("pdstrengthvalueis%v",pd);$display("currentscopeis%m");$display("%sisasciivaluefor101",101);$display("simulationtimeis%t",$time);endendmodule其输出结果为:rval=00000065hex101decimalrval=00000000145octal00000000000000000000000001100101binaryrvalhaseasciicharactervaluepdstrengthvalueisStXcurrentscopeisdispeisasciivaluefor101simulationtimeis01输出列表中数据的显示宽度是自动按照输出格式进行调整的。2用表达式的最大可能值所占的位数来显示表达式的当前值。3十进制数格式输出时,输出结果前面的0值用空格来代替。对moduleprintval;reg[11:0]r1;initialbeginr1=10;$display("Printingwithmaximumsize=%d=%h",r1,r1);$display("Printingwithminimumsize=%0d=%0h",r1,r1);endenmodule输出结果为:Printingwithmaximumsize=10=00a:printingwithminimumsize=10=a在显示输出数据时,在经过格式转换以后,总是用最少的位数来显示表达式的当前值$display("Simulationtimeis%t",$time);$display($time,":R=%b,Q=%b,QB=%b",R,S,Q,QB);//因为没有指定格式,时间按十进制显示。$write("Simulationtimeis:);$write("%t\n",$time);上述语句输出$time、R、S、Q和QB等值的执行结果如下:Simulationtimeis1010:R=1,S=0,Q=0,QB=1Simulationtimeis10end如果输出列表中表达式的值包含有不确定的值或高阻值,其结果输出遵循以下规则:(1).在输出格式为十进制的情况下:如果表达式值的所有位均为不定值,则输出结果为小写的x。如果表达式值的所有位均为高阻值,则输出结果为小写的z。如果表达式值的部分位为不定值,则输出结果为大写的X。如果表达式值的部分位为高阻值,则输出结果为大写的Z。2).在输出格式为十六进制和八进制的情况下:每4位二进制数为一组代表一位十六进制数,每3位二进制数为一组代表一位八进制数。如果表达式值相对应的某进制数的所有位均为不定值,则该位进制数的输出的结果为小写的x。如果表达式值相对应的某进制数的所有位均为高阻值,则该位进制数的输出结果为小写的z。如果表达式值相对应的某进制数的部分位为不定值,则该位进制数输出结果为大写的X。如果表达式值相对应的某进制数的部分位为高阻值,则该位进制数输出结果为大写的Z。对于二进制输出格式,表达式值的每一位的输出结果为0、1、x、z。下面举例说明:$display("%d",1'bx); 输出结果为:x$display("%h",14'bx0_1010);输出结果为:xxXa$display("%h%o",12'b001x_xx10_1x01,12'b001_xxx_101_x01); 输出结果为:XXX1x5X注意:因为$write在输出时不换行,要注意它的使用。可以在$write中加入换行符\n,以确保明确的输出显示格式在VerilogHDL中,除了$display与$write这两种主要的标准输出任务外,还有以下几种标准输出任务:(1) $displayb与$writeb(输出二进制数)。(2) $displayo与$writeo(输出八进制数)。(3) $displayh与$writeh(输出十六进制数)。通过显示任务中的%m的选项,可以显示任意级别的层次。例modulem;initial$display(“displayingin%m”)Endmodule显示层次moduletop;mm1();mm2();mm3();Endmodule仿真输出如下显示:displayingintop.m1displayingintop.m2displayingintop.m3$strobe属探测监控任务,用于在某时刻所有的事件都已处理完毕后,在时间步的末尾将结果输出。更多地用来显示用非阻塞方式赋值的变量的值探测任务与显示任务的不同之处在于:显示任务在遇到语句时执行,而探测任务的执行要推迟到时间步结束时进行

integerCool;initialbeginCool=1;$display("Afterfirstassignment,Coolhasvalue%d"cool);$strobe("Whenstrobeisexecuted,Coolhasvalue%d"cool);Cool=2;$display("Aftersecondassignment,Coolhasvalue%d"cool);end产生的输出为:Afterfirstassignment,Coolhasvalue1Whenstrobeisexecuted,Coolhasvalue2Aftersecondassignment,Coolhasvalue2modulestrobe_demo;rega,b;//initial语句块1initialbegina=0;$display(“abydisplayis:”,a);//displayo$strobe("abystrobeis:",a);//display1a=1;endStrobe举例//initial语句块2initialbeginb<=0;$display("bbydisplayis:",b);//displayx$strobe("bbystrobeis:",b);//displayo#5;$display("#5bbydisplayis:",b);//displayo$strobe("#5bbystrobeis:",b);//display1b<=1;endendmodule$monitor一旦被调用后,将随时对输出变量名表项中列出的各个变量进行检测,如发现其中的任何一个变量在模拟过程中的某一时刻发生了任何形式的改变,就会启动$monitor任务,整个输出列表中所有变量和表达式的值都会按照所规定的格式,在时间步结束时输出结果。如果在同一仿真时刻,多个变量或表达式值发生变化,则该时刻只输出显示一次。如$monitor(“a=%b,b=%b,out=%b\n”,a,b,out)

可以通过系统任务$monitoron打开监控任务,通过系统任务$monitoroff关闭监控任务。多模块调试时,会有多个模块调用monitor,但是任意时刻只能有一个monitor被启动,这就需要用$monitoron和$monitoroff在特定时刻启动需要检测的模块,关闭其它模块。缺省情况下,监控任务在仿真开始时自动打开。

【例7-13】系统任务$monitor的例子。modulemyTest;integera,b;initialbegina=2;b=4;foreverbegin#5a=a+b;#5b=a-1;endendinitial#40$finish;initialbegin$monitor($time,"a=%d,b=%d",a,b);endendmodule输出结果为:0a=2,b=45a=6,b=410a=6,b=515a=11,b=520a=11,b=1025a=21,b=1030a=21,b=2035a=41,b=20不要用monitor监控周期性循环变化的信号下面是模块textio仿真的输出:$writeb输出:0xxxxxxxxx注意data是32位数据,由8位十六进制数表示。时间以没有前导零的十进制形式输出。缺省情况下,值以十进制显示,忽略前导零,与%0d格式符相同。可以在一个格式化符前插入一个0使Verilog忽略开头的零。$displayh:00000000000000f000000101注意当前时间,一个64位量,需要16个十六进制的数。$display:1020$strobe:1030moduletextio;regflag;reg[31:0]data;initialbegin

$writeb($time,,%d,%h"\t",data,,flag,"\n");#15flag=1;data=16;

$displayh($time,,data,,flag);endinitialbegin#10data=20;

$strobe($time,,data);

$display($time,,data);

data=30;endendmodule调用形式$finish;$stop;$finish(n);$stop(n);$finish的作用就是终止仿真器的运行,结束$stop暂时挂起仿真器,进入Verilog界面,可以通过输入相应命令使仿真继续运行,$stop的作用只相当于一个pause暂停语句。n只能取以下三个值:0:不输出任何信息。1:输出结束仿真的时间及模拟文件的位置2:在1的基础上增加对CPU时间、机器内存占有情况等统计结果的输出。当$finish不带参数时,对应于缺省值1。【例7-15】仿真结束任务的例子。initialbeginclock=1'b0;…… //需要完成的任务#200$stop //暂停仿真并进入交互方式#500$finish //结束仿真任务End又if()$stope;或#ntime$finish;系统函数$time与$realtime都属模拟时标类系统函数,调用形式:$time$realtime都返回从模拟程序开始执行到被调用时刻的时间,$time返回64位的整数,指定当前的仿真时间;$realtime以实数形式返回当前的仿真时间。时刻是以模块的仿真时间尺度为基准的。`timescale10ns/1nsmoduletest;regset;parameterp=1.6;initialbegin$monitor($time,,"set=",set);#pset=0;#pset=1;endendmodule输出结果为:0set=x2set=03set=1`timescale10ns/1nsmoduletest;regset;parameterp=1.55;initialbegin$monitor($realtime,,"set=",set);#pset=0;#pset=1;endendmodule输出结果为:0set=x1.6set=03.2set=1从本例可以看出,$realtime将仿真时刻经过尺度变换以后即输出,不需进行取整作。所以$realtime返回的时刻是实型数

1将数据和分析的工作从testbench中隔离出来,便于协同工作。2,可通过其它软件工具c/c++、matlab等快速产生数据3,将数据写入文档后,同通过c/c++、excel以及matlab工具分析。因此在测试代码中完成文件输入输出操作,是测试大型设计的必备手段。为什么要用veriloghdl语言读取/写入文件呢?Verilog的结果通常输出到标准输出或verilog.log文本中,通过输入输出任务可将结果定向选择输出到指定的文件首先定义integer指针,然后调用$fopen(file_name,mode)任务,不需要模式时,调用$fopen(file_name),常用mode包括:“w"打开文件并从文件头开始写,如果不存在就创建文件。“w+"打开文件并从文件头开始读写,如果不存在就创建文件"a"打开文件并从文件末尾开始写,如果不存在就创建文件“a+"打开文件并从文件末尾开始读写,如果不存在就创建文件用法integerfile_id;file_id=fopen("file_path/file_name");$fopen将返回关于文件file_name的整数(指针),并把它赋给整形变量file_id打开文件例integerhandle1,handle2,handle3;//标准输出是打开的,descriptor=32`h0000_0001initialbeginhandle1=$fopen("file1.out");//handle1=32`h0000_0002handle2=$fopen("file2.out");//handle1=32`h0000_0004handle3=$fopen("file3.out");//handle1=32`h0000_0008显示、写入、探测和监控系统任务都有一个用于向文件输出的相应副本,该副本可用于将信息写入文件调用格式:$fdisplay(file_id,p1,p2,…,pn)$fmonitor(file_id,p1,p2,…,pn)$fstrobe(file_id,p1,p2,…,pn)$fwrite(file_id,p1,p2,…,pn)p1,p2,…,pn可以是变量、信号名或者带引号的字符串。file_id是一个多通道描述符,他可以是一个句柄或者多个文件句柄按位的组合。Verilog会将输出写到与file_id中值为1的位相关联的所有文件中。//所有的file_id都在上例中定义integerdesc1,desc2,desc3;initialbegindesc1=handle1│1;$fdisplay(desc1,"display1");//写到文件file1_out和标准输出stdoutdesc2=handle1│handle1;$fdisplay(desc1,"display2");//写到文件file1_out和file2_outdesc3=handle3;$fdisplay(desc3,"display2");//只写到文件file3_out$fclose(file_id);系统函数$fopen用于打开一个文件,并还回一个整数指针.然后,$fdisplay就可以使用这个文件指针在文件中写入信息写完后,则可以使用$fclose系统关闭这个文件例如:integerwrite_out_file;//定义一个文件指针

integerwrite_out_file=$fopen("write_out_file.txt");

$fdisplay(write_out_file,"@%h\n%h",addr,data);$fclose("write_out_file");以上语法是将addr,data分别显示在"@%h\n%h"中的2个%h的位置,并写入write_out_file文件指针所指向的write_out_file.txt中.$fopen打开一个文件并返回一个多通道描述符(MCD)。MCD是与文件唯一对应的32位无符号整数。如果文件不能打开并进行写操作,MCD将等于0。如果文件成功打开,MCD中的一位将被置位。以$f开始的显示系统任务将输出写入与MCD相对应的文件中...integerMCD1;

MCD1=$fopen("<name_of_file>");$fdisplay(MCD1,P1,P2,..,Pn);$fwrite(MCD1,P1,P2,..,Pn);$fstrobe(MCD1,P1,P2,..,Pn);$fmonitor(MCD1,P1,P2,..,Pn);$fclose(MCD1);......integermessages,broadcast,cpu_chann,alu_chann;initialbegin

cpu_chann=$fopen("cpu.dat");if(!cpu_chann)$finish;

alu_chann=$fopen("alu.dat");if(!alu_chann)$finish;//channeltobothcpu.datandalu.dat

messages=cpu_chann|alu_chann;//channeltobothfiles,standardout,andverilog.log

broadcast=1|messages;endalways@(posedgeclock)//printthefollowingtoalu.dat

$fdisplay(

alu_chann,"acc=%hf=%ha=%hb=%h",acc,f,a,b);/*ateveryresetprintamessagetoalu.dat,cpu.dat,standardoutputandtheverilog.logfile*/always@(negedgereset)$fdisplay(broadcast,"systemresetattime%d",$time);...必须声明为integer通道0(编号为1)为标准输出及verilog.logVerilogHDL程序中有两个系统任务$readmemb和$readmemh能够把一个数据文件中的数据内容,读入到一个指定的存储器中.。其区别在于,前者要求以二进制数据格式存放数据文件,而后者要求以十六进制数据格式存放数据文件这两个系统任务可以在仿真的任何时刻被执行使用其使用格式共有以下六种:$readmemb("<数据文件名>",<存贮器名>);$readmemb("<数据文件名>",<存贮器名>,<起始地址>);$readmemb("<数据文件名>",<存贮器名>,<起始地址>,<结束地址>);$readmemh("<数据文件名>",<存贮器名>);$readmemh("<数据文件名>",<存贮器名>,<起始地址>);$readmemh("<数据文件名>",<存贮器名>,<起始地址>,<结束地址>);在这两个系统任务中,被读取的数据文件的内容只能包含:空白位置(空格,换行,制表格(tab)和form-feeds),注释行(//形式的和/*...*/形式的都允许),二进制或十六进制的数字。数字中不能包含位宽说明和格式说明,对于$readmemb系统任务,每个数字必须是二进制数字,对于$readmemh系统任务,每个数字必须是十六进制数字。数字中不定值x或X,高阻值z或Z,和下划线(_)的使用方法及代表的意义与一般VerilogHDL程序中的用法及意义是一样的。另外数字必须用空白位置或注释行来分隔开。在下面的讨论中,地址一词指对存贮器(memory)建模的数组的寻址指针。当数据文件被读取时,每一个被读取的数字都被存放到地址连续的存贮器单元中去。存贮器单元的存放地址范围由系统任务声明语句中的起始地址和结束地址来说明,每个数据的存放地址在数据文件中进行说明。当地址出现在数据文件中,其格式为字符“@”后跟上十六进制数。如:@hh...h对于这个十六进制的地址数中,允许大写和小写的数字。在字符“@”和数字之间不允许存在空白位置。可以在数据文件里出现多个地址。当系统任务遇到一个地址说明时,系统任务将该地址后的数据存放到存贮器中相应的地址单元中去。【例7-16】从文件中读出数据到存储器的例子。moduletestmemory;reg[7:0]memory[9:0];integerindex;initialbegin$readmemb("mem.dat",memory);for(index=0;index<10;index=index+1)$display("memory[%d]=%b",index[4:0],memory[index]);endendmodule1如果系统任务声明语句中和数据文件里都没有进行地址说明,则缺省的存放起始地址为该存贮器定义语句中的起始地址。数据文件里的数据被连续存放到该存贮器中,直到该存贮器单元存满为止或数据文件里的数据存完。2如果系统任务中说明了存放的起始地址,没有说明存放的结束地址,则数据从起始地址开始存放,存放到该存贮器定义语句中的结束地址为止。3如果在系统任务声明语句中,起始地址和结束地址都进行了说明,则数据文件里的数据按该起始地址开始存放到存贮器单元中,直到该结束地址,而不考虑该存贮器的定义语句中的起始地址和结束地址。4如果地址信息在系统任务和数据文件里都进行了说明,那么数据文件里的地址必须在系统任务中地址参数声明的范围之内。否则将提示错误信息,并且装载数据到存贮器中的操作被中断。5如果数据文件里的数据个数和系统任务中起始地址及结束地址暗示的数据个数不同的话,也要提示错误信息。modulereadmem;

reg[7:0]mem[7:0];

reg[2:0]i;

integerfile;

initial

begin

file=$fopen("memory.txt","w");

$readmemb("memoryb.txt",mem,4,0);//从文本的读取数据向mem[4]开始写入,直到写到mem[0]

for(i=0;i<7;i=i+1)

begin

$display("mem[%d]=%b",i,mem[i]);

$fdisplay(file,"mem[%d]=%b",i,mem[i]);

end

$readmemh("memoryh.txt",mem);//如果没有地址的限制,就默认从//mem[0]到mem定义的最大地址。

for(i=0;i<7;i=i+1)

begin

$display("mem[%d]=%h",i,mem[i]);

$fdisplay(file,"mem[%d]=%h",i,mem[i]);

end

$fclose(file);

end

endmodulemeomoryb.txt的文本文件,文件内容如下:1010110100011101011011110110000100000001111111101111111111101110控制台输出与生成的memory.txt中内容一致。mem[0]=00000001mem[1]=01100001mem[2]=01101111mem[3]=00011101mem[4]=10101101mem[5]=xxxxxxxxmem[6]=xxxxxxxxmem[0]=32mem[1]=36mem[2]=4fmem[3]=8amem[4]=admem[5]=xxmem[6]=xx结果分析:首先读取memoryb.txt中从地址4到地址0的数据写入mem[0]至mem[4],没有写入的存储器内容为xx,然后读取memoryh.txt从地址0到地址6的数据写入mem[0]至mem[6],由于memoryh.txt只有4个数据,mem[4]以后的数据就没有了,保持上一次写的内容,所以,mem[4]为ad(十六进制)即二进制10101101VCD文件(valuechangedump文件)是常用的波形记录文件,与波形的作用等同,是一个ASCII文件。包含设计中指定变量取值变化的信息。它的主要目的是为其它后处理工具提供信息。dump系统任务基本都在initial模块中使用下面的系统任务用于创建和将信息导入VCD文件。1)$dumpfile:本系统任务指定转储文件名。例如:$dumpfile(“uart.dump”);2)$dumpvars:本系统任务指定哪些变量值变化时转储进转储文件。$dumpvars;//无参数,它指定在设计中转储所有变量。$dumpvars(level,module_name);//在指定模块和所有指定层次下面的模块中的转储变量。$dumpvars(1,UART);//只转储模块UART中的变量。$dumpvars(2,UART);//转储UART及其下一层模块中的所有变量。$dumpvars(0,UART);//第0层导致UART模块及其下面层次中所有模块中的各个变量被转储。$dumpvars(0,P_State,N_State);//转储关于P_State和N_State的变量信息。层次数与此例无关,但是必须给出//层次数。$dumpvars(3,Div.Clk,UART);//层次数只作用于模块本身及其下面两个层次中的所有变量。在此例中,只作用于模块UART,即UART中所有变量及UART下面两个层次中各模块的所有变量,同时转储变量Div.Clk上值的变化。3)$dumpoff:本系统任务促使转储任务被挂起。$dumpoff;4)$dumpon:本系统任务促使所有转储任务被挂起。语法如下:$dumpon;5)$dumpall:本系统任务执行时转储所有当前指定的变量值。语法如下:$dumpall6)$dumplimit:本系统任务为VCD文件指定最大长度(字节)。转储在到达此界限时停止。例如,$dumplimit(1024);//VCD文件的最大值为1024字节。7)$dumpflush:本系统任务刷新操作系统VCD文件缓冲区中的数据,将数据存到VCD文件中。执行此系统任务后,转储任务处于唤醒状态。$dumpflush;•文件头信息:提供日期、模拟器版本和时间标度单位。•节点信息:定义转储作用域和变量类型。•取值变化:实际取值随时间变化。记录绝对模拟时间。下面是在5~12之间计数的可逆计数器的例子:moduleCountUpDown(Clk,Count,Up_Down);inputClk,Up_Down;output[0:3]Count;reg[0:3]Count;initialCount=4‘d5;always@(posedgeClk)beginif(Up_Down)beginCount=Count+1;if(Count>12)Count=12;endelsebeginCount=Count-1;if(Count<5)Count=5;endendendmodulemoduletest;regClock,UpDn;wire[0:3]Cnt_Out;parameterON_DELAY=1,OFF_DELAY=2;CountUpDown

C1(Clock,Cnt_Out,UpDn);alwaysbeginClock=1;#ON_DELAY;Clock=0;#OFF_DELAY;endinitialbeginUpDn=0;#50UpDn=1;#100$dumpflush;$stop;//停止模拟。endinitialbegin$dumpfile(“count.dump”);$dumplimit(4096);$dumpvars(0,Test;)$dumpvars(0,Cl.Count,Cl.Clk,C1.Up_Down);endendmodule当进行模块测试时,常需要提供随机脉冲序列,该功能可以通过系统函数$random来实现,它的语法格式为$random%<number>;其中,<number>为一大于0的整数,用来指定所产生随机数的范围,即-<number>+1到<number>-1。这个系统函数提供了一个产生随机数的手段。当函数被调用时返回一个32bit的随机数。reg[23:0]rand;rand=$random%60;上面的例子给出了一个范围在-59到59之间的随机数,下面的例子通过位并接操作产生一个值在0到59之间的数。reg[23:0]rand;rand={$random}%60;“编译预处理”是VerilogHDL编译系统的一个组成部分。VerilogHDL语言允许在程序中使用几种特殊的命令(它们不是一般的语句)。VerilogHDL编译系统通常先对这些特殊的命令进行“预处理”,然后将预处理的结果和源程序一起在进行通常的编译处理。与C语言中的编译预处理指令类似,VerilogHDL中提供了大量的编译指令。通过这些编译指令,EDA工具开发商使他们的工具解释VerilogHDL模型变得相当容易。(1)编译指令以字符“`”开头。

(2)编译指令并非VerilogHDL的描述,因而编译指令末尾不需要分号。

(3)编译指令不受模块与文件的限制。在进行Verilog语言编译时,已定义的编译指令一直有效,直到有其它的编译指令修改它或将该编译指令关闭VerilogHDL中文件包含指令`include类似于C语言中的编译指令#include ,文件包含指令在模块调用时非常有用,可以通过该指令包含诸如类型声明与函数之类的Verilog码把语句中指定的源文件全部包含到当前的文件中形式定义:`include“文件名”几点说明:1.每条`include语句只能用于对一个文件的包含,多个文件的包含只需用多条语句分别注明即可。2.文件包含允许嵌套。3.`include命令可以出现在VerilogHDL源程序的任何地方,被包含文件名可以是相对路径名,也可以是绝对路径名。例如:'include"parts/count.v“4可以将多个`include命令写在一行,在`include命令行,只可以出空格和注释行。例如下面的写法是合法的。'include"fileB"'include"fileC"//includingfileBandfileC

【例7-17】文件包含指令的例子。//文件file1.v的内容`defineWORDSIZE8function[WORDSIZE-1:0]fastadder;……endfunction//文件secondfile的内容modulesecondfile(in1,in2,out)`includefile1.vwire[WORDSIZE-1:0]temp;assigntemp=fastadder(in1,in2);……endmodule用一个指定的标识符来代表一个字符串,它的一般形式为:`define标识符(宏名)字符串(宏内容)如:`definesignalstring它的作用是指定用标识符signal来代替string这个字符串,在编译预处理时,把程序中在该命令以后所有的signal都替换成string。这种方法使用户能以一个简单的名字代替一个长的字符串,也可以用一个有含义的名字来代替没有含义的数字和符号,因此把这个标识符(名字)称为“宏名”,在编译预处理时将宏名替换成字符串的过程称为“宏展开”。`define是宏定义命令。这里需要注意的是,文本内容必须在一行中定义,不能采用多行。宏替换指令与参数定义的区别在于,参数具有全局可见性,而宏替换指令只局限于宏函数。

【例7-18】宏替换的例子。

`definecycle20//clockperiod

always#(cycle/4)clk=~clk;

`defineNAND(dval)nand#(dval)

`NAND(3)i1(y,a,b);

`NAND(3:4:5)i2(o,c,d);可以利用`undef指令来取消宏定义。1宏名可以用大写字母表示,也可以用小写字母表示。建议使用大写字母,以与变量名相区别。2`define命令可以出现在模块定义里面,也可以出现在模块定义外面。宏名的有效范围为定义命令之后到原文件结束。通常,`define命令写在模块定义的外面,作为程序的一部分,在此程序内有效。3在引用已定义的宏名时,必须在宏名的前面加上符号“`”,表示该名字是一个经过宏定义的名字。4宏定义是用宏名代替一个字符串,也就是作简单的置换,不作语法检查。预处理时照样代入,不管含义是否正确。只有在编译已被宏展开后的源程序时才报错5使用宏名代替一个字符串,可以减少程序中重复书写某些字符串的工作量。而且记住一个宏名要比记住一个无规律的字符串容易,这样在读程序时能立即知道它的含义,当需要改变某一个变量时,可以只改变`define命令行,一改全改。如例1中,先定义WORDSIZE代表常量8,这时寄存器data是一个8位的寄存器。如果需要改变寄存器的大小,只需把该命令行改为:`defineWORDSIZE16。这样寄存器data则变为一个16位的寄存器。由此可见使用宏定义,可以提高程序的可植性和可读性。6宏定义不是VerilogHDL语句,不必在行末加分号。如果加了分号会连分号一起进行置换。

如:moduletest;rega,b,c,d,e,out;`defineexpressiona+b+c+d;assignout=`expression+e;...endmodule经过宏展开以后,该语句为:assignout=a+b+c+d;+e;显然出现语法错误7在进行宏定义时,可以引用已定义的宏名,可以层层置换。如:[例7-19]:moduletest;rega,b,c;wireout;`defineaaa+b`defineccc+`aaassignout=`cc;endmodule这样经过宏展开以后,assign语句为assignout=c+a+b;8宏名和宏内容必须在同一行中进行声明。如果在宏内容中包含有注释行,注释行不会作为被置换的内容。如:module`definetyp_nandnand#5//defineanandwithtypicaldelay`typ_nandg121(q21,n10,n11);………endmodule经过宏展开以后,该语句为:nand#5g121(q21,n10,n11);宏内容可以是空格,在这种情况下,宏内容被定义为空的。当引用这个宏名时,不会有内容被置换组成宏内容的字符串不能够被以下的语句记号分隔开的。注释行数字字符串确认符关键词双目和三目字符运算符如下面的宏定义声明和引用是非法的。`definefirst_half"startofstring$display(`first_halfendofstring");注意在使用宏定义时要注意以下情况:1对于某些EDA软件,在编写源程序时,如使用和预处理命令名相同的宏名会发生冲突,因此建议不要使用和预处理命令名相同的宏名。2宏名可以是普通的标识符(变量名)。例如signal_name和‘signal_name的意义是不同的。但是这样容易引起混淆,建议不要这样使用。`timescale命令用来说明跟在该命令后的模块的时间单位和时间精度。使用`timescale命令可以在同一个设计里包含采用了不同的时间单位的模块。例如,一个设计中包含了两个模块,其中一个模块的时间延迟单位为ns,另一个模块的时间延迟单位为ps。EDA工具仍然可以对这个设计进行仿真测试。`timescale命令的格式如下:`timescale<时间单位>/<时间精度>在这条命令中,时间单位参量是用来定义模块中仿真时间和延迟时间的基准单位的。时间精度参量是用来声明该模块的仿真时间的精确程度的,该参量被用来对延迟时间值进行取整操作(仿真前),因此该参量又可以被称为取整精度。如果在同一个程序设计里,存在多个`timescale命令,则用最小的时间精度值来决定仿真的时间单位。另外时间精度至少要和时间单位一样精确,时间精度值不能大于时间单位值。在`timescale命令中,用于说明时间单位和时间精度参量值的数字必须是整数

温馨提示

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

评论

0/150

提交评论