概述
在UVM世界,利用其核心特性,在创建了组件和顶层环境,并且完成组件之间的TLM端口连接以后,接下来就可以使得整个环境开始运转了。
在经过一番实践,掌握了组件之间的TLM通信方式,开辟了建筑之间的道路、桥梁和河道以后,就可以进入紧张繁忙的物流期了运转的必要条件是组件之间需要有事务(transaction)传送,这就同管道连接好需要引入水流一样。如果按交通道路的车流来打比方,sequence就是道路,sequence_item是道路上行驶的货车,sequencer是目的地的关卡,而driver便是最终卸货的地方。从软件实施层面来讲,这里的货车是从sequence一端出发的,经过了sequencer,最终抵达driver。经过driver的卸货,每一辆货车也就完成了它的使命。driver对每一件到站的货物,经过扫描处理,将它们分解为更小的信息量,提供给DUT。
序列组件的互动
sequence
在这个过程中,sequence对象会产生目标数量的sequence_item对象。借助于SV的随机化和sequence_item对随机化的支持,使得产生的每个sequence_item对象中的数据内容都不相同。
产生的sequence_item会经过sequencer再流向driver。
对于一个sequence而言,它会产生多个sequence_item,也可以产生多个sequence。从产生层次来看,sequence_item是最小粒度,它可以由sequence生成,而相关sequence也可以进一步组织继而实现层次化,最终由更上层的sequence进行调度。这么看来,sequence可以看做是产生激励内容的载体。
driver
激励驱动链的最后一道关卡是driver。driver陆续得到每一个sequence_item,经过数据解析,将数据按照与DUT的物理接口协议写入到接口上,对DUT形成有效激励。
当有必要时,driver在每解析并消化完一个sequence_item后,它会将最后的状态信息写回sequence_item对象再返回给sequencer,最终抵达sequence对象一侧。这么做的目的在于,有时sequence需要得知driver与DUT互动的状态,这就需要driver有一个回路将更新过的sequence_item对象写回至sequence一侧。同时再请求下一个sequence_item。
driver与sequencer之间的TLM通信参数即sequence_item类。由于这一限制,使得sequencer到driver的传输数据类型不能改变,同时与sequencer挂接的sequence创建的sequence_item类型也应为指定类型。它会把item中的数据按照与DUT的物理协议时序关系驱动到接口上面。例如对于一个标准的写操作,driver不但需要按照时序依次驱动地址总线、命令码总线和数据总线,还应该等待从端的返回信号和状态值,这样才算完成了一次数据写传输。
sequence_item
sequence_item是driver与DUT每一次互动的最小粒度内容。例如DUT如果是一个slave端,driver扮演master去访问DUT的寄存器,那么sequense_item需要定义的数据信息至少包括访问地址、命令码、数据和状态值,这样的信息在drive取得后,会通过时序方式在interface一侧发起激励送至DUT。
按照一般总线做寄存器访问的习惯,这种访问在时序上大致会保持几个时钟期,直至数据传送完毕,而由driver再准备发起下一次操作。
用户除了可以在声明sequence_item时添加必要的成员变量,也可以添加对这些成员变量进行操作的成员方法。这些添加了的成员变量,需要充分考虑在通过sequencer传递到driver前是否需要随机化。
sequencer
在sequence与driver之间起到桥梁作用的是sequencer。
继承关系
由于sequencer与driver均是component组件,它们之间的通信也是通过TLM端口实现的.uvm_sequence_item和uvm_sequence都是基于uvm_object
,它们不同于uvm_component只应当在build阶段作为UVM环境的“不动产”。进行创建和配置,而是可以在任何阶段创建。
这种类的继承带来的UVM应用区别在于:
- 由于无法判定环境在run阶段什么时间点会创建sequenge和将其挂载(attach)到sequencer上面,所以无法通过UVM环境结构或者phase机制来识别sequence的运行阶段。
- 由于uvm_object独立于build阶段之外,这使得用户可以有选择地、动态地在合适时间点挂载所需要的sequence和item。
- 考虑到uvm_sequence和uvm_sequence_item并不处于UVM结构当中,所以顶层在做配置时,无法按照层次关系直接配置到sequence中。
- 如果sequence一旦活动起来,它必须挂载到一个sequencer上,这样sequence可以依赖于sequencer的结构关系,间接通过sequencer来获取顶层的配置和更多信息。
- 从常规的认知方式来看,用户可能更愿意将时序控制的权利赋予sequence。这种从sequence产生item,继而将item通过sequencer推送给driver的方式,实际上有一些“越俎代庖”的嫌疑。如果明确划分责任的话,sequence应该只负责生成item的内容,而不应该控制item消化的方式和时序,而驱动激励时序的任务应当由driver来完成。
- item的生成和传送,并不表示最终的接口驱动时序,决定这一点的还包括sequencer和driver。sequencer之所以作为一个“路由”管道,设立在sequence和driver之间,主要是它的两个特点:
- sequencer作为一个组件,它可以通过TLM端口与driver传送item对象。
- sequencer在面向多个并行sequence时,它有充分的仲裁机制来合理分配和传送item继而实现并行item数据传送driver的测试场景。
总结
数据传送机制采用的是get模式而不是put模式。在TLM传输中介绍过两种典型的数据传送场景,如果是put模式,那么应该是sequencer将数据put至driver,而如果是get模式,那么应当是driver从sequencer获取item。
之所以选择get模式,UVM是基于下面的考虑:
- 如果是get模式,那么当item从sequence产生,穿过sequencer到达driver时,我们就可以结束该传输(假如不需要返回值的话)。而如果是put模式,则必须是sequencer将item传送至driver,同时必须收到返回值才可以发起下一次的传输。这从效率上看,是有差别的。
- 如果需要让sequencer拥有仲裁特性,可以使得多个sequence同时挂载到sequencer上面,那么get模式更符合“工学设计”。这是因为driver作为initiator,一旦发出get请求,它会先通过sequencer,继而获得仲裁后的item。
这篇笔记参考《UVM实战》、《芯片验证漫游指南》和某验证视频整理而成,仅作学习心得交流,如果涉及侵权烦请请告知,我将第一时间处理。