资源描述
,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,语法要点详细讲解,有关测试模块编写的语法;,语法的高级部分:,函数、任务、文件、存贮器建立模型、,双向总线、,UDP、,综合指令。,语法详细讲解,Verilog,测试模块的编写,目的:,复习如何编写较复杂的测试文件,对所做的设计,进行完整的测试和验证。,掌握组织模块测试的常用方法;学会编写常用的,测试代码。,语法详细讲解,用,Verilog,设计的步骤,注:虚线表示编译器能检查输入文件的可读性和是否存在以及是否允许生成输出文件,include,文件,设计文件,厂家元件,库文件,输入文件:激励和期望的输出信号,输出文件:激励和实际输出的信号,编译器,仿真器,仿真器,语法详细讲解,测试平台的组成,激励,信号,需要验证的,设计,激励信号,和用于验,证的结果,数据,需要验证的,设计,简单的测试平台,复杂的测试平台,语法详细讲解,并行块,在测试块中常用到,forkjoin,块。用并行块能表示以同一个时间起点算起的多个事,件的运行,并行地执行复杂的过程结构,如循环或任务。举例说明如下:,module inline_,tb,;,reg,7:0 data_bus;,initial fork,data_bus=8b00;,#10 data_bus=8h45;,/,这两个,repeat,开始执行时间不同,但能同时运行,#20,repeat(10)#10 data_bus=data_bus+1;,#25 repeat(5)#20 data_bus=data_bus 1;,#140 data_,bua,=8h0f;,join,endmodule,语法详细讲解,并行块,时间,data_bus,0 8b0000_0000,10 8b0100_0101,30 8b0100_0110,40 8b0100_0111,45 8b1000_1110,50 8b1000_1111,60 8b1001_0000,65 8b0010_0000,70 8b0010_0001,时间,data_bus,80 8b0010_0010,85 8b0100_0100,90 8b0100_0101,100 8b0010_0001,105 8b0100_0110,110 8b1000_1100,120 8b1000_1110,125 8b0001_1100,140 8b0000_1111,上面模块的仿真输出如下:,语法详细讲解,强制激励,在一个过程块中,可以用两种不同的方式对信号变量或表达式进行连续赋值。,过程连续赋值往往是不可以综合的,通常用在测试模块中。,两种方式都有各自配套的命令来停止赋值过程。,两种不同方式均不允许赋值语句间的时间控制。,assign,和,deassign,适用于对寄存器类型的信号,(例如:,RTL,级上的节点或测试模块中在多个地方被赋值的信号)进行赋值。,initial begin,#10 assign top.,dut,.,fsml,.state_,reg,=init_state;,#20,deassign,top.,dut,.,fsml,.state_,reg,;,end,force,和,release,用于寄存器类型和网络连接类型(例如:门级扫描寄存器的输出)的强制赋值,强制改写其它地方的赋值。,initial begin,#10 force top.,dut,.counter.scan_reg.q=0;,#20 release top.,dut,.counter.scan_reg.q;,end,在以上两个例子中,在10到20 这个时间段内,网络或寄存器类型的信号被强制赋值,而别处对该变量的赋值均无效。,force,的赋值优先级高于,assign。,如果先使用,assign,,再使用,force,对同一信号赋值,则信号的值为,force,所赋 的值,,语法详细讲解,强制激励,语法详细讲解,强制激励,当执行,release,后,则信号的值为,assign,所赋 的值。,如果用,force,对同一个信号赋了几次值,再执行,release,,则所有赋的值均不再存在。,可以对信号的某(确定)位、某些(确定)位或拼接的信号,使用,force,和,release,赋值;但不能对信号的可变位使用,force,和,release,来赋值。,不能对寄存器类型的信号某位或某些位使用,assign,和,deassign,来赋值。,虽然有时在设计中会包含时钟,但时钟通常用在测试模块中。下面,三个例子分别说明如何在门级和行为级建立不同波形的时钟模型。,例1 简单的对称方波时钟:,reg clk,;,always begin,#period/2,clk,=0;,#period/2,clk,=1;,end,reg,go;,wire,clk,;,nand,#(period/2),ul,(,clk,clk,go);,initial begin,go=0;,#(period/2)go=1;,end,注:在有些仿真器中,如果设计所用的时钟是由与其相同抽象级别的时钟模型产生的,则仿真器的性能就能得到提高。,语法详细讲解,建立时钟,例2,简单的带延迟的对称方波时钟:,语法详细讲解,建立时钟,reg clk,;,initial begin,clk,=0;,#(period),forever,#(period/2),clk,=!,clk,end,reg,go;,wire,clk,;,nand,#(period/2),ul,(,clk,clk,go);,initial begin,go=0;,#(period)go=1;,end,注:这两个时钟模型有些不同,行为描述的模型延迟期间一直是低电平,而门级描述的模型开始延迟有半个周期是不确定的。,例3.带延迟、头一个脉冲不规则的、占空比不为1的时钟:,reg clk,;,initial begin,#(period+1),clk,=1;,#(period/2-1),forever begin,#(period/4),clk,=0;,#(3*period/4),clk,=1;,end,end,reg,go;,wire,clk,;,nand,#(3*period/4,period/4),ul,(,clk,clk,go);,initial begin,#(period/4+1)go=0;,#(5*period/4-1)go=1;,end,注:这两个时钟模型也有些不同,行为描述的模型一开始就有确定的电平,而门级描述的模型有延迟,开始时电平是不确定的。,语法详细讲解,建立时钟,例2,简单的带延迟的对称方波时钟:,语法详细讲解,建立时钟,reg clk,;,initial,begin,clk,=0;#(period),forever#(period/2),clk,=!,clk,end,reg,go;,wire,clk,;,nand,#(period/2),ul,(,clk,clk,go);,initial begin,go=0;,#(period)go=1;,end,注:这两个时钟模型有些不同,行为描述的模型延迟期间一直是低电平,而门级描述的模型开始延迟有半个周期是不确定的。,语法详细讲解,怎样使用任务,举例说明如何使用任务:,module bus_ctrl_,tb,;,reg,7:0 data;,reg,data_valid,data_rd;,cpu ul,(data_valid,data,data_rd);,initial begin,cpu,_driver(8b0000_0000);,cpu,_driver(8b1010_1010);,cpu,_driver(8b0101_0101);,end,语法详细讲解,怎样使用任务,task,cpu,_driver;,input 7:0 data_in;,begin,#30 data_valid=1;,wait(data_rd=1);,#20 data=data_in;,wait(data_rd=0);,#20 data=8,hzz,;,#30 data_valid=0;,end,endtask,endmodule,语法详细讲解,怎样使用任务,在测试模块中使用任务可以提高程序代码的效率,可以用任务把多次重复的操作包装起来。,wait,wait,wait,wait,data1,data2,data3,data4,cpu,_data,clk,data_valid,data_rd,read_,cpu,_state,语法详细讲解,存储建模,目标,学会如何用,Verilog,对存储器建模。,学会如何用,Verilog,中对双向(即输入/输出)端口,(,inout,),建模。,存储器建模必须注意以下两个方面的问题:,声明存储器容量的大小。,明确对存储器访问操作的权限。,例如:指出可以对存储器做以下哪几种操作:,1)只读,2)读写,3)同步读写,4)多次读,同时进行一次写,5)多次同步读写,同时提供一些方法保证一致性,语法详细讲解,存储器建模,timescale 1ns/10ps,module,myrom,(read_data,addr,read_en_);,input read_en_;,input 3:0,addr,;,output 3:0 read_data;,reg,3:0 read_data;,reg,3:0,mem,0:15;,initial,$,readmemb,(“my_,rom,_data”,mem,);,always (,addr,or read_en_),if(!read_en_),read_data=,mem,addr,;,endmodule,语法详细讲解,简单,ROM,建模,my_,rom,_data,0000,0101,1100,0011,1101,0010,0011,1111,1000,1001,1000,0001,1101,1010,0001,1101,ROM,的数据存储在另外的一个独立的文件中,语法详细讲解,简单,ROM,建模,上页所示的,ROM,模型说明:,如何在,Verilog,中用二维的寄存器组来定义存储器。,ROM,中的数据保存在一个独立的文件中,如上页的右边的虚线方框所示。,这是一种保存,ROM,数据的通用的方法,它可以使数据和,ROM,模型分开。,语法详细讲解,简单,RAM,建模,timescale 1ns/1ns,module,mymem,(data,addr,read,write);,inout,3:0 data;,inout,3:0,addr,;,input read,write;,reg,3:0 memory 0:15;,/4 bits,16,个单元,/从存储器读出到总线上,assign data=read?memory,addr,:4,bz,;,/,从总线写入存储器,always (,posedge,write),memory,addr,=data;,endmodule,语法详细讲解,简单,RAM,建模,RAM,模型比,ROM,模型稍微复杂:,它必须具有读写能力;,进行读写时通常使用相同的数据总线;,需要新技术来处理双向总线;,当读信号无效时,,RAM,模型与总线脱离,如果此时写,信号也无效,总线无驱动源,则总线进入高阻状态,,这就避免了,RAM,中的读写竞争。,上页的,RAM,模块是可综合的,但综合出来是一大堆寄存器,占比较大的面积,经济上不太合算。,例:,module scalable_ROM(,mem,_word,address);,parameter,addr,_bits=8;/size of address bus,parameter,wordsize,=8;/width of a word,parameter words=(1,addr,_bits);/size of,mem,output,wordsize,:1,mem,_word;/word of memory,input ,addr,_bits:1 address;/address bus,reg,wordsize,:1,mem,0:words-1;/,mem,declaration,/output one word of memory,wire,wordsize,:1,mem,_word=,mem,address;,endmodule,语法详细讲解,存储量可变的只读存储器建模,语法详细讲解,存储量可变的只读存储器建模,上述的例子演示了怎样通过设置字长和地址位数来编,写 只读存储器的行为模块。,注意!在上例中,存储字的范围从0开始的,而不是从1开始,这是因为存储单元是直接通过地址线寻址定位的。,同样地,也可以用下面的方法来定义存储器和寻址:,reg,wordsize,:1,mem,1:words;,/,存储器地址 从1 开始,/地址一个一个地增加直到包含了每个地址对应的存储器,wire,wordsize,:1,mem,_word=,mem,address+1;,可以在初始化块中用一个循环或系统任务把初始数据存入存储器的每个单元。,使用循环把值赋给存储器数组。,for(i=0;i,memsize,;i=i+i)/initialize memory,mema,i=,wordsize,1b1;,调用$,readmem,系统任务。,/从文件,mem,_file.txt,中,把初始数据存入存储器(,mem,),的每个单元,$,readmemb,(“,mem,_file.txt”,mem,);,注意:上面两项必须写 在,initial,块中,加载这些初始化数据不需要时间。,语法详细讲解,存储器的加载,语法详细讲解,怎样使用双向口,使用,inout,关键字声明端口为双向口。,inout,7:0,databus,;,使用双向口必需遵循下面的规则:,inout,口只能声明为网络连接类型,不允许把它声明为寄存器类型。(所以仿真器能确定多个驱动源的最终值。),在设计中,每次只能从一个方向来驱动,inout,口。,例如:当使用总线读,RAM,中的数据时,如果同时又向,RAM,模型的双向数据总线写数据,就会产生逻辑竞争,导致总线数据无法确定。所以必须为,inout,口设计控制逻辑,只有这样才能保证正确的操作。,语法详细讲解,怎样使用双向口,注意:,声明一个,inout,口,可以用来输入或输出数据。,inout,口默认为网络连接类型。不允许在过程块(,initial,或,always,块)中对网络连接类型的数据进行过程赋值;但可以在过程块外把一个寄存器数据类型通过连续赋值语句赋给它(,inout,口),或者把它与用户定义的源语(,UDP),相连。,必须为,inout,口设计控制逻辑,用来保证正确的操作。当把,inout,口作为输入口时,必须通过控制逻辑禁止输出到,inout,口。,使用,Verilog,中的基本元件(,bufif1),为双向口建模:,语法详细讲解,双向口建模,b2,b1,en_a_b,en_b_a,bus_a,bus_b,语法详细讲解,双向口建模,注意:,在上页的例子中,使用,en_a_b,和,en_b_a,来控制元器件,bufifl,如果控制信号同时有效,则结果无法确定。,所以必须把控制信号,en_a_b,和,en_b_a,在时间上分开。,module bus_,xcvr,(bus_a,bus_b,en_a_b,en_b_a);,inout,bus_a,bus_b;,input en_a_b,en_b_a;,bufifl,b1(bus_b,bus_a,en_a_b);,bufifl,b2(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,上,使用连续赋值为双向口建模:,语法详细讲解,双向口建模,b2,b1,en_a_b,en_b_a,bus_a,bus_b,注意:在,assign,语句中,通过,en_a_b,和,en_b_a,控制,bus_a,与,bus_b,之间的数据交换。如果控制信号同时有效,则结果不能确定。所以必须把控制信号,en_a_b,和,en_b_a,在时间上分开。,语法详细讲解,双向口建模,module bus_,xcvr,(bus_a,bus_b,en_a_b,en_b_a);,inout,bus_a,bus_b;,input en_a_b,en_b_a;,assign bus_b=en_a_b?bus_a:,bz,;,assign bus_a=en_b_a?bus_b:,bz,;,/,结构模块逻辑,endmodule,当,en_a_b=1,时,,bus_a,的值传到,bus_b,上,当,en_b_a=1,时,,bus_b,的值传到,bus_a,上,存储器的端口建模:,语法详细讲解,双向口建模,module ram_cell(,databus,rd.,wr,);,inout databus,;,input rd,wr,;,reg datareg,;,assign,databus,=rd?,datareg,:,bz,;,always(,negedge wr,),datareg,=,databus,;,endmodule,当,rd,等于1时,datareg,的值被赋给,databus,当,wr,的下降沿到达时,,databus,的值被写入,datareg,测试模块,RAM,单元,数据总线,数据,寄存,器,rd,wr,注意:,上页中存储单元在,wr,的下降沿到达时存入数据。上页模块在,wr,处于高电平时,通过数据总线写入数据,但必须保证,wr,的高电平维持时间长于数据的写入时间。,在,rd,处于高电平时,上述存储单元通过数据总线读出数据。由于此模型为单口存储模型,因此,wr,变低电平时,,rd,不能同时为高电平,否则就无法确定存储器的读出/写入的结果。,语法详细讲解,双向口建模,目标:,学会怎样定义或调用任务和函数。,学会怎样使用命名块。,学会怎样禁止命名块和任务。,理解有限状态机的作用,学会如何显式地为有限状态机建模。,语法详细讲解,Verilog,中的高级结构,通过把代码分成小的模块或者使用任务和函数,可把一项任务分成许多较小的、易于管理的部分,从而提高代码的可读性、可维护性和可重用性。,任务:,一般用于编写测试模块或者行为描述的模块。其中可以包含时间控制(如:#,delays,wait);,也可以包含,input,output、,inout,端口定义和参数;也可以调用其他的任务或函数,语法详细讲解,Verilog,中的高级结构,函数:,一般用于计算,或者用来代替组合逻辑。,不能包含任何延迟;函数在零时间执行。,函数只有,input,变量,虽然没有,output,变量,,但可以通过函数名返回一个值。,可以调用其他的函数,但不可以调用任务,语法详细讲解,Verilog,中的高级结构,注意:,只能调用本模块内的任务和函数。,在任务和函数中不能声明网络连接类型的变量。,所有的输入和输出变量实际上都是本地寄存器。,只有当任务或函数调用并执行完后,才能有返回值。,举例说明:,若任务或函数中包含一个,forever,循环时,永远无法执行完,就不可能有返回值。,语法详细讲解,Verilog,中的高级结构,语法详细讲解,Verilog,任务,下面模块中的任务含有定时控制和一个输入,并且引用了一个本模块的变量,但是没有输出,也没有双向总线和内部变量,不显示任何内容。,用于定时控制的信号,例如,clk,,,绝对不能作为任务的输入,这是因为输入值只向任务内部传递一次。,module top;,reg clk,a,b;,DUT u1(out,a,b,clk,);,always#5,clk,=!,clk,;,语法详细讲解,Verilog,任务,task,neg,_clocks;,input 31:0 number_of_edges;,repeat(number_of_edges),(,negedge clk,);,endtask,initial begin,clk,=0;a=1;b=1;,neg,_clocks(3);/,任务调用,a=0;,neg,_clocks(5);,b=0;,end,endmodule,要点:,任务调用是通过在,Verilog,模块中写入任务名来实现的。,任务中可以包含,input,output,和,inout,端口变量的声明。,传递给任务的变量与任务,I/O,端口变量的声明次序相同。虽然传递给任务的变量名可以和任务内声明的,I/O,端口变量名相同,但是为了使任务成为一个独立的可共用的任务块,建议不要使用与任务内声明的,I/O,端口变量名相同的变量名,最好给传递到任务的变量起新的不同的名字。,在任务中可以使用时间控制。,任务使,Verilog,有更广阔的适用范围。,关键字,disable,可以用来禁止任务的执行。,语法详细讲解,Verilog,任务,注意:,不要在程序的不同部分同时调用同一个任务。这是因为任务只有一组本地变量,同一时刻调用两次相同的任务将会导致错误。这种情况常发生在使用定时控制的任务中。,在任务或函数中,引用父模块中声明的变量时要特别注意(即注意变量的层次命名规则)。若想在其它模块中调用任务或函数,该任务和函数中所使用的变量必须全都包含在输入/输出口列表中。,语法详细讲解,Verilog,任务,下面模块中的任务只含有一个双向总线(,inout,),端口和一个内部变量,没有其它输入端口、输出端口和定时控制,没有引用模块变量,不显示任何内容。,在任务调用时,任务的输入变量(端口)在任务内部被当作寄存器类型变量处理。,语法详细讲解,Verilog,任务,parameter MAX_BITS=8;,reg,MAX_BITS:1 D;,task reverse_bits;,inout,7:0 data;/,双向总线端口被当作寄存器类型!,integer K;,for(k=0;kMAX_BITS;K=K+1),reverse_bits MAXBITS (K+1)=dataK;,endtask,always (,posedge clk,),reverse_bits(D);,语法详细讲解,Verilog,任务,下面模块中定义的任务含有输入、输出、时间控制和一个内部变量,并且引用了一个本模块的变量,但是没有输出,不显示任何内容。任务调用时变量顺序应与任务定义中声明的顺序相同。,语法详细讲解,Verilog,任务,module,mult,(,clk,a,b,out,en_,mult,);,input,clk,en_,mult,;,input 3:0 a,b;,output 7:0 out;,reg,15:0 out;,always (,posedge clk,),multme,(a,b,out);/,任务调用,task,multme,;/,任务定义,input 3:0,xme,tome;,output 7:0 result;,wait(en_,mult,),result=,xme,*tome;,endtask,endmodule,语法详细讲解,Verilog,任务,module,orand,(a,b,c,d,e,out);,input 7:0 a,b,c,d,e;,output 7:0 out;,reg,7:0 out;,always (a or b or c or d or e),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),else,f_or_and=0;,endfunction,endmodule,语法详细讲解,Verilog,函数,虽然函数不能包含定时控制,但是可以在包含定时控制的过程块中调用函数。在模块中,使用名为,f_or_and,的函数时,是把它作为名为,f_or_and,的寄存器类型变量来处理的。,语法详细讲解,Verilog,函数,要点,函数定义不能包含任何定时控制语句。,函数必须至少有一个输入,但绝不能含有任,何输出和总线口;,一个函数只能返回一个值,该值的变量名与,函数同名,数据类型默认为,reg,类型。,传递给函数的变量顺序与函数输入口声明的,顺序相同。,函数定义必须包含在模块定义之内。,函数不能调用任务,但任务可以调用函数。,函数使,Verilog,有更广阔的适用范围。,虽然函数只能返回一个值,但是它的返回值,可以直接赋给一个由多个子信号拼接构成的,信号变量,使其实际等效于产生了多个输出。,o1,o2,o3,o4=f_or_and(a,b,c,d,e);,语法详细讲解,Verilog,函数,在函数定义时,如果在函数名前面定义了位宽,该函数就可以返回由多位构成的矢量。如果定义函数的语句比较多时,可以用,begin,和,end,把它们组合起来。,在函数内,无论以函数名命名的变量被赋了多少次值,函数只有一个返回值。,下例中的函数,声明了一个内部整型变量,。举例说明如下:,语法详细讲解,Verilog,函数,module,foo,;,input 7:0,loo,;,/,也可以用连续赋值语句调用函数,wire 7:0,goo,=zero_count(,loo,);,function 3:0 zero_count;,input 7:0 in_bus;,integer I;,begin zero_count=0;,for(I=0;I8;I=I+1),if(!in_busI),zero_count=zero_count+1;,end,endfunction,endmodule,语法详细讲解,Verilog,函数,若把函数定义为整型、实型或时间类型,就可以返回相应类型的数据。我们可以在任何类型的表达式中调用函数,。,module,checksub,(,neg,in_a,in_b);,output,neg,;,input a,b;,reg neg,;,function integer,subtr,;,input 7:0 in_a,in_b;,subtr,=in_a in_b;,/,运算结果可以为负数,endfunction,语法详细讲解,Verilog,函数,always (a or b),begin if(,subtr,(a,b)0),neg,=1;,else,neg,=0;,end,endmodule,语法详细讲解,Verilog,函数,函数类型、端口和行为定义时也可以使用参数,这样就可以构成参数化函数使其返回的数据类型、输入端口的位宽等很容易做修改。所以参数化函数就有更广泛的适用范围。,语法详细讲解,Verilog,函数,.,parameter MAX_BITS=8;,reg,MAX_BITS:1 D;,function MAX_BIT:1 reverse_bits;,input 7:0 data;,for(K=0;K MAX_BITS;K=K+1),reverse_bits MAX_BITS (K+1)=data K;,endfunction,always (,posedge clk,),begin .,D=reverse_bits(D);,.,end,语法详细讲解,Verilog,函数,语法详细讲解,命名块,可以通过在关键字,begin,或,fork,后加上:块名来给块命名。,module named_,blk,;,begin:,seq,_,blk,end,fork:par_,blk,join,endmodule,可以在命名块中声明本地变量。,可以使用,disable,禁止命名块。,注意:,命名块使,Verilog,有更广阔的适用范围。,命名块的使用缩短了仿真的时间。,语法详细讲解,命名块,语法详细讲解,禁止命名块和任务,module do_,arith,(out,a,b,c,d,e,clk,en_,mult,);,input,clk,en_,mult,;,input 7:0 a,b,c,d,e;,output 15:0 out;,reg,14:0 out;,always(,posedge clk,),begin:,arith,_block /*,命名名为,arith,_block,的块*,reg,3:0 tmp1,tmp2;/*,本地变量*,tmp,tmp2=f_or_and(a,b,c,d,e);/,函数调用,if(en_,mult,),multme,(tmp1,tmp2,out);/,任务调用,end,语法详细讲解,禁止命名块和任务,always(,negedge,en_,mult,),begin /,停止计算,disable,multme,;/*,禁止任务的执行,diable arith,_block;/*,禁止命名块的执行,end,/,在此定义任务和函数,.,endmodle,注意:,disable,语句用来终止命名块或任务的执行。这是指在尚未执行该命名块或任务任何一条语句前,就从该命名块/任务执行中返回。,语法:,disable,块名 或,disable,任务名,禁止执行命名块或任务后,所有在事件队列中由该命名块/任务安排的事件都将被删除。,一般 情况下,disable,语句是不可综合的。,在上页的例子中,只禁止命名块也可以得到预期的结果:命名块中所有的事件,包括任务和函数的执行都将,被取消。,语法详细讲解,禁止命名块和任务,目的:,学习,LPM,(Library of,Parameterrized,Modules),资源的利用;,学习调试用系统任务的利用:,$,random;,$,fmonitor,;$,fdisplay,.,$,fopen,;$,fclose,;$,readmemh,.,语法详细讲解,系统资源和任务的利用,语法详细讲解,怎样利用参数化模块,在,LPM,库中必须已经有该具体参数化模块,名称和使用注意点已经通过阅读说明书搞清楚了,举例如下:,module,adderlpm,(,cin,x,y,s,cout,);,input,cin,;,input 15:0 x,y;,output 15:0 s;,output,cout,;,lpm,_add_sub m(.,cin,(,cin,),.,dataa,(x),.,datab,(y),.result(s),.,cout,(,cout,);,defparam,m.,lmp,_width=16;,endmodule,语法详细讲解,随机数的产生$,random,语法要点:$,random;$random();,举例如下:,module t;,integer r_seed;,rom,m1(data,addr,);,.,initial r_seed=2;,always(,posedge clk,),addr,=$random(r_seed)%1024;,.,/,用来测试地址为0到1024之间任意值时的,Rom。,endmodule,语法详细讲解,文件的使用,语法要点,:,$,fopen,(,文件名);,file_handle=$,fopen,(,文件名);,/标准的输出显示器,descriptor=32h0000_0001(bit 0 set),integer handle1,handle2.;,initial begin,handle1=$,fopen,(file1.out);/bit 1 set,handle2=$,fopen,(file2.out);/bit 2 set,handle3=$,fopen,(file3.out);/bit 2 set,end,语法详细讲解,写到文件中去,语法要点:,$,fdisplay,(,,p1,p2,.,pn,);,$,fmonitor,(,,p1,p2,.,pn,);,integer desc1,desc2,desc3;,initial begin desc1=handle1|1;,fdisplay,(desc1,Display 1,);,/,写到文件,file1.out(handle1),和显示器(1)(,stdout,),desc2=handle2|handle1;,fdisplay,(desc2,Display 2,);,/,写到文件,file1.out(handle1),和文件,file2.(handle2),desc3=handle3;,fdisplay,(desc3,Display 3,);,/,只写到文件,file3.out(handle1),中,end,语法详细讲解,关闭文件,语法要点:,$,fclose,();,举例:,$,fclose,(handle1);/,关闭,file1.out,语法详细讲解,层次信息的显示,可以用于任何显示任务如:$,display,$write,$monitor,$strobe.,举例:,module M;,.,initial$display(Displaying in%m);,endmodule,module top;,M m1();/,显示层次信息,M m2();,M m3();.,endmodule,语法详细讲解,层次信息的显示,显示任务结果如下:,Displaying in top.m1,Displaying in top.m2,Displaying in top.m3,语法详细讲解,用文件中的数据初始化存储器,语法要点:,$,readmemb,(,文件名,存储器名);,$,readmemb,(,文件名,存储器名,起始地址);,$,readmemh,(,文件名,存储器名,起始地址);,举例:,module test;,reg,7:0 memory 0:1023,integer i;,inititial,begin$,readmemb,(init.,dat,memory);,for(i=0;i1024;i=i+1;),$display(memory%0d=%b,i,memory);,end,endmodule,语法详细讲解,用文件中的数据初始化存储器,init.,dat,文件内容:,002,1111_1111 0101_0101,0000_0000 1010_1010,008,Zzzz,_1111 0000_1111,1111_0000 0001_1000,.,memory 0=,xxxxxxxx,memory 1=,xxxxxxxx,memory 2=11111111,memory 3=01010101,memory 4=00000000,memory 5=10101010,memory 6=,xxxxxxxx,memory 7=,xxxxxxxx,memory 8=zzzz1111,memory 9=00001111,memory 10=11110000,memory 11=00011000,.,语法详细讲解,有限状态机(,FSM),隐式,FSM:,不需要状态寄存器,仿真更加有效,只能很好地处理线性的状态改变,大部分综合工具不支持隐式,FSM,state 1,state 2,state 3,state 4,语法详细讲解,有限状态机(,FSM),显式,FSM:,结构比较复杂,可以很方便地用来处理默认状态,能够处理复杂的状态改变,所有的综合工具均支持显式,FSM,的综合,state A,state B1,state B2,state C,state D,注意:,在隐式状态机中,只要发生在一个时钟周期内写数据,在另一个时钟周期内读数据的情况,都会生成寄存器。,任何状态机都必须有复位控制信号,状态的改变必需只与某单一时钟信号沿同步。,一般情况下,如果状态改变比较简单,又定义得比较好,而且综合工具支持隐式状态机的综合,就可以使用隐式状态机。如果状态改变比较复杂,最好使用显式状态机,这样效果更好。,隐式状态机属于行为级
展开阅读全文