0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看威廉希尔官方网站 视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

UVM中的虚拟序列:为什么,如何?

星星科技指导员 来源:synopsys 作者:Hari Balisetty,Broa 2023-05-29 09:46 次阅读

大多数UVM测试平台由可重复使用的验证组件组成,除非我们正在对像MIPI-CSI这样的简单协议进行块级验证。考虑验证简单协议的场景;在这种情况下,我们可以忍受只有一个音序器将刺激发送给驱动器。顶级测试将使用此序列器来处理序列(如上一篇博客文章中所述)。在这里,我们可能不需要虚拟序列(或虚拟序列器)。

但是,当我们尝试将此IP集成到我们的SOC(或顶级块)中时,我们肯定要考虑重用用于验证这些块的测试平台组件。让我们考虑一个简单的案例,其中我们正在集成两个这样的块:两个音序器驱动这两个块。从顶级测试来看,我们需要一种方法来控制这两个音序器。

这可以通过使用虚拟序列器和虚拟序列来实现。另一种方法是通过将序列器传递给启动方法,从顶级测试显式调用序列的启动方法。

我将通过一个例子来解释这种用法,其中 USB 主机集成在 AXI 环境中。让我们看看如何从顶级测试中控制USB音序器和AXI音序器。对于此特定测试,我想配置 AXI 寄存器,然后发送 USB 传输。对于配置 AXI 寄存器,我使用序列说axi_cfg_reg_sequence,对于发送 USB 传输,我使用我在上一篇博客文章中使用的序列 (usb_complex_sequence)。下面是一个示例,其中在不使用虚拟序列的情况下控制多个序列器。

//Top-level test where multiple sequencers are controlled from the
//phase method.
class axi_cfg_usb_bulk_test extends uvm_test;
  `uvm_component_utils(usb_ltssm_bulk_test)

  //Sequences which needs to be exercised
  usb_reset_sequence u_reset_seq;
  axi_reset_sequence a_reset_seq;
  usb_complex_sequence u_bulk_seq;
  axi_cfg_reg_sequence a_cfg_reg_seq;

  function new (strint name=”axi_cfg_usb_bulk_test”,
                uvm_component parent=null);
    …
  endfunction: new

  //Call the reset sequences in the reset_phase
  virtual task reset_phase (uvm_phase phase);
    phase.raise_objections(this);
    …
    //Executing sequences by calling the start method directly by passing the
    //corresponding sequencer
    a_reset_seq.start(env.axi_master_agent_obj.sequencer);
    u_reset_seq.start(env.usb_host_agent_obj.sequencer);
    …
    phase.drop_objections(this);
  endtask:reset_phase

  virtual task main_phase (uvm_phase phase);
    phase.raise_objections(this);
    …
    //Executing sequences by calling the start method directly by passing the
    //corresponding sequencer
    a_cfg_reg_seq.start(env.axi_master_agent_obj.sequencer);
    u_bulk_seq.start(env.usb_host_agent_obj.sequencer);
    …
    phase.drop_objections(this);
  endtask:main_phase
endclass: axi_cfg_usb_bulk_test

这不是控制序列器的最有效方法,因为我们直接在测试中使用简单的序列并使其变得复杂。通过这样做,我们无法进一步重用这些复杂的场景来开发更复杂的场景。相反,如果我们尝试创建一个序列并在测试中使用该序列,那么我们也可以在其他测试(或序列)中重用这些序列。此外,与在顶级测试中创建整个方案相比,维护和调试这些序列将更容易。

在理解了为什么我们需要虚拟序列和虚拟序列器之后,让我们看看如何通过上面显示的相同示例来实现这一点。

我们需要做的第一件事是创建一个虚拟序列器。请注意,虚拟序列只能与虚拟序列器关联(但不能与非虚拟序列器关联)。虚拟排序器也像任何其他非虚拟排序器一样派生自uvm_sequencer,但不附加到任何驱动程序。虚拟音序器引用了我们尝试控制的音序器。这些引用从顶部环境分配给非虚拟序列器。

//Virtual sequencer having references to non-virtual sequencers
Class system_virtual_sequencer extends uvm_sequencer;
  //References to non-virtual sequencer
  usb_sequencer usb_seqr;
  axi_sequencer axi_seqr;

  function new (string name=”usb_ltssm_bulk_test”,
                uvm_component parent=null);
    …
  endfunction: new

  `uvm_component_utils(system_virtual_sequencer)

endclass: system_virtual_sequencer

