验证基础技巧记录(三)

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那么大的空间;

 

posted @ 2025-07-03 09:16  NoNounknow  阅读(22)  评论(0)    收藏  举报