EDA技术与Verilog设计王金明版第6章.ppt

上传人:小飞机 文档编号:5428619 上传时间:2023-07-06 格式:PPT 页数:88 大小:600KB
返回 下载 相关 举报
EDA技术与Verilog设计王金明版第6章.ppt_第1页
第1页 / 共88页
EDA技术与Verilog设计王金明版第6章.ppt_第2页
第2页 / 共88页
EDA技术与Verilog设计王金明版第6章.ppt_第3页
第3页 / 共88页
EDA技术与Verilog设计王金明版第6章.ppt_第4页
第4页 / 共88页
EDA技术与Verilog设计王金明版第6章.ppt_第5页
第5页 / 共88页
点击查看更多>>
资源描述

《EDA技术与Verilog设计王金明版第6章.ppt》由会员分享,可在线阅读,更多相关《EDA技术与Verilog设计王金明版第6章.ppt(88页珍藏版)》请在三一办公上搜索。

1、第6章 Verilog设计进阶,主要内容,过程语句(initial、always)块语句(begin-end、fork-join)赋值语句(assign、=、=)条件语句(if-else、case、casez、casex)循环语句(for、forever、repeat、while)编译指示语句(define、include、ifdef、else、endif)任务(task)与 函数(function)顺序执行与并发执行,Verilog HDL行为语句,6.1 过程语句,一、initial和alwaysinitial 从0时刻起,顺序执行其后的块语句一次;always 从0时刻起(若带有触发条件

2、的话,则从触发时刻起),反复执行其后的块语句多次,仅当碰到诸如$finish之类的结束控制语句之后,才能停止循环过程,initial 过程块的使用主要是面向功能模拟的,通常用来描述测试模块的初始化、监视、波形生成等功能;always过程块的使用主要是对硬件功能模拟的行为进行描述,也可以在测试模块用来对时钟进行描述。利用always过程块可以实现触发器、锁存器和组合电路。一个模块中可有多个initial和always语句,代表多个过程块的存在,它们之间相互独立,并行运行,1.always过程语句使用模板,always()begin/过程赋值/if-else,case,casex,casez选择语

3、句/while,repeat,for循环/task,function调用end“always”过程语句通常是带有触发条件的,触发条件写在敏感信号表达式中,只有当触发条件满足时,其后的“begin-end”块语句才能被执行。,敏感信号表达式“event-expression”,敏感信号表达式又称事件表达式或敏感信号列表,即当该表达式中变量的值改变时,就会引发块内语句的执行。因此敏感信号表达式中应列出影响块内取值的所有信号。若有两个或两个以上信号时,它们之间用“or”连接。例如:(a)/当信号a的值发生改变(a or b)/当信号a或信号b的值发生改变(posedge clock)/当clock

4、的上升沿到来时(negedge clock)/当clock 的下降沿到来时(posedge clk or negedge reset)/当clk的上升沿到来或reset信号的下降沿到来,敏感信号列表举例(4选1数据选择器),module mux4_1(out,in0,in1,in2,in3,sel);output out;input in0,in1,in2,in3;input1:0 sel;reg out;always(in0 or in1 or in2 or in3 or sel)/敏感信号列表case(sel)2b00:out=in0;2b01:out=in1;2b10:out=in2;2

5、b11:out=in3;default:out=2bx;endcaseendmodule,敏感信号分为两类:边沿敏感型;电平敏感型,每一个always过程最好由一种类型的敏感信号来触发,而不要将边沿敏感型和电平敏感型信号列在一起,比如:always(posedge clk or posedge clr)/边沿型always(A or B)/两个敏感信号都是电平敏感型always(posedge clk or clr)/不建议这样用,最好不要将边沿敏感型和电平敏感型信号列在一起,posedge和negedge关键字,对于时序电路,事件通常是由时钟边沿触发的,为表达边沿这个概念,Verilog提供

