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相关推荐

  1. (18)UVM sequencer和sequence

    UVM sequencer和sequence 文章目录 UVM sequencer和sequence 一.概述 二.sequence和item发送实例 三.发送sequence/item方法建议 四. ...

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

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

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

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

  4. (17)UVM sequencer和driver

    UVM sequencer和driver 文章目录 UVM sequencer和driver 一.概述 二.端口和方法 三.事务传输实例 四.事务传输过程分析 五.通信时序 六.握手建议 关注作者 一 ...

  5. (8)UVM Sequencer和Driver

    UVM Sequencer和Driver 概述 端口和方法 实例 通信时序 握手建议 概述 driver同sequencer之间的TLM通信采取了get模式,即由driver发起请求,从sequenc ...

  6. UVM知识点总结-sequence

    sequence及相关组件 基本的点 (1)uvm_sequence_item可以在uvm_sequece的任何阶段进行创建(2)sequence一旦活动起来就必须挂载在一个sequencer,通过这 ...

  7. UVM——Sequencer Driver

    driver和sequencer之间的通信方式采取get模式,即由driver发起请求,从sequencer一端获得item,再由sequencer将其传递至drive.driver只要可以从sequ ...

  8. UVM中的sequence

    sequence基础 1. 如果将激励放在driver的main_phase中,是可行的,但是如果要对激励作修改,那么扩展性较差,所以我们将激励改为放在sequence中去写. driver就负责驱动 ...

  9. Sequencer和Sequence

    一.sequence和item发送实例 class bus_trans extends uvm_sequence_item;rand int data;`uvm_object_utils_begin( ...

  10. 关于UVM中的Sequence(一)

    1.sequence存在的意义 sequence机制的目的是为了将激励的产生功能从driver中剥离出来.这样在不同的测试用例中,就可以将不同的sequence设置成sequencer的main_ph ...

最新文章

  1. CEVA引入新的可配置传感器集线器DSP架
  2. 轨迹规划概念总结——Dubins曲线
  3. tomcat日志格式中的含义
  4. ASP.NET MVC视图和控制器之间的传值总结(一)
  5. jsp九大内置对象和四种属性范围介绍
  6. scrapy python下载图片_使用Scrapy自带的ImagesPipeline下载图片,并对其进行分类。
  7. Mongodb亿级数据量的性能测试
  8. Looksery Cup 2015 B. Looksery Party 暴力
  9. 基于麻雀算法优化的Tsallis相对熵图像多阈值分割 -附代码
  10. 对于NAS,IP SAN以及iSCSCI SAN存储的一些认识和理解
  11. CCNA培训视频教程下载
  12. 掌握这些,你也可以轻松扒谱(下)
  13. Unable to find setter method for attribute: [commandName]
  14. STM32学习心得三十七:MPU6050六轴传感器实验
  15. 虾皮男装类目市场如何?哪些产品好卖?
  16. 3岁女儿被骑摩托车男子一把抱走警方贴出寻人启事
  17. bilibili弹幕获取api
  18. icns文件_感染phobos家族勒索病毒文件后缀.phobos如何应对处理?
  19. C语言-出生日期输入输出
  20. 计算机软件总体上分为,计算机软件分为哪两大类?它们各自的作用是什么?

热门文章

  1. 嚣张:分库分表就能无限扩容吗?
  2. 计算机启用来宾用户,win10怎么启用来宾账户_win10启用guest来宾账户的教程
  3. 用Eclipse读取excel中全部数据
  4. 上传服务器后字体文件丢失,详解Vue+elementUI build打包部署后字体图标丢失问题...
  5. 【ArcGIS风暴】ArcGIS标注和注记的区别及用法案例详解
  6. c语言飞机源代码,C语言写的飞机源码
  7. wsl arch linux图形,WSL2(Arch Linux)使用systemd
  8. mysql 美东时间格式_C#/.NET怎么样将UTC时间转换成美国东部时间(EST)
  9. 如何4步绘制出高水平的气泡图?
  10. vm虚拟机分配处理器_虚拟机处理器核数与物理cpu的关系