验证基础技巧记录(三)
1.如需使用interface,则必须在TB顶层进行例化;
2.为了让class可以使用tf,需要在成员变量中声明virtual if_name if_class_name;,并通过函数从顶层传入;
3.sv语言的声明不可中断,否则报错;
4.传递句柄一般比传递单一数据更好,也比传递结构体更好。因为句柄指向一块数据空间及数据处理方法,可以生成更复杂的激励或完成一些打印;
5.module不能封装,约束,local,protect,class可以;
6.interface也可以附带参数,此外interface声明的数据类型一般都是logic;
7.注意随机化以后进行计算时可能出现的位宽溢出问题;
8.注意二值信号驱动四值信号的问题,验证时有可能需要关心X态;
9.动态数组是申请的一片空间,队列则是离散分布的空间,再通过指针链接;(但其实这种detail知识不需要太在意)
10.队列的灵活性会比动态数组高一些,队列和链表的选择:涉及描述符,需要动态添加和删除一些操作的时候,可以采用队列;
例如:始终push_back新数据,同时pop_front老的数据,以完成更新,避免使用下标的出错;
11.typedef class class_name;一些agent需要例化其他的class,但其实他们的编译顺序可能会在其他class之前,所以需要提前使用typedef class class_name;来避免编译报错;
12.枚举;枚举类型不能被遍历或使用foreach等操作,但可以把枚举类型声明为动态数组来存储;
13.注意代码的通用性,位宽等不要写死;(我挺喜欢在verilog里这样干,parameter好用哦);
14.动态与静态:动态变量在使用的时候视为进栈,使用结束则出栈,而静态变量在编译完成就已经存在了(data statement字段);
15.uvm不推荐在class里声明静态变量,但是要灵活。
例如:有时想要在check一个开关,这个开关可以在类里声明为静态变量;常规方法需要打包成config tb,但是项目太紧,就做成静态变量再通过作用域解析运算符吧;
16.如果task被定义成static,则多次调用可能会共享相同的参数,并且后面调用的数值将会覆盖前面的值,因此最好都声明为automatic;
17.基于16,并发线程中也需要使用静态变量来存储数值;
18.基于16,解决静态句柄被覆盖的方法:
*动态变量定义在循环内为佳,定义在循环外则难以揣测;
Trans tr_queue[$]; // 动态队列保存所有对象句柄
repeat (10) fork
automatic int i = $urandom;
automatic Trans local_tr = new(); // 创建独立对象
tr_queue.push_back(local_tr); // 保存句柄
// 操作 local_tr...
join_none
// 后续可通过 tr_queue 访问所有对象
task automatic create_and_operate();
automatic Trans tr = new();
// 操作 tr...
endtask
repeat (10) fork
create_and_operate(); // 每个任务有独立的 tr
join_none
19.在task和function端口列表定义数据类型比较方便;
20.关联数组可能在验证中被应用于ddr mem的构造:传递地址,并在地址增加指定的数值,来避免真的生成ddr那么大的空间;

浙公网安备 33010602011771号