UVM入门进阶8:Sequencer仲裁_Sequence层次化

参考文档链接:https://verificationacademy.com/verification-methodology-reference/uvm/docs_1.2/html/

本节内容为上一节《UVM入门进阶7:Item_Sequence_Sequencer_Driver》的后半部节选,因为UVM7内容过多因此创建本小节。本节主要学习Sequencer和Sequence的关系

4 Sequencer和Sequence:初步

4.1 概述

4.1.1 主要学习内容

主要讲几种常见的仲裁方式,一般可能用不太到

4.1.2 sequence宏概述:区分两种挂载seq到sqr方式

  • start()
    • 在test对top_seq挂载(参考第三章),在top_sep对child_sep和item挂载,在child_sep对item挂载
  • `uvm_do
    • 一种宏:参考第五章

4.2 sequence和item发送示例

bus_trans

child_seq

top_seq

包含child_seq与item

sqr

driver

driver里面get的全是最小颗粒度item,seq在sqr处被拆解

env

test与输出结果

4.3 示例总结:两种挂载方式

两种挂载方式,分别把seq和item挂载到sqr上

4.3.1 把seq挂载到sqr上:这种挂载发生在top_seq上

top_seq中的uvm_sequence::start()

  • start内部参数解释
    • uvm_sequencer_base sequencer:
      • 挂载到的sqr实例句柄
    • uvm_sequence_base parent_sequence:
      • 上层对象句柄,示例中top_seq调用该方法时代入”this”代表child_seq的上层对象为自己
      • 这样做的好处是保持子对象优先级一致,进而对仲裁有帮助仲裁表现一致
    • int this_priority:
      • 优先级,默认值-1,此时实际优先级为100
    • call_pre_post:
      • 建议使用默认值
        • 补充:body的pre和post回调函数不建议实现

4.3.2 把item挂载到sqr上

第二个参数不需要特别关心,往往知道挂载哪个item就够了

4.3.3 item创建发送过程

pre_do(),mid_do(),post_do():不建议实现,会变复杂


4.3.4 seq/item的start()挂载内部逻辑

sequence挂载到sequencer

为什么可以不关心:有时候call_pre_post=1时这些post和pre都不会执行

item挂载到sequencer

start_item立即返回,因为只有一个sqr进行仲裁可以立刻返回结果

5 Sequencer和Sequence:更简单的创建挂载传输方式:宏

图中宏省略了`

图中宏省略了`

这些宏封装了好多方法函数,x表示包括,空表示不包括

Item:

  • 宏解释:

    • `uvm_do:是一个完整的过程,但直接randomiztion
    • `uvm_do_with:做一个带constraints的randomiztion
    • `uvm_create:就是一个创建
    • `uvm_send():就是发送
  • 执行顺序解释:

    • body为空,因为item没有

Sequence:

  • 宏解释:

    • `uvm_do:是一个完整的过程
      +
    • `uvm_do_with:做一个constraints的randomiztion
    • `uvm_create:就是一个创建
    • `uvm_send():就是发送
  • 执行顺序解释:

    • 没有做sync和post-sync
      • 因为sync和post-sync需要在body里面拿到优先级,`uvm_do本身不会拿到优先级,只有在seq_body里面,只有在发送item时候才会拿到(即每次发送一个item的时候都会申请一次优先级)

宏的调用位置

  • 这些宏调用的都是 sequence方法,因此只有sequence才可以调用这些宏

宏带来的怠惰

5.2 其他的宏

  • 将优先级作为参数传递的`uvm_do_pri/`uvm_do_on_prio等宏
    • 并行发送多个seq时,伴随优先级发送
    • 形参优先级,默认为100
    • `uvm_do_on:这个on是什么意思,表示把这个特定的seq挂载到某一个sqr上面
      • 对于item来说,使用`uvm_do则会被同样挂载到seq挂载到的sqr上
      • `uvm_do_on则可以进行指定
  • 专门针对seq的`uvm_create_seq/`uvm_do_seq/`uvm_do_seq_with等宏

5.3 序列宏的示例

child_seq

怎样利用宏发送的:

  • `uvm_create(req):创建item
  • `uvm_rand_send_with:添加constraint

