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

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

3天内不再提示

UVM中的可重用序列

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

在这篇博客中,我描述了在编写序列时必须采取的必要步骤,以确保它可以重用。就我个人而言,我觉得编写序列是验证任何IP最具挑战性的部分。编写序列需要仔细规划,否则我们最终会从头开始为每个场景编写一个序列。这使得序列难以维护和调试。

众所周知,序列由几个数据项组成,它们共同构成了一个有趣的场景。序列可以是分层的,从而创建更复杂的方案。在最简单的形式中,序列应该是 uvm_sequence 基类的派生,方法是指定请求和响应项类型参数,并使用要执行的特定方案实现 body 任务。

usb_simple_sequence 扩展uvm_sequence #(usb_transfer);

    rand int unsigned sequence_length;
    constraint reasonable_seq_len { sequence_length < 10 };

    //Constructor
    function new(string name=”usb_simple_bulk_sequence”);
        super.new(name);
    endfunction

   //Register with factory
   `uvm_object_utils(usb_simple_bulk_sequence)

   //the body() task is the actual logic of the sequence
   virtual task body();
      repeat(sequence_length)
      `uvm_do_with(req,  {
      //Setting the device_id to 2
          req.device_id == 8’d2;
          //Setting transfer type to BULK
          req.type == usb_transfer::BULK_TRANSFER;
       })
   endtask : body
endclass

在上面的顺序中,我们尝试将 USB 批量传输发送到 id 为 2 的设备。测试编写者可以通过将此序列分配给顶级测试中序列器的默认序列来调用此序列。

类usb_simple_bulk_test扩展uvm_test;

…
    virtual function void build_phase(uvm_phase phase );
        …
        uvm_config_db#(uvm_object_wrapper)::set(this, "sequencer_obj.
        main_phase","default_sequence", usb_simple_sequence::type_id::get());
        …
    endfunction : build_phase
endclass

到目前为止,事情看起来简单明了。为了确保序列可重用于更复杂的场景,我们必须遵循更多准则。

首先,通过在序列类中pre_start和post_start任务中提出和放弃异议来管理测试结束非常重要。这样,我们只在最上面的序列中提出和放弃异议,而不是对所有子序列都这样做。

t问 pre_start()

    if(starting_phase != null)
    starting_phase.raise_objection(this);
endtask : pre_start

t问 post_start()

    if(starting_phase != null)
    starting_phase.drop_objection(this);
endtask : post_start

请注意,starting_phase仅为作为特定阶段的默认序列启动的序列定义。如果已通过调用序列的 start 方法显式启动它,则用户负责设置starting_phase。

类usb_simple_bulk_test扩展uvm_test;

    usb_simple_sequence seq;
    …
    virtual function void main_phase(uvm_phase phase );
        …
        //User need to set the starting_phase as sequence start method
        is explicitly called to invoke the sequence
        seq.starting_phase = phase;
        seq.start();
        …
    endfunction : main_phase

结束类

使用 UVM 配置从顶级测试中获取值。在上面的示例中,没有为测试编写者提供可控性,因为序列不使用配置从顶级测试或序列中获取值(将使用此序列来构建复杂场景)。修改序列以更好地控制使用此简单序列的顶级测试或序列。

