systemverilog验证学习笔记汇总.docx
- 文档编号:24137468
- 上传时间:2023-05-24
- 格式:DOCX
- 页数:15
- 大小:37.46KB
systemverilog验证学习笔记汇总.docx
《systemverilog验证学习笔记汇总.docx》由会员分享,可在线阅读,更多相关《systemverilog验证学习笔记汇总.docx(15页珍藏版)》请在冰豆网上搜索。
systemverilog验证学习笔记汇总
=阻塞串行
<=非阻塞并行
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);
Endinterface
Modulearb(arb_if.testarbif);
…………
Endmodule
数组定位
Inttq[$],d[]=’{9,1,8,3,4,4};
Tq=d.find_index(x)with(item>3);//{0,2,4,5}得到的是脚标
Tq=d.findwith(item>3);//{9,8,4,4}
数组求和
Intcount,total;
Count=d.sumwith(item>7);//2:
{9,8}返回结果为元素与7比较表达式返回1为真或者零这里面返回,{1,0,1,0,0,0}求和得2
Total=d.sumwith((item>7)*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);
Endinterface
Modulearb(arb_if.testarbif);
Initialbegin
Arbif.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);endproperty
a2b_a:
assertproperty(a2b_p);a2b_c:
coverproperty(a2b_p);
并发断言
并发断言的计算基于时钟周期,在时钟边沿根据变量的采样值计算表达式。
它可以放在过程块(procedural block)、模块(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或1
elseif(a[2]==0)y=in2;//a是2或3
elsey=in3;//如果a为其他的值
uniquecase(a)0,1:
y=in1;2:
y=in2;4:
y=in3;
endcase//值3、5、6、7会引起一个警告
类
Classtrans;
…………
Endclass
transa;声明一个句柄(指针)
a=new();//为一个trans对象分配空间
用户定义的new()函数
Classtrans;
Logic[31:
0]addr,crc,data[8];
Functionnew;
Addr=3;
Foreach(data[i])
Data[i]=5;
Endfunction
Endclass
随机化
Classpacket
Randbit[31:
0]a,b,c[8];
Randcbit[7:
0]k;
Constraintd{a>10;
a<15;}
endclass
packetp;
initialbegin
p=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);
Fork
begin
Fork:
check_stop
Begin
Wait(tbus.cb.addr==tr.addr);
$display(“……….”);
End
#timeout$display(“……….”);
Join_any
Disablecheck_stop;
End
Join_none
Endtask
事件
信箱
扩展的类
Classbadtrextandstransaction;
Randbitbad_crc;
Virtualfunctionvoidcalc_crc;
Super.calc_crc();//super调用基类里面的函数
………..
Endfunction
Endclass:
badtr
回调
测试程序在不修改原始累得情况下注入新代码
可以用来
注入错误
放弃事务
延迟事务
将事务放入记分板
收集功能覆盖率等等
记分板
保存期望事务,找出测试平台接收到的实际事务相匹配的期望事务。
Classscorebroad;
Transactionscb[$];
Functionvoidsave_expect(transactiontr);
Scb.push_back(tr);
Endfunction
Functionvoidcompare_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”);
Endcase
Endfunction:
compare_actual
Endclass
功能覆盖率
Programautomatictest(busifc.TB.ifc);
Classtransaction;
Randbit[31:
0]data;
Randbit[2:
0]port;
Endclass
Covergroupcovport;
Coverpointtr.port;
Endgroup
Initialbegin
Transactiontr;
Covportck;
Tr=new();
Ck=new();
Repeat(32)begin
Assert(tr.randomize);
Ifc.cb.port<=tr.port;
Ck.sample();//收集覆盖率,触发覆盖组
@ifc.cb;
End
End
Endprogram
Auto_bin_max指明了自动创建仓的最大值
CovergroupCovPort;
Option.Auto_bin_max=2;
Coverpointtr.port;
Endgroup
分成两个仓
bit[2:
0]port
auto[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
发生器
Classgeneration
UNI_cellblueprint;//定义的需要测试的对象的蓝图,可以通过修改起约束或者扩展替换他
mailboxgen2drv;//信箱
eventdrv2gen;//drive完成时的事件
intncells;
…………
Functionnew(Inputmailboxgen2drv,
Inputeventdrv2gen,
……….
)
This.gen2drv=gen2drv;
This.drv2gen=drv2gen;
This.ncell=ncell;
……………….
Blueprint=new();
Endfunction:
new
Taskrun();
UNI_cellcell;
Repeat(ncells)begin
Assert(blueprint.randomize());
$cast(cell,blueprint.copy());//基类句柄指向拓展对象
Gen2drv.put(cell);//事务放进信箱发送给驱动器
@drv2gen;
end
Endtask:
run
Endclass:
generation
驱动类
TypedefclassDrive_cbs;
Classdrive
Mailboxgen2drv;
Eventdrv2gen;
vUtopiaRxRx;//发送的数据的接口
Drive_cbscbs[$];//回调队列
Intportid;
Externfunctionnew(
InputMailboxgen2drv,
InputEventdrv2gen,
InputvUtopiaRxRx,
InputIntportid;
)
Externtaskrun();
Externtasksend();
Endclass:
drive
Taskdrive:
:
run()
UNI_cellcell;
Bitdrop=0;
Rx.cbr.data<=0;
……….//初始化端口
Foreverbegin
Gen2drv.peek();//从信箱中读取一个数据
//发送前回调
begin:
tx
Foreach(cbs[i]);
Cbs[i].pre_tx(this,cell,drop);
If(drop)disabletx;//不发送这个数据
End
Send(cell);
//发送后的回调
Foreach(cbs[i]);
Cbs[i].post_tx(this,cell,drop);
End:
tx
Gen2drv.get(cell);//删除数据
->drv2gen;
Endtask:
run
Taskdrive:
:
send(inputUNI_cellcell)
……………….
Rx.cbr.data<=cell.data//数据发送给接口时钟块
@rx.cbr
…………………….
Endtask
UVM
Factory机制
‘uvm_componet_utils(my_driver);
Run_test(“my_driver”);
Factory集中在一个宏uvm_componet_utils中
这个宏将类my_driver登记在uvm内部一张表中,在定义一个新的类时使用这个宏,就相当于把这个类注册到了这张表中。
Run_test语句会创建一个my_driver实例,然后自动调用其中的main_phase.
‘uvm_object_utils(my_transaction);
My_transaction有生命周期,用‘uvm_object_utils实现factory机制。
而整个仿真中一直存在的用uvm_componet_utils注册
只有用uvm_componet才能成为uvm树的结点,而uvm_object不能。
为了使用factory机制的重载功能
验证平台的组件在实例化是都应该使用type_name:
:
type_id:
:
create
My_driverdiv;
Virtualfunctionvoidbuild_phase(uvm_phasephase);
Super.build_phase(phase);
Drv=my_driver:
:
type_id:
:
create(“drv”,this)
Endfuntion
实例化传递两个参数,一个名字,一个是是parent最为父结点,通过parent的形式建立了uvm的树形结构
env建立一个容器类,在这个容器类中实例化driver,monitor,referencemodel和scoreboard.
验证平台实时监测dut行为的组件monitor,收集端口数据转刷成transaction交给后续组件处理。
Objection
在每个phase中,uvm会见啥是否有objection被提起(raise_objection),如果有,那么等待这个objection被撤销(drop_objection)后停止仿真。
如果没有,则马上结束当前phase。
Phase.raise_objection(this);
Phase.drop_objection(this);
build_phase是自上而下执行,其他至下而上执行
driver像sequencer申请transaction
uvm_driver中成员变量seq_item_port
uvm_suquencer中有成员变量seq_item_export
两者之间可以建立一个通道。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- systemverilog 验证 学习 笔记 汇总