VerilogHDL详细语法.ppt_第1页
VerilogHDL详细语法.ppt_第2页
VerilogHDL详细语法.ppt_第3页
VerilogHDL详细语法.ppt_第4页
VerilogHDL详细语法.ppt_第5页
已阅读5页,还剩89页未读 继续免费阅读

下载本文档

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

文档简介

第三部分VerilogHDL详细语法,主要内容:Verilog与C的主要不同点模块实例化要点如何选择正确的数据类型VerilogHDL模块的测试Verilog测试模块的编写存储器建模Verilog中的高级结构用户定义的原语,3.1Verilog与C的主要不同点,Verilog有许多语法规则与C语言一致。但与C语言有根本的区别:-并行性-块的含义:initial块和always块两种赋值语句:阻塞赋值“=”非阻塞赋值“=”,系统任务和函数,$符号表示Verilog的系统任务和函数常用的系统任务和函数有下面几种:$time/找到当前的仿真时间$display,$monitor/显示和监视信号值的变化$stop/暂停仿真$finish/结束仿真-例:initial$monitor($time,”a=%b,b=%h”,a,b);/每当a或b值变化时该系统任务都显示当前的仿真时刻并分别用二进制和十六进制显示信号a和b的值,特殊符号“#”,特殊符号“#”常用来表示延迟:在过程赋值语句时表示延迟。例:initialbegin#10rst=1;#50rst=0;end在门级实例引用时表示延迟。例:not#1not1(nsel,sel);and#2and2(a1,a,nsel);在模块实例引用时表示参数传递,编译引导语句,编译引导语句用主键盘左上角小写键“”起头用于指导仿真编译器在编译时采取一些特殊处理编译引导语句一直保持有效,直到被取消或重写resetall编译引导语句把所有设置的编译引导恢复到缺省状态常用的编译引导有:defineincludetimescaleuselibresetall.,编译引导语句,使用define编译引导能提供简单的文本替代功能define在编译时会用宏文本来替代源代码中的宏名。合理地使用define可以提高程序的可读性举例说明:defineon1b1defineoff1b0defineand_delay#3在程序中可以用有含义的文字来表示没有意思的数码提高了程序的可读性,在程序中可以用on,off,and_delay分别表示1,0,和#3。,编译引导语句,使用include编译引导,在编译时能把其指定的整个文件包括进来一起处理举例说明:include“global.v”include“parts/counter.v”include“././library/mux.v”合理地使用include可以使程序简洁、清晰、条理清楚、易于查错。,编译引导语句,timescale用于说明程序中的时间单位和仿真精度举例说明:timescale1ns/100pstimescale语句必须放在模块边界前面举例说明:timescale1ns/100psmoduleMUX2_1(out,a,b,sel);not#1not1(nsel,sel);and#2and1(a1,a,nsel);endmodule尽可能地使精度与时间单位接近,只要满足设计的实际需要就行。举例说明:在上例中所有的时间单位都是1ns的整数倍,编译引导语句,仿真步长即仿真单位(STU)是所有参加仿真模块中由timescale指定的精度中最高(即时间最短)的那个决定的:(STU=100fs)举例:timescale1ns/10psmoduleM1(.);not#1.23not1(nsel,sel);/1.23ns中共有12300个STU(100fs)endmoduletimescale100ns/1nsmoduleM2(.);not#1.23not1(nsel,sel);/123ns中共有1230000个STU(100fs)endmoduletimescale1ps/100fsmoduleM3(.);not#1.23not1(nsel,sel);/1.23ps中共有12个STU(100fs)endmodule,编译引导语句,时间单位:fs(呼秒)femptoseconds:1.0E-15秒ps(皮秒)picoseconds:1.0E-12秒ns(纳秒)nonoseconds:1.0E-9秒us(微秒)microseconds:1.0E-6秒ms(毫秒)milliseconds:1.0E-3秒s(秒)seconds:1.0秒,编译引导语句,uselib编译引导语句:用于定义仿真器到哪里去找库元件如果该引导语句启动的话,它就一直有效直到遇到另外一个uselib的定义或resetall语句比其他配置库搜索路径的命令选项作用大如果仿真器在uselib定义的地点找不到器件库,它不会转向由编译命令行-v和-y选项指定的器件库去找。,编译引导语句,使用uselib的语法:uselib器件库1的地点器件库2的地点。上面的器件库地点可用以下两种方法表示:1)file=库文件名的路径2)dir=库目录名的路径libext=.文件扩展例如:uselibdir=/lib/FAST_lib/uselibdir=/lib/TTL_lib/libext=.vfile=/libs/TTL_U/udp.lib,3.2模块实例化要点,可以将模块的实例通过端口连接起来构成一个大的系统或元件。每个实例都有自己的名字。实例名是每个对象唯一的标记,通过这个标记可以查看每个实例的内部。实例中端口的次序与模块定义的次序相同。模块实例化与调用程序不同。每个实例都是模块的一个完全的拷贝,相互独立、并行。,端口与外部信号的连接,在调用模块时,可以用顺序连接和按名连接把模块定义的端口与外部信号连接起来顺序连接:需要连接的信号需要与模块声明的端口列表一致;按名连接:端口和外部信号按名字连接在一起.,moduleD_FF(d,clk,clr,q,qb);.endmodulemoduleREG4(d,clk,clr,q,qb);output3:0q,qb;input3:0d;inputclk,clr;D_FFd0(d0,clk,clr,q0,qb0);D_FFd1(d1,clk,clr,q1,qb1);D_FFd2(d2,clk,clr,q2,qb2);D_FFd3(d3,clk,clr,q3,qb3);endmodule,当设计大规模系统时,端口太多,记住端口顺序不大可能,可以采用按名连接方法。,不需要连接的端口直接忽略掉即可,D_FFd0(.d(d0),.clk(clk),.clr(clr),.q(q0),.qb(qb0);,D_FFd0(.d(d0),.clk(clk),.clr(clr),.q(q0);,3.3如何选择正确的数据类型,输入口(input)可以由寄存器或网络连接驱动,但它本身只能驱动网络连接。输出口(output)可以由寄存器或网络连接驱动,但它本身只能驱动网络连接。输入/输出口(inout)只可以由网络连接驱动,但它本身只能驱动网络连接。如果信号变量是在过程块(initial块或always块)中被赋值的,必须把它声明为寄存器类型变量,moduletop;wirey;rega,b;DUTu1(y,a,b);initialbegina=0;b=0;#10a=1;.endendmodule,moduleDUT(Y,A,B_);outputY;inputA,B:wireY,A,B;and(Y,A,B);endmodule,举例说明数据类型的选择,选择数据类型时常犯的错误,在过程块中对变量赋值时,忘了把它定义为寄存器类型(reg)或已把它定义为连接类型了(wire)把实例的输出连接出去时,把它定义为寄存器类型了把模块的输入信号定义为寄存器类型了。这是经常犯的三个错误!,3.4模块的测试,如何检查模块功能是否正确?需要有测试激励信号输入到被测模块需要记录被测模块的输出信号需要把用功能和行为描述的Verilog模块转换为门级电路互连的电路结构(综合)。需要对已经转换为门级电路结构的逻辑进行测试(门级电路仿真)。需要对布局布线后的电路结构进行测试。(布局布线后仿真)。,模块的测试(续),模块的测试(续),测试模块常见的形式:modulet;reg;/被测模块输入/输出变量类型定义wire;/被测模块输入/输出变量类型定义initialbegin;end/产生测试信号always#delaybegin;end/产生测试信号testedmdm(.in1(ina),.in2(inb),.out1(outa),.out2(outb);/被测模块的实例引用initialbegin.;.;.end/记录输出和响应endmodule,模块的测试(续),测试模块中常用的过程块:,always,所有的过程块都在0时刻同时启动;它们是并行的,在模块中不分前后。initial块只执行一次。always块只要符合触发条件可以循环执行。,模块的测试(续),如何描述激励信号:modulet;rega,b,sel;wireout;/引用多路器实例mux2_m(out,a,b,sel);/加入激励信号initialbegina=0;b=1;sel=0;#10b=0;#10b=1;sel=1;#10a=1;#10$stop;end,模块的测试(续),如何观察被测模块的响应:在initial块中,用系统任务$time和$monitor$time返回当前的仿真时刻$monitor只要在其变量列表中有某一个或某几个变量值发生变化,便在仿真单位时间结束时显示其变量列表中所有变量的值。例:initialbegin$monitor($time,“out=%ba=%bsel=%b”,out,a,sel);end,模块的测试(续),如何把被测模块的输出变化记录到数据库文件中?(文件格式为VCD,大多数的波形显示工具都能读取该格式)可用以下七个系统任务:$dumpfile(“file.dump”);/打开记录数据变化的数据文件$dumpvars();/选择需要记录的变量$dumpflush;/把记录在数据文件中的资料转送到硬盘保存$dumpoff;/停止记录数据变化$dumpon;/重新开始记录数据变化$dumplimit();/规定数据文件的大小(字节)$dumpall;/记录所有指定信号的变化值到数据文件中,模块的测试(续),如何把被测模块的响应变化记录到数据库文件中?举例说明:$dumpvars;/记录各层次模块中所有信号的变化$dumpvars(1,top);/只记录模块top中所有信号的变化$dumpvars(2,top.u1);/记录top模块中实例u1和它以下一层子模块所有信号的变化$dumpvars(0,top.u2,top.u1.u13.q);/记录top模块中实例u2和它本层所有信号的变化,还有top.u1.u13.q信号的变化。$dumpvars(3,top.u2,top.u1);/记录top模块中u2和u1所有信号的变化(包括其两层以下子模块的信号变化)。,模块的测试(续),如何把被测模块的响应变化记录到数据库文件中?举例说明:下面的Verilog代码段可以代替测试文件中的系统任务$monitorinitialbegin$dumpfile(“vlog.dump”);$dumpvars(0,top);end,3.5Verilog测试模块的编写,目的:复习如何编写较复杂的测试文件,对所做的设计进行完整的测试和验证。掌握组织模块测试的常用方法;学会编写常用的测试代码。,用Verilog设计的步骤,注:虚线表示编译器能检查输入文件的可读性和是否存在以及是否允许生成输出文件,include文件,设计文件,厂家元件库文件,输入文件:激励和期望的输出信号,输出文件:激励和实际输出的信号,编译器,仿真器,仿真器,测试平台的组成,激励信号,需要验证的设计,激励信号和用于验证的结果数据,需要验证的设计,简单的测试平台,复杂的测试平台,并行块,在测试块中常用到forkjoin块。用并行块能表示以同一个时间起点算起的多个事件的运行,并行地执行复杂的过程结构,如循环或任务。举例说明如下:moduleinline_tb;reg7:0data_bus;initialforkdata_bus=8b00;#10data_bus=8h45;#20repeat(10)#10data_bus=data_bus+1;#25repeat(5)#20data_bus=data_bus1;#140data_bua=8h0f;joinendmodule,/这两个repeat开始执行时间不同,但能同时运行。,并行块,时间data_bus08b0000_0000108b0100_0101308b0100_0110408b0100_0111458b1000_1110508b1000_1111608b1001_0000658b0010_0000708b0010_0001,时间data_bus808b0010_0010858b0100_0100908b0100_01011008b0010_00011058b0100_01101108b1000_11001208b1000_11101258b0001_11001408b0000_1111,上面模块的仿真输出如下:,强制激励,在一个过程块中,可以用两种不同的方式对信号变量或表达式进行连续赋值。过程连续赋值往往是不可以综合的,通常用在测试模块中。两种方式都有各自配套的命令来停止赋值过程。两种不同方式均不允许赋值语句间的时间控制。assign和deassign适用于对寄存器类型的信号(例如:RTL级上的节点或测试模块中在多个地方被赋值的信号)进行赋值。initialbegin#10assigntop.dut.fsml.state_reg=init_state;,#20deassigntop.dut.fsml.state_reg;endforce和release用于寄存器类型和网络连接类型(例如:门级扫描寄存器的输出)的强制赋值,强制改写其它地方的赋值。initialbegin#10forcetop.dut.counter.scan_reg.q=0;#20releasetop.dut.counter.scan_reg.q;end在以上两个例子中,在10到20这个时间段内,网络或寄存器类型的信号被强制赋值,而别处对该变量的赋值均无效。force的赋值优先级高于assign。如果先使用assign,再使用force对同一信号赋值,则信号的值为force所赋的值,,语法详细讲解强制激励,语法详细讲解字符串,强制激励,语法详细讲解强制激励,当执行release后,则信号的值为assign所赋的值。如果用force对同一个信号赋了几次值,再执行release,则所有赋的值均不再存在。可以对信号的某(确定)位、某些(确定)位或拼接的信号,使用force和release赋值;但不能对信号的可变位使用force和release来赋值。不能对寄存器类型的信号某位或某些位使用assign和deassign来赋值。,强制激励,语法详细讲解建立时钟,虽然有时在设计中会包含时钟,但时钟通常用在测试模块中。下面三个例子分别说明如何在门级和行为级建立不同波形的时钟模型。例1简单的对称方波时钟:,建立时钟,regclk;alwaysbegin#period/2clk=0;#period/2clk=1;end,reggo;wireclk;nand#(period/2)ul(clk,clk,go);initialbegingo=0;#(period/2)go=1;end,注:在有些仿真器中,如果设计所用的时钟是由与其相同抽象级别的时钟模型产生的,则仿真器的性能就能得到提高。,例2简单的带延迟的对称方波时钟:,建立时钟,regclk;initialbeginclk=0;#(period)forever#(period/2)clk=clk;end,reggo;wireclk;nand#(period/2)ul(clk,clk,go);initialbegingo=0;#(period)go=1;end,注:这两个时钟模型有些不同,行为描述的模型延迟期间一直是低电平,而门级描述的模型开始延迟有半个周期是不确定的。,语法详细讲解建立时钟,例3.带延迟、头一个脉冲不规则的、占空比不为1的时钟:,建立时钟,regclk;initialbegin#(period+1)clk=1;#(period/2-1)foreverbegin#(period/4)clk=0;#(3*period/4)clk=1;endend,reggo;wireclk;nand#(3*period/4,period/4)ul(clk,clk,go);initialbegin#(period/4+1)go=0;#(5*period/4-1)go=1;end,注:这两个时钟模型也有些不同,行为描述的模型一开始就有确定的电平,而门级描述的模型有延迟,开始时电平是不确定的。,语法详细讲解怎样使用任务,举例说明如何使用任务:modulebus_ctrl_tb;reg7:0data;regdata_valid,data_rd;cpuul(data_valid,data,data_rd);initialbegincpu_driver(8b0000_0000);cpu_driver(8b1010_1010);cpu_driver(8b0101_0101);end,怎样使用任务,语法详细讲解怎样使用任务,taskcpu_driver;input7:0data_in;begin#30data_valid=1;wait(data_rd=1);#20data=data_in;wait(data_rd=0);#20data=8hzz;#30data_valid=0;endendtaskendmodule,怎样使用任务,语法详细讲解怎样使用任务,在测试模块中使用任务可以提高程序代码的效率,可以用任务把多次重复的操作包装起来。,怎样使用任务,wait,wait,wait,wait,data1,data2,data3,data4,cpu_data,clk,data_valid,data_rd,read_cpu_state,语法详细讲解存储建模,目标学会如何用Verilog对存储器建模。学会如何用Verilog中对双向(即输入/输出)端口,(inout)建模。,3.6存储器建模,存储器建模必须注意以下两个方面的问题:声明存储器容量的大小。明确对存储器访问操作的权限。例如:指出可以对存储器做以下哪几种操作:1)只读2)读写3)同步读写4)多次读,同时进行一次写5)多次同步读写,同时提供一些方法保证一致性,存储器建模,timescale1ns/10psmodulemyrom(read_data,addr,read_en_);inputread_en_;input3:0addr;output3:0read_data;reg3:0read_data;reg3:0mem0:15;initial$readmemb(“my_rom_data”,mem);always(addrorread_en_)if(!read_en_)read_data=memaddr;endmodule,简单ROM建模,my_rom_data0000010111000011110100100011111110001001100000011101101000011101,ROM的数据存储在另外的一个独立的文件中,简单ROM建模,上页所示的ROM模型说明:如何在Verilog中用二维的寄存器组来定义存储器。ROM中的数据保存在一个独立的文件中,如上页的右边的虚线方框所示。这是一种保存ROM数据的通用的方法,它可以使数据和ROM模型分开。,简单RAM建模,timescale1ns/1nsmodulemymem(data,addr,read,write);inout3:0data;inout3:0addr;inputread,write;reg3:0memory0:15;/4bits,16words/从存储器读出到总线上assigndata=read?memoryaddr:4bz;/从总线写入存储器always(posedgewrite)memoryaddr=data;endmodule,简单RAM建模,RAM模型比ROM模型稍微复杂:它必须具有读写能力;进行读写时通常使用相同的数据总线;需要新技术来处理双向总线;当读信号无效时,RAM模型与总线脱离,如果此时写信号也无效,总线无驱动源,则总线进入高阻状态,这就避免了RAM中的读写竞争。上页的RAM模块是可综合的,但综合出来是一大堆寄存器,占比较大的面积,经济上不太合算。,例:modulescalable_ROM(mem_word,address);parameteraddr_bits=8;/sizeofaddressbusparameterwordsize=8;/widthofawordparameterwords=(1addr_bits);/sizeofmemoutputwordsize:1mem_word;/wordofmemoryinputaddr_bits:1address;/addressbusregwordsize:1mem0:words-1;/memdeclaration/outputonewordofmemorywirewordsize:1mem_word=memaddress;endmodule,存储量可变的只读存储器建模,存储量可变的只读存储器建模,上述的例子演示了怎样通过设置字长和地址位数来编写只读存储器的行为模块。注意!在上例中,存储字的范围从0开始的,而不是从1开始,这是因为存储单元是直接通过地址线寻址定位的。同样地,也可以用下面的方法来定义存储器和寻址:regwordsize:1mem1:words;/存储器地址从1开始/地址一个一个地增加直到包含了每个地址对应的存储器wirewordsize:1mem_word=memaddress+1;,可以在初始化块中用一个循环或系统任务把初始数据存入存储器的每个单元。使用循环把值赋给存储器数组。for(i=0;imemsize;i=i+i)/initializememorymemai=wordsize1b1;调用$readmem系统任务。/从文件mem_file.txt中,把初始数据存入存储器(mem)的每个单元$readmemb(“mem_file.txt”,mem);注意:上面两项必须写在initial块中,加载这些初始化数据不需要时间。,存储器的加载,怎样使用双向口,使用inout关键字声明端口为双向口。inout7:0databus;使用双向口必需遵循下面的规则:inout口只能声明为网络连接类型,不允许把它声明为寄存器类型。(所以仿真器能确定多个驱动源的最终值。)在设计中,每次只能从一个方向来驱动inout口。例如:当使用总线读RAM中的数据时,如果同时又向RAM模型的双向数据总线写数据,就会产生逻辑竞争,导致总线数据无法确定。所以必须为inout口设计控制逻辑,只有这样才能保证正确的操作。,怎样使用双向口,注意:声明一个inout口,可以用来输入或输出数据。inout口默认为网络连接类型。不允许在过程块(initial或always块)中对网络连接类型的数据进行过程赋值;但可以在过程块外把一个寄存器数据类型通过连续赋值语句赋给它(inout口),或者把它与用户定义的源语(UDP)相连。必须为inout口设计控制逻辑,用来保证正确的操作。当把inout口作为输入口时,必须通过控制逻辑禁止输出到inout口。,使用Verilog中的基本元件(bufif1)为双向口建模:,双向口建模,en_a_b,en_b_a,bus_a,bus_b,modulebus_xcvr(bus_a,bus_b,en_a_b,en_b_a);inoutbus_a,bus_b;inputen_a_b,en_b_a;bufiflb1(bus_b,bus_a,en_a_b);bufiflb2(bus_a,bus_b,en_b_a);/结构模块逻辑endmodule,当en_a_b=1时,元器件b1激活,bus_a的值传到bus_b上,当en_b_a=1时,元器件b1激活,bus_b的值传到bus_a上,双向口建模,注意:在上页的例子中,使用en_a_b和en_b_a来控制元器件bufifl,如果控制信号同时有效,则结果无法确定。所以必须把控制信号en_a_b和en_b_a在时间上分开。,使用连续赋值为双向口建模:,en_a_b,en_b_a,bus_a,bus_b,modulebus_xcvr(bus_a,bus_b,en_a_b,en_b_a);inoutbus_a,bus_b;inputen_a_b,en_b_a;assignbus_b=en_a_b?bus_a:bz;assignbus_a=en_b_a?bus_b:bz;/结构模块逻辑endmodule,当en_a_b=1时,bus_a的值传到bus_b上,当en_b_a=1时,bus_b的值传到bus_a上,双向口建模,注意:在assign语句中,通过en_a_b和en_b_a控制bus_a与bus_b之间的数据交换。如果控制信号同时有效,则结果不能确定。所以必须把控制信号en_a_b和en_b_a在时间上分开。,双向口建模,存储器的端口建模:,双向口建模,moduleram_cell(databus,rd.wr);inoutdatabus;inputrd,wr;regdatareg;assigndatabus=rd?datareg:bz;always(negedgewr)datareg=databus;endmodule,当rd等于1时datareg的值被赋给databus,当wr的下降沿到达时,databus的值被写入datareg,注意:上页中存储单元在wr的下降沿到达时存入数据。上页模块在wr处于高电平时,通过数据总线写入数据,但必须保证wr的高电平维持时间长于数据的写入时间。在rd处于高电平时,上述存储单元通过数据总线读出数据。由于此模型为单口存储模型,因此wr变低电平时,rd不能同时为高电平,否则就无法确定存储器的读出/写入的结果。,双向口建模,目标:学会怎样定义或调用任务和函数。学会怎样使用命名块。学会怎样禁止命名块和任务。理解有限状态机的作用,学会如何显式地为有限状态机建模。,3.7Verilog中的高级结构,通过把代码分成小的模块或者使用任务和函数,可把一项任务分成许多较小的、易于管理的部分,从而提高代码的可读性、可维护性和可重用性。任务一般用于编写测试模块,或者行为描述的模块。其中可以包含时间控制(如:#delays,wait);也可以包含input,output、inout端口定义和参数;也可以调用其他的任务或函数函数一般用于计算,或者用来代替组合逻辑。不能包含任何延迟;函数在零时间执行。函数只有input变量,虽然没有output变量,但可以通过函数名返回一个值。可以调用其他的函数,但不可以调用任务,Verilog中的高级结构,注意:只能调用本模块内的任务和函数。在任务和函数中不能声明网络连接类型的变量。所有的输入和输出变量实际上都是本地寄存器。只有当任务或函数调用并执行完后,才能有返回值。举例说明:若任务或函数中包含一个forever循环时,永远无法执行完,就不可能有返回值。,Verilog中的高级结构,3.7.1Verilog任务,下面模块中的任务含有定时控制和一个输入,并且引用了一个本模块的变量,但是没有输出,也没有双向总线和内部变量,不显示任何内容。用于定时控制的信号,例如clk,绝对不能作为任务的输入,这是因为输入值只向任务内部传递一次。moduletop;regclk,a,b;DUTu1(out,a,b,clk);always#5clk=!clk;,语法详细讲解整数和实常数,taskneg_clocks;input31:0number_of_edges;repeat(number_of_edges)(negedgeclk);endtaskinitialbeginclk=0;a=1;b=1;neg_clocks(3);/任务调用a=0;neg_clocks(5);b=0;endendmodule,Verilog任务,要点:任务调用是通过在Verilog模块中写入任务名来实现的。任务中可以包含input,output和inout端口变量的声明。传递给任务的变量与任务I/O端口变量的声明次序相同。虽然传递给任务的变量名可以和任务内声明的I/O端口变量名相同,但是为了使任务成为一个独立的可共用的任务块,建议不要使用与任务内声明的I/O端口变量名相同的变量名,最好给传递到任务的变量起新的不同的名字。在任务中可以使用时间控制。任务使Verilog有更广阔的适用范围。关键字disable可以用来禁止任务的执行。,Verilog任务,注意:不要在程序的不同部分同时调用同一个任务。这是因为任务只有一组本地变量,同一时刻调用两次相同的任务将会导致错误。这种情况常发生在使用定时控制的任务中。在任务或函数中,引用父模块中声明的变量时要特别注意(即注意变量的层次命名规则)。若想在其它模块中调用任务或函数,该任务和函数中所使用的变量必须全都包含在输入/输出口列表中。,Verilog任务,下面模块中的任务只含有一个双向总线(inout)端口和一个内部变量,没有其它输入端口、输出端口和定时控制,没有引用模块变量,不显示任何内容。在任务调用时,任务的输入变量(端口)在任务内部被当作寄存器类型变量处理。parameterMAX_BITS=8;regMAX_BITS:1D;taskreverse_bits;inout7:0data;/双向总线端口被当作寄存器类型!integerK;for(k=0;kMAX_BITS;K=K+1)reverse_bitsMAXBITS(K+1)=dataK;endtaskalways(posedgeclk)reverse_bits(D);,Verilog任务,下面模块中定义的任务含有输入、输出、时间控制和一个内部变量,并且引用了一个本模块的变量,但是没有输出,不显示任何内容。任务调用时变量顺序应与任务定义中声明的顺序相同。modulemult(clk,a,b,out,en_mult);inputclk,en_mult;input3:0a,b;output7:0out;reg15:0out;always(posedgeclk)multme(a,b,out);/任务调用,Verilog任务,taskmultme;/任务定义input3:0xme,tome;output7:0result;wait(en_mult)result=xme*tome;endtaskendmodule,Verilog任务,moduleorand(a,b,c,d,e,out);input7:0a,b,c,d,e;output7:0out;reg7:0out;always(aorborcordore)out=f_or_and(a,b,c,d,e);/函数调用function7:0f_or_and;input7:0a,b,c,d,e;if(e=1)f_or_and=(a|b)endfunctionendmodule,3.7.2Verilog函数,虽然函数不能包含定时控制,但是可以在包含定时控制的过程块中调用函数。在模块中,使用名为f_or_and的函数时,是把它作为名为f_or_and的寄存器类型变量来处理的。要点函数定义不能包含任何定时控制语句。函数必须至少有一个输入,但绝不能含有任何输出和总线口;一个函数只能返回一个值,该值的变量名与函数同名,数据类型默认为reg类型。传递给函数的变量顺序与函数输入口声明的顺序相同。函数定义必须包含在模块定义之内。函数不能调用任务,但任务可以调用函数。函数使Verilog有更广阔的适用范围。,Verilog函数,虽然函数只能返回一个值,但是它的返回值可以直接赋给一个由多个子信号拼接构成的信号变量,使其实际等效于产生了多个输出。o1,o2,o3,o4=f_or_and(a,b,c,d,e);,Verilog函数,在函数定义时,如果在函数名前面定义了位宽,该函数就可以返回由多位构成的矢量。如果定义函数的语句比较多时,可以用begin和end把它们组合起来。在函数内,无论以函数名命名的变量被赋了多少次值,函数只有一个返回值。下例中的函数,声明了一个内部整型变量。举例说明如下:modulefoo;input7:0loo;/也可以用连续赋值语句调用函数wire7:0goo=zero_count(loo);function3:0zero_count;input7:0in_bus;integerI;beginzero_count=0;for(I=0;I8;I=I+1)if(!in_busI)zero_count=zero_count+1;endendfunctionendmodule,Verilog函数,若把函数定义为整型、实型或时间类型,就可以返回相应类型的数据。我们可以在任何类型的表达式中调用函数。modulechecksub(neg,in_a,in_b);outputneg;inputa,b;regneg;functionintegersubtr;input7:0in_a,in_b;subtr=in_ain_b;/运算结果可以为负数endfunctionalways(aorb)beginif(subtr(a,b)0)neg=1;elseneg=0;endendmodule,Verilog函数,函数类型、端口和行为定义时也可以使用参数,这样就可以构成参数化函数使其返回的数据类型、输入端口的位宽等很容易做修改。所以参数化函数就有更广泛的适用范围。.parameterMAX_BITS=8;regMAX_BITS:1D;functionMAX_BIT:1reverse_bits;input7:0data;for(K=0;KMAX_BITS;K=K+1)reverse_bitsMAX_BITS(K+1)=dataK;endfunctionalways(posedgeclk)begin.D=reverse_bits(D);.end,Verilog函数,3.7.3命名块,可以通过在关键字begin或fork后加上:块名来给块命名。modulenamed_blk;begin:seq_blkendfork:par_blkjoinendmodule可以在命名块中声明本地变量。可以使用disable禁止命名块。,注意:命名块使Verilog有更广阔的适用范围。命名块的使用缩短了仿真的时间。,命名块,禁止命名块和任务,moduledo_arith(out,a,b,c,d,e,clk,en_mult);inputclk,en_mult;input7:0a,b,c,d,e;output15:0out;reg14:0out;always(posedgeclk)begin:arith_block/*命名名为arith_block的块*reg3:0tmp1,tmp2;/*本地变量*tmp,tmp2=f_or_and(a,b,c,d,e);/函数调用if(en_mult)multme(tmp1,tmp2,out);/任务调用endalways(negedgeen_mult)begin/停止计算disablemultme;/*禁止任务的执行*diablearith_block;/*禁止命名块的执行*end/在此定义任务和函数.endmodle,注意:disable语句用来终止命名块或任务的执行。这是指在尚未执行该命名块或任务任何一条语句前,就从该命名块/任务执行中返回。语法:disable块名或disable任务名禁止执行命名块或任务后,所有在事件队列中由该命名块/任务安排的事件都将被删除。一般情况下disable语句是不可综合的。在上页的例子中,只禁止命名块也可以得到预期的结果:命名块中所有的事件,包括任务和函数的执行都将被取消。,禁止命名块和任务,3.7.4有限状态机(FSM),隐式FSM:不需要状态寄存器仿真更加有效只能很好地处理线性的状态改变大部分综合工具不支持隐式FSM,语法详细讲解编译引导语句,显式FSM:结构比较复杂可以很方便的用来处理默认状态能够处理复杂的状态改变所有的综合工具均支持显式FSM的综合,有限状态机(FSM),注意:在隐式状态机中,只要发生在一个时钟周期内写数据,在另一个时钟周期内读数据的情况,都会生成寄存器。任何状态机都必须有复位控制信号,状态的改变必需只与某单一时钟信号沿同步。一般情况下,如果状态改变比较简单,又定义得比较好,而且综合工具支持隐式状态机的综合,就可以使用隐式状态机。如果状态改变比较复杂,最好使用显式状态机,这样效果更好。隐式状态机属于行为级,不属于RTL级。代码中主要包含循环语句、嵌入的定时控制,有时也含有命名事件、wait和disable语句。一般情况下,常用的综合工具不支持隐式状态机的综合。,有限状态机(FSMs),语法详细讲解显式有限状态机,moduleexp(out,datain,clk,rst);inputclk,rst,datain;outputout;regout;regstate;always(posedgeclkorposedgerst)if(rst)state,out=2b00;elsecase(state)1b0:beginout=1b0;if(!datain)state=1b0;elsestate=1b1;end1b1begin,状态变量,显式有限状态机,case语句,out=datain;state=1b0;enddefault:state,out=2b00;endcaseendmodule注:在过程块中可以使用一个时钟沿和case语句来描述一个显式状态机。必须指定一个状态变量,来记录状态机的状态。要改变当前的状态,必须改变状态变量的值,其改变要与时钟沿同步。写得比较好的状态机常为不应产生的条件规定一个默认

温馨提示

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

评论

0/150

提交评论