6、了posedge和negedge关键字来描述。比如:【例】同步置数、同步清零的计数器module count(out,data,load,reset,clk);output7:0 out;input7:0 data;input load,clk,reset;reg7:0 out;always(posedge clk)/clk上升沿触发 begin if(!reset)out=8h00;/同步清0,低电平有效 else if(load)out=data;/同步预置 else out=out+1;/计数 endendmodule,posedge和negedge关键字,always(posedge

7、clk or posedge clear)/clear信号上升沿到来时清零,故高电平清零有效always(posedge clk or negedge clear)/clear信号下降沿到来时清零,故低电平清零有效注意:块内的逻辑描述要与敏感信号表达式中信号的有效电平一致。下面描述错误:always(posedge clk or negedge clear)begin if(clear)out=0;out=in;else end,2、always语句:其声明格式如下:always always语句包括的所有行为语句构成了一个always块。该块从仿真0时刻开始顺序执行其中的语句。在仿真过程中不

8、断重复执行的。always语句由于其不断重复执行的特性,只有和一定的时序控制结合在一起才有用。如果一个always语句没有时序控制,则这个always语句将会成为一个仿真死锁。例:always areg=areg;这个always语句将会生成一个0延迟的无限循环跳变过程,这时会发生仿真死锁。,如果加上时序控制,则这个always语句将变为一条非常有用的描述语句。见下例:例:always#half_period areg=areg;这个例子生成了一个周期为:period(=2*half_period)的无限延续的信号波形,常用这种方法来描述时钟信号,作为激励信号来测试所设计的电路。Verilog

9、提供三种时序控制方法:基于延迟的时序控制、基于事件的时序控制和电平敏感的时序控制。,timescale 1ns/1nsmodule clk_gen_demo(clock1,clock2);output clock1,clock2;reg clock1,clock2;initial/完成时钟信号的初始化beginclock1=0;clock2=1;#500$finish;endalways#50 clock1=clock1;always#100 clock2=clock2;endmodule,用always过程块实现复杂组合逻辑电路,例:用always过程语句描述简单算术逻辑单元。define

10、add 3d0define minus 3d1define band 3d2define bor 3d3define bnot 3d4module alu(out,opcode,a,b);input2:0 opcode;/操作码input7:0 a,b;/操作数output7:0 out;reg7:0 out;always(opcode or a or b)begin,case(opcode)add:out=a+b;minus:out=a-b;band:out=a endcaseendendmodule,边沿触发的always块常常描述时序逻辑,如果符合可综合风格要求可用综合工具自动转换为表示

11、时序逻辑的寄存器组和门级逻辑,而电平触发的always块常常用来描述组合逻辑和锁存器,如果符合可综合风格要求可转换为表示组合逻辑的门级逻辑或锁存器。一个模块中可以有多个always块,它们都是并行运行的。,2.initial过程语句,initial语句使用格式 initial begin 语句1;语句2;endinitial语句不带触发条件,initial过程中的语句块沿时间轴只执行一次。initial语句通常用于仿真模块中对激励向量的描述,或用于给寄存器变量赋初值,它是面向模拟仿真的过程语句,通常不能被逻辑综合工具所接受。,用initial过程语句对测试变量赋值,timescale 1ns/

12、1nsmodule test;reg A,B,C;initial begin A=0;B=1;C=0;#50 A=1;B=0;#50 A=0;C=1;#50 B=1;#50 B=0;C=0;#50 finish;endendmodule,例1:initial begin areg=0;/初始化寄存器areg memoryindex=0;end在这个例子中用initial语句在仿真开始时对各变量进行初始化。,6.2 块语句,块语句通常用来将两条或多条语句组合在一起,使其在格式上看更象一条语句。块语句有两种,一种是begin_end语句,通常用来标识顺序执行的语句,用它来标识的块称为顺序块。一种是