上述宏可以合并为:

  • `uvm_do_with

top_seq

  • `uvm_do:这里发送了child_seq
  • `uvm_do_with:这里发送了item

5.4 序列宏的建议

(1)不管seq在哪个层次,都应在test结束前执行完毕

(2)可以用fork_join完成seq发送。而不建议用fork_join_any和fork_join_none,可能会导致seq没结束就立即退出,使得后台仍然有一些seq像挂载到sqr上面;进一步如果你针对fork调用disable可能会所锁sqr,因为你来不及释放seq线程权限。

  • 补充:你在代码中使用fork_join_any和fork_join_none一定要使用同步,如此处假如你使用了fork_join_any和fork_join_none你应该完成即便fork退出seq运行在后台时,仍然能与后台运行的seq进行同步,使得所有seq结束以后才进行后续的操作

(3)fork_join其中一个seq线程无法结束时,考虑在合适时间点使用disbale

5 Sequencer和Sequence:仲裁特性

5.1 Sequencer和Sequence的仲裁特性

5.1.1 仲裁特性介绍

仲裁场景结构图:

仲裁场景结构图


(1)sqr已经内建了仲裁机制,只需要在top_seq设置仲裁的模式就足够

(2)

如何设置:uvm_sequencer::set_arbitration(UVM_SEQ_ARB_TYPE val)

模式介绍:

  • UVM_SEQ_ARB_FIFO:默认模式,竞争优先
  • UVM_SEQ_ARB_WEIGHTED:优先级模式
  • UVM_SEQ_ARB_RANDOM:随机模式
  • UVM_SEQ_ARB_STRICT_FIFO:按照优先和抵达顺序授权
  • UVM_SEQ_ARB_STRICT_RANDOM:最高优先级并随机授权
  • UVM_SEQ_ARB_USER:自定义仲裁,很少用

5.1.2 Sequencer的仲裁示例

item和child_seq

top_seq和sqr

top_seq:

  • body:
    • 设置优先级模式
    • fork_join进行调度:
      • 三个同一时间申请的,seq1和seq2优先级更高
      • base是constraint
      • 此时赋予了优先级之后child_seq中的`uvm_do_with就可以进行挂在了,因为它们等待的就是这个顶层的优先级,使用wait_for_guant等待授权

driver

没有太多新意

env

test和输出结果

test:

  • 为什么test里面不用宏:因为用不了只能在seq里面用

为什么是seq1seq2seq1seq2seq3seq3,而且还是0时刻?:

  • 发送item没有耗时

示例分析

5.2 Sequencer的锁定机制介绍

(1)锁定机制

什么是锁定机制:seq拿到权限后进行锁定,

什么是锁定:seq拿到一个item后锁定下来,后续item都可以拿到

(2)两种锁定方式:两个函数都可以

  • lock()与unlock
    • 一定记得unlock
  • grab()与ungrab()
    • 优先级比lock高,下一次授权周期可以无条件获取授权

5.2.2 Sequencer的锁定示例

item、child_seq、lock_seq

child_seq:内部重复发送两次,间隔10ns,参考之前一节的示例

lock_seq:

  • 先等了10ns,试图达到等待授权把sqr锁住

  • m_sequencer.lock(this);

    • 什么时候才能lock住:下一次等待授权的时候,即大家都在等待的时候
  • 重复发送三次

grab_seq

grab_seq:

  • 等了20ns

  • m_sequencer.grab(this);

    • 什么时候才能锁住:只要重新做仲裁就能锁住
  • 重复发送三次

top_seq

seq1,seq2,seq3

lock_seq:优先级为300

grab_seq:没有优先级

输出结果


注释版:

结果解释

10ns:

  • seq1,seq2优先级500先发送sep3优先级300再发送(发送完等待10纳秒,重新排队伍)
  • lock_seq开始要权限

10ns-20ns:

  • seq发送

20ns:

  • seq1,2,3,lock都开始等待(lock因为优先级低所以也要等待)

20ns-40ns:

  • 被lock锁住

40ns:

  • grabs拿到权限(实际上20nsgrab就开始试图拿权限,但被lock控制,只能等到重新仲裁,届时即可直接锁住无需)

40ns-70ns:

  • 被grabs锁住

70ns:

  • seq1,seq2优先级500先发送sep3优先级300再发送

结果补充

seq优先级如果使用默认,不给定,则默认100

