UVM降龙十八掌

第一手:sequence内的方法调用(sequence或item的启动或发送)

下面的parent是指父节点。(以下内容参考uvm源码src/seq/uvm_sequence_base

pre_body/start和post_body/start是只用于sequence方面的任务

在test_case这层启动sequence的2种方法:default_sequence和start。

采用start启动sequence会调用以下方法:(可以在test_case和sequence这两层使用start

//| sub_seq.randomize(...); // optional
//| sub_seq.start(seqr, parent_seq, priority, call_pre_post)


//|   sub_seq.pre_start()        (task)
//|   sub_seq.pre_body()         (task)  if call_pre_post==1
//|     parent_seq.pre_do(0)     (task)  if parent_sequence!=null
//|     parent_seq.mid_do(this)  (func)  if parent_sequence!=null
//|   sub_seq.body               (task)  YOUR STIMULUS CODE
//|     parent_seq.post_do(this) (func)  if parent_sequence!=null
//|   sub_seq.post_body()        (task)  if call_pre_post==1
//|   sub_seq.post_start()       (task)

 采用`uvm_do系列宏启动sequence会调用以下方法:(但是不会执行pre/post_body任务;只能用于sequence内部,不能用于test_case那一层;

//| `uvm_do_with_prior(seq_seq, { constraints }, priority)


//|   sub_seq.pre_start()         (task)
//|   parent_seq.pre_do(0)        (task)
//|   parent_req.mid_do(sub_seq)  (func)
//|     sub_seq.body()            (task)
//|   parent_seq.post_do(sub_seq) (func)
//|   sub_seq.post_start()        (task)

 采用`uvm_do系列宏发送item会调用以下方法:

//| `uvm_do_with_prior(item, constraints, priority)
以上等价于下面这种形式:

//| parent_seq.start_item(item, priority);
//| item.randomize(...) [with {constraints}];
//| parent_seq.finish_item(item);


//|   sequencer.wait_for_grant(prior) (task) \ start_item  \
//|   parent_seq.pre_do(1)            (task) /              \
//|                                                      `uvm_do* macros
//|   parent_seq.mid_do(item)         (func) \              /
//|   sequencer.send_request(item)    (func)  \finish_item /
//|   sequencer.wait_for_item_done()  (task)  /
//|   parent_seq.post_do(item)        (func) /

上面send_request(item)和wait_for_item_done()是sequence与seqr、driver之间的握手机制。


// Attempting to execute a sequence via <start_item>/<finish_item>
// will produce a run-time error.

也就是说不能用 <start_item>/<finish_item>来启动一个sequence

 default_sequence:启动sequence也是通过调用start任务来启动sequence的;白皮书P165

 

第二手:clone

a_class    A1 ;
a_class    A2 ;

assert(  A1.randomize() with{ xx == 1; zz == 0; } );// 对所有变量随机
void'($cast(A2,A1.clone()));
assert(  A2.randomize(a1,a2,a3) with{ } );// 只对a1/a2/a3随机,其他变量保持A1的随机结果

//在UVM中要注意,涉及到约束的成员都应该被注册到工厂,否则clone时不会复制上一个的随机结果,然后如果它又不在a1/a2/a3里面的话,它的结果就会是0,这样很可能会与constraint相冲突,导致随机失败;

第三式:活用PHASE

1、应该在reset_phase阶段,去等待rst_n的上升沿(完成复位)(rst_n下降沿:开始复位;rst_n上升沿:复位完成;)(这样才能允许进入下一个configure_phase)

2、对寄存器和表项的配置的seq一般指定在configure_phase执行;

3、对发送激励的seq一般指定在main_phase阶段执行;

4、某一个类的句柄在class中声明后,虽然没有去get,但是它在build phase阶段已经接收到了指针,那么它可以在run phase阶段被其他组件调用,而不会报错空指针错误,因为run phase在build phase 之后执行的;(全局接口 在xxx_tr里面声明了,在refm_mode(或env)的build phase中赋值了,而xxx_tr又set到cfg_seq,cfg_seq就可以在build phase后的任意一个phase阶段正常去访问xxx_tr.v_glb_intf.xx_signal)


1、设置后门路径:两部分构成:top_tb.dut.u_reg_xx + reg_model里面的add_hdl_path_slice;后门实际是通过force强制去修改值; 

应该是有两种方式:一种是在env这层设置(如上图) ;另一种是在uvm_reg_block这层通过add_hdl_path(“TOP_TB.DUT”);(DUT实际上是你在top_tb里面例化RTL的名字,不一定是这里的这个名字)来设置,参考红皮书P419


调试:(加到run选项# run options)

(RUN_OPTS += +UVM_CONFIG_DB_TRACE +UVM_PHASE_TRACE #)

+UVM_DUMP_CMDLINE_ARGS:导出所有命令行参数,确认当前的命令行参数符合预期;

+UVM_CONFIG_DB_TRACE:打开访问config_db的追踪功能,可以看到config_db的set和get操作是在什么时间由什么组件发起的;(在log里面搜索:CFGDB/GET)

+UVM_PHASE_TRACE:可以看到不同phase的执行顺序;(在log里面搜索:PH/TRC/STRT,PH/TRC/DONE)

+UVM_OBJECTION_TRACE:打开objection相关活动的追踪功能,可以看到objection的运行状态;(在log里面搜索:OBJTN_TRC)

+RUN_OPTS += +UVM_VERBOSITY=UVM_HIGH:设置打印信息的冗余程度,有效控制不必要的层次信息;

UVM内置的打印函数:

uvm_root::print_topology():打印整个验证环境的组件拓扑结构;

uvm_component::print_config():打印当前组件可见视角下的所有配置资源信息;


后门访问:本质上就是通过层次化路径点到具体的reg或mem去赋值;

前门访问:本质上是模拟实际物理场景的总线接口访问;

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值