白皮书---uvm实战笔记(一)

第六章 sequence

1.Seq的启动和执行——将seq和sqr联系起来              P165

有三种不同的方式,大致分第一种为直接启动start(),第二种使用default_sequence,使用default_sequence会自动调用start任务;

在不同的testcase中,将不同的seq设置成sqr.main_phase的default_sequence。当sqr执行到main.phase时,发现有default_sequence,那么它就启动seq

当seq启动后,会自动执行body任务,同时还有回调函数,pre_body和post_body

2.当有一个sqr上启动多个seq时,sqr会启动仲裁机制

首先,一个sqr上启动多个seq,常用的方法是start();

其次可以通过在seq的body()中使用`uvm_do_pri_with对tr进行配置优先级

然后可以通过在testcase的main_phase中通过start()对seq进行配置优先级

最后在testcase的main_phase配置sqr的仲裁方式即可;

注:若只对tr配置优先级,而不对seq配置优先级,sqr还是会交替开启seq,在当前的seq选取优先级最高的tr进行生成

3.当有一个sqr上启动多个seq时,并且一个seq中部分的tr一旦开始发送就要连续发送时,使用lock操作

不对seq配置优先级的话,seq会轮流发送自己的tr,当seq中对部分tr进行lock操作时,当开始执行lock时,sqr会连续生成同一个seq的tr,直至执行unlock后,sqr再交替执行不同seq;

当有多个seq中都进行了lock操作时,sqr的所有权采取先到先得模式

4.sqr的grab操作,类似lock,但是具体不明白

5.seq的有效性

Sqr在仲裁的时候,会查看seq的is_relevant函数的返回结果;如果是1,说明seq有效,否则无效;

因此可以通过重载(virtue function)is_relevant函数来控制seq的有效性;

同时还有一个task wait_for_relevant(),当seq失效之后,sqr会执行别的seq,当执行完了之后,会执行失效了的seq的task wait_for_relevant(),恢复当前seq的有效性,前提是该task中必须要将seq无效的条件清除;

6.uvm_do系列宏

Uvm_do_on有两个参数,第一个参数是tr的指针,第二个是sqr的指针;所以这个宏的作用是显式的指定使用那一个sqr发送这个tr;

而uvm_do会默认由启动时指定的seq发送tr,即seq将sqr的指针放在其自身的成员面量m_sequence中;

也就是说uvm_do 等价于 uvm_do_on(tr,m_sequence)

简单概括就是,pri控制tr的优先级,on指定sqr的指针,with用于加随机条件

7.uvm_create和uvm_send联合使用可以相当于uvm_do,但是过程可以更加灵活

Uvm_create的作用是例化tr,uvm_send是将tr交给sqr

8.uvm_rand_send系列宏

uvm_rand_send系列宏可以随机化tr

该系列的意义在于,如果tr需要的内存比较大,希望前后发送的tr都用同一块内存,可以节省内存

9.uvm__do宏实际上是将一系列的动作封装在了宏里面

具体如下:

tr=new(“tr”);

assert(tr.randomize()with{});

start_item(tr);

finish_item(tr);

可以在start_item和finish_item中加入优先级

10.使用pre_do、mid_do、post_do增加uvm_do的灵活性

11.嵌套的seq

在顶层的seq中嵌套其他的seq 操作如下:

Class top_seq extends uvm_sequence#(my_tr);

       Virtual task body();

              Seq1 seq_1;

              Seq2 seq_2;

              Repeat(10)begin

              `uvm_do(seq_1)

              `uvm_do(seq_2)

              End

       Endtask

Endclass

嵌套seq的前提是,在顶层seq下所有的seq产生的tr都是用一种类型,可以被同一个sqr所接受,不然将会报错;

若想让tr不是用一个类型,程序还能正常运行,可以参考白皮书P186,会稍微复杂一些

12.p_sequencer的使用

其实m_sequencer与p_sequencer本质上是一样的,都是指向同一个sequencer(即sequence start时挂载的那个sequencer)

区别在于它们的类型不同,m_sequencer是sequence的成员变量,其类型为uvm_sequencer_base。而p_sequencer类型为user_sequencer(用户定义的),在sequence中通过uvm_declare_p_sequencer(user_sequencer)可以声明一个为user_sequencer类型的成员变量,之后UVM会在pre_body()阶段之前将通过$cast自动完成m_sequencer转化为p_sequencer的过程(此时p_sequencer指向m_sequencer指向的sequencer)。而m_sequencer的赋值是在sequence启动时即将sequence挂载至某sequencer上时,UVM会自动将该sequencer的句柄赋值给m_sequencer。

为什么引入m_sequencer与p_sequencer?

m_sequencer的引入使得嵌套的sequence得以更加方便地实现,这样就可以在一个sequence中启动其它的sequence,内部这些sequence都可以挂载在m_sequencer中,因为m_sequencer实质上也是最外部sequence挂载sequencer的句柄,因此无论外部sequence今后挂载在哪一个sequencer上,嵌套的sequence都能挂载在同一个sequencer上,当有多个相同类型的sequence时,使用嵌套的sequence能简化了测试代码,提高了可靠性。

p_sequencer的引入是为了解决sequence访问其挂载的sequencer变量的问题,若直接使用m_sequencer会因句柄类型问题编译报错。因为想要访问挂载的sequencer中的变量,应该与该sequencer同一类型,而m_sequencer是uvm_sequencer_base,不同于该sequencer,因此引入了类型与该sequencer一样且值与m_sequencer相同的p_sequencer!

13.virtual sequence和virtual sequencer的实例应用

14. 什么时候需要virtual sequencer?

环境中有多个driver_agent,且这些driver之间需要同步,此时需要virtual sequencer。由于virtual sequence 的body是顺序执行的,所以只需在body调整seq的顺序即可;

virtual sequence:承载不同目标sequencer的sequence群落,实现sequence同步;virtual sequence一般只会挂载到virtual sequencer上,且没有自己的sequence_item,只用于控制其他的sequence执行顺序,起统一调度作用。

virtual sequencer:桥接其它sequencer,即连接所有底层sequencer的句柄(指针),是一个中心化的路由器。virtual sequencer本身并不传送item数据对象,因此不需要与driver进行TLM连接。所以用户需在顶层的connect阶段做好virtual sequencer中各个sequencer句柄与sequencer实体对象的一一连接,避免句柄悬空。

15.在seq中使用config_db去get参数

由testcase中向seq中set参数:

Uvm_config_db#(int)::set(this,”env.i_agt.sqr.*”,”count”,9);

Seq中get参数

Uvm_config_db#(int)::get(null,get_full_name(),”count”,count);

在get函数原型中,第一个参数必须是一个component,而sequence不是一个component,所以这里不能使用this指针,只能使用null或者uvm_root::get();

而使用null的话uvm会自动替换为uvm_root::get();

16.在seq中设置set参数

向sb中传递了一个cmp_en的参数

Uvm_config_db#(bit)::set(uvm_root::get(),”uvm_test_top.env0.scb”,”cmp_en”,0);

Seq向seq传递参数

Uvm_config_db#(bit)::set(uvm_root::get(),”uvm_test_top.v_sqr.*”,”cmp_en”,0);

17.wait_modified的使用

Component一般是在build_phase中调用get函数,并且调用的前提是参数已经被设置过。而seq设置set参数是在task_phase中运行的,当设置一个参数的时候,其时间往往是不固定的,故提供wait_modified检测参数是否已经更新

Uvm_config_db#(bit)::wait_modified(this,””,“cmp_en”);

Void’(Uvm_config_db#(bit)::get(this,””,“cmp_en”,cmp_en);

在seq中一样可以调用

18.put_response和get_response

Sequence机制提供反馈的支持,允许driver将一个response返回给sequence

在seq的task body 中完成uvm_do后,get_response(rsp);

在driver的main_phase中完成发送req后,

       Rsp=new(“rsp”);

Rsp.set_id_info(req);

Seq_item_port.put_response(rsp);

Seq_item_port.item_done();

//当一个tr只对应一个response时,Seq_item_port.item_done(rsp);可以代替最后两句话

19.sequence library

可以满足sqr发送seq的时候,随机从sequence library中选取seq进行发送

第一步:定义sequence library

第二步:在需要加入library的seq中,使用`uvm_add_to_seq_lib

第三步:testcase的build_phase中,

Uvm_config_db#(uvm_object_wrapper)::set(this,”env.i_agt.sqr.main_phase”,”default_sequence”,simple_seq_library::type_id::get());

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值