13、fork_join语句,通常用来标识并行执行的语句,用它来标识的块称为并行块。下面进行详细的介绍。,6.2 块语句,块语句是由块标志符begin-end或fork-join界定的一组语句,当块语句只包含一条语句时,块标志符可以缺省。begin-end串行块中的语句按串行方式顺序执行。比如:beginregb=rega;regc=regb;end由于begin-end块内的语句顺序执行,在最后,将regb、regc 的值都更新为rega的值,该begin-end块执行完后,regb、regc 的值是相同的。,6.2 块语句,并行块fork-joinfork-join块中的所有语句是并发执行的。比

14、如:forkregb=rega;regc=regb;join由于fork-join块内的语句同时执行,在上面的块语句执行完后,regb更新为rega的值,而regc的值更新为没有改变前regb的值,故执行完成后,regb与regc的值是不同的。,6.3 赋值语句,1、持续赋值语句(Continuous Assignments)assign为持续赋值语句,主要用于对wire型变量的赋值。比如:assign c=a/持续赋值,如果sel为0,则out=a;否则out=bendmodule,2、过程赋值语句:过程赋值语句可以给寄存器、整数、时间变量赋值。连续赋值语句总是处于活动状态,而过程赋值语句只

15、有在执行到的时候才会起作用。在Verilog HDL语言中,信号有两种赋值方式:(1).非阻塞(Non_Blocking)赋值方式(如 b=a;),1)它不会阻塞位于同一个顺序块中其后语句的执行。同一顺序块中的语句并发执行。2)b的值并不是立刻就改变的,块结束后才完成赋值操作。(2).阻塞(Blocking)赋值方式(如 b=a;)1)顺序块中的阻塞赋值语句按顺序执行。2)b的值在赋值语句执行完后立刻就改变。,非阻塞赋值方式和阻塞赋值方式的区别常给设计人员带来问题。问题主要是给“always”块内的reg型信号的赋值方式不易把握。一般情况下,如果用一个always块来描述时序电路,这个的“al

16、ways”模块内的reg型信号都是采用下面的非阻塞赋值方式:b=a;,例1:always(posedge clk)begin b=a;c=b;end例1 中的always块中用了非阻塞赋值方式,定义了两个reg型信号b和c,clk信号的上升沿到来时,b就等于a,c就等于b,这里应该用到了两个触发器。请注意:赋值是在always块结束后执行的,c应为原来b的值。这个always块实际描述的电路功能如下图所示:,例2:always(posedge clk)begin b=a;c=b;end例2中的 always块用了阻塞赋值方式。clk信号的上升沿到来时,将发生如下的变化:b马上取a的值,c马上取

17、b的值(即等于a),生成的电路图如下所示只用了一个触发器来寄存器a的值,又输出给b和c。这大概不是设计者的初衷,如果采用例1所示的非阻塞赋值方式就可以避免这种错误。,阻塞赋值与非阻塞赋值,非阻塞赋值仿真波形图,阻塞赋值仿真波形图,用阻塞方式完成与上述非阻塞赋值同样的功能,可用两个always块来实现,其中,两个always过程块是并发执行的。module non-block(c,b,a,clk);input clk,a;output c,b;reg c,b;always(posedge clk)begin b=a;end always(posedge clk)begin c=b;end end

18、module,阻塞赋值与非阻塞赋值,在可综合的硬件设计中,使用阻塞和非阻塞赋值语句时,应注意以下原则(1)当用“always”块来描述组合逻辑时,既可以用阻塞赋值,也可以采用非阻塞赋值,应尽量使用阻塞赋值。(2)对时序逻辑描述和建模,使用非阻塞赋值方式。(3)为锁存器(Latch)建模,应尽量使用非阻塞赋值。(4)若在同一个“always”过程块中既为组合逻辑建模,又为时序逻辑建模,最好使用非阻塞赋值方式。(5)在一个“always”过程块中,最好不要混合使用阻塞赋值和非阻塞赋值,虽然同时使用这两种赋值方式在综合时并不一定会出错,但对同一个变量不能既进行阻塞赋值,又进行非阻塞赋值,这样在综合时