即直接:

  • `uvm_do_pri_with(seq)
  • `uvm_do_pri_with(lock)
  • `uvm_do_pri_with(grab)

5.2.3 结论

无论是lock或者grab都是在重新仲裁时才能锁住

6 Sequence的层次化

对于小白我们可能更关心如何让你的sequence层次化,如何理解别人写的层次化的sequence,以及把它们作为更顶层的sequence如何一层一层的调用

6.1 概述:水平复用和垂直复用

  • hierarchical sequence:层次序列,seq都挂载在一个sqr上
  • virtual sequence:seq可挂载在多个sqr上
  • layering sequence

6.2 Hierarchical Sequence层次序列

6.2.1 Hierarchical Sequence介绍

6.2.2 Hierarchical Sequence代码示例

cmd 和 item

clk_rst_seq

reg_test_seq

top_seq

reg_master_sequencer

driver

agent

  • 例化与连接

6.2.3 示例解析

6.2.4 总结

6.3 Virtual Sequence

6.3.1 Virtual Sequence介绍


把所有子系统的sqr都放在virtual_sequencer里面

  • virtual_sequencer包含着很多实例句柄
  • 它就像一个路由一样,找到他就能找到各个子系统的sqr
  • 起到一个统筹的作用
  • virtual sequencer往往与virtual sequence有联系的


virtual sequencer就是个简单的路由器,包含句柄而已,没有任何item经过,也不需要与driver连接

6.3.2 Virtual Sequence示例

vritual sequencer结构图

vritual sequencer结构图

【重要】有关挂载

mcdf_normal_seq(virtual sequence)要挂载到virutal sequencer

其他的seq间接的通过virutal sequencer挂载到不同的sqr上面,挂载的目的地不一样所以用uvm_do_on


virtual sequence

定义了一个sequence:实际上就是我们的virtual sequence

包括了好多seq句柄

sqr与vsqr区别:

  • 用了很多`uvmdoon
  • 有别于Hierarchical Sequence使用的`uvm_do

p_sequencer和m_sequencer的区别:

  • m_sequencer:是父类句柄,类型是uvm_sequencer
  • p_sequencer:是子类句柄,类型是`uvm_declare_p_sequencer(mcdf_virtual_sequencer)
    • 自定义出来的,不是与定义好的,定义语句就来源于`uvm_declare_p_sequencer(mcdf_virtual_sequencer)
    • 定义语句完成了两个步骤:
      • mcdf_virtual_sequencer p_sequencer;
      • $cast(p_sequencer, m_sequencer);//把父类句柄转为子类句柄
    • 为什么一定要子类句柄:
      • 因为父类的访问不到这些子系统sqr句柄
      • 通过这个子类句柄p_sequencer我们可以访问到vsqr里面所有成员变量

子一级的sqr,agent,和virutal sequencer

virutal sequencer 包含各个句柄就完事了

mcdf_env

千万不要忘了再connect里进行句柄传递,避免悬空

test

6.3.3 示例解析

6.3.4 总结

中心化协调

6.3.5 Virutal Sequencer建议

  • vseq与普通seq区分
  • vsqr同底层负责传输对象的sqr区分
  • vseq中使用`uvm_declare_p_sqr来创建p_sequencer变量方便之后索引
  • 顶层环境中创建vsqr并完成内部各个sqr句柄与底层sqr实例连接

6.4 Layering Sequence:层次化

6.4.1 Layering Sequence介绍

  • 普通协议,构建协议总线时通过:sequencer item包含与约束关系

  • 复杂协议,网络传输协议,需要更深层次一层一层解析,通过:若干个抽象层次去做

由高抽象级到低抽象级(传输层>>链路层>>物理层)的构建,我们称为Layering Sequence

接下来学习,一定考虑三个层次:高抽象级的item,低抽象级的item,中间做转化的sequence

Layering Sequence层次结构图:

Layering Sequence层次结构图


寄存器模型下的item传递结构图与layering sequence具体作用内容:

寄存器模型下的item传递结构图

  • 对寄存器的reg.write()和reg.read()指令,通过寄存器模型的Adaption Layer转化层次,进而转化为总线的一个item。即把reg_item转为bug_item
  • 得出layering sequence包括三者:高抽象级的item,低抽象级的item,中间做转化的sequence
  • 高抽象级的item与低抽象级的item没有直接的继承关系所以需要做一个映射
  • 高抽象级不包括具体的数据,只有类似命令、长度、idle等信息

6.4.2 Layering Sequence代码示例

Layering Sequence层次结构图


cmd和bus_trans(item)

比较底层

packet_seq

layer_trans(item)

比较抽象:

  • 没有任何与数据有关的传输内用,只有cmd,len,idle
  • 与底层的bus_trans没有任何继承关系所以要做一个映射

adapter_seq:转化层

  • p_sequencer通过`ucm_declare获得,通过p_sqr拿到up_sqr更上层的layersqr句柄
  • 拿到子类句柄void($cast(trans,req))

  • 转化为一个底层个seq,把高抽象级的长度转化为低抽象级的pkt_seq,`uvm_do挂载到了phy_driver上

  • 做一个握手,告诉高层,我已经把高抽象层的trans消化掉了

top_seq , layering_sqr , phy_sqr

layering_sqr , phy_sqr定义不讲了

phy_sqr里面有个句柄up_sqr,需要顶层把相关实例传递进来

top_seq:连续发送了两个layer_trans

phy_driver

phy_agent

包含phy_drv和phy_sqr的例化与连接

test,重点在这里,查看连接关系

  • 例化了layer_sqr与phy_agt
  • sqr句柄的传递,layer_seq/top_seq,adapter_seq,phy_seq的挂载
    • up_sqr句柄的传递
    • adapter_seq的挂载
    • top_seq的挂载
    • phy_seq的挂载实际上不是个挂载而是产生的过程,在adapter_seq用uvm_do出来好多pkg_seq,这些pkg_seq时加上就属于phy到drv的seq
  • 为什么用fork_join_none
    • 用fork_join_none直接挂载上去就可以了
    • 用fork_join不行,这个start会自动帮我们执行body(),adapter.body()是个forever会卡在这里

6.4.3 如何实现sequencer layer协议转换的方法:

(1)layer_trans,bus_trans完全两个不同的抽象级

(2)需要adapter_seq完成从获取layer_trans再去生成phy_trans和seq,再从physqr发送出去

(2)fork_join_none

(4)至于多少个层次取决于

6.4.4 总结

(2)只有高抽象级到低抽象级,低到高需要有回路,通过response_item实现,两者的思想实际上一样

(3)也可以不通过高到低的回路,而是外部通过monitor采集response trans最终实现返回,避开adapter


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!