verilog中的高级结构_第1页
verilog中的高级结构_第2页
verilog中的高级结构_第3页
verilog中的高级结构_第4页
verilog中的高级结构_第5页
已阅读5页,还剩36页未读 继续免费阅读

下载本文档

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

文档简介

7.1任务和函数

在行为级设计中,经常需要在程序的多个不同地方实现同样的功能。这表明有必要把这些公共的部分提取出来,将其组成子程序,然后在需要的地方调用这些子程序,以避免重复编码。绝大多数程序设计语言都提供了过程或子程序来达到这个目的。同样,verilog语言提供的任务和函数可以将较大的行为级设计划分为较小的代码段,允许verilog设计者将在多个地方位用的相同代码提取出来,编写成任务和函数。

任务(task)通常用于调试,或对硬件进行行为描述可以包含时序控制(#延迟,@,wait)可以有input,output,和inout参数可以调用其他任务或函数函数(function)通常用于计算,或描述组合逻辑不能包含任何延迟;函数仿真时间为0只含有input参数并由函数名返回一个结果可以调用其他函数,但不能调用任务1.任务与函数的区别和联系区别任务和函数必须在module内调用在任务和函数中不能声明wire所有输入/输出都是局部寄存器任务/函数执行完成后才返回结果。

例如,若任务/函数中有forever语句,则永远不会返回结果共同点2.任务使用task和endtask来声明含有延迟、时序或事件控制结构没有输出或输出变量数目大于1没有输入变量moduletop;regclk,a,b;DUTu1(out,a,b,clk);always#5clk=!clk;

taskneg_clocks;

input[31:0]number_of_edges;

repeat(number_of_edges)@(negedgeclk);

endtaskinitialbeginclk=0;a=1;b=1;

neg_clocks(3);//任务调用

a=0;

neg_clocks(5);b=0;endendmodule满足以上三点的,一般用任务而不用函数

任务中含有时序控制和一个输入,并引用了一个module变量,但没有输出、输入输出和内部变量,也不显示任何结果。时序控制中使用的信号(例如clk)一定不能作为任务的输入,因为输入值只向该任务传送一次。任务可以有input,output

和inout参数。传送到任务的参数和与任务I/O说明顺序相同。尽管传送到任务的参数名称与任务内部I/O说明的名字可以相同,但在实际中这通常不是一个好的方法。参数名的唯一性可以使任务具有好的模块性。可以在任务内使用时序控制。在Verilog中任务定义一个新范围(scope)要禁止任务,使用关键字disable

。主要特点:

从代码中多处调用任务时要小心。因为任务的局部变量的只有一个拷贝,并行调用任务可能导致错误的结果。在任务中使用时序控制时这种情况时常发生。

在任务或函数中引用调用模块的变量时要小心。如果想使任务或函数能从另一个模块调用,则所有在任务或函数内部用到的变量都必须列在端口列表中。

下面的任务中有输入,输出,时序控制和一个内部变量,并且引用了一个module变量。但没有双向端口,也没有显示。任务调用时的参数按任务定义的顺序列出。modulemult(clk,a,b,out,en_mult);

inputclk,en_mult;

input[3:0]a,b;

output[7:0]out;

reg[7:0]out;

always@(posedgeclk)multme(a,b,out);//任务调用

task

multme;//任务定义

input

[3:0]xme,tome;

output

[7:0]result;

wait

(en_mult)

result=xme*tome;

endtaskendmodule自动任务任务在本质上是静态的,任务中的所有声明项的地址空间是静态分配的。因此,如果这个任务在模块中的两个地方被同时调用,则这两个任务调用将对同一块地址空间进行操作。操作的结果很有可能是错误的。为了避免这个问题,verilog通过在task关键字前面添加关键字automatic,使任务成为可重入的,这样声明的任务也称为自动任务,每次调用时,在动态任务中声明的所有模块项的存储空间都是动态分配的,每个调用都对各自独立的地址空间进行操作。这样.每个任务调用只对自己所拥有的独立变量副本进行操作.因此可以得到正确的执行结果。所以,如果某一任务有可能在程序代码的两处被同时调用,我们建议读者最好使用自动任务。moduletop;reg[15:0]cd_xor,ef_xor;

reg[15:0]c,d,e,f;task

automaticbitwise_xor;//任务定义

output

[15:0]ab_xor;input

[15:0]a,b;begin

#delayab_and=a&b;

ab_or=a|b;ab_xor=a^b;

endendtaskalways@(posedgeclk)bitwise_xor(ef_xor,e,f);always@(posedgeclk2)bitwise_xor(cd_xor,c,d);endmodule自动任务3.函数(function)以关键词function和endfunction声明函数内不含延迟、时序或事件控制结构moduleorand(a,b,c,d,e,out);

input[7:0]a,b,c,d,e;

output[7:0]out;

reg

[7:0]out;

always@(aorborcordore)out=f_or_and(a,b,c,d,e);//函数调用

function[7:0]f_or_and;

input[7:0]a,b,c,d,e;

if(e==1)f_or_and=(a|b)&(c|d);

elsef_or_and=0;

endfunctionendmodule只有一个返回值至少有一个输入变量没有输出变量不含有非阻塞赋值语句主要特性:函数定义中不能包含任何时序控制语句。函数至少有一个输入,不能包含任何输出或双向端口。函数只返回一个数据,其缺省为reg类型。传送到函数的参数顺序和函数输入参数的说明顺序相同。函数在模块(module)内部定义。函数不能调用任务,但任务可以调用函数。函数在Verilog中定义了一个新的范围(scope)。虽然函数只返回单个值,但返回的值可以直接给信号连接赋值。这在需要有多个输出时非常有效。

{o1,o2,o3,o4}=f_or_and(a,b,c,d,e);

要返回一个向量值(多于一位),在函数定义时在函数名前说明范围。函数中需要多条语句时用begin和end。不管在函数内对函数名进行多少次赋值,值只返回一次。下例中,函数还在内部声明了一个整数。modulefoo;input[7:0]loo;

output[7:0]goo;//可以持续赋值中调用函数

wire[7:0]goo=zero_count(loo);

function

[3:0]

zero_count;

input[7:0]in_bus;

integerI;

begin

zero_count=0;

for(I=0;I<8;I=I+1)

if(!in_bus[I])

zero_count

=zero_count+1;

end

endfunctionendmodule函数返回值可以声明为其它register类型:integer,real,或time。在任何表达式中都可调用函数modulechecksub(neg,a,b);outputneg;regneg;inputa,b;

function

integer

subtr;

input[7:0]in_a,in_b;

subtr=in_a-in_b;//结果可能为负

endfunction

always@(aorb)

if(subtr(a,b)<0)neg=1;

elseneg=0;endmodule函数中可以对返回值的个别位进行赋值。函数值的位数、函数端口甚至函数功能都可以参数化。...parameterMAX_BITS=8;reg[MAX_BITS:1]D;function

[MAX_BITS:1]

reverse_bits;

input[MAX_BITS-1:0]data;

integerK;for(K=0;K<MAX_BITS;K=K+1)

reverse_bits[MAX_BITS-(K+1)]=data[K];endfunctionalways@(posedgeclk)D=reverse_bits(D);...a.递归函数verilog中的函数是不能进行递归调用的;若在函数声明时使用了关键字automatic,那么该函数将成为自动的或可递归的.moduletop;function

automatic

integerfactorial;

input[31:0]oper;

integerI;beginif(oper>=2)factorial=factorial[oper-1]*oper;elsefactorial=1;endendfunction

integerresult;initialbegin

result=factorial(4);endendmoduleb.常量函数

常量函数实际上是一个带有某些限制的常规verilog函数。这种函数能够用来引用复杂的值,因此可用来代替常量。moduleram(….);parameterram_depth=256;input[clogb2(ram_depth)-1:0]addr_bus;function

integerclogb2(inputintegerdepth);

beginfor(clogb2=0;depth>0;clogb2=clogb2+1)depth=depth>>1;endendfunctionendmodule

c.带符号函数返回值可以作为带符号数进行运算moduletop;

function

signed

[63:0]compute_signed

(input[63:0]vector);

……..…….

endfunction

if(compute_signed(vector)<-3)begin…..endendmodule7.2电路级建模Verilog没有描述模拟电路的功能,可以描述mos晶体管,但晶体管仅被当作开关来描述,即只有导通和截止状态。1.MOS开关以关键词nmos用于NMOS晶体管建模以关键词pmos用于PMOS晶体管建模

因为开关是用verilog原语定义的,类似于逻辑门,实例名称是可选顶,所以调用实例引用开关时可以不给出实例名称。//实例名引用nmosn1(out,data,control);pmos

p1(out,data,control);//无实例名引用nmos

(out,data,control);pmos

(out,data,control);

信号out的值由信号data和control值确定。out的逻辑值如表所示。信号data和cotrol的不同组合导致这两个开关输出1,0或者z或x.逻辑值(如果不能确定输出为1或.就有可能输出z值或x值)。符号L代表0或z,H代表1或z;2.CMOS开关以关键词cmos用于CMOS晶体管建模//实例名引用cmosc1(out,data,ncontrol,pcontrol);cmos

(out,data,ncontrol,pcontrol);

信号ncontrol和pcontrol通常是互补的。当信号ncontrol为1且pcontrol信号为0时,开关导通。如果信号ncontrol为0且pcontrol为1,则开关的输出为高阻值。CMOSE本质上是两个开关(NMOS和PMOS)的组合体。//无实例名引用nmos

(out,data,ncontrol);pmos

(out,data,pcontrol);3.双向开关NMOS,PMOS和CMOS门都是从漏极向源极导通,是单向的。在数字电路中,双向导通的器件很重要。对双向导通的器件而言,其两边的信号都可以是驱动信号。通过设计双向开关就可以实现双向导通的器件。有三个关键字用来定义双向开关:tran,tranif0和tranif1。

tran开关作为两个信号inout1和inout2之间的缓存,inout1或inout2都可以是驱动信号。仅当control信号是逻辑0时,开关tranif0连接inout1和inout2两个信号。如果control信号为1,则没有驱动源的信号取高阻态值z,有驱动源的信号仍然从驱动源取值。//实例名引用tran

t1(inout1,inout2);tranif0(inout1,inout2,control);tranif1(inout1,inout2,control);4.电源和地以关键词supply1用于表示源极类型,相当于电路中的VDD,代表逻辑1以关键词supply0用于表示地极类型,相当于电路中的VSS或GND,代表逻辑0supply1vdd;supply0gnd;assigna=vdd;assignb=gnd;5.阻抗开关比一般的开关具有更高的源极到漏极阻抗在一般开关的关键词前面加r声明阻抗开关在传输信号时减小了信号的强度关键词rnmos

rpmos

rcmosrtranrtranif1rtranif06.设计实例a.cmos或非门modulemy_nor(out,a,b);outputout;inputa,b;wirec;supply1pwr;supply0gnd;pmos(c,pwr,b);pmos(out,c,a);nmos(out,gnd,a);nmos(out,gnd,b);endmodule

b.cmos反相器modulemy_not(out,in);outputout;inputin;supply1pwr;supply0gnd;pmos(out,pwr,in);nmos(out,gnd,in);endmodule7.3UDP用户自定义原语学习如何使用用户定义基本单元进行逻辑设计组合逻辑UDP设计时序逻辑UDP设计1.术语及定义UDP:userdefinedprimitive,用户自定义原语,其行为和Verilog内部的原语相似。其功能用真值表定义。UDP有两类:表示组合逻辑的UDP,输出仅取决于输入信号的组合逻辑。表示时序逻辑的UDP。下一个输出值不但取决于当前的输入值,还取决于当前的内部状态。在Verilog结构描述中,可以使用:二十多个内部门级基本单元用户自定义基本单元UDP在ASIC库单元开发、中小型芯片设计中很有用可以使用UDP扩充已定义的基本单元集UDP是自包容的,也就是不需要实例化其它模块UDP可以表示时序元件和组合元件UDP的行为由真值表表示UDP实例化与基本单元实例化相同可以使用UDP扩充已定义的基本单元集UDP是一种非常紧凑的逻辑表示方法。UDP可以减少消极(pessimism)因素,因为一个input上的x不会像基本单元那样自动传送到output。一个UDP可以替代多个基本单元构成的逻辑,因此可以大幅减少仿真时间和存储需求。相同逻辑的行为级模型甚至可以更快,这取决于仿真器。UDP的特点UDP只能有一个输出如果在功能上要求有多个输出,则需要在UDP输出端连接其它的基本单元,或者同时使用几个UDP。

UDP可以有1到10个输入若输入端口超过5,存储需求会大幅增加。下表列出输入端口数与存储需求的关系。所有端口必须为标量且不允许双向端口不支持逻辑值Z输出端口必须列为端口列表的第一个时序UDP输出端可以用initial语句初始化为一个确定值。UDP不可综合#输入存储器(KB)#输入存储器(KB)1-51856659187717106232.语法定义primitive

<udp名称>(<输出端口名>,<输入端口名>);//端口说明语句output<输出端口名>;input<输入端口名>;reg

<输出端口名>;(可选,只有在表示时序逻辑的udp才需要)//udp初始化(只有时序逻辑才需要)Initial<输出端口名>=<值>//udp状态表table<状态表>endtableendprimitive这两行用于减少消极因素。表示若a,b有相同逻辑值,即使sel=x,o也输出与a,b相同的值。Verilog内部基本单元不能描述这种行为。UDP将X作为真实世界的未知值(0或1),而不是Verilog值,描述也更为精确。这两行表示不管a为何值,若s为o,o输出b值3.组合逻辑UDPUDP在模块(module)外部定义。没有在真值表中说明的输入组合,输出X。真值表中输入信号按端口列表顺序给出。primitive

multiplexer(o,a,b,s);outputo;inputs,a,b;

table//abs:o0?1:0;1?1:1;?00:0;?10:1;00x:0;11x:1;

endtableendprimitiveUDP名称输出端口真值表中?表示的逻辑值为:0、1或x这两行表示不管b为何值,若s为1,o输出a值举例:2-1数据选择器组合逻辑举例2:全加器//FULLADDERCARRY-OUTTERMprimitiveU_ADDR2_C(CO,A,B,CI);

outputCO;

inputA,B,Ci;

table

//ABCI:CO11?:1; 1?1:1; ?11:1; 00?:0; 0?0:0; ?00:0;

endtableendprimitive全加器可以由两个组合逻辑UDP实现//FULLADDERSUMTERMprimitive

U_ADDR2_S(S,A,B,CI);

outputS;

inputA,B,CI;

table//ABCI:S 000:0; 001:1; 010:1; 011:0; 100:1; 101:0; 110:0; 111:1;

endtableendprimitive4.时序逻辑电路锁存器的行为如下:当时钟输入为0时,data输入的值传送到输出。当时钟输入为1时,输出不变。这种加电初始化在实际元件中很少见,但在UDP功能测试时很有用。primitive

latch(q,clock,data);

outputq;

reg

q;

inputclock,data;

initialq=1'b1;

table//clockdatacurrentnext//statestate01:?:1;00:?:0;1?:?:-;

endtableendprimitive输出必须声明为reg以保存前一状态时序UDP初始化语句,将输出初始化为1输入及当前状态中的?表示无关值用另一个场表示下一状态‘-’状态值表示输出没有变化举例1:锁存器latch举例2:D触发器在任何一个真值表入口语句中只能说明一个输入跳变。如果说明了任何输入跳变,则必须说明所有输入上的所有跳变。primitive

d_edge_ff(q,clk,data);outputq;

inputclk,data;regq;table//clkdatstatenext (01)0:?:0; (01)1:?:1; (0x)1:1:1; (0x)0:0:0; (x1)0:0:0; (x1)1:1:1;//忽略时钟下降沿

(?0)?:?:-; (1x)?:?:-;//时钟稳定时忽略data变化

?(??):?:-;

endtableendprimitive表里有边沿项表示输入跳变。在一条入口语句中只能说明一个输入跳变,因为Verilog仿真是基于事件,一次只允许一个事件发生。在每个时间步中,电平入口优先于边沿入口,因为电平最后处理。因此,下面的出口:

(?0)?:?:-;

可由下式取代:0?:?:-;

两个都给出时,只有后者起作用

5.提高可读性的简写形式Verilog中有一些符号可用于UDP真值表中以提高可读性符号表示解释-没有变化时序元件输出的下一个值与当前值相同?0、1或x任何值b0或1任何确定值r(01)0->1跳变f(10)1->0跳变p(01)、(0x)或(x1)任何上升沿(posedge)n(10)、(1x)或(x0)任何下降沿(negedge)*(??)任何跳变提高可读性的简写形式table//clkdatstatenext

r0:?:

温馨提示

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

最新文档

评论

0/150

提交评论