UVM--Sequencer和Sequence
1 Sequencer和Sequence
发送sequence及item的方法和宏
class bus_trans extends uvm_sequence_item;
rand int data;
`uvm_object_utils_begin(bus_trans)
`uvm_field_int(data, UVM ALL ON)
`uvm_object_utils_end
...
endclassclass child_seq extends uvm_sequence;
`uvm_object_utils(child_seq)
...
task body();
uvm_sequence_item tmp;
bus_trans req;
tmp = create_item(bus trans::get_type(), m_sequencer, "req");
void'($cast (req, tmp));
start_item(req);
req.randomize with {data == 10;);
finish_item(req);
endtask
endclass class top_seq extends uvm_sequence;
`uvm_object_utils(top_seq)
...
task body();
uvm_sequence_item tmp;
child_seq cseq;
bus_trans req;
//create child sequence and items
cseq = child_seq::type_id::create ("cseq");
tmp = create_item(bus_trans::get_type(), m_sequencer, "req"); //创建uvm_sequence_item
//send child sequence via start ()
cseq.start(m_sequencer, this);
//将child_sequence 挂载到sequencer上
//执行child_sequence_body 实际上执行的是里边的最小颗粒度item
//m_sequencer表示要挂载到m_sequencer
//this表示parent sequence,此处表示top_sequence,
//给出parent sequence表示与顶层的优先级一致,自动为100,用于仲裁
// send sequence item
void'($cast (req, tmp));
start_item(req); //item挂载
req.randomize with {data == 20;};
finish_item(req); //item挂载
endtask
endclass class sequencer extends uvm_sequencer;
`uvm_component_utils(sequencer)
...
endclassclass driver extends uvm_driver;
`uvm component utils(driver)
...
task run_phase(uvm_phase phase);
REQ tmp;
bus_trans req;
forever begin
seq_item_port.get_next_item(tmp);
void'($cast (req, tmp));
uvm_info("DRV", $sforrnatf ("got a item \n %s", req.sprint()), UVM_LOW)
seq_item_port.item_done();
end
endtask
endclass class env extends uvm_env;
sequencer sqr;
driver drv;
`uvm_component_utils(env)
...
function void build_phase(uvm_phase phase);
sqr = sequencer::type_id::create("sqr", this);
drv = driver::type_id::create("drv", this);
endfunction
function void connect_phase(uvm_phase phase);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction
endclass class testl extends uvm_test;
env e;
`uvm_component_utils(testl)
function void build_phase(uvm_phase phase);
e = env::type_id::create("e", this);
endfunction
task run_phase(uvm_phase phase);
top_seq seq;
phase.raise_objection(phase); seq= new();
seq.start(e.sqr); //挂载
phase.drop_objection(phase);
endtask
endclass
在这段例码中, 主要使用两种方法。 第一种方法是针对将 sequence 挂载到 sequencer 上的应用。
uvm_sequence: :start(uvm_sequencer_base sequencer, uvm_sequence_base parent_sequence = null ,int this_priority = -1, bit call_pre_post = 1)
在使用该方法的过程中, 用户首先应该指明 sequencer 的句柄。 如果该 sequence 是顶部的 sequence, 即没有更上层的 sequence 嵌套它, 则它可以省略对第二个参数 parent_sequence 的指定。 第三个参数的默认值为-1, 使得该 sequence 的 parent_sequence (若有)继承其优先级值;如果是顶部 (root) sequence, 则其优先级自动设定为 100, 用户也可以指定优先级数值。第四个参数建议使用默认值, 这样的话 uvm_ sequence::pre _ body()和 uvm_sequence::post_ body()两个方法会在 uvm_sequence::body()的前后执行。 在上面的例子中,child_seq 被嵌套到 top_seq 中, 继而在挂载时需要指定 parent_sequence; 而在 test 一层调用 top_seq 时, 由于它是 root sequence, 则不需要再指定 parent sequence, 这一点大家需要注意。另外,在调用挂载 sequence 时, 需要对这些 sequence 进行例化。
第二种发送方法是针对将 item 挂载到 sequencer 上的应用。
uvm _sequence: : start_item (uvm _sequence_ item item, int set_priority = -1,
uvm_sequencer_base sequencer=null);
uvm_sequence: :finish_item (uvm_sequence_item item, int set_priority = -1);
对于 start_item()的使用, 第三个参数用户需要注意是否要将 item 挂载到 “ 非当前 parent sequence 挂载的 sequencer"上面,有点绕口是吗?简单来说,如果你想将 item 和其 parent sequence 挂载到不同的 sequencer 上面,你就需要指定这个参数。默认情况下,”父"(sequence) 与"子"(item) 都是走的一条道路 (virtual sequence 除外)。 在使用这一对方法时, 用户除了需要记得创建 item, 例如通过 uvm_ object: :create()或 uvm_sequence::create _item(), 还需要在它们之间完成 item 的随机化处理。 从这一点建议来看, 需要读者了解到, 对于一个 item 的完整传送, sequence 要在 sequencer 一侧获得通过权限, 才可以顺利将 item 发送至 driver。我们可以通过拆解这些步骤得到更多的细节:
• 创建 item。
• 通过 start_item()方法等待获得 sequencer 的授权许可, 其后执行 parent sequence 的方法 pre_do()。
• 对 item 进行随机化处理。
• 通过 finish_item()方法在对 item 进行了随机化处理之后, 执行 parent sequence 的 mid_do(), 以及调用 uvm_sequencer::send_request() 和 uvm_ sequencer: :wait_ for_ i tem_done()来将 item 发送至 sequencer 再完成与 driver 之间的握手。 最后, 执行了 parent_ sequence 的 post_do()。
这些完整的细节有两个部分需要注意。 第一, sequence 和 item 自身的优先级, 可以决定什么时刻可以获得 sequencer 的授权;第二, 读者需要意识到, parent sequence 的虚方法pre_do( )、 mid_do()和 post_do()会发生在发送 item 的过程中间。 如果对比 start()方法和start _item()/finish _item(), 读者首先要分清它们面向的挂载对象是不同的。 此外还需要清楚,在执行 start()过程中,默认情况下会执行 sequence 的 pre_body()和 post_body(), 但是如果 start() 的参数 call_pre_post = 0, 那么就不会这样执行, 所以在一些场景中, UVM 用户会奇怪为什么pre_body()和 post_body () 没有被执行。 在这里, pre_body()和 post_body()并不是一定会被执行,这一点同 UVM 的 phase 顺序执行是有区别的。建议是,用户可以在 base_sequence 中自定义一些方法,确保它们会按照顺序执行,比如下面这段例码,用户可以分别在 user_pre_ body()、user_post_ body()和 user_body0中填充代码,确保这些方法会被顺序执行,或也可以考虑使用 pre_start()和 post_start()这两个预定义的方法。
virtual task user_pre_body ();
endtask
virtual task user_post_body();
endtask
virtual task user_body ();
endtask
virtual task body();
user_pre_body();
user_body ();
user_post_body();
endtask
下面一段代码是对 start()方法执行过程的自然代码描述, 大家可以看到它们执行的顺序关系和条件:
对于 pre_do()、mid_do()、post_do()而言,子 一级的sequence/item在被发送过程中会间接调用parent sequence的pre_do()等方法。
• 正是通过几个sequence/item宏来打天下的方式,用户可以通过'uvm_ do/'uvm _do_ with 来发送sequence或item。这种不区分对象是sequence还是 item的方式, 带来了不少便捷,但容易引起验证师的惰性。在使用之前,需先了解它们背后的sequence和 item 各自发送的方法。
• 不同的宏可能包含创建对象的过程也可能不会创建对象。例如'uvm_do/、uvm _do_ with 会创建对象, 而'uvm_send 则不会创建对象, 也不会将对象做随机处理, 因此要了解 它们各自包含的执行内容和顺序。
• 此外还有其他的宏, 可以在 UVM 用户手册关于 sequence 的宏部分深入了解。例如, 将优先级作为参数传递的 'uvm_do_pri/'uvm_do_on_prio等, 还有专门针对 sequence 的uvm_create_ seq/'uvm _do_ seq/、uvm_do_ seq_ with等宏。 不过, 我们在列表中给出的宏已经可以满足大多数的场景应用, 而且整齐统一,便于用户记忆和使用, 所以我们在这里不再对其他一些宏做额外说明。
class child_seq extends uvm_sequence;
`uvm_object_utils(child_seq)
...
task body();
bus_trans req;
`uvm_create(req)
`uvm_rand_send_with(req, {data == 10;})
// =`uvm_do _with(req,{data ==10;})
endtask
endclass class top_seq extends uvm_sequence;
...
task body();
child_seq cseq;
bus_trans req;
// send child sequence via start()
`uvm_do(cseq)
//send sequence item
`uvm_do_with (req, {data == 20;})
endtask
endclass
几点建议:
• 无论 sequence 处于什么层次, 都应当让 sequence 在 test 结束前执行宪毕。 但这不是充分条件,一般而言,还应当保留出一部分时间供DUT将所有发送的激励处理完毕, 进入空闲状态才可以结束测试。
• 尽朵避免使用 fork-join_any 或 fork-join_none 来控制 sequence 的发送顺序。 因为这背后隐藏的风险是, 如果用户想终止在后台运行的 sequence 线程而简单使用 disable 方式, 那么就可能在不恰当的时间点上锁住 sequencer。 一旦 sequencer 被锁住而又无法释放,接下来也就无法发送其他 sequence。所以如果用户想实现类似 fork-join_any 或fork-join_none 的发送顺序, 还应节在使用 disable 前, 对各个 sequence 线程的后台运行保持关注, 尽量在发送完 item 完成握手之后再终止 sequence, 这样才能避免 sequencer 被死锁的问题。
• 如果用户要使用 fork-join 方式, 那么应当确保有方法可以让 sequence 线程在满足 一些条件后停止发送 item。否则只要有一个 sequence 线程无法停止, 则整个 fork-join 无法退出。面对这种情况, 仍然需要用户考虑监测合适的事件或时间点,才能够使用 disable 来关闭线程。
sequencer的仲裁特性及应用
uvm_ sequencer 类自建了仲裁机制用来保证多个 sequence 在同时挂载到 sequencer 时, 可以按照仲裁规则允许特定 sequence 中的 item 优先通过。在实际使用中, 我们可以通过uvm_sequencer: :set_ arbitration(UVM _ SEQ_ ARB_TYPE val)函数来设置仲裁模式,这里的仲裁模式UVM_SEQ_ ARB_ TYPE有下面几种值可以选择:
• UVM _ SEQ_ ARB _FIFO: 默认模式。 来自于 sequence 的发送请求, 按照FIFO先进先出的方式被依次授权, 和优先级没有关系。
• UVM_SEQ_ARB_ WEIGHTED: 不同 sequence 的发送请求, 将按照它们的优先级权重随机授权。
• UVM_SEQ_ARB_RANDOM: 不同的请求会被随机授权,而无视它们的抵达顺序和优先级。
• UVM_SEQ_ARB_STRICT_FIFO: 不同的请求,会按照它们的优先级以及抵达顺序来依次授权, 因此与优先级和抵达时间都有关。
• UVM_SEQ_ARB_STRICT_RANDOM: 不同的请求,会按照它们的最高优先级随机授权, 与抵达时间无关。
• UVM _ SEQ_ ARB_ USER: 用户可以自定义仲裁方法 user_priority_ arbitration()来裁定哪个 sequence的请求被优先授权。
在上面的仲裁模式中,与priority有关的模式有UVM_SEQ_ARB_WEIGHTED、 UVM_SEQ_ARB_STRJCT_FIFO和UVM_ SEQ_ ARB_ STRICT_ RANDOM。这三种模式的区别在于,UVM_SEQ_ARB_WEIGHTED的授权可能会落到各个优先级 sequence的请求上面,
而UVM_ SEQ_ARB _ STRJCT _ RANDOM则只会将授权随机安排到最高优先级的请求上面, UVM_ SEQ_ARB _ STRJCT _FIFO则不会随机授权,而是严格按照优先级以及抵达顺序来依次
授权。没有特别的要求,用户不需要再额外自定义授权机制,因此使用UVM_SEQ_ARB _ USER这一模式的情况不多见, 其他模式可以满足绝大多数的仲裁需求。
class bus_trans extends uvm_sequence_item;
rand int data;
...
endclass
class child_seq extends uvm_sequence;
rand int base;
...
task body();
bus_trans req;
repeat (2)
`uvm_do_with (req, {data inside {[base: base+9)};})
endtask
endclass class top_seq extends uvm_sequence;
...
task body();
child_seq seql, seq2, seq3;
m_sequencer.set_arbitration (UVM_SEQ_ARB_STRICT_FIFO);
fork
`uvm_do_pri_with(seql, 500, {base == 10;})
`uvm_do_pri_with(seq2, 500, {base == 20;})
`uvm_do_pri_with(seq3, 300, {base == 30;})
join
endtask
endclass
class sequencer extends uvm_sequencer;
endclass class driver extends uvm_driver;
...
task run_phase(uvm_phase phase);
REQ tmp;
bus_trans req;
forever begin
seq_item_port.get_next_item(tmp);
void'($cast (req, tmp));
`uvm_info("DRV",$sformatf("got a item %0d from parent sequence %s",reg.data, req.get_parent_sequence().get_name ()),UVM LOW)
seq_item_port.item_done();
end
endtask
endclass class env extends uvm_env;
sequencer sqr;
driver drv;
...
function void build_phase(uvm_phase phase);
sqr = sequencer::type_id::create("sqr", this);
drv = driver::type_id::create("drv", this);
endfunction
function void connect_phase(uvm_phase phase);
drv.seq_item_port.connect(sqr.seq item export);
endfunction
endclass
class test1 extends uvm_test
env e;
...
task run_phase(uvm_phase phase);
top_seq seq;
phase.raise_objection(phase);
seq = new();
seq.start(e.sqr);
phase.drop_objection(phase);
endtask
endclass //输出结果:
UVM_INFO@ 0: uvm_test_top.e.drv [DRV] got a item 16 from parent sequence seql
UVM_INFO@ 0: uvm_test_top.e.drv [DRV] got a item 22 from parent sequence seq2
UVM_INFO@ 0: uvm_test_top.e.drv [DRV] got a item 19 from parent sequence seql
UVM_INFO@ 0: uvm_test_top.e.drv [DRV) got a item 23 from parent sequence seq2
UVM_INFO@ 0: uvm_test_top.e.drv [DRV] got a item 33 from parent sequence seq3
UVM_INFO@ 0: uvm_test_top.e.drv [DRV] got a item 32 from parent sequence seq3
上面的例码中 , seq1、seq2、seq3在同一时刻发起传送请求 ,通过uvm_ do_prio_with的宏, 在发送sequence时可以传递优先级参数。 由于将seq1与seq2设置为同样的高优先级, 而seq3设置为较低的优先级 , 这样在随后的UVM_SEQ_ARB_STRlCT_FIFO仲裁模式下, 可以从输出结果看到, 按照优先级高低和传送请求时间顺序, 先将seq1 和seq2中的 item发送完毕,随后将seq3发送完。除了sequence遵循仲裁机制,在一些特殊情形下,有 一些sequence需要有更高权限取得sequencer的授权来访问driver。例如, 在需要响应中断的情形下, 用于处理中断的sequence应该有更高的权限来获得sequencer的授权。为此,uvm_ sequencer提供了两种锁定机制 , 分别通过lock()和grab()方法实现, 这两种方法的区别在于:
• lock()与unlock()这一对方法可以为sequence提供排外的访问权限, 但前提条件是,该sequence首先需要按照sequencer的仲裁机制获得授权。而且sequence获得授权则无须担心权限被收回, 只有该 sequence主动解锁(unlock)它的 sequencer, 才可以释放这一锁定的权限。lock()是一种阻塞任务, 只有获得了权限, 它才会返回。
• grab()与ungrab()也可以为sequence提供排外的访问权限,而且它只需要在sequencer下一次授权周期时就可以无条件地获得授权。 与lock方法相比,grab方法无视同一时刻内发起传送请求的其他sequence,而唯一可以阻止它的只有已经预先获得授权的其他lock或grab的sequence。
如果sequence使用了lock()或grab()方法,必须在sequence结束前调用unlock()或ungrab()方法来释放权限, 否则sequencer会进入死锁状态而无法继续为其余sequence授权。 下面给出一段例码 , 展示如何使用上述方法实现锁定的 sequence传送方式。
class bus_trans extends uvm_sequence_item;
...
endclass class child_seq extends uvm_sequence;
...
endclass class lock_seq extends uvm_sequence;
...
task body();
bus_trans req;
#l0ns;
m_sequencer.lock (this) ;
`uvm_info ("LOCK", "get exclusive access by lock()", UVM LOW)
repeat (3)
#l0ns
`uvm_do_with(req, {data inside { (100: 110)};})
m_sequencer.unlock(this);
endtask
endclass class grab_seq extends uvm_sequence;
...
task body ();
bus_trans req;
#20ns;
m_sequencer.grab(this)
`uvm_info("GRAB", "get exclusive access by grab()", UVM_LOW)
repeat (3)
#l0ns
`uvm_do_with(req, {data inside { (200: 210)};})
m_sequencer.ungrab(this);
endtask
endclass class top_seq extends uvm_sequence;
...
task body();
child_seq seql, seq2, seq3;
lock_seq locks;
grab_seq grabs;
m_sequencer.set_arbitration(UVM_SEQ_ARB_STRICT_FIFO);
fork
`uvm_do_pri_with(seql, 500, {base == 10; })
`uvm_do_pri_with(seq2, 500, {base == 20; })
`uvm_do_pri_with(seq3, 300, {base == 30; })
`uvm_do_pri(locks, 300)
`uvm_do(grabs)
join
endtask
endclass //输出结果
UVM_INFO@ 10000: uvm_test_top.e.drv [DRV] got a item 16 from parent sequence seql
UVM_INFO@ 10000: uvm_test_top.e.drv [ORV] got a item 22 from parent sequence seq2
UVM_INFO @ 10000: uvm_七est_top.e. sqr@@ top _seq. locks [LOCK] get exclusive access by lock ()
UVM_INFO@ 10000: uvm_test_top.e.drv [DRV] got a item 33 from parent sequence seq3
UVM_INFO@ 20000: uvm_test_top.e.drv [ORV] got a item 108 from parent sequence locks
UVM INFO@ 30000: uvm_test_top.e.drv [DRV] got a item 110 from parent sequence locks
UVM_INFO@ 40000: uvm_test_top.e.drv [DRV] got a item 101 from parent sequence locks
UVM_INFO @ 40000: uvm_test_top.e.sqr@@top_seq.grabs [GRAB] get exclusive access by grab ()
UVM_INFO@ 50000: uvm_test_top.e.drv [DRV] got a item 203 from parent sequence grabs
UVM_INFO@ 60000: uvm_test_top.e.drv [DRV] got a item 202 from parent sequence grabs
UVM_INFO@ 70000: uvm_test_top.e.drv[DRV] got a 工tern 204 from parent sequence grabs
UVM_INFO@ 70000: uvm_test_top.e.drv [DRV] got a item 19 from parent sequence seql
UVM_INFO@ 70000: uvm_test_top.e.drv [DRV] got a item 23 from parent sequence seq2
UVM_INFO@ 70000: uvm_test_top.e.drv [DRV] got a item 32 from parent sequence seq3
结合例码和输出结果,我们从中可以发现如下几点:
• sequence locks在10 ns时与其他几个sequence 一同向sequencer发起请求, 按照仲裁模式,sequencer授权给seq1、seq2、seq3, 最后才授权给locks。locks在获得授权后,就可以 一直享有权限而无须担心权限被sequencer收回,locks结束前, 用户需要通过 unlock()方法返还权限 。
• 对于sequence grabs, 尽管它在20 ns时就发起了请求权限(实际上seq1、seq2、seq3 也在同 一时刻发起了权限请求), 而由于权限已经被locks占用, 所以它也无权收回权限。 因此只有当locks在40ns结束时, grabs才可以在sequencer没有被锁定的状态下获得权限,而grabs 在此条件下获取权限是无视同 一时刻发起请求的其他 sequence 的。 同样地,在 grabs 结束前,也应当通过ungrab()方法释放权限, 防止 sequencer的死锁行为。
UVM--Sequencer和Sequence相关推荐
- (18)UVM sequencer和sequence
UVM sequencer和sequence 文章目录 UVM sequencer和sequence 一.概述 二.sequence和item发送实例 三.发送sequence/item方法建议 四. ...
- UVM学习笔记--sequence和sequencer
1. UVM sequence机制的意义 UVM的sequence机制最大的作用就是将test case和testbench分离开来. 对一个项目而言,testbench是相对稳定的框架,而针对各个m ...
- UVM入门与进阶学习笔记16——sequencer和sequence(2)
目录 sequence的层次化 Hierarchical Sequence Virtual Sequence Layering Sequence sequence的层次化 就水平复用而言,在MCDF各 ...
- (17)UVM sequencer和driver
UVM sequencer和driver 文章目录 UVM sequencer和driver 一.概述 二.端口和方法 三.事务传输实例 四.事务传输过程分析 五.通信时序 六.握手建议 关注作者 一 ...
- (8)UVM Sequencer和Driver
UVM Sequencer和Driver 概述 端口和方法 实例 通信时序 握手建议 概述 driver同sequencer之间的TLM通信采取了get模式,即由driver发起请求,从sequenc ...
- UVM知识点总结-sequence
sequence及相关组件 基本的点 (1)uvm_sequence_item可以在uvm_sequece的任何阶段进行创建(2)sequence一旦活动起来就必须挂载在一个sequencer,通过这 ...
- UVM——Sequencer Driver
driver和sequencer之间的通信方式采取get模式,即由driver发起请求,从sequencer一端获得item,再由sequencer将其传递至drive.driver只要可以从sequ ...
- UVM中的sequence
sequence基础 1. 如果将激励放在driver的main_phase中,是可行的,但是如果要对激励作修改,那么扩展性较差,所以我们将激励改为放在sequence中去写. driver就负责驱动 ...
- Sequencer和Sequence
一.sequence和item发送实例 class bus_trans extends uvm_sequence_item;rand int data;`uvm_object_utils_begin( ...
- 关于UVM中的Sequence(一)
1.sequence存在的意义 sequence机制的目的是为了将激励的产生功能从driver中剥离出来.这样在不同的测试用例中,就可以将不同的sequence设置成sequencer的main_ph ...
最新文章
- CEVA引入新的可配置传感器集线器DSP架
- 轨迹规划概念总结——Dubins曲线
- tomcat日志格式中的含义
- ASP.NET MVC视图和控制器之间的传值总结(一)
- jsp九大内置对象和四种属性范围介绍
- scrapy python下载图片_使用Scrapy自带的ImagesPipeline下载图片,并对其进行分类。
- Mongodb亿级数据量的性能测试
- Looksery Cup 2015 B. Looksery Party 暴力
- 基于麻雀算法优化的Tsallis相对熵图像多阈值分割 -附代码
- 对于NAS,IP SAN以及iSCSCI SAN存储的一些认识和理解
- CCNA培训视频教程下载
- 掌握这些,你也可以轻松扒谱(下)
- Unable to find setter method for attribute: [commandName]
- STM32学习心得三十七:MPU6050六轴传感器实验
- 虾皮男装类目市场如何?哪些产品好卖?
- 3岁女儿被骑摩托车男子一把抱走警方贴出寻人启事
- bilibili弹幕获取api
- icns文件_感染phobos家族勒索病毒文件后缀.phobos如何应对处理?
- C语言-出生日期输入输出
- 计算机软件总体上分为,计算机软件分为哪两大类?它们各自的作用是什么?
热门文章
- 嚣张:分库分表就能无限扩容吗?
- 计算机启用来宾用户,win10怎么启用来宾账户_win10启用guest来宾账户的教程
- 用Eclipse读取excel中全部数据
- 上传服务器后字体文件丢失,详解Vue+elementUI build打包部署后字体图标丢失问题...
- 【ArcGIS风暴】ArcGIS标注和注记的区别及用法案例详解
- c语言飞机源代码,C语言写的飞机源码
- wsl arch linux图形,WSL2(Arch Linux)使用systemd
- mysql 美东时间格式_C#/.NET怎么样将UTC时间转换成美国东部时间(EST)
- 如何4步绘制出高水平的气泡图?
- vm虚拟机分配处理器_虚拟机处理器核数与物理cpu的关系