一、概述

水平复用而言,在MCDF各个子模块的验证环境中,它指的是如何利用已有资源,完成高效的激励场景创建。而就垂直复用来看,它指的是在MCDF子系统验证中,可以完成结构复用激励场景复用两个方面。无论是水平复用还是垂直复用,激励场景的复用很大程度上取决于如何设计sequence,使得底层的sequence实现合理的粒度,帮助完成水平复用,进一步依托于底层激励场景,最终可以实现底层到高层的垂直复用。

二、Hierarchical Sequence介绍


在验证MCDF的寄存器模块时,将SV验证环境进化到了UVM环境之后,关于测试寄存器模块的场景可以将其拆分为:

  • 设置时钟和复位
  • 测试通道1的控制寄存器和只读寄存器
  • 测试通道2的控制寄存器和只读寄存器
  • 测试通道3的控制寄存器和只读寄存器

上面的测试场景拆解下的sequence需要挂载的都是reg_master_agent中的sequencer

typedef enum {CLKON, CLKOFF, RESET, WRREG, RDREG} cmd_t;
class bus_trans extends uvm_sequence_item;rand cmd_t cmd;rand int addr;rand int data;constraint cstr{soft addr == 'h0;soft data == 'h0;}...
endclassclass clk_rst_seq extends uvm_sequence;rand int freq;...task body();bus_trans req;`uvm_do_with(req, {cmd == CLKON; data == freq;})`uvm_do_with(req, {cmd == RESET;})endtask
endclassclass reg_test_seq extends uvm_sequence;rand int chnl;...task body();bus_trans req;//write and read test for WR register`uvm_do_with(req, {cmd == WRREG; addr == chnl * 'h4;})`uvm_do_with(req, {cmd == RDREG; addr == chnl * 'h4;})//read for the RD register`uvm_do_with(req, {cmd == RDREG; addr == chnl * 'h4 + 'h10;})endtask
endclassclass top_seq extends uvm_sequence;...task body();clk_rst_seq clkseq;reg_test_seq regseq0, regseq1, regseq2;//turn on clock with 150Mhz and assert reset`uvm_do_with(clkseq, {freq == 150;})//test the register of channel0`uvm_do_with(regseq0, {chnl == 0;})//test the register of channel1`uvm_do_with(regseq1, {chnl == 1;})//test the register of channel2`uvm_do_with(regseq2, {chnl == 2;})      endtask
endclassclass reg_master_sequencer extends uvm_sequencer;...
endclassclass reg_master_driver extends uvm_driver;...task run_phase(uvm_phase phase);REQ tmp;bus_trans req;forever beginseq_item_port.get_next_item(tmp);void'($cast(req, tmp));`uvm_info("DRV", $sformatf("got a item \n %s", req.sprint()), UVM_LOW)seq_item_port.item_done();endendtask
endclassclass reg_master_agent extends uvm_agent;reg_master_sequencer sqr;reg_master_driver drv;...function void build_phase(uvm_phase phase);sqr = reg_master_sequencer::type_id::create("sqr", this);drv = reg_master_driver::type_id::create("drv", this);endfunctionfunction void connect_phase(uvm_phase phase);drv.seq_item_port.connect(sqr.seq_item_export);endfunction
endclass

itembus_trans包含了几个简单的域cmdaddrdata。在clk_rst_seqreg_test_seq这两个底层的sequence在例化和传送item时,就通过随机化bus_trans中的域来实现不同的命令和数据内容。通过不同的数据内容的item,最终可以实现不同的测试目的。在top_seq中,它就通过对clk_rst_seqreg_test_seq这两个element sequence进行组合和随机化赋值,最终实现了一个完整的测试场景,即先打开时钟和完成复位,其后对寄存器模块中的寄存器完成读写测试。所以如果将clk_rst_seqreg_test_seq作为底层sequence,或者称之为element sequencetop_seq作为一个更高层的协调sequence,它本身也会容纳,并对它们进行协调和随机限制,通过将这些element sequence进行有机的调度,最终完成一个期望的测试场景。那么这样的top_seq就可以成为Hierarchical Sequence,它内部 可以包含多个sequenceitem,而通过层层嵌套,最终完成测试序列的合理切分。验证时,有了粒度合适的element sequence,就会更容易在这些设计好的”轮子“上面,实现验证的加速过程。而水平复用,就非常依赖于hierarchical sequence的实现。