19、会报错。(6)不能在两个个或两个以上的“always”过程块中对同一个变量赋值,这样会引发冲突,在综合时会报错。(7)使用$strobe显示非阻塞赋值的变量。,6.4 条件语句,(if-else语句)if-else语句使用方法有以下3种:(1)if(表达式)语句1;(2)if(表达式)语句1;else 语句2;(3)if(表达式1)语句1;else if(表达式2)语句2;else if(表达式3)语句3;else if(表达式n)语句n;else 语句n+1;条件语句必须在过程块语句中使用。所谓过程块语句是指由initial和always语句引导的执行 语句集合,除这两种块语句引导的begi

20、n end块中可以编写条件语句外,模块中的其他地方都不能编写。,if(条件表达式)块语句;若条件表达式成立(即值为1,若为0、x、z均为不成立)执行后面的块语句,否则不执行。,if(条件表达式)块语句1 else 块语句2若条件表达式成立执行块语句1,否则执行块语句2,if(条件表达式1)块语句1 else if(条件表达式2)块语句2 else if(条件表达式n)块语句n else 块语句n+1,说明,(1)3种形式的if语句中在if后面都有“表达式”,一般为逻辑表达式或关系表达式,系统对表达式的值进行判断,若为0,x,z,按“假”处理;若为1,按“真”处理,执行指定的语句。(2)第2,3

21、种形式的if语句,在每个else前面有一分号,整个语句结束处有一分号。例如:if(ab)out1=int1;else out1=int2;,说明,(3)在if和else后面可以包含一个内嵌的操作语句,也可以有多个操作语句,此时用begin和end这两个关键字将几个语句包含起来成为一个复合块语句 例如:if(ab)begin out1=int1;out2=int2;end else begin out1=int2;out2=int1;end,说明,(4)允许一定形式的表达式简写方式 例如:if(expression)等同与 if(expression=1)if(!expression)等同与 i

22、f(!expression=1)(5)if语句的嵌套。在if语句中又包含一个或多个if语句称为if语句的嵌套。,例:模为60的8421BCD码加法计数器module count60(qout,cout,data,load,cin,reset,clk);input load,cin,clk,reset;input 7:0 data;output 7:0 qout;output cout;reg7:0 qout;always(posedge clk)/clk上升沿时刻计数 begin if(reset)qout=0;/同步复位 else if(load)qout=data;/同步置数 else i

23、f(cin)begin if(qout3:0=9)/低位是否为9,是则 begin qout3:0=0;/回0,并判断高位是否为5 if(qout7:4=5)qout7:4=0;else qout7:4=qout7:4+1;/高位不为5,则加1 end else qout3:0=qout3:0+1;/低位不为9,则加1endendassign cout=(qout=8h59)/产生进位输出信号enmodule,case语句是一种多分支语句,故case语句多用于多条件译码电路,如描述译码器、数据选择器等,case语句有case、casez、casex三种表示方法。case语句的使用格式如下。ca

24、se(敏感表达式)值1:语句1;/case分支项 值2:语句2;值n:语句n;default:语句n+1;endcase,case语句,BCD码七段数码管显示译码器,module decode4_7(decodeout,indec);output6:0 decodeout;input3:0 indec;reg6:0 decodeout;always(indec)begin case(indec)/用case语句进行译码 4d0:decodeout=7b1111110;4d1:decodeout=7b0110000;4d2:decodeout=7b1101101;4d3:decodeout=7b

25、1111001;4d4:decodeout=7b0110011;4d5:decodeout=7b1011011;4d6:decodeout=7b1011111;4d7:decodeout=7b1110000;4d8:decodeout=7b1111111;4d9:decodeout=7b1111011;default:decodeout=7bx;endcase endendmodule,Verilog HDL针对电路的特性提供了case语句的其它两种形式用来处理case语句比较过程中的不必考虑的情况(dont care condition)。其中casez语句用来处理不考虑高阻值z的比较过程,

