=阻塞串行=非阻塞并行1)时序逻辑----使用非阻塞赋值2)锁存器----使用非阻塞赋值3)用always块生成的组合逻辑----用阻塞赋值4)在同一个always块中既有时序逻辑又有组合逻辑---用非阻塞赋值5)在同一个always块中不要既用阻塞赋值又用非阻塞赋值6)不要在一个以上的always块中对同一个变量赋值7)用$strobe显示用非阻塞赋值指定的变量值8)不要用#0过程性赋值Modport将信号分组并指明方向函数不能消耗时间,不能有#100@(posedgeclk)wait之类的阻塞语句Interfacearb_if(inputbitclk);Logic[1:0]a,b;Logicrst;Modporttest(outputa,rst,Inputb,clk);EndinterfaceModulearb(arb_if.testarbif);…………Endmodule数组定位Inttq[$],d[]=’{9,1,8,3,4,4};Tq=d.find_index(x)with(item3);//{0,2,4,5}得到的是脚标Tq=d.findwith(item3);//{9,8,4,4}数组求和Intcount,total;Count=d.sumwith(item7);//2:{9,8}返回结果为元素与7比较表达式返回1为真或者零这里面返回,{1,0,1,0,0,0}求和得2Total=d.sumwith((item7)*item);//{1,0,1,0,0,0}和对应元素相乘求和得17=9加8数组排序d.reverse();//逆序d.sort();//从小到大d.rsotr();//从大到小d.shuffle();时钟块指定同步信号相对于时钟的时序Interfacearb_if(inputbitclk);Logic[1:0]a,b;Logicrst;Clockingcb@(posedgeclk);Outputa;Inputb;Modporttest(outputrst,Clockingcb);EndinterfaceModulearb(arb_if.testarbif);InitialbeginArbif.cb.a=0;@arbif.cb;$dispiay(………..)Endmodule断言A1:assert(bus.cb.a==2’b01)Else$error(“grantnotasserted”);四种有输出消息的函数可在断言内部使用$info$waring$error$fatal要验证这样一个属性:“当信号a在某一个时钟周期为高电平时,那么在接下来的2~4个时钟周期内,信号b应该为高电平”。用Verilog语言描述这样一个属性需要一大段代码,而用SVA描述就只需要几行代码。下面的代码为SVA。例1:propertya2b_p;@(posedgesclk)$rose(a)|-[2:4]$rose(b);endpropertya2b_a:assertproperty(a2b_p);a2b_c:coverproperty(a2b_p);并发断言并发断言的计算基于时钟周期,在时钟边沿根据变量的采样值计算表达式。它可以放在过程块(proceduralblock)、模块(module)、接口(interface)或一个程序块(program)的定义中。并发断言可以在静态(形式化)验证工具和动态(仿真)验证工具中使用。上面的例子就是并发断言SVA提供了3个内嵌函数,用于检查信号的边沿变化。$rose(布尔表达式或信号名)当信号/表达式的最低位由0或x变为1时返回真值。$fell(布尔表达式或信号名)当信号/表达式的最低位由1变为0或x时返回真值。$stable(布尔表达式或信号名)当信号/表达式的最低位不发生变化时返回真值。断言的建立过程“编写布尔表达式—编写序列(sequence)-编写属性(property)—编写断言(assertproperty)和覆盖语句(coverproperty)”唯一性和优先级决定语句在Verilog中,如果没有遵循严格的编码风格,它的if-else和case语句会在RTL仿真和RTL综合间具有不一致的结果。如果没有正确使用full_case和parallel_case综合指令还会引起一些其它的错误。SystemVerilog能够显式地指明什么时候一条决定语句的分支是唯一的,或者什么时候需要计算优先级。我们可以在if或case关键字之前使用unique或requires关键字。这些关键字可以向仿真器、综合编译器、以及其它工具指示我们期望的硬件类型。工具使用这些信息来检查if或case语句是否正确建模了期望的逻辑。例如,如果使用unique限定了一个决定语句,那么在不希望的case值出现的时候仿真器就能够发布一个警告信息bit[2:0]a;uniqueif((a==0)||(a==1))y=in1;elseif(a==2)y=in2;elseif(a==4)y=in3;//值3、5、6、7会引起一个警告priorityif(a[2:1]==0)y=in1;//a是0或1elseif(a[2]==0)y=in2;//a是2或3elsey=in3;//如果a为其他的值uniquecase(a)0,1:y=in1;2:y=in2;4:y=in3;endcase//值3、5、6、7会引起一个警告类Classtrans;…………Endclasstransa;声明一个句柄(指针)a=new();//为一个trans对象分配空间用户定义的new()函数Classtrans;Logic[31:0]addr,crc,data[8];Functionnew;Addr=3;Foreach(data[i])Data[i]=5;EndfunctionEndclass随机化ClasspacketRandbit[31:0]a,b,c[8];Randcbit[7:0]k;Constraintd{a10;a15;}endclasspacketp;initialbeginp=new();assert(p.randomize());transmit(p);end指示通过引用传递的参数,参数声明需要以ref关键字开始线程always_comb过程来建模组合逻辑行为在0时刻结束时自动触发一次always_latch过程来建模锁存逻辑行为always_ff过程可以用来建模可综合的时序逻辑行为它仅能包含一个事件控制过程并且没有阻塞定时控制always_comb过程提供了不同于正常always过程的功能:具有一个推断的敏感列表赋值语句左侧的变量不应该被任何其它进程写入。在所有的initial和always块被启动以后,过程在时间0处被自动地触发一次,因此过程的输出与输入一致。SystemVerilog的always_comb过程在下述几个方面上不同于Verilog-2001的always@*:always_comb在时间0处自动执行,而always@*直到推断的敏感列表中的一个信号发生变化的时候才会执行。always_comb敏感于一个函数内容内部的改变,而always@*仅敏感于一个函数自变量的改变。在always_comb内部赋值左侧的变量(包括来自被调用函数内容中的变量)不应该被其它进程写入,而always@*则允许多个进程写入相同的变量。always_comb中的语句不应该包含阻塞语句、具有阻塞定时或事件控制的语句,或者fork...join语句。如果always_comb过程内的行为没有代表组合逻辑,例如推断出了锁存器,软件工具执行额外的检查来发布警告信息。Fork……join所有并行语句执行完毕才执行后续Fork…….join_none执行块儿内语句的同时父线程后面的程序继续进行Fork…..join_any当块内第一个语句完成后,父线程才继续执行。停止单个线程Parametertimeout=1000;Taskcheck(transtr);ForkbeginFork:check_stopBeginWait(tbus.cb.addr==tr.addr);$display(“……….”);End#timeout$display(“……….”);Join_anyDisablecheck_stop;EndJoin_noneEndtask事件信箱扩展的类Classbadtrextandstransaction;Randbitbad_crc;Virtualfunctionvoidcalc_crc;Super.calc_crc();//super调用基类里面的函数………..EndfunctionEndclass:badtr回调测试程序在不修改原始累得情况下注入新代码可以用来注入错误放弃事务延迟事务将事务放入记分板收集功能覆盖率等等记分板保存期望事务,找出测试平台接收到的实际事务相匹配的期望事务。Classscorebroad;Transactionscb[$];Functionvoidsave_expect(transactiontr);Scb.push_back(tr);EndfunctionFunctionvoidcompare_actual(transationtr);Intb[$];B=scb.find_index(x)with(x.src=tr.src);Case(b.size())0:$display(“nomatchfind”);1:scb.delete(q[0]);Default:$display(“error,multiplematchesfound”);EndcaseEndfunction:compare_actualEndclass功能覆盖率Programautomatictest(busifc.TB.ifc);Classtransaction;Randbit[31:0]data;Randbit[2:0]port;EndclassCovergroupcovport;Coverpointtr.port;EndgroupInitialbeginTransactiontr;Covportck;Tr=new();Ck=new();Repeat(32)beginAssert(tr.randomize);Ifc.cb.port=tr.port;Ck.sample();//收集覆盖率,触发覆盖组@ifc.cb;EndEndEndprogramAuto_bin_max指明了自动创建仓的最大值CovergroupCovPort;Option.Auto_bin_max=2;Coverpointtr.port;Endgroup分成两个仓bit[2:0]portauto[0:3]auto[4:7]两个仓仓CovergroupCovport;Kind:Coverpointtr.kind;{binszero={0};Binslo={[1:3],5};//1:3和5是一个仓Binshi[]={8:$};//8到最大值15,8个独立的仓,hi_0,hi_1……..Binsmisc=deflaut;//一个仓代表剩余的值Binst1=(1,2=3,4);//翻转覆盖率,表示自重翻转过程Ignore_binsh2={[6,7]};//被忽略的仓Illegal_binsh3={[6,7]};//非法的仓,出现会报错}Port:coverpointtr.port;Crosskind,port;//交叉覆盖率Endgroup发生器ClassgenerationUNI_cellblueprint;//定义的需要测试的对象的蓝图,可以通过修改起约束或者扩展替换他mailboxgen2drv;//信箱eventdrv2gen;//drive完成时的事件intncells;…………Functionnew(Inputmailboxgen2drv,Inputeventdrv2gen,……….)测试发生器代理驱动器