文章目录
1.概述
在UVM世界,利用其核心特性,在创建了组件和顶层环境,并完成组件之间的TLM端口连接之后,下面使环境运转,运转的必要条件是组件之间需要有事务(transaction)传送。
围绕下面几个核心词来阐述它们的作用、分类以及之间的互动关系。
- sequence item
- sequence
- sequencer
- driver
如果按照交通道路的车流来打比方,sequence就是道路,sequence item是道路上行驶的货车,sequence是目的地的关卡,而driver便是最终目的地卸货的地方。从软件实施的层面来讲,这里的货车是从sequence一端出发的,在经过了sequencer,最终抵达了driver,经过driver的卸货,每一辆货车也就完成了它的使命。而driver对每一件到站的货物,经过它的扫描处理,将它分解为更小的信息量,提供给DUT。
基本概念: - 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模式,get模式是driver从sequencer获取item
序列组件的互动:
- sequence对象会产生目标数量的sequence item对象。借助于SV的随机化和sequence item对随机化的支持,使得产生的每个sequence item对象中的数据内容都不同
- 产生的sequence item会经过sequencer再流向driver
- driver得到每一个sequence item,经过数据解析,将数据按照与DUT的物理接口协议写入到接口上,对DUT形成有效的激励
由于sequence需要得知driver与DUT互动状态,driver在每解析并消化完一个sequence item后,它会将最后的状态信息写回sequence item对象再返回给sequencer,最终抵达sequence对象一侧。
对于常见的用法,driver往往是一个sequence item消化完,报告给sequencer和sequence,同时再请求消化下一个sequence item。
继承关系:
uvm_sequence_item和uvm_sequence都是基于uvm_object,它们不同于uvm_component只在build阶段作为UVM环境的“不动产”进行创建和配置,而是可以在任何阶段创建。
sequence存在的意义:
- sequence是一个组件,可以通过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的仲裁特性看,当多个sequence同时挂载到sequencer上面,driver作为initiator,一旦发出get请求,它会通过sequencer,继而获得仲裁后的item
2.sequence和item
item的使用:
- 如果数据使用来做驱动,应该定义为rand,同时按照驱动协议给出合适的constraint
- 通过宏`uvm_field_XX声明必要的数据成员,以便日后使用uvm_object的基本数据方法的自动实现,例如print()
- UVM要求item的创建和随机化都发生在sequence的body()任务中
- item对象的声明周期始于sequence中的body方法中的create_item(),直到被driver消化后,item生命周期结束,如果要对item做操作,可以合理利用copy()或clone()等数据方法
sequence的分类: - 扁平化(flat sequence)。只用来组织更小的粒度,即item实例构成的组织
- 层次类(hierarchical sequence)。由更高层次的sequence来组织底层的sequence,让这些sequence按照顺序方式或者并行方式,挂载到同一个sequencer上
- 虚拟类(virtual sequence)。是最终控制整个测试场景的方式,鉴于整个环境中往往存在不同种类的sequencer和其对应的sequence,我们需要一个虚拟的sequence来协调顶层的测试场景。 其特点是该序列本身并不会固定挂载于某一种sequencer类型上,而是将其内部不同类型sequence最终挂载到不同的sequencer上面。 这也是virtual sequence不同于hierarchical sequence的最大一点。
sequence中的步骤: - 通过create_item()创建request item对象
- 调用start_item()方法,将item挂载到sequencer上,准备发送item
- 在完成发送item之前,对item进行随机化
- 调用finish_item()方法完成item发送
3.sequencer和driver
driver同sequencer之间的TLM通信采取了get模式,即由driver发起请求,从sequencer一端获得item,再由sequencer将其传递至driver
1.端口连接和方法:
//driver的TLM端口
uvm_seq_item_pull_port #(REQ,RSQ)
//sequence的端口
uvm_seq_item_pull_imp #(REQ,RSP,this_type)
//driver和sequence的端口连接
seq_item_port.connect(sequencer::seq_item_export)
task get_next_item(output REQ req_arg)
采取blocking方式等待从sequence中获取一个item;
function void item_done(input RSP rep_arg = null)
通知sequence当前的item已经消化完毕
function void put_response(input RSP rep_arg)
采用nonblocking方式发送response,成功返回
2.事务传输
sequence_item中:
- 创建item—create_item(bus_trans::get_type(),m_sequence,“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上
4.sequencer 和 sequence
4.1 常用的方法和宏
针对将sequence挂载到sequencer上的应用:
uvm_sequence::start(uvm_sequencer_base sequencer, uvm_sequencer_base parent_sequence = null, int this_priority = -1, bit call_pre_post = 1)
第一个参数:sequencer的句柄
第二个参数:上层sequence
第三个参数:优先级
第四个参数:建议使用默认值指定pre_body()和post_body()执行次序
针对将item挂载到sequencer上的应用
uvm_sequence::start_item(uvm_sequence_item item, int set_priority = -1, uvm_sequencer_base aequencer = null);
第一个参数:item对象
第二个参数:优先级
第三个参数:指定item和其parent sequence挂载到sequencer是否是一个,默认相同
uvm_sequence::finish_item(uvm_sequence_item, int set_priority = -1);
第一个参数:item对象
第二个参数:优先级
通过uvm_sequence::start()来挂载root sequence,而在内部的child sequence则可以通过宏`uvm_do来实现
对于一个item完整传送,sequence要在sequencer一侧获得通过权限
拆解步骤:
- 创建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在完成与driver之间的握手
- 最后执行parent sequence的post_do()
4.2 sequencer 仲裁特性
设置仲裁模式:
uvm_sequencer::set_arbitration(UVM_SEQ_ARB_TYPE val)
- UVM_SEQ_ARB_FIFO: 默认模式。来自sequences的发送请求,按照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的请求被优先授权
锁定机制:lock()和grab()区别
- lock():当sequencer按照仲裁机制授权给该sequence,一旦该sequence拿到授权,就不会将授权返回。只有当sequence执行**unlock()**时,才会释放这一锁定的权限
- grab():下一次授权周期就可以无条件地获取授权,也就是说,当已经有他sequence获得授权时,grab()就无法获得授权
注意:
如果sequence使用了lock()或者grab()方法,必须在sequence结束前调用unlock()或者ungrab()方法来释放权限,否则sequencer会进入死锁状态而无法继续为其余sequence授权。
5.sequence的层次化
5.1 hierarchical sequence
hierarchical sequence本身直接挂载到sequencer上,与virtual sequence 相比,它们两者之间的共同点就是对于各个sequence的协调,不同点在于,hierarchical sequence 面对的对象是同一个sequencer,即hierarchical sequence本身也会挂载到sequencer上面,而对于virtual sequence而言,它内部不同sequence可以允许面向不同的sequencer种类。
5.2 virtual sequence
解决多个sequence挂载到多个sequencer上的问题
如果将各个模块环境的element sequence 和hierarchical sequence都作为可以复用的sequence资源,那么就需要一个可以容纳各个sequence的容器来承载它们,同时也需要一个合适的routing sequence 来组织不同结构中sequencer,这样的sequence和sequencer分别称之为virtual sequence和virtual sequencer.
与上述sequence的不同点:
- virtual sequence 可以承载不同目标表sequencer的sequence群落,而组织协调这些sequence的方式则类似于高层次的hierarchical sequence。virtual sequence一般只会挂载到virtual sequencer上面。
- virtual sequencer 是一个链接所有底层sequence句柄的地方,它是一个中心化路由器
- virtual sequencer本身不传送item数据,不需要与driver进行连接。UVM需要在顶层的connect阶段,做好virtual sequence中各个sequencer句柄与底层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上
5.3 layering sequence
通过层次化的sequence可以分别构建transaction layer、transport layer和physical layer等从高抽象级到低抽象级的transaction转化。这种层次化的sequence构建方式,称之为layering sequence。
参考:
https://blog.csdn.net/SummerXRT/article/details/117752637