三、virtual sequence介绍

virtual sequence也是协调各个sequence,但hierarchical sequence面对的对象是同一个sequencer,即hierarchical sequence本身也会挂载到sequencer上面,而对于virtual sequence而言,它内部不同的sequence可以允许面向不同的sequencer种类。

在MCDF子系统验证环境集成过程中,完成了前期的结构垂直复用,就需要考虑如何各个模块的element sequencehierarchical sequence。对于更上层的环境,顶层的测试序列要协调的不再只是面向一个sequencersequence群,而是要面向多个sequencersequence群。面向单一的sequencer,可以通过uvm_sequence::start()来挂载root sequence,而在内部的child sequence则可以通过宏'uvm_do来实现。如果将各个模块环境的element sequencehierarchical sequence都作为可以复用的sequence资源,那么就需要一个可以容纳各个sequence的容器来承载它们,同时也需要一个合适的routing sequencer来组织不同结构中的sequencer,这样的sequencesequencer分别称之为virtual sequencevirtual sequencer

virtual sequence可以承载不同目标sequencersequence群落,而组织协调这些sequence的方式则类似于高层次的hierarchical sequencevirtual sequence一般只会挂载到virtual sequencer上面。virtual sequencer与普通的sequencer相比有着很大的不同,它们起到了桥接其它sequencer的作用,即virtual sequencer是一个链接所有底层sequencer句柄的地方,它是一个中心化的路由器。同时virtual sequencer本身并不会传送item数据对象,因此virtual sequencer不需要与任何的driver进行TLM连接。所以UVM需要在顶层的connect阶段,做好virtual sequencer中各个sequencer句柄与底层sequencer实体对象的一一对接,避免句柄悬空。

virtual sequencer示例

class mcdf_normal_seq extends uvm_sequence;`uvm_object_utils(mcdf_normal_seq)`uvm_declare_p_sequencer(mcdf_virtual_sequencer)  //p_sequencer是一个uvm_sequencer的子类//这一行的宏相当于,定义了mcdf_virtual_sequencer、p_sequencer,然后$(p_sequencer, mcdf_virtual_sequencer)做了转换,完成了父类句柄到子类句柄的转换,然后就可以访问子类所有的成员变量,进而实现路由功能...task body();clk_rst_seq clk_seq;reg_cfg_seq cfg_seq;data_trans_seq data_seq;fmt_slv_cfg_seq fmt_seq;//配置formatter slave agent`uvm_do_on(fmt_seq, p_sequencer.fmt_sqr)//打开时钟并完成复位`uvm_do_on(clk_seq, p_sequencer.cr_sqr)//配置MCDF寄存器`uvm_do_on(cfg_seq, p_sequencer.reg_sqr)//传递channel数据包fork`uvm_do_on(data_seq, p_sequencer.chnl_sqr0)`uvm_do_on(data_seq, p_sequencer.chnl_sqr1)`uvm_do_on(data_seq, p_sequencer.chnl_sqr2)joinendtask
endclassclass mcdf_virtual_sequencer extends uvm_sequencer;cr_master_sequencer cr_sqr;reg_master_sequencer reg_sqr;chnl_master_sequencer chnl_sqr;chnl_master_sequencer chnl_sqr;chnl_master_sequencer chnl_sqr;fmt_slave_sequencer fmt_sqr;`uvm_component_utils(mcdf_virtual_sequencer)function new(string name, uvm_component parent);super.new(name, parent);endfunction
endclassclass mcdf_env extends uvm_env;cr_master_agent cr_agt;reg_master_agent reg_agt;chnl_master_agent chnl_agt0;chnl_master_agent chnl_agt1;chnl_master_agent chnl_agt2;fmt_slave_agent fmt_agt;mcdf_virtual_sequencer virt_sqr;`uvm_component_utils(mcdf_env)function new(string name, uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);cr_agt = cr_master_agent::type_id::create("cr_agt", this);reg_agt = reg_master_agent::type_id::create("reg_agt", this);chnl_agt0 = chnl_master_agent::type_id::create("chnl_agt0", this);chnl_agt1 = chnl_master_agent::type_id::create("chnl_agt1", this);chnl_agt2 = chnl_master_agent::type_id::create("chnl_agt2", this);fmt_agt = fmt_slave_agent::type_id::create("fmt_agt", this);virt_sqr = mcdf_virtual_sequencer::type_id::create("virt_sqr", this);endfunctionfunction void connect_phase(uvm_phase phase);virt_sqr.cr_sqr = cr_agt.sqr;virt_sqr.reg_sqr = reg_agt.sqr;virt_sqr.chnl_sqr = chnl_agt.sqr;virt_sqr.chnl_sqr = chnl_agt.sqr;virt_sqr.chnl_sqr = chnl_agt.sqr;virt_sqr.fmt_sqr = fmt_agt.sqr;endfunction
endclassclass test1 extends uvm_test;mcdf_env e;...task run_phase(uvm_phase phase);mcdf_normal_seq seq;phase.raise_objection(phase);seq = new();seq.start(e.virt_sqr);phase.drop_objection(phase);endtask
endclass