//Top level environment, where virtual sequencer’s references
//are connected to non-virtual sequencers
class system_env extends uvm_env;
  //Agents where the non-virtual sequencers are present
  usb_host_agent usb_host_agent_obj;
  axi_master_agent axi_master_agent_obj;
  //Virtual sequencer
  system_virtual_sequencer sys_vir_seqr;

  `uvm_component_utils(system_env)

  function new (string name=”system_env”, uvm_component parent=null);
   …
  endfunction: new

  function void connect_phase(uvm_phase phase);
    //Assigning the virtual sequencer’s references to non-virtual sequencers
    sys_vir_seqr.usb_seqr = usb_host_agent_obj.sequencer;
    sys_vir_seqr.axi_seqr = axi_master_agent_obj.sequencer;
  endfunction: connect_phase

endclass: system_virtual_sequencer

现在我们有虚拟序列器,其中包含对非虚拟序列器的引用,我们想要控制这些序列,让我们看看如何使用虚拟序列控制这些非虚拟序列器。

虚拟序列与任何其他序列相同,但与非虚拟序列不同,它与虚拟序列器相关联,因此它需要指示它必须使用哪个非虚拟序列来执行基础序列。另请注意,虚拟序列只能执行序列或其他虚拟序列,而不能执行项目。使用“uvm_do_on/”uvm_do_on_with执行非虚拟序列,使用“uvm_do/”uvm_do_with执行其他虚拟序列。

//virtual sequence for reset operation
class axi_usb_reset_virtual_sequence extends uvm_sequence;

  `uvm_object_utils(axi_usb_reset_virtual_sequence)

  //non-virtual reset sequences
  usb_reset_sequence u_reset_seq;
  axi_reset_sequence a_reset_seq;

  function new (string name=” axi_usb_reset_virtual_sequence”,
                uvm_component parent=null);
    …
  endfunction: new

  …

  task body();
    …
    //executingnon-virtual sequence on the corresponding
    //non-virtual sequencer using `uvm_do_on
    `uvm_do_on(a_reset_seq, p_sequencer.axi_seqr)
    a_reset_seq.get_response();
    `uvm_do_on(u_reset_seq, p_sequencer.usb_seqr)
    u_reset_seq.get_response();
  endtask: body

endclass: axi_usb_reset_virtual_sequence

//virtual sequence for doing axi register configuration
//followed by USB transfer
class axi_cfg_usb_bulk_virtual_sequence extends uvm_sequence;

  `uvm_object_utils(axi_cfg_usb_bulk_virtual_sequence)
  `uvm_declare_p_sequencer(system_virtual_sequencer)

  //Re-using the non-virtual sequences
  usb_complex_sequence u_bulk_seq;
  axi_cfg_reg_sequence a_cfg_reg_seq;

  function new (string name=” axi_cfg_usb_bulk_virtual_sequence”,
                uvm_component parent=null);
    …
  endfunction: new

  task body();
    …
    //executingnon-virtual sequence on the corresponding
    //non-virtual sequencer using `uvm_do_on
    `uvm_do_on(a_cfg_reg_seq, p_sequencer.axi_seqr)
    a_cfg_req_seq.get_response();
    `uvm_do_on(u_bulk_seq, p_sequencer.usb_seqr)
    u_bulk_seq.get_response();
  endtask: body

endclass: axi_cfg_usb_bulk_virtual_sequence

在上面的虚拟序列中,我们执行axi_cfg_reg_sequence然后执行usb_complex_sequence。现在虚拟序列和虚拟序列器已经准备就绪,让我们看看如何从顶级测试中执行此虚拟序列。

//virtual sequence for reset operation
class axi_usb_reset_virtual_sequence extends uvm_sequence;

  `uvm_object_utils(axi_usb_reset_virtual_sequence)

  //non-virtual reset sequences
  usb_reset_sequence u_reset_seq;
  axi_reset_sequence a_reset_seq;

  function new (string name=” axi_usb_reset_virtual_sequence”,
                uvm_component parent=null);
    …
  endfunction: new

  …

  task body();
    …
    //executingnon-virtual sequence on the corresponding
    //non-virtual sequencer using `uvm_do_on
    `uvm_do_on(a_reset_seq, p_sequencer.axi_seqr)
    a_reset_seq.get_response();
    `uvm_do_on(u_reset_seq, p_sequencer.usb_seqr)
    u_reset_seq.get_response();
  endtask: body

endclass: axi_usb_reset_virtual_sequence

//virtual sequence for doing axi register configuration
//followed by USB transfer
class axi_cfg_usb_bulk_virtual_sequence extends uvm_sequence;

  `uvm_object_utils(axi_cfg_usb_bulk_virtual_sequence)
  `uvm_declare_p_sequencer(system_virtual_sequencer)

  //Re-using the non-virtual sequences
  usb_complex_sequence u_bulk_seq;
  axi_cfg_reg_sequence a_cfg_reg_seq;

  function new (string name=” axi_cfg_usb_bulk_virtual_sequence”,
                uvm_component parent=null);
    …
  endfunction: new

  task body();
    …
    //executingnon-virtual sequence on the corresponding
    //non-virtual sequencer using `uvm_do_on
    `uvm_do_on(a_cfg_reg_seq, p_sequencer.axi_seqr)
    a_cfg_req_seq.get_response();
    `uvm_do_on(u_bulk_seq, p_sequencer.usb_seqr)
    u_bulk_seq.get_response();
  endtask: body

