[UVM源代码研究] 关于default_sequence和p_sequencer的一点思考

[UVM源代码研究] 关于default_sequence和p_sequencer的一点思考

1. 引言

今天在用virtual_sequence和virtual_sequencer的时候碰到了一个以前没太留意的问题,就是说在virtual_sequence的构造函数new()中能否引用p_sequencer中的内容,换句话说,在virtual_sequence的new()函数中p_sequencer有没有完成创建。

如图1所示,这样调用是否会报错。

图1 virtual_sequence的new()函数中引用p_sequencer句柄

在这里插入图片描述

答案是会报错,如图2所示

图2 图1代码log结果

在这里插入图片描述

意思就是说p_sequencer还没有被创建就引用了。

这里就涉及到一个问题,p_sequencer所指向的virtual_sequencer什么时候才被创建了?

我们实际项目中一般的做法都是在test_base或者env的build_phase创建virtual_sequencer,如下图3所示

图3 virtual_sequencer的创建

在这里插入图片描述

然后virtual_sequence在testcase的build_phase被设为virtual_sequencer的main_phase上的default_sequence,如图4所示

图4 virtual_sequence被set为default_sequence

在这里插入图片描述

那么问题就转化为了两个时间点执行的先后顺序问题,这两个时间点分别是:

  1. 我们执行的virtual_sequence的构造函数是在什么时间点(t1)执行的呢?
  2. uvm_declare_psequencer()所赋值的p_sequencer又是在什么时间点(t2)指向了我们实际的virtual_sequencer实例的呢?

结论我们不难得出,之所以出现图2的错误,一定是t1在t2之前执行了,导致p_sequencer还是没有指向任何实例的空句柄。

下面我们从UVM源代码执行顺序的角度来看看t1和t2分别是什么时候被执行的。

2. 源代码分析

首先我们来看宏 `uvm_declare_p_sequencer 都干了啥。

查找宏 `uvm_declare_p_sequencer 的定义如图5所示:

图5 src/macros/uvm_sequence_defines.svh中的代码

在这里插入图片描述

`uvm_declare_p_sequencer可以认为就是定义一个SEQUENCER类型的变量p_sequencer,并且定义一个函数m_set_p_sequencer()(这个函数在uvm_sequence类中肯定以经存在了,否则还需要用户再手动调用,而我们从来没有自己调用过,所以UVM源代码中原本应该已经实现了该函数的调用了,这里要做的就是override覆盖原有函数定义),该函数将m_sequencer $cast给了p_sequencer,由此我们关注的点变成了m_set_p_sequencer()这个函数在什么时候被调用的。

源代码目录查找m_set_p_sequencer()信息,如图6所示,m_set_p_sequencer()在set_sequencer()中被调用,

图6 src/seq/uvm_sequence_item.svh中的代码截图

在这里插入图片描述

同一个文件继续搜索如图7所示显示set_sequencer()在set_item_context()中被调用

图7 src/seq/uvm_sequence_item.svh中的代码截图

在这里插入图片描述

源代码目录搜索set_item_context()如图8所示,set_item_context()在start()中被调用。

图8 src/seq/uvm_sequence_base.svh中的代码截图

在这里插入图片描述

即sequence启动的时候才会调用m_set_p_sequencer()函数,完成p_sequencer的赋值。

而virtual_sequence中的构造函数呢?

答案不言而喻,肯定是在创建virtual_sequence的时候被调用的,那结论是不是很显而易见了,肯定是先创建sequence才会启动sequence,所以t1肯定在t2前面执行,所以肯定不能在virtual_sequence的构造函数里引用p_sequencer。

下面我们再做一些额外的探索,就是上面提到的virtual_sequence在testcase的build_phase被设为virtual_sequencer的main_phase上的default_sequence,那么这个default_sequence在UVM源代码中又是在when & where被创建执行的呢?

源代码目录搜索一下"default_sequence",在src/seq/uvm_sequencer_base.svh文件中找到如图9所示的内容(继承关系为uvm_sequencer extends uvm_sequencer_param_base extends uvm_sequencer_base)

图9 src/seq/uvm_sequencer_base.svh中的代码截图

在这里插入图片描述

但是这里使用的是get_config_string来获取的,而我们在set的时候传递的是uvm_object_wrapper类型,所以这里由于类型不一致并不会get到我们set的内容。

继续往下查看,如图10所示。

图10 src/seq/uvm_sequencer_base.svh中的代码截图

在这里插入图片描述

可以看到1373行get的类型跟我们get的类型是一致的,并且会在1376行创建我们传递过来的virtual_sequence类型的实例,这便是我们virtual_sequence中的构造函数new调用的地方,至于这里的1367行声明的uvm_factory类型的变量f以及1376行通过调用f.create_object_by_type()创建virtual_sequence这部分内容之前在讲factory的时候有提到过,这里就不细讲了,可以简单认为是virtual_sequence中通过`uvm_object_utils宏将virtual_sequence类注册到factory中,这样uvm_factory就可以通过查找类型wrapper来创建对应的变量。(这个wrapper的类型是通过testcase的build_phase中set过来的virtual_sequence::type_id::get()获取的,也就是说set的是一个uvm_object_wrapper类型,而不是一个实例,uvm_object_wrapper作为一个UVM源代码中定义的基类可以接受任何类型)

1394行主动调用set_sequencer()将virtual_sequencer设置为virtual_sequence启动的sequencer(因为virtual_sequence被set到了virtual_sequencer的main_phase,所以这里的this指的就是virtual_sequencer)。根据图6的分析,其实这一步就已经实现了p_sequencer的赋值的。

1408行启动virtual_sequence。

这个start_phase_sequence是在如图11所示代码中被调用的。由之前我们在 数字验证大头兵:[UVM源代码研究] 浅谈UVM PHASE机制的运行 中所讲的内容可知,在每一个task_phase都会调用该函数,这样其实我们在build_phase除了把这个virtual_sequence设置到virtual_seuquencer的main_phase之外,另外11中runtime_phase和run_phase都是可以的,就看你想让这个virtual_sequence什么时间点被执行起来。

图11 src/base/uvm_task_phase.svh中的代码截图

在这里插入图片描述

这里再做一点引申,由图10的1370行可以看出,除了使用与1373行代码对应的

uvm_config_db#(uvm_object_wrapper)::set(this, "env.v_sqr.main_phase", "default_sequence", virtual_sequence::type_id::get());

的方法set default_sequence,还可以用与1370行对应的代码的另一种方法(直接set virtual_sequence的实例):

virtual_sequence myseq = new("myseq");
uvm_config_db #(uvm_sequence_base)::set(null, "env.v_sqr.main_phase", "default_sequence", myseq);

3. 总结

本文通过工作过程中使用virtual_sequence和virtual_sequencer时遇到的一个bug,引申出了UVM源代码中`uvm_declare_psequencer()宏和default_sequence相关代码的实现机制,对virtual_sequence®的使用相信会有更深刻的认识。

回到我们文章一开始遇到的那个bug问题,如果我们想在virtual_sequence的主体代码body()之前做一些预处理工作(这也是为什么会在new()函数里引用p_sequencer的原因),可以把这部分工作放在pre_body()里完成。

  • 44
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值