Sequence的层次化
一、概述
就水平复用而言,在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
item
类bus_trans
包含了几个简单的域cmd
、addr
、data
。在clk_rst_seq
和reg_test_seq
这两个底层的sequence
在例化和传送item
时,就通过随机化bus_trans
中的域来实现不同的命令和数据内容。通过不同的数据内容的item
,最终可以实现不同的测试目的。在top_seq
中,它就通过对clk_rst_seq
和reg_test_seq
这两个element sequence
进行组合和随机化赋值,最终实现了一个完整的测试场景,即先打开时钟和完成复位,其后对寄存器模块中的寄存器完成读写测试。所以如果将clk_rst_seq
和reg_test_seq
作为底层sequence
,或者称之为element sequence
,top_seq
作为一个更高层的协调sequence
,它本身也会容纳,并对它们进行协调和随机限制,通过将这些element sequence
进行有机的调度,最终完成一个期望的测试场景。那么这样的top_seq
就可以成为Hierarchical Sequence
,它内部 可以包含多个sequence
和item
,而通过层层嵌套,最终完成测试序列的合理切分。验证时,有了粒度合适的element sequence
,就会更容易在这些设计好的”轮子“上面,实现验证的加速过程。而水平复用,就非常依赖于hierarchical sequence
的实现。
三、virtual sequence介绍
virtual sequence
也是协调各个sequence
,但hierarchical sequence
面对的对象是同一个sequencer
,即hierarchical sequence
本身也会挂载到sequencer
上面,而对于virtual sequence
而言,它内部不同的sequence
可以允许面向不同的sequencer
种类。
在MCDF子系统验证环境集成过程中,完成了前期的结构垂直复用,就需要考虑如何各个模块的element sequence
和hierarchical sequence
。对于更上层的环境,顶层的测试序列要协调的不再只是面向一个sequencer
的sequence
群,而是要面向多个sequencer
的sequence
群。面向单一的sequencer
,可以通过uvm_sequence::start()
来挂载root sequence
,而在内部的child sequence
则可以通过宏'uvm_do
来实现。如果将各个模块环境的element sequence
和hierarchical sequence
都作为可以复用的sequence
资源,那么就需要一个可以容纳各个sequence
的容器来承载它们,同时也需要一个合适的routing sequencer
来组织不同结构中的sequencer
,这样的sequence
和sequencer
分别称之为virtual sequence
和virtual sequencer
。
virtual sequence
可以承载不同目标sequencer
的sequence
群落,而组织协调这些sequence
的方式则类似于高层次的hierarchical sequence
。virtual 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_sequencer
的p_sequencer
。只要声明的挂载sequencer
类型正确,可以通过这个宏,完成方便的类型转换,因此可以通过p_sequencer
索引到在mcdf_virtual_sequencer
中声明的各个sequencer
句柄。
四、Layering Sequence介绍
如果在构建更加复杂的协议总线传输,例如PCie、USB3.0等,那么通过一个单一的传输层次会对以后的激励复用、上层控制不那么友好。对于这钟更深层次化的数据传输,在实际中无论是VIP还是自开发的环境,都倾向于通过若干抽象层次的sequence
群落来模拟协议层次。通过层次化的sequence
可以分别构建transaction layer
、transport layer
和physical 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_sequencer
和phy_master_sequencer
分别作为layer_trans
和bus_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的层次化相关推荐
- sequence和sequencer — UVM
文章目录 简介 1.sequence 和 item 2.sequencer 和 driver 1. 通信方式--TLM端口 2.事务传输 3. 通信时序 3.sequence和sequencer 1. ...
- UVM入门与进阶学习笔记16——sequencer和sequence(2)
目录 sequence的层次化 Hierarchical Sequence Virtual Sequence Layering Sequence sequence的层次化 就水平复用而言,在MCDF各 ...
- UVM——sequence、sequencer、driver概述
sequence.sequencer.driver关系 三者的关系如上图所示: - sequence产生目标数量的sequence item,并通过随机化使每一个sequence item对象的数据内 ...
- IC验证培训——SystemVerilog与UVM,IC验证线上培训九月澎湃将至
路科验证精品线下培训 为响应全国各地心心念路科验证培训的路粉们,路科将在9月1日进行线上培训,线上报名方式如下: 手机安卓端(暂不支持iOS)可在[腾讯课堂]APP搜索"路科验证&quo ...
- UVM学习笔记--sequence和sequencer
1. UVM sequence机制的意义 UVM的sequence机制最大的作用就是将test case和testbench分离开来. 对一个项目而言,testbench是相对稳定的框架,而针对各个m ...
- UVM学习笔记(四)sequence与sequencer
目录 一.概述 1.1 类的继承 1.2 数据传送机制 二.uvm_sequence_item 2.1 功能与数据成员 2.2 示例 三.uvm_sequence 3.1 功能与分类 3.2 flat ...
- sequence与sequencer
文章目录 1. sequence与sequencer 1.1 sequence和item发送实例 1.2 sequence和item方法 1.3 发送序列的uvm宏 1.4 序列宏实例 1.5 seq ...
- java sequencer_UVM学习笔记--sequence和sequencer(转)
1. UVM sequence机制的意义 ======================= UVM的sequence机制最大的作用就是将test case和testbench分离开来. 对一个项目而言, ...
- UVM—virtual sequencer and virtual sequence详解
目录 1.前言 2.virtual sequencer使用环境 3. virtual sequencer 和virtual sequence的作用 4.m_sequencer与p_sequencer ...
最新文章
- 计算机二级无法完成初始化,2012年计算机等级考试二级C语言常见问题:声明和初始化...
- 面试中Spring常见问题
- python字符串大全_python学习笔记:字符串操作大全
- 编写mysql的工具_自己编写的数据库工具类
- oauth2 access_denied 不允许访问_OAuth 2 是什么-入门介绍
- 笔记本中美化代码的方法
- 集成UG和ANSYS之二----upupdate之x_t
- java 蓝桥杯算法提高 身份证号码升级(题解)
- 用户空间和内核空间通讯之【Netlink 中】
- ArcGIS 城市生活区用地适宜性评价(二)
- Atiitt 程序语言vm与rt 虚拟机与运行时 目录 1. 运行时 虚拟机的一种,一般指进程级别的虚拟机。	1 1.1. 线程模型	1 1.2. 堆栈机vs 寄存器	1 1.3. 存储模型	2 1
- SSH集成项目,使用注解方式,竟然还有这样的问题!!
- 尚观python培训视频教程
- 51单片机入门——LED灯
- 程序员必修课-颈椎问题的预防
- 印度软件腾飞不是偶然
- 三国论(21-25章)
- python怎么绘制渐变图_有没有一种使用Python生成渐变位图的简单方法?
- Java并发深度总结:synchronized 关键字
- 鲍尔默给微软带来了什么
热门文章
- 老闪创业那些事儿(38)——小龙的离职面谈
- PocketGamer专访Adrealm:数字广告将迎来全新解决方案
- 小丸子学Hadoop系列之——部署Hbase集群
- MathType在word中的安装使用方法(要配合microsoft公式3.0才能使用)(ps:弄得不好可能造成word中Ctrl+V失灵)
- REID计算机网络,什么是行人重识别(ReID)?为什么要ReID?
- 一年讲50本书,年收入过亿,罗振宇没做到的,樊登读书会凭什么?
- CAD偏移尺寸出问题该如何解决?
- 笔记本实现Win10+Ubuntu双系统(超详细)
- matlab中bitget函数用法_Matlab函数大全
- 如何简单快速的获取到页面上的svg图标?