对于virtual sequence mcdf_normal_seq而言,它可以承载各个子模块环境的element sequence,而通过最后挂载的virtual sequencer mcdf_virtual_sequencer中的各个底层sequencer句柄,各个element sequence可以分别挂载到对应的底层sequencer上。

尽管在最后test1中,将virtual sequence挂载到了virtual sequencer上面,但是这种挂载的根本目的是为了提供给virtual sequence一个中心化的sequencer路由,而借助在virtual sequence mcdf_normal_seq中使用了宏'uvm_declare_p_sequencer,使得virtual sequence可以使用声明后的成员变量p_sequencer(类型为mcdf_virtual_sequencer),来进一步回溯到virtual sequencer内部的各个sequencer句柄。在这里使用'uvm_declare_p_sequencer这个宏会在后台,新创建一个p_sequencer类型,而将m_sequencer的默认变量(uvm_sequencer_base类型)通过动态转换,变为类型为mcdf_virtual_sequencerp_sequencer。只要声明的挂载sequencer类型正确,可以通过这个宏,完成方便的类型转换,因此可以通过p_sequencer索引到在mcdf_virtual_sequencer中声明的各个sequencer句柄。

四、Layering Sequence介绍

如果在构建更加复杂的协议总线传输,例如PCie、USB3.0等,那么通过一个单一的传输层次会对以后的激励复用、上层控制不那么友好。对于这钟更深层次化的数据传输,在实际中无论是VIP还是自开发的环境,都倾向于通过若干抽象层次的sequence群落来模拟协议层次。通过层次化的sequence可以分别构建transaction layertransport layerphysical layer等从高抽象级到低抽象级的transaction转化。这种层次化的sequence构建方式,称之为layering sequence。例如在进行寄存器级别的访问操作,其需要通过transport layer转化,最终映射为具体的总线传输。


Layering Sequence示例