类 usb_simple_sequence 扩展uvm_sequence #(usb_transfer);

    rand int unsigned sequence_length;
    constraint reasonable_seq_len { sequence_length < 10 };
    …
    virtual task body();
        usb_transfer::type_enum local_type;
        bit[7:0] local_device_id;
        //Get the values for the variables in case toplevel
         //test/sequence sets it.
        uvm_config_db#(int unsigned)::get(null, get_full_name(),
            “sequence_length”, sequence_length);
        uvm_config_db#(usb_transfer::type_enum)::get(null,
            get_full_name(), “local_type”, local_type);
        uvm_config_db#(bit[7:0])::get(null, get_full_name(),?
            “local_device_id”, local_device_id);
        repeat(sequence_length)
        `uvm_do_with(req, {
            req.device_id == local_device_id;
            req.type == local_type;
        })
    endtask : body

结束类

通过上述修改,我们已经控制了顶级测试或序列来修改device_id、sequence_length和类型。这里需要注意的几点:uvm_config_db#()::set 中使用的参数类型和字符串(第三个参数)应该与 uvm_config_db#()::get 中使用的类型匹配。确保使用确切的数据类型“设置”和“获取”。否则,值将无法正确设置,调试将成为一场噩梦。

上述序列的一个问题是:如果 usb_transfer 类中对device_id或类型有任何约束,那么这将限制顶级测试或序列以确保它在约束范围内。

例如,如果usb_transfer类中的device_id存在约束,将其约束为低于 10,则顶级测试或序列应在此范围内约束它。如果顶级测试或序列将其设置为类似 15 的值(超过 10),则在运行时将看到约束失败。

有时,顶级测试或序列可能需要完全控制,并且可能不希望启用在较低级别的序列或数据项中定义的约束。需要这样做的一个示例是阴性测试:- 主机希望确保设备不会响应device_id大于 10 的传输,因此希望发送device_id 15 的传输。因此,为了完全控制顶级测试或序列,我们可以修改正文任务,如下所示:

虚拟任务正文();

    usb_transfer::type_enum local_type;
    bit[7:0] local_device_id;
    int status_seq_len = 0;
    int status_type = 0;
    int status_device_id = 0;
    status_seq_len = uvm_config_db#(int unsigned)::get(null,
        get_full_name(), “sequence_length”, sequence_length);
    status_type = uvm_config_db#(usb_transfer::type_enum)::get(null,
        get_full_name(),“local_type”,local_type);
    status_device_id = uvm_config_db#(bit[7:0])::get(null,
        get_full_name(), “local_device_id”,local_device_id);
    //If status of uvm_config_db::get is true then try to use the values
        // set by toplevel test or sequence instead of the random value.
    if(status_device_id || status_type)
    begin
        `uvm_create(req)
        req.randomize();
        if(status_type)
        begin
        //Using the value set by top level test or sequence
        //instead of the random value.
            req.type = local_type;
        end
        if(status_device_id)
        begin
            //Using the value set by top level test or sequence
        //instead of the random value.
            req.device_id = local_device_id;
        end
    end
    repeat(sequence_length)
        `uvm_send(req)

结束任务:正文

使用'uvm_do_with时总是要小心的,因为它会在较低级别的序列或序列项中的任何现有约束之上添加约束。

另请注意,如果您有更多变量要“设置”和“获取”,那么我建议您创建对象并在创建的对象中设置值,然后使用顶级测试/序列中的uvm_config_db设置此对象(而不是显式设置此对象中的每个变量)。这样,我们可以通过不搜索每个变量(当我们执行 uvm_config_db::get 时)来提高运行时性能,而是使用该对象一次性获取所有变量。

虚拟任务正文();

    usb_transfer::type_enum local_type;
    bit[7:0] local_device_id;
    int status_seq_len = 0;
    int status_type = 0;
    int status_device_id = 0;
    status_seq_len = uvm_config_db#(int unsigned)::get(null,
        get_full_name(), “sequence_length”, sequence_length);
    status_type = uvm_config_db#(usb_transfer::type_enum)::get(null,
        get_full_name(),“local_type”,local_type);
    status_device_id = uvm_config_db#(bit[7:0])::get(null,
        get_full_name(), “local_device_id”,local_device_id);
    //If status of uvm_config_db::get is true then try to use the values
        // set by toplevel test or sequence instead of the random value.
    if(status_device_id || status_type)
    begin
        `uvm_create(req)
        req.randomize();
        if(status_type)
        begin
        //Using the value set by top level test or sequence
        //instead of the random value.
            req.type = local_type;
        end
        if(status_device_id)
        begin
            //Using the value set by top level test or sequence
        //instead of the random value.
            req.device_id = local_device_id;
        end
    end
    repeat(sequence_length)
        `uvm_send(req)

结束任务:正文

始终尝试通过为复杂方案创建顶级序列来重用简单序列。例如,在下面的顺序中,我尝试发送批量传输,然后向 2 个不同的设备发送中断传输。对于此场景,我将使用我们的usb_simple_sequence如下所示:

类 usb_complex_sequence 扩展uvm_sequence #(usb_transfer);

    //Object of simple sequence used for sending bulk transfer
    usb_simple_sequence simp_seq_bulk;
    //Object of simple sequence used for sending interrupt transfer
    usb_simple_sequence simp_seq_int;
    …
    virtual task body();
        //Variable for getting device_id for bulk transfer
        bit[7:0] local_device_id_bulk;
        //Variable for getting device_id for interrupt transfer
        bit[7:0] local_device_id_int;
        //Variable for getting sequence length for bulk
        int unsigned local_seq_len_bulk;
        //Variable for getting sequence length for interrupt
        int unsigned local_seq_len_int;
        //Get the values for the variables in case top level
        //test/sequence sets it.
        uvm_config_db#(int unsigned)::get(null, get_full_name(),
        “local_seq_len_bulk”,local_seq_len_bulk);
        uvm_config_db#(int unsigned)::get(null, get_full_name(),
        “local_seq_len_int”,local_seq_len_int);
        uvm_config_db#(bit[7:0])::get(null, get_full_name(),
        “local_device_id_bulk”,local_device_id_bulk);
        uvm_config_db#(bit[7:0])::get(null, get_full_name(),
        “local_device_id_int”,local_device_id_int);
        //Set the values for the variables to the lowerlevel
        //sequence/sequence item, which we got from
        //above uvm_config_db::get.
        //Setting the values for bulk sequence
        uvm_config_db#(int unsigned)::set(null, {get_full_name(),”.”,
        ”simp_seq_bulk”}, “sequence_length”,local_seq_len_bulk);
        uvm_config_db#(usb_transfer::type_enum)::set(null, {get_full_name(),
        “.”,“simp_seq_bulk”} , “local_type”,usb_transfer::BULK_TRANSFER);
        uvm_config_db#(bit[7:0])::set(null, {get_full_name(),“.”,
        ”simp_seq_bulk”}, “local_device_id”,local_device_id_bulk);
        //Setting the values for interrupt sequence
        uvm_config_db#(int unsigned)::set(null, {get_full_name(),”.”,
        ”simp_seq_int”}, “sequence_length”,local_ seq_len_int);
        uvm_config_db#(usb_transfer::type_enum)::set(null, {get_full_name(),
        “.”,“simp_seq_int”} , “local_type”,usb_transfer::INT_TRANSFER);
        uvm_config_db#(bit[7:0])::set(null,{get_full_name(),“.”,
        ”simp_seq_bulk”},“local_device_id”,local_device_id_int);
        `uvm_do(simp_seq_bulk)
        simp_seq_bulk.get_response();
        `uvm_send(simp_seq_int)
        simp_seq_int.get_response();
    endtask : body

结束类

请注意,在上面的序列中,我们使用 uvm_config_db::get 从顶级测试或序列中获取值,然后使用 uvm_config_db::set 再次将其设置为较低级别的序列。如果我们尝试使用 'uvm_do_with 并将值传递到约束块内,那么这将作为附加约束应用而不是设置这些值,这很重要。

审核编辑:郭婷


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

    关注

    60

    文章

    7945

    浏览量

    264619
  • IP
    IP
    +关注

    关注

    5

    文章

    1708

    浏览量

    149541
  • UVM
    UVM
    +关注

    关注

    0

    文章

    182

    浏览量

    19169
收藏 人收藏

    评论

    相关推荐

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

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

    重用机床编码技术及重构算法研究

    重用机床编码技术及重构算法研究摘要:在产品开发过程80%的设计工作是在重用的基础上进行的。设计重用能够缩短产品开发周期、降低设计成本和避
    发表于 05-17 11:58

    IC验证"为什么要学习UVM呢"

    验证的基本常识,将会散落在各个章节之间。UVM的一些高级功能,如何灵活地使用sequence机制、factory机制等。如何编写代码才能保证重用性。
    发表于 12-01 15:09

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

    会在一定范围内产生,减少无用的激励,提高效率。支持覆盖率驱动模式,根据当前覆盖率的情况,验证工程师可以决定下一步的验证内容,当覆盖率达到了一定的要求时,就可以宣告验证工作的完成。uvm验证平台,它具有很高的重用
    发表于 01-21 16:00

    数字IC验证之“典型的UVM平台结构”(3)连载...

    应用的过程,将uvm的组件封装起来,可以将这些封装的组件呢作为一个整体进行重用,在进行芯片级或者是系统级验证的时候,往往会出现多个模块的验证。  此时,测试平台的结构会发生变化,图中的测试平台实现了
    发表于 01-22 15:32

    谈谈UVMuvm_info打印

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

    重用机床编码技术及重构算法研究

    重用机床编码技术及重构算法研究:摘要:在产品开发过程80%的设计工作是在重用的基础上进行的。设计重用能够缩短产品开发周期、降低设计成本和
    发表于 05-16 15:31 14次下载

    UVM验证平台执行硬件加速

    UVM已经成为了一种高效率的、从模块级到系统级完整验证环境开发标准,其中一个关键的原则是UVM可以开发出重用的验证组件。获得重用动力的一个
    发表于 09-15 17:08 14次下载
    <b class='flag-5'>UVM</b>验证平台执行硬件加速

    ASIC芯片设计之UVM验证

    百度百科对UVM的释义如下:通用验证方法学(Universal Verification Methodology, UVM)是一个以SystemVerilog类库为主体的验证平台开发框架,验证工程师可以利用其
    发表于 11-30 12:47 1512次阅读

    什么是UVM environment?

    UVM environment**包含多个重用的验证组件,并根据test case的需求进行相应的配置。例如,UVM environment可能具有多个agent(对应不同的inte
    的头像 发表于 03-21 11:35 1086次阅读
    什么是<b class='flag-5'>UVM</b> environment?

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

    大多数UVM测试平台由重复使用的验证组件组成,除非我们正在对像MIPI-CSI这样的简单协议进行块级验证。考虑验证简单协议的场景;在这种情况下,我们可以忍受只有一个音序器将刺激发送给驱动器。顶级
    的头像 发表于 05-29 09:46 807次阅读

    介绍从一组重用的验证组件构建测试平台所需的步骤

    本文介绍了从一组重用的验证组件构建测试平台所需的步骤。UVM促进了重用,加速了测试平台构建的过程。
    的头像 发表于 06-13 09:11 489次阅读
    介绍从一组<b class='flag-5'>可</b><b class='flag-5'>重用</b>的验证组件<b class='flag-5'>中</b>构建测试平台所需的步骤

    重用的验证组件构建测试平台的步骤

    本文介绍了从一组重用的验证组件构建测试平台所需的步骤。UVM促进了重用,加速了测试平台构建的过程。 首先对 测试平台集成者(testbe
    的头像 发表于 06-13 09:14 603次阅读
    <b class='flag-5'>可</b><b class='flag-5'>重用</b>的验证组件<b class='flag-5'>中</b>构建测试平台的步骤

    创建UVM Testcase的步骤

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

    UVMuvm_config_db机制背后的大功臣

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