试写,纯属看书个人理解;无任何实践经验。
框图
- sequence_item,负责定义事务,就是transaction;
- sequence,负责产生事务。注意sequence是uvm_object,不在UVM树形结构里,它要负责
raise_objection
和drop_objection
的工作,从而决定了仿真的结束$finish
。 - sequencer,负责事务相关请求的调度。sequence、sequencer、driver之间有一个完整的协议(这时由OVM之sequence机制的一篇网文了解的。类似总线的握手协议),需要遵守。这个协议,是由uvm内部的factory机制实现。
- driver,负责申请事务。另外还要负责事务到信号的转换。
简单描述
基于UVM实战的代码2.5.2章节。
driver
关键功能,都在task main_phase里。
1. 申请事务transaction。利用的TLM(Transaction Level Model),端口之类的原理。
2. 事务转化为信号级别。
3. 申请事务结束,表明事务处理完成。
4. 循环上述1~3步骤;表示申请下一个事务。注意:是个永久循环,因为driver,不同于uvm_object,不存在仿真生命周期,在仿真过程中,需要保持一直存在。
sequencer
- 只需要factory机制化,就可以了。背后的动作,暂时不考虑,按照OVM的说法,整个sequence机制有一套完整的以事务为接口的传输协议,sequencer只是一个调度者而已。uvm_component之间,就是以事务为单位互连的。
sequence
关键功能都在task body里。注意:sequence必须保证要有task body。
1. starting_phase.raise_objection
;
2. uvm_do宏,发起事务给sequencer。
starting_phase.drop_objection`;
3.
sequence_item
负责定义各种各样的transaction
1. rand变量定义;
2. constraint约束定义;
3. 字段注册。目的是使得各个事务transaction都可以使用下述函数,比如copy/print/compare/pack/unpack等等。
细节理解
最初的验证平台,只需要driver即可,为什么还需要sequence机制?
如果事务在driver里定义,会产生一个问题。比如事务种类繁多,岂不是每次启动一个事务,都要修改driver的main_phase代码部分。
如果定义多个driver,那么会把UVM树形结构搞的乱七八糟。
所以,要从driver里剥离,事务产生(具体包括事务定义、事务产生的步骤)的代码部分。driver只负责事务驱动即可。
补充一句,验证的case_list,是用sequence机制去实现的;并保证了UVM树形结构的单一性、统一性。使得可维护的能力大大加强。
上述解释,也是sequence和sequence_item不属于uvm_componet
的原因。case相关的代码改动,都在sequence和sequence_item里实现。
sequence机制的内部协议
还没做。。
下面是plantuml画图工具的源码,借此备份一下。
@startuml
scale 500*500
driver -> sequencer: seq_item_port.get_next_item(req) ,申请事务
sequence -> sequencer:
driver -> dut: 事务转换为信号,驱动DUT
driver -> sequencer: seq_item_port.item_done()
caption figure uvm sequence机制
@enduml
sequence还有很多细节需要补充
- sequence负责事务的产生;
- sequencer负责sequence和driver之间的事务请求调度;
- sequencer可以并行执行多个sequence;
- sequencer可以按照优先级顺序执行多个sequence;也有lock、grab、is_relevant方式去按照顺序执行多个sequence。
- sequence的uvm_do宏,告知相关sequencer,已经有事务产生了。这个时候如果driver申请事务,sequencer就会把sequence的事务传给driver。
- sequence可以嵌套。意义是新建sequence时,可以利用已有sequence去构建;而不是非得用uvm_do宏定义。方便代码的实现和理解。
- 一个sequencer和一个driver,如何实现传输多种transaction事务?这个是由sequencer和driver类定义时的参数决定的。只需要参数写为
uvm_sequence_item
即可。这时,考虑driver的seq_item_port.get_next_item(req)
,req通过$case(your_tr,req)
去判断请求的事务类型,是哪一种。 - 待续。。。