typedef enum {CLKON, CLKOFF, RESET, WRREG, RDREG} phy_cmd_t;
typedef enum {FREQ_LOW_TRANS, FREQ_MED_TRANS, FREQ_HIGH_TRANS}layer_cmd_t;class bus_trans extends uvm_sequence_item;rand phy_cmd_t cmd;rand int addr;rand int data;constraint cstr {soft addr == 'h0;soft data == 'h0;}...endclassclass packet_seq extends uvm_sequence;rand int len;rand int addr;rand int data[];rand phy_cmd_t cmd;constraint cstr {soft len inside {[30:50]};soft addr[31:16] == 'hFF00;data.size() == len;}...task body();bus_trans req;foreach(data[i])`uvm_do_with(req, {cmd == local::cmd;addr == local::addr;data == local::data[i];})endtaskendclassclass layer_trans extends uvm_sequence_item;rand layer_cmd_t layer_cmd;rand int pkt_len;rand int pkt_idle;constraint cstr {soft pkt_len inside {[10:20]};layer_cmd == FREQ_LOW_TRANS -> pkt_idle inside {[300:400]};layer_cmd == FREQ_MED_TRANS -> pkt_idle inside {[100:200]};layer_cmd == FREQ_HIGH_TRANS -> pkt_idle inside {[20:40]};}...endclassclass adapter_seq extends uvm_sequence;`uvm_object_utils(adapter_seq)`uvm_declare_p_sequencer(phy_master_sequencer)...task body();layer_trans trans;packet_seq pkt;forever beginp_sequencer.up_sqr.get_next_item(req);    //获得高抽象层的transactionvoid'h(trans, req);repeat(trans.pkt_len) begin`uvm_do(pkt)delay(trans.pkt_idle);endp_sequencer.up_sqr.item_done();endendtaskvirtual task delay(int delay);...endtaskendclassclass top_seq extends uvm_sequence;...task body();layer_trans trans;`uvm_do_with(trans, {layer_cmd == FREQ_LOW_TRANS;})`uvm_do_with(trans, {layer_cmd == FREQ_HIGH_TRANS;})endtaskendclassclass layering_sequencer extends uvm_sequencer;...endclassclass phy_master_sequencer extends uvm_sequencer;layering_sequencer up_sqr;...endclassclass phy_master_driver extends uvm_driver;...task run_phase(uvm_phase phase);REQ tmp;bus_trans req;forever beginseq_item_port.get_next_item(tmp);void'($cast(req, tmp));`uvm_info("DRV", $sformatf("got a item \n %s", req.sprint()), UVM_LOW)seq_item_port.item_done();endendtaskendclassclass phy_master_agent extends uvm_agent;phy_master_sequencer sqr;phy_master_driver drv;...function void build_phase(uvm_phase phase);sqr = phy_master_sequencer::type_id::create("sqr", this);drv = phy_master_driver::type_id::create("drv", this);endfunctionfunction void connect_phase(uvm_phase phase);drv.seq_item_port.connect(sqr.seq_item_export);endfunctionendclassclass test1 extends uvm_test;layering_sequencer layer_sqr;phy_master_agent phy_agt;...function void build_phase(uvm_phase phase);layer_sqr = layering_sequencer::type_id::create("layer_sqr", this);phy_agt = phy_master_agent::type_id::create("phy_agt", this);endfunctionfunction connect_phase(uvm_phase phase);phy_agt.sqr.up_sqr = layer_sqr;endfunctiontask run_phase(uvm_phase phase);top_seq seq;adapter_seq adapter;phase.raise_objection(phase);seq = new();adapter = new();forkadapter.start(phy_agt.sqr);join_noneseq.start(layer_sqr);phase.drop_objection(phase);endtaskendclass

通过上面的代码,可以得出一些关于如何实现sequence layer协议转换的方法:

  • 无论有多少抽象层次的transaction类定义,都应该有对应的sequencer作为transaction的路由通道。例如layer_sequencerphy_master_sequencer分别作为layer_transbus_trans的通道。
  • 在各个抽象级的sequencer中,需要有相应的转换方法,将从高层次的transaction从高层次的sequencer获取,继而转换为低层次的transaction,最终通过低层次的sequencer发送出去。例如adapter_seq负责从layer_sequencer获取layer_trans,再将其转换为phy_master_sequencer一侧对应的sequence或者transaction,最后将其从phy_master_sequencer发送出去。
  • 这些adaption sequence应该运行在低层次的sequencer一侧,作为“永动”的sequence时刻做好服务准备,从高层次的sequencer获取transaction,通过转化将其从低层次的sequencer一侧送出。例如上面的test1中,adapter sequence通过adapter.start(phy_agt.sqr)挂载到低层次的sequencer,做好转换transaction并将其发送的准备。

Sequence的层次化相关推荐

  1. sequence和sequencer — UVM

    文章目录 简介 1.sequence 和 item 2.sequencer 和 driver 1. 通信方式--TLM端口 2.事务传输 3. 通信时序 3.sequence和sequencer 1. ...

  2. UVM入门与进阶学习笔记16——sequencer和sequence(2)

    目录 sequence的层次化 Hierarchical Sequence Virtual Sequence Layering Sequence sequence的层次化 就水平复用而言,在MCDF各 ...

  3. UVM——sequence、sequencer、driver概述

    sequence.sequencer.driver关系 三者的关系如上图所示: - sequence产生目标数量的sequence item,并通过随机化使每一个sequence item对象的数据内 ...

  4. IC验证培训——SystemVerilog与UVM,IC验证线上培训九月澎湃将至

    ​ 路科验证精品线下培训 为响应全国各地心心念路科验证培训的路粉们,路科将在9月1日进行线上培训,线上报名方式如下: 手机安卓端(暂不支持iOS)可在[腾讯课堂]APP搜索"路科验证&quo ...

  5. UVM学习笔记--sequence和sequencer

    1. UVM sequence机制的意义 UVM的sequence机制最大的作用就是将test case和testbench分离开来. 对一个项目而言,testbench是相对稳定的框架,而针对各个m ...

  6. UVM学习笔记(四)sequence与sequencer

    目录 一.概述 1.1 类的继承 1.2 数据传送机制 二.uvm_sequence_item 2.1 功能与数据成员 2.2 示例 三.uvm_sequence 3.1 功能与分类 3.2 flat ...

  7. sequence与sequencer

    文章目录 1. sequence与sequencer 1.1 sequence和item发送实例 1.2 sequence和item方法 1.3 发送序列的uvm宏 1.4 序列宏实例 1.5 seq ...

  8. java sequencer_UVM学习笔记--sequence和sequencer(转)

    1. UVM sequence机制的意义 ======================= UVM的sequence机制最大的作用就是将test case和testbench分离开来. 对一个项目而言, ...

  9. UVM—virtual sequencer and virtual sequence详解

    目录 1.前言 2.virtual sequencer使用环境 3. virtual sequencer 和virtual sequence的作用 4.m_sequencer与p_sequencer ...

最新文章

  1. 计算机二级无法完成初始化,2012年计算机等级考试二级C语言常见问题:声明和初始化...
  2. 面试中Spring常见问题
  3. python字符串大全_python学习笔记:字符串操作大全
  4. 编写mysql的工具_自己编写的数据库工具类
  5. oauth2 access_denied 不允许访问_OAuth 2 是什么-入门介绍
  6. 笔记本中美化代码的方法
  7. 集成UG和ANSYS之二----upupdate之x_t
  8. java 蓝桥杯算法提高 身份证号码升级(题解)
  9. 用户空间和内核空间通讯之【Netlink 中】
  10. ArcGIS 城市生活区用地适宜性评价(二)
  11. Atiitt 程序语言vm与rt 虚拟机与运行时 目录 1. 运行时 虚拟机的一种,一般指进程级别的虚拟机。 1 1.1. 线程模型 1 1.2. 堆栈机vs 寄存器 1 1.3. 存储模型 2 1
  12. SSH集成项目,使用注解方式,竟然还有这样的问题!!
  13. 尚观python培训视频教程
  14. 51单片机入门——LED灯
  15. 程序员必修课-颈椎问题的预防
  16. 印度软件腾飞不是偶然
  17. 三国论(21-25章)
  18. python怎么绘制渐变图_有没有一种使用Python生成渐变位图的简单方法?
  19. Java并发深度总结:synchronized 关键字
  20. 鲍尔默给微软带来了什么

热门文章

  1. 老闪创业那些事儿(38)——小龙的离职面谈
  2. PocketGamer专访Adrealm:数字广告将迎来全新解决方案
  3. 小丸子学Hadoop系列之——部署Hbase集群
  4. MathType在word中的安装使用方法(要配合microsoft公式3.0才能使用)(ps:弄得不好可能造成word中Ctrl+V失灵)
  5. REID计算机网络,什么是行人重识别(ReID)?为什么要ReID?
  6. 一年讲50本书,年收入过亿,罗振宇没做到的,樊登读书会凭什么?
  7. CAD偏移尺寸出问题该如何解决?
  8. 笔记本实现Win10+Ubuntu双系统(超详细)
  9. matlab中bitget函数用法_Matlab函数大全
  10. 如何简单快速的获取到页面上的svg图标?