endclass: axi_cfg_usb_bulk_virtual_sequence

到目前为止,我们了解为什么以及如何使用虚拟序列。在使用虚拟序列和虚拟序列器时,我们还应该记住一些事情,以节省大量的调试时间。

1. 在配置序列中的变量(使用虚拟序列执行)时,我们必须使用通过虚拟序列的路径。在上面的示例中,使用非虚拟序列器路径在较低级别的序列中设置变量将不起作用。

uvm_config_db#(int unsigned)::set(this,“env.usb_host_agent_obj.sequencer.u_bulk_sequence”,“sequence_length”,10);

即使u_bulk_sequence在 usb_host_agent_obj.sequencer 上运行,这也不起作用,因为此序列是由虚拟序列创建的,因此分层路径应来自虚拟序列,但不使用非虚拟序列器。因此,设置变量的正确方法是使用虚拟序列路径。

uvm_config_db#(int unsigned)::set(this,“env.sys_vir_seqr.axi_cfg_usb_bulk_virtual_sequence.u_bulk_sequence”,“sequence_length”,10);

对于工厂覆盖也是如此。例如,由于上述原因相同,下面的工厂覆盖将不起作用。

set_inst_override_by_type(“env.usb_host_agent_obj.*”,usb_transfer_item::get_type(), cust_usb_transfer_item::get_type());

在上面的示例中,我们尝试使用顶级测试中的新派生类型更改基础序列项。为此,我们需要使用虚拟序列器路径。

set_inst_override_by_type(“env.sys_vir_seqr.*”,usb_transfer_item::get_type(), cust_usb_transfer_item::get_type());

经验法则是:
• 如果序列是由虚拟序列直接或间接创建的,则工厂覆盖或配置中的任何分层路径都应使用虚拟序列器的分层路径。
• 如果序列是由非虚拟序列创建的,则工厂覆盖或配置中的任何分层路径都应使用非虚拟序列器的分层路径。

2. 即使我们有虚拟序列器来控制多个序列器,在某些测试中,我们可能只需要一个序列器(例如单独的 USB 序列器)。在这种情况下,我们必须直接使用非虚拟序列器的分层路径(而不是虚拟序列器的引用路径)来配置变量或工厂覆盖。使用虚拟序列器的引用路径将不起作用,因为非虚拟序列器的层次结构不正确。

uvm_config_db#(uvm_object_wrapper)::set(this, “env.sys_vir_seqr.usb_seqr.main_phase”, “default_sequence”, usb_complex_sequence::type_id::get());

上述配置将不起作用,因为非虚拟序列器 (usb_seqr/usb_host_agent_obj.sequencer) 实际上是在代理中创建的,因此此排序器的父级是代理,而不是虚拟序列器,尽管引用在虚拟序列器中。因此,在尝试在实际序列器中设置变量时,我们不应使用虚拟序列器路径,而是必须使用通过代理的分层路径(序列器的实际父级)。

uvm_config_db#(uvm_object_wrapper)::set(this, “env.usb_host_agent_obj.sequencer.main_phase”, “default_sequence”, usb_complex_sequence::type_id::get());

3. 每当我们使用虚拟音序器并希望从虚拟音序器控制非虚拟音序器时,请确保将所有实际音序器中的default_sequence设置为 null。

uvm_config_db#(uvm_object_wrapper)::set(this, “env.usb_host_agent_obj.sequencer.main_phase”, “default_sequence”, null);
uvm_config_db#(uvm_object_wrapper)::set(this, “env.axi_master_agent_obj.sequencer.main_phase”, “default_sequence”, null);

这很重要,因为如果有任何default_sequence集,那么我们的非虚拟序列器将同时运行虚拟序列中的default_sequence和序列。要仅从虚拟序列器控制非虚拟序列器,我们需要将非虚拟序列器的default_sequence设置为 null。

我希望您发现这篇文章有助于理解虚拟序列并通过概述的指南节省调试时间。我相信在使用虚拟序列时会还有其他准则,我们学习调试复杂环境的更难的方法;请与我分享任何此类准则。

审核编辑:郭婷

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • UVM
    UVM
    +关注

    关注

    0

    文章

    182

    浏览量

    19167
  • MIPI
    +关注

    关注

    11

    文章

    310

    浏览量

    48614
  • 音序器
    +关注

    关注

    0

    文章

    30

    浏览量

    3817
