语法要点详细讲解有关测试模块编写的语法;语法的高级部分:函数、任务、文件、存贮器建立模型、双向总线、UDP、综合指令。。。。语法详细讲解Verilog测试模块的编写目的:复习如何编写较复杂的测试文件,对所做的设计进行完整的测试和验证。掌握组织模块测试的常用方法;学会编写常用的测试代码。语法详细讲解用Verilog设计的步骤注:虚线表示编译器能检查输入文件的可读性和是否存在以及是否允许生成输出文件include文件设计文件厂家元件库文件输入文件:激励和期望的输出信号输出文件:激励和实际输出的信号编译器仿真器仿真器语法详细讲解测试平台的组成激励信号需要验证的设计激励信号和用于验证的结果数据需要验证的设计简单的测试平台复杂的测试平台语法详细讲解并行块在测试块中常用到fork…join块。用并行块能表示以同一个时间起点算起的多个事件的运行,并行地执行复杂的过程结构,如循环或任务。举例说明如下:moduleinline_tb;reg[7:0]data_bus;initialforkdata_bus=8’b00;#10data_bus=8’h45;//这两个repeat开始执行时间不同,但能同时运行#20repeat(10)#10data_bus=data_bus+1;#25repeat(5)#20data_bus=data_bus1;#140data_bua=8’h0f;joinendmodule语法详细讲解并行块时间data_bus08’b0000_0000108’b0100_0101308’b0100_0110408’b0100_0111458’b1000_1110508’b1000_1111608’b1001_0000658’b0010_0000708’b0010_0001时间data_bus808’b0010_0010858’b0100_0100908’b0100_01011008’b0010_00011058’b0100_01101108’b1000_11001208’b1000_11101258’b0001_11001408’b0000_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;endreggo;wireclk;nand#(period/2)ul(clk,clk,go);initialbegingo=0;#(period/2)go=1;end注:在有些仿真器中,如果设计所用的时钟是由与其相同抽象级别的时钟模型产生的,则仿真器的性能就能得到提高。语法详细讲解建立时钟[例2]简单的带延迟的对称方波时钟:语法详细讲解建立时钟regclk;initialbeginclk=0;#(period)forever#(period/2)clk=!clkendreggo;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;endendreggo;wireclk;nand#(3*period/4,period/4)ul(clk,clk,go);initialbegin#(period/4+1)go=0;#(5*period/4-1)go=1;end注:这两个时钟模型也有些不同,行为描述的模型一开始就有确定的电平,而门级描述的模型有延迟,开始时电平是不确定的。语法详细讲解建立时钟[例2]简单的带延迟的对称方波时钟:语法详细讲解建立时钟regclk;initialbeginclk=0;#(period)forever#(period/2)clk=!clkendreggo;wireclk;nand#(period/2)ul(clk,clk,go);initialbegingo=0;#(period)go=1;end注:这两个时钟模型有些不同,行为描述的模型延迟期间一直是低电平,而门级描述的模型开始延迟有半个周期是不确定的。语法详细讲解怎样使用任务举例说明如何使用任务:modulebus_ctrl_tb;reg[7:0]data;regdata_valid,data_rd;cpuul(data_valid,data,data_rd);initialbegincpu_driver(8’b0000_0000);cpu_driver(8’b1010_1010);cpu_driver(8’b0101_0101);end语法详细讲解怎样使用任务taskcpu_driver;input[7:0]data_in;begin#30data_valid=1;wait(data_rd==1);#20data=data_in;wait(data_rd==0);#20data=8’hzz;#30data_valid=0;endendtaskendmodule语法详细讲解怎样使用任务在测试模块中使用任务可以提高程序代码的效率,可以用任务把多次重复的操作包装起来。waitwaitwaitwaitdata1data2data3data4cpu_dataclkdata_validdata_rdread_cpu_state语法详细讲解存储建模目标学会如何用Verilog对存储器建模。学会如何用Verilog中对双向(即输入/输出)端口,(inout)建模。存储器建模必须注意以下两个方面的问题:声明存储器容量的大小。明确对存储器访问操作的权限。例如:指出可以对存储器做以下哪几种操作:1)只读2)读写3)同步读写4)多次读,同时进行一次写5)多次同步读写,同时提供一些方法保证一致性语法详细讲解存储器建模`timescale1ns/10psmodulemyrom(read_data,addr,read_en_);inputread_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@(addrorread_en_)if(!read_en_)read_data=mem[addr];endmodule语法详细讲解简单ROM建模my_rom_data0000010111000011110100100011111110001001100000011101101000011101ROM的数据存储在另外的一个独立的文件中语法详细讲解简单ROM建模上页所示的ROM模型说明:如何在Verilog中用二维的寄存器组来定义存储器。ROM中的数据保存在一个独立的文件中,如上页的右边的虚线方框所示。这是一种保存ROM数据的通用的方法,它可以使数据和ROM模型分开。语法详细讲解简单RAM建模`timescale1ns/1nsmodulemymem(data,addr,read,write);inout[3:0]data;inout[3:0]addr;inputread,write;reg[3:0]memory[0:15];//4bits,16个单元//从存储器读出到总线上assigndata=read?memory[addr]:4’bz;//从总线写入存储器always@(posedgewrite)memory[addr]=data;endmodule语法详细讲解简单RAM建模RAM模型比ROM模型稍微复杂:它必须具有读写能力;进行读写时通常使用相同的数据总线;需要新技术来处理双向总线;当读信号无效时,RAM模型与总线脱离,如果此时写信号也无效,总线无驱动源,则总线进入高阻状态,这就避免了RAM中的读写竞争。上页的RAM模块是可综合的,但综合出来是一大堆寄存器,占比较大的面积,经济上不太合算。例:modulescalable_ROM(mem_word,address);parameteraddr_bits=8;//sizeofaddressbusparameterwordsize=8;//widthofawordparameterwords=(1addr_bits);//sizeofmemoutput[wordsize:1]mem_word;//wordofmemoryinput[addr_bits:1]address;//addressbusreg[wordsize:1]mem[0:words-1];//memdeclaration//outputonewordofmemorywire[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;imemsize;i=i+i)//initializememorymema[i]={wordsize{1’b1}};调用$readmem系统任务。//从文件mem_file.tx