引入sequence的原因:
- 将 生成测试case的语句 从 main_phase 中独立出来,使得使用不同测试用例时,只需要修改sequence部分即可,而不用关注 UVM剩余部分。(提高剩余部分的可复用性)。
引入sequence的仲裁机制的原因:
- 一个sequencer上通过fork...join可以启动多个sequence,而多个sequence按照什么顺序启动需要一定的仲裁机制来控制,具体而言主要从两个角度控制
- sequence角度:自身的优先级、原子性、有效性
- sequencer角度:对多个sequence的仲裁算法
引入sequence相关宏的原因:
- 更方便地控制transaction的产生过程,主要有:
- uvm_do系列宏:实例化transaction+将transaction交给sequencer(对应start_item与finish_item任务)
- uvm_create宏:实例化transaction,可用new代替
- uvm_send宏:将transaction交给sequencer(对应start_item与finish_item任务)
- uvm_rand_send系列宏:对transaction进行随机化+将transaction交给sequencer(对应start_item与finish_item任务)
不同类型sequence共用sequencer的方法(一个driver):
- transaction类型例化的一个sequencer 对应 多个不同约束的transaction包
- 可以通过一个sequence启动其他sequence(即嵌套的sequence),然后间接生成多个不同约束的transaction包 —— 注意:这里使用了cseq. start ( m_sequencer );这样的语句
- 也可以通过一个sequence直接生成多个不同约束的transaction包
- 通过类型转换,实现同一个sequencer处理不同两个截然不同的transaction,步骤如下
- 将sequencer和driver能够接受的数据类型设置为uvm_sequence_item
- driver中使用时,使用cast将uvm_sequence_item转换为各自transaction的类型
补充:start任务参数说明 seq0.start(env.i_agt.sqr, null, 100);
- 第一个参数:sequencer的位置,指明seq0由哪个sequencer启动
- 第二个参数:parent sequence
- 第三个参数:seq0的优先级
补充:m_sequencer是一个属于每个sequence的成员变量,它指向执行当前sequence的sequencer句柄,其类型是uvm_sequencer_base。
sequencer向sequence传递变量(约束)的方法:
- 方法一:通过cast转换将sequence内置变量m_sequencer(类型为uvm_sequencer_base)转换成my_sequencer类型, 然后引用uvm_sequencer中的成员变量作为约束
- 方法二:在sequence中使用`uvm_declare_p_sequencer(my_sequencer),然后通过宏默认生成的变量p_sequencer来引用uvm_sequencer中的成员变量作为约束
补充:uvm_declare_p_sequence的实质是在base_sequence中声明了一个成员变量p_sequencer,并将其指向启动本sequence的sequencer。
发往不同driver的sequence之间的同步的方法:
- 方法一:通过全局事件进行简单同步:在drv0_seq中触发事件,在drv1_seq中等待这个全局事件。
- 方法二:使用 virtual sequence+virtual sequencer,可以实现类似crossbar的连接,且因为virtual sequence的body是顺序执行,所以可以轻松实现整体顺序(同步),局部并行的效果。
补充:verilog中事件的基本使用
- event变量声明为:
- event触发为:
- ->var;
- 捕获触发为:
- @(var);
sequence library的概念:
- 派生自uvm_sequence,就是一系列sequence的集合,它会根据特定的算法随机选择注册在其中的一些sequence, 并在body中执行这些sequence。