收藏 人收藏

    评论

    相关推荐

    UVM序列的创建和运行及中断服务程序实现方案

    SystemVerilog通用验证方法(UVM)是一种生成测试和检查结果以进行功能验证的有效方法,最适合用于块级IC或FPGA或其他“小型”系统。在UVM测试台中,大多数活动是通过编写序列来生
    的头像 发表于 04-09 16:09 4274次阅读
    <b class='flag-5'>UVM</b><b class='flag-5'>序列</b>的创建和运行及中断服务程序实现方案

    数字IC验证之“什么是UVM”“UVM的特点”“UVM提供哪些资源”(2)连载...

    原文链接:https://zhuanlan.zhihu.com/p/345775995大家好,我是一哥,上章内容主要讲述两个内容,芯片验证以及验证计划。那本章我们主要讲述的内容有介绍什么是uvm
    发表于 01-21 16:00

    什么是uvmuvm的特点有哪些呢

    直观的印象,就是uvm验证平台,它是分层的结构。图中的每一个巨型框都代表着平台的一个构成元素。这些元素呢,我们称为平台组建,下面来简单的分析一下。从最底层上来看,agent 包含了driver,monitor和sequencer,其中driver ,monitor
    发表于 02-14 06:46

    请问一下在UVM的UVMsequences是什么意思啊

    UVM方法学,UVMsequences 是寿命有限的对象。UVM sequences从uvm_sequence_item基类扩展得到,uvm
    发表于 04-11 16:43

    如何构建UVM寄存器模型并将寄存器模型集成到验证环境

    ),通常也叫寄存器模型,顾名思义就是对寄存器这个部件的建模。本文要介绍的内容,包括对UVM寄存器模型的概述,如何构建寄存器模型,以及如何将寄存器模型集成到验证环境。篇幅原因,将在下一篇文章再给出寄存器
    发表于 09-23 14:29

    谈谈UVMuvm_info打印

    uvm_report_enabled(xxx),会分析传过来的severity和id的配置verbosity要大于传过来的verbosity,(get_report_verbosity_level(severity, id
    发表于 03-17 16:41

    UVMseq.start()和default_sequence执行顺序

      1. 问题  假如用以下两种方式启动sequence,方法1用sequence的start()方法启动seq1,方法2用UVM的default_sequence机制启动seq2。那么seq1
    发表于 04-04 17:15

    UVM的可重用序列

    众所周知,序列由几个数据项组成,它们共同构成了一个有趣的场景。序列可以是分层的,从而创建更复杂的方案。在最简单的形式序列应该是 uvm_
    的头像 发表于 05-29 09:50 679次阅读

    创建UVM Testcase的步骤

    UVM,Testcase是一个类,它封装了测试用例开发者编写的特定激励序列
    的头像 发表于 06-15 09:41 1601次阅读
    创建<b class='flag-5'>UVM</b> Testcase的步骤

    UVMuvm_config_db机制背后的大功臣

    本次讲一下UVMuvm_config_db,在UVM中提供了一个内部数据库,可以在其中存储给定名称下的值,之后可以由其它TB组件去检索。
    的头像 发表于 06-20 17:28 1418次阅读

    如何用Verdi查看UVM环境的变量?

    我们常用的debug UVM的方法是通过打印log实现。有没有办法像 debug RTL代码一样将 UVM 变量拉到波形上看呢?答案是有的,下面让我们看看是怎么做到的。
    的头像 发表于 06-25 16:01 1738次阅读
    如何用Verdi查看<b class='flag-5'>UVM</b>环境<b class='flag-5'>中</b>的变量?

    UVMuvm_config_db机制背后的大功臣

    本次讲一下UVMuvm_config_db,在UVM中提供了一个内部数据库,可以在其中存储给定名称下的值,之后可以由其它TB组件去检索。
    的头像 发表于 06-29 16:57 1278次阅读

    一文详解UVM设计模式

    本篇是对UVM设计模式 ( 二 ) 参数化类、静态变量/方法/类、单例模式、UVM_ROOT、工厂模式、UVM_FACTORY[1]单例模式的补充,分析静态类的使用,
    的头像 发表于 08-06 10:38 1796次阅读
    一文详解<b class='flag-5'>UVM</b>设计模式

    行为型设计模式在UVM的应用

    接下来介绍行为型设计模式在UVM的应用。
    的头像 发表于 08-09 14:01 703次阅读
    行为型设计模式在<b class='flag-5'>UVM</b><b class='flag-5'>中</b>的应用

    UVM设计的sequence启动方式有哪几种呢?

    本篇介绍UVM的sequence,这是UVM中最基础的部分。对于前面介绍的uvm_callback, uvm_visitor等,很少被使用
    的头像 发表于 08-17 10:07 4259次阅读
    <b class='flag-5'>UVM</b>设计<b class='flag-5'>中</b>的sequence启动方式有哪几种呢?