sequence和sequencer — UVM

简介

发送item的过程:

  • sequence是产生sequence item对象的地方,也可以产生sequence对象来实现sequence层次化;
  • 产生sequence item经过sequencer流向driver;
  • driver得到sequence item后,将数据按照与DUT的物理接口协议写入到接口上,对DUT形成有效激励;如果DUT与driver要进行互动,需要driver返回一个sequence item,经过sequencer到达sequence;

基本概念:

  • sequence item是driver与DUT互动的最小粒度内容;
  • 通过SV的随机化和sequence item对随机化的支持,产生的每个sequence item对象中的数据内容都不同;
  • driver和sequencer的通信时通过TLM端口实现;
  • driver 和 sequencer 是component ;uvm_sequence_item 和 uvm_sequence 是object;
  • uvm_sequence 和 uvm_sequence_item并不处于UVM树结构中,所以顶层无法直接做配置。sequence活动起来,会挂载在sequencer上,这样sequence就可以依赖于sequencer的结构关系,通过sequencer来获取顶层配置
  • 数据传送机制采取的get模式,而不是put模式;

sequencer存在的意义?

  • sequencer是一个组件,可以通过TLM端口与driver传输item对象;
  • 当有多个sequence挂载在sequencer上时,sequencer有充分的仲裁机制来合理分配和传送item,继而实现并行item数据传送至driver的测试场景;
  • 由于sequence是一个object,而uvm_object是独立于build阶段的,这就使得用户可以有选择地、动态地在合适时间点挂载所需的sequence和item;

选取get()模式的原因?

  • 如果是get模式,那么当item从sequence产生,穿过sequencer到达driver时,我们就可以结束该传输。而如果是put模式,则必须是sequencer将item传送至driver,同时必须收到返回值才可以发起下一次的传输。从效率上看,是由差别的。
  • 如果需要让sequencer具有仲裁的特性,使得多个sequencer同时挂载sequencer上,那么get模式更符合“工学设计”。这是因为driver作为initiator,一旦发出get请求,会先通过sequencer,继而获得仲裁后的item。

1.sequence 和 item

item的使用:

  • 如果数据域使用来做驱动,应该定义为rand,同时按照驱动协议给出合适的constraint
  • 通过宏`uvm_field_xxx声明必要的数据成员,以便日后使用uvm_object的基本数据方法的自动实现,例如print( );
  • UVM要求item的创建和随机化都发生在sequence的body()任务中;
  • item对象的声明周期始于sequence中的body方法中的create_item(),直到被driver消化后,item生命周期结束;如果要对item做操作,可以合理利用copy()或clone()等数据方法。

sequence的分类:

  • flat sequence只产生和发送item ;
  • hierarchical sequence,区别于flat sequence的地方在于它可以使用其他sequence和item,具有层次;
  • virtual sequence ,区别于hierarchical sequence,该序列本身不会固定挂载与某一个sequencer类型上,而是将内部不同类型的sequence最终挂载到不同目标的sequencer上

sequence中的步骤:

  • 通过create_item()创建 request item对象
  • 调用start_item()方法,将item挂载到sequencer上,准备发送item
  • 在完成发送item之前,对item进行随机化
  • 调用finish_item()方法完成item发送

2.sequencer 和 driver

1. 通信方式——TLM端口

driver的TLM端口:

  • uvm_seq_item_pull_port #(REP,RSQ) seq_item_port

sequencer的端口:

  • uvm_seq_item_pull_imp #(REQ,RSP,this_type) seq_item_export

driver和sequencer的端口连接:

  • driver::seq_item_port.connect(sequencer::seq_item_export)

端口中定义的常用方法:

  • task get_next_item (output REQ req_arg)

    采取blocking方式等待从sequence中获取一个item;

    注:这个方法属于uvm_sequencer中的方法,在layering sequencer中会提到

  • function void item_done(input RSP rep_arg = null)

    通知sequence当前的item已经消化完毕

  • function void put_response( input RSP rep_arg )

    采用nonblocking方式发送response,成功返回1

2.事务传输

sequence_item中:

  • 创建item —— create_item(bus_trans::get_type(),m_sequencer,“rsp”);
  • 发送item—— start_item() 等待获取sequencer的授权许可,立即返回结果;
  • 在start_item()和finish_item()之间,对item做随机化;
  • 完成发送item——finish_item(),阻塞,等待driver的item_done()返回;
  • 如果driver返回rsp,可调用get_response对rsp处理,注意做句柄转换

driver中:

  • 通过TLM端口seq_item_port.get_next_item(REQ),从sequencer获取item;
  • clone() 获取的REQ,生成response item;
  • 通过seq_item_port.item_done(RSP),告诉sequence item已经”消化“完毕;

高层环境中:

  • connect_phase中对TLM端口做连接,driver.seq_item_port.connect(sequencer.seq_item_export)完成driver和sequencer的连接

在顶层test中:

  • 利用uvm_sequnce类的方法,uvm_sequnce::start(“sequencer的句柄”)实现sequence挂载到sequencer上

3. 通信时序

  • 无论是flat sequence 还是 hierarchical sequence,进一步切分的话,流向sequencer的都是sequence item;通过create_item创建item,继而通过start_item()尝试从sequencer那里获取通过的权限;
  • driver一侧始终通过 get_next_item()尝试从sequencer那获取item;
  • sequencer将通过权限交给底层的sequence之前,目标sequence中的item应该完成随机化;sequence在获得sequencer通过权限后,执行finish_item(),但这个是阻塞的方法,不会立刻执行结束。
  • item将穿过sequencer到达driver一侧,由driver消化;
  • driver在消化完item后,执行item_done()方法来告知sequence已经完成数据传输,完成一次握手;如果driver通过item_done(rsp)将RSP作为状态值返回,sequence可以选择调用get_response(rsp),此时finish_item()才算真正的结束。

建议:

  • 多个sequence同时向sequencer发送item时,每个item都会在sequence创建时就自带一个id值。driver在返回response item时,可以使用rsp.set_sequence_id(req.get_sequence_id())给response item设置同样的id值,发送至对应的源sequence;
  • 尽量不要直接对req直接做操作然后当做response item返回给sequence,这样会延长request item的寿命,也会导致request item原始数据记录丢失。通过clone()的方式创建response item,在进行操作;
  • 修改原有sequence item时,通过继承原有sequence item的方式定义新的item;
  • 注意get_response()传递的是uvm_sequence_item 类型的句柄,get_next_item() 传递的是一个REQ类型的句柄,任务执行完后,要做类型转换后得到正确的句柄在进行后续操作;

3.sequence和sequencer

1.常用方法和宏的定义

1.将sequence挂载到sequencer上

  • uvm_sequence::start(“sequecer 句柄”,“上层sequence”,”优先级“,“指定pre_body()和post_body()执行次序”);
  • 一般在顶层test中将顶层sequence挂载到sequencer上,挂载前需要将sequence例化;

2.将item挂载到sequencer上

  • uvm_sequence::start_item(“item对象”,“优先级”,“指定item和其parent sequence挂载到的sequencer是否是一个,默认相同”)
  • uvm_sequence::finish_item(“item对象”,”优先级“)

3.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_item_done()来将item发送至driver在完成与diver之间的握手。
  • 最后执行parent sequence的post_do();

4.宏(红宝书P384)

  • 只能在sequence中被调用 ,一般在sequence中的body()任务中调用;
  • 如宏`uvm_do(item)就将create_item等方法封装了
  • 避免使用fork…join_any或fork…join_none来控制sequence的发送顺序,避免产生sequence死锁的问题。