26、casex语句则将高阻值z和不定值都视为不必关心的情况。所谓不必关心的情况,即在表达式进行比较时,不将条件表达式或分支表达式中的该位的状态考虑在内。这样在case语句表达式进行比较时,就可以灵活地设置以对信号的某些位进行比较。,casez语句中,如果分支表达式某些为的值为高阻z,那么对这些位的比较就不予考虑,因此只需关注其他位的比较结果。casex,如果比较的双方有一方的某些位的值是x或z,那么这些为的比较就都不予考虑。case(a)2b1x:out=1;/只有a=1x,才有out=1casez(a)2b1x:out=1;/如果a=1x,1z,则有out=1casex(a)2b1x:out=1

27、;/如果a=10、11、1x、1z等,都有out=1casez(a)3b1?:out=1;/如果a=100、101、110、111或1xx、1zz等,都有out=1 3b01?:out=1/如果a=010、011、01x、01z,都有out=1,case语句,Verilog HDL设计中容易犯的一个通病是由于不正确使用语言,生成了并不想要的锁存器。下面我们给出了一个在“always块中不正确使用if语句,造成这种错误的例子。,检查一下左边的always块,if语句保证了只有当al=1时,q才取d的值。这段程序没有写出 al=0 时的结果,那么当al=0时会怎么样呢?在always块内,如果在给

28、定的条件下变量没有赋值,这个变量将保持原值,也就是说会生成一个锁存器!如果设计人员希望当 al=0 时q的值为0,else项就必不可少了,请注意看右边的always块,整个Verilog程序模块综合出来后,always块对应的部分不会生成锁存器。,Verilog HDL程序另一种偶然生成锁存器是在使用case语句时缺少default项的情况下发生的。case语句的功能是:在某个信号(本例中的sel)取不同的值时,给另一个信号(本例中的q)赋不同的值。注意看下图左边的例子,如果sel=0,q取a值,而sel=11,q取b的值。这个例子中不清楚的是:如果sel取00和11以外的值时q将被赋予什么值

29、?在下面左边的这个例子中,程序是用Verilog HDL写的,即默认为q保持原值,这就会自动生成锁存器。,右边的例子很明确,程序中的case语句有default项,指明了如果sel不取00或11时,编译器或仿真器应赋给q的值。程序所示情况下,q赋为0,因此不需要锁存器。,以上就是怎样来避免偶然生成锁存器的错误。如果用到if语句,最好写上else项。如果用case语句,最好写上default项。遵循上面两条原则,就可以避免发生这种错误,使设计者更加明确设计目标,同时也增强了Verilog程序的可读性。,在Verilog HDL中存在着四种类型的循环语句,用来控制执行语句的执行次数。1)forev

30、er 连续的执行语句。2)repeat 连续执行一条语句 n 次。3)while 执行一条语句直到某个条件不满足。如果一开始条件即不满足(为假),则语句一次也不能被执行。4)for通过三个步骤来决定语句的循环执行。注意:循环语句只能在always或initial块中使用。,6.5 循环语句,for语句 for语句的一般形式为:for(表达式1;表达式2;表达式3)语句 通过以下三个步骤来决定语句的循环执行。a)先给确定循环次数的变量赋初值。b)判定控制循环的表达式的值,如为假则跳出循环语句,如为真则执行指定的语句后,转到第三步。c)执行一条赋值语句来修正控制循环变量次数的变量的值,然后返回第二

31、步。,它的执行过程如下:1)先求解表达式1;2)求解表达式2,若其值为真(非0),则执行for语句中指定的内嵌语句,然后执行下面的第3步。若为假(0),则结束循环,转到第5步。3)若表达式为真,在执行指定的语句后,求解表达式3。4)转回上面的第2步骤继续执行。5)执行for语句下面的语句。,用for语句描述的七人投票表决器,module voter7(pass,vote);output pass;input6:0 vote;reg2:0 sum;integer i;reg pass;always(vote)beginsum=0;for(i=0;i=6;i=i+1)/for语句if(votei)

32、sum=sum+1;if(sum2)pass=1;/若超过4人赞成,则pass=1else pass=0;endendmodule,用for 语句实现两个8位二进制数的乘法,module mult_for(outcome,a,b);parameter size=8;inputsize:1 a,b;output2*size:1 outcome;reg2*size:1 outcome;integer i;always(a or b)begin outcome=0;for(i=1;i=size;i=i+1)if(bi)outcome=outcome+(a(i-1);endendmodule,repe

33、at语句,repeat语句的使用格式为:repeat(循环次数表达式)语句;或 repeat(循环次数表达式)begin end,用repeat实现8位二进制数的乘法,module mult_repeat(outcome,a,b);parameter size=8;inputsize:1 a,b;output2*size:1 outcome;reg2*size:1 temp_a,outcome;regsize:1 temp_b;always(a or b)begin outcome=0;temp_a=a;temp_b=b;repeat(size)/repeat语句,size为循环次数begin

34、if(temp_b1)/如果temp_b的最低位为1,就执行下面的加法outcome=outcome+temp_a;temp_a=temp_a1;/操作数b右移一位endendendmodule,while语句,while语句的使用格式如下:while(循环执行条件表达式)语句;或while(循环执行条件表达式)begin end while语句在执行时,首先判断循环执行条件表达式是否为真,若为真的话,执行后面的语句或语句块,然后再回头判断循环执行条件表达式是否为真,为真的话,再执行一遍后面的语句,如此不断重复,知道表达式不为真,因此在执行该语句中,必须有一条改变循环执行条件表达式的值的语句。

35、,例1:integer count;initial begin count=0;while(count128)count=count+1;end,for循环语句实际上相当于采用while循环语句建立以下的循环结构:begin循环变量赋初值;while(循环结束条件)begin执行语句循环变量增值;endend这样对于需要8条语句才能完成的一个循环控制,for循环语句只需两条即可。,forever语句,forever语句的使用格式如下:forever 语句;或forever begin end forever循环语句不包含任何条件表达式,只执行无限循环,直到遇到系统任务$finish为止。常用于

36、产生周期性的波形,用来作为仿真测试信号。它与always语句不同处在于不能独立写在程序中,而必须写在initial块中。,例:reg clock;initial begin clock=1b0;forever#10 clock=clock;end,6.6 编译指示语句,Verilog允许在程序中使用特殊的编译向导(Compiler Directives)语句,在编译时,通常先对这些向导语句进行“预处理”,然后再将预处理的结果和源程序一起进行编译。向导语句以符号“”开头,以区别于其它语句。Verilog提供了十几条编译向导语句,如:define、ifdef、else、endif、restall等

37、。比较常用的有define,include和ifdef、else、endif等。,宏替换define,define语句用于将一个简单的名字或标志符(或称为宏名)来代替一个复杂的名字或字符串,其使用格式为:define 宏名(标志符)字符串 如:define sum ina+inb+inc+ind 在上面的语句中,用简单的宏名sum来代替了一个复杂的表达式ina+inb+inc+ind,采用了这样的定义形式后,在后面的程序中,就可以直接用sum来代表表达式ina+inb+inc+ind了。assign out=sum+ine;与assign out=ina+inb+inc+ind+ine;是完全

38、等价的。,宏替换define 特点:,define用于将一个简单的宏名来代替一个字符串或一个复杂的表达式。宏定义语句行末不加分号,这一点需要注意。在引用已定义的宏名时,不要忘了在宏名的前面加上符号“”,以表示该名字是一个宏定义的名字。采用宏定义,可以简化程序的书写,也便于修改。,文件包含include,include是文件包含语句,它可将一个文件全部包含到另一个文件中。其格式为:include“文件名”使用include语句时应注意以下几点:(1)一个include语句只能指定一个被包含的文件。(2)include语句可以出现在源程序的任何地方。被包含的文件若与包含文件不在同一个子目录下,必须

39、指明其路径名。(3)文件包含允许多重包含,比如文件1包含文件2,文件2又包含文件3等。,6.7 任务和函数,在行为级设计中,经常需要在程序的多个不同地方实现同样的功能。这表明有必要把这些公共的部分提取出来,将其组成子程序,然后在需要的地方调用这些子程序,以避免重复编码。绝大多数程序设计语言都提供了过程或子程序来达到这个目的。同样,verilog语言提供的任务和函数可以将较大的行为级设计划分为较小的代码段,允许verilog设计者将在多个地方位用的相同代码提取出来,编写成任务和函数。,Verilog的任务及函数区别和联系,任务(task)通常用于调试,或对硬件进行行为描述可以包含时序控制(#延迟

40、,等)可以有 input,output,和inout参数可以调用其他任务或函数函数(function)通常用于计算,或描述组合逻辑不能包含任何延迟;函数仿真时间为0只含有input参数并由函数名返回一个结果可以调用其他函数,但不能调用任务,区别,6.7 任务与函数,任务(task)任务定义格式:task;/注意无端口列表 端口及数据类型声明语句;其它语句;endtask任务调用的格式为:(端口1,端口2,);需要注意的是:任务调用时和定义时的端口变量应是一一对应的。,任务举例1module alutask(code,a,b,c);input1:0 code;input3:0 a,b;outpu

41、t4:0 c;reg4:0 c;task my_and;/任务定义,注意无端口列表input3:0 a,b;/a,b,out 名称的作用域范围为task 任务内部output4:0 out;integer i;beginfor(i=3;i=0;i=i-1)outi=ai/按位与endendtask,always(code or a or b)begincase(code)2b00:my_and(a,b,c);/*调用任务my_and,需注意端口列表的顺序应与任务定义中的一致,这里的a,b,c分别对应任务定义中的a,b,out*/2b01:c=a|b;/或2b10:c=a-b;/相减2b11:c

42、=a+b;/相加endcaseendendmodule,使用任务时,需要注意以下几点:,任务的定义与调用须在一个module模块内。定义任务时,没有端口名列表,但需要紧接着进行输入输出端口和数据类型的说明。当任务被调用时,任务被激活。任务的调用与模块调用一样通过任务名调用实现,调用时,需列出端口名列表,端口名的排序和类型必须与任务定义中的相一致。一个任务可以调用别的任务和函数,可以调用的任务和函数个数不限。,7.2 Verilog 函数,函数(function)类似于其它编程语言中的函数概念。与任务一样,Verilog HDL语言中的函数使用包括了函数的定义和函数的调用。1.函数的定义函数定义

43、的语法如下:function;beginendendfunction,其中:关键词function 和endfunction表示这部分语句是一个函数定义结构,function语句标识着这个函数定义结构的开头;endfunction语句标识着函数定义结构的结尾。“”是为被定义函数所取的一个名称,对被定义函数的调用是通过这个函数名来进行的。这个函数名在函数定义结构内部还代表着一个内部变量,函数调用后的返回值是通过这个函数名变量传递给调用语句(调用语句就是对函数进行了调用的语句)的。,“”是可选的,它用来对函数调用返回数据的类型或宽度进行说明(这个数据是通过函数名返回的),它可以有如下形式:“msb

44、:lsb”:这种形式说明函数名所代表的返回数据变量是一个多位的寄存器变量,它的位数由msb:lsb指定,比如如下函数定义语句:function 7:0 adder;就定义了一个函数“adder”,它的函数名“adder”还代表着一个8位宽的寄存器变量,其最高位为第7位,最低位为第0位。,函数的主要特性,函数定义中不能包含任何时序控制语句。函数至少有一个输入,不能包含任何输出或双向端口。函数只返回一个数据,其缺省为reg类型。传送到函数的参数顺序和函数输入参数的说明顺序相同。函数在模块(module)内部定义。函数不能调用任务,但任务可以调用函数。,函数举例,function7:0 get0;i

45、nput7:0 x;reg7:0 count;integer i;begin count=0;for(i=0;i=7;i=i+1)if(xi=1b0)count=count+1;get0=count;endendfunction 上面的get0函数循环核对输入数据x的每一位,计算出x中0的个数,并返回一个适当的值。,在进行函数定义时必须注意:(1)与任务一样,函数定义结构只能出现在模块中,而不能出现在过程块内。(2)函数至少必须有一个输入端口。(3)函数不能有任何类型的输出端口(output端口)和双向端口(inout端口)。(4)在函数定义结构中的行为语句部分内不能出现任何类型的时间控制描述

46、,也不允许使用disable终止语句。(5)与任务定义一样,函数定义结构内部不能出现过程块。(6)在一个函数内可以对其它函数进行调用,但是函数不能调用其它任务。(7)在第一行“function”语句中不能出现端口名列表。,2.函数的调用函数调用的格式如下:(,);其中,m个“”与函数定义结构中说明的各个输入端口一一对应,它们代表着各个输入端口的输入数据。这些输入表达式的排列顺序及类型必须与各个输入端口在函数定义结构中的排列顺序及类型保持严格一致。,在调用函数时必须注意如下两点:(1)函数的调用不能单独作为一条语句出现,它只能作为一个操作数出现在调用语句内。例如,下面这条语句对前面所定义的函数“

47、getbyte”进行了调用:out=getbyte(input1,number);在这条调用语句中,函数调用部分“getbyte(input1,number)”被看作是一个操作数,这个操作数的取值就是函数调用的返回值。在整个调用语句中,函数调用部分是作为“赋值表达式”出现在整条过程赋值语句中的,函数调用部分不能单独地作为一条语句出现,这就是说语句“getbyte(input1,number);”是非法的。,函数举例,module code_83(din,dout);input7:0 din;output2:0 dout;function2:0 code;input7:0 din;casex(d

48、in)8b1xxx_xxxx:code=3h7;8b01xx_xxxx:code=3h6;8b001x_xxxx:code=3h5;8b0001_xxxx:code=3h4;8b0000_1xxx:code=3h3;8b0000_01xx:code=3h2;8b0000_001x:code=3h1;8b0000_000 x:code=3h0;default:code=3hx;endfunctionassign dout=code(din);endmodule,函数举例,module funct(clk,n,result,reset);input reset,clk;input3:0 n;out

49、put31:0 result;reg31:0 result;always(posedge clk)begin if(!reset)result=0;else begin result=2*factorial(n);endendfunction31:0 factorial;Input 3:0 opa;reg3:0 i;begin factorial=opa?1:0;for(i=2;i=opa;i=i+1)factorial=i*factorial;endendfunction,任务与函数的比较,6.8 顺序执行与并发执行,两个或更多个“always”过程块、“assign”持续赋值语句、实例元件

50、调用等操作都是同时执行的。在“always”模块内部,其语句如果是非阻塞赋值,也是并发执行的;而如果是阻塞赋值,则语句是按照指定的顺序执行的,语句的书写顺序对程序的执行结果有着直接的影响。,顺序执行的例子,顺序执行模块1module serial1(q,a,clk);output q,a;input clk;reg q,a;always(posedge clk)begin q=q;a=q;endendmodule,顺序执行模块2module serial2(q,a,clk);output q,a;input clk;reg q,a;always(posedge clk)begin a=q;q=

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号