2. sequencer仲裁特性

  • 通过uvm_sequencer::set_arbitration(“UVM预定枚举类型的仲裁模式”) 设置仲裁模式;(P385)
  • uvm提供的两种锁定机制:lock()和grab()

lock()和grab()的区别:

  • lock():当sequencer按照仲裁机制授权给该sequence,一旦该sequence拿到授权,就不会将授权返回。只有当sequence执行unlock()时,才会释放这一锁定的权限;
  • grab():下一次授权周期就可以无条件地获取授权。也就是说,当已经有其他sequence获得授权时,grab()就无法获得授权。

4.sequence的层次化

1. hierarchical sequence

  • hierarchical sequence本身直接挂载到sequencer上

2. virtual sequence

解决多个sequence挂载到多个sequencer上的问题

  • virtual sequence中有各个子模块环境的sequence,
  • virtual sequence中使用宏`uvm_declare_p_sequencer定义了一个virtual sequencer类型的变量p_sequencer通过p_sequencer可以索引到virtua sequencer中的声明的各个sequencer句柄
  • virtual sequencer中有各个子模块环境的sequencer句柄,其本身并不传递item,承担一个路由的作用;
  • 顶层环境中例化virtual sequencer,然后将virtual sequencer中各个sequencer句柄同各个子模块中的sequencer实例做连接,避免句柄悬空;
  • 顶层test中将virtua sequence挂载在virtual sequencer上

注意:

  • 宏`uvm_declare_p_sequencer(virtual_sequencer)的作用:1.定义了一个virtual_sequencer p_sequencer;2.做了$(p_sequencer,m_sequencer)的类型转换;
  • 在顶层test将virtua sequence挂载在virtual sequencer上之后,virtual sequence中的p_sequencer变量就可以索引到virtual sequencer中的声明的各个sequencer句柄;
  • 在virtual sequence中,使用宏`uvm_do_on(“各个sequence”,p_sequencer,“virtual sequencer中的各个sequencer句柄”),将不同sequence的item指向不同的sequencer

3. layering sequence

将高抽象级的item,通过层次化的sequence,转变为底层的item。这种层次化的sequence称为layering sequence。

  • 转化层adapter sequence会不断forever接收高抽象级layer sequence传送过来的高抽象级item,将其转化为底层item,然后发送底层item;
  • adapter sequence挂载的sequencer(phy_master_sequencer)中要声明layer sequencer句柄;
  • 顶层环境中将phy_master_sequencer同driver做连接
  • 顶层test中将layer sequence挂载在layer sequencer上,adapter sequence挂载phy_master_sequencer上;并且将phy_master_sequencer中声明的layer sequencer句柄同实例做连接;

adapter sequence中如何找到layer sequence传送过来的高抽象级item?

  • 过程:adapter sequence — (p_sequencer) —> layer sequencer ——> 高抽象级item

  • 因为adapter sequence挂载在phy_master_sequencer上,通过在adapter sequence中使用宏`uvm_declare_p_sequencer(phy_master_sequencer) 声明p_sequencer,;

  • phy_master_sequencer中声明layer sequencer句柄,而layer sequence是挂载在layer sequencer上的;

  • 在顶层test中将phy_master_sequencer中声明layer sequencer句柄同layer sequencer的实例做连接;

  • 这样在adapter sequence中就可以通过p_sequencer.layer_sequencer.get_next_item(req),获取layer sequence中发送的高抽象级item。

  • 9
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小verifier

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值