UVM入门进阶6:同步通信元件(解决组件同步与进程同步)
参考文档链接:https://verificationacademy.com/verification-methodology-reference/uvm/docs_1.2/html/
本节目录:
- 同步通信元件
- 第一组类:uvm_event、uvm_event_pool、uvm_event_callback
- 第二组类:uvm_barrier, uvm_barrier_pool
1 同步通信元件
SV的同步通信元件:event, semaphore, mailbox
UVM的线程同步,不局限于同一对象中,而针对不同组件之间的同步问题
同步类(保证了封闭性):
- uvm_event, uvm_event_pool和uvm_event_callback
- uvm_barrier, uvm_barrier_pool
补充:
不推荐句柄的形式进行同步:
- 什么是句柄的形式?
c2拿到了c1中例化的event1句柄
两组类指的是这两组:
第一组:uvm_event, uvm_event_pool和uvm_event_callback
第二组:uvm_barrier, uvm_barrier_pool
uvm_callback具有回调特点的同时还能有丰富特性供层次化调用
2 第一组类:uvm_event、uvm_event_pool、uvm_event_callback
学习内容:第一组类:
- uvm_event
- uvm_event_pool
- uvm_event_callback
uvm_event解决问题(详细参考2.5节总结)
- obj与comp的同步
- comp之间的同步
- seq与dri之间的同步
- seq之间的同步
2.1 对比与注意
- 有post/pre trigger回调
- trigger时能传入数据
2.2 uvm_event介绍
不同组件共享一个名称相同的uvm_event,这个uvm_event创建、存放、例化、管理在uvm_pool这一个资源池中,uvm_pool是继承于uvm_object_string_pool#(T)一个参数类
关于uvm_object_string_pool #(T):
T pool [stirng] —>uvm_event pool [“event_name”]
2.3 部分总结(详细参考2.1)
(1) uvm_event_pool不需要例化,就在后台一直工作
(2) 如何在组件中拿到/创建event:
声明一个uvm_event句柄e1
e1.uvm_event_pool::get_gobal("event_name");
//创建或得到了一个event句柄真正的创建其实时在uvm_event_pool自动完成的
(3) 如何触发、被触发、重复触发:
- 与SV不同
- trigger()触发,同时可以传入数据
- wait_trigger()/wait_trigger_data等待
- 重复触发之前一定要reset
(4) 如何增加回调函数:
- 创建一个回调类uvm_callback(按照组件创建的方式)
- 在类里面实现:pre_trigger,post_trigger两种方法
- pre_trigger()有返回值,返回1时表明uvm_event不会被trigger同时不会执行post_trigger(),否则反之
- 最后在event被例化处使用add_callback添加回调函数
(5) 获取等待某个事件的进程数:
- get_num_waiters()
(6) 查看uvm_event状态(即查看是否已被触发)或者说是电平触发
- wait_ptrigger()与wait_ptrigger_data()
(7) 补充:wait_trigger与wait_ptrigger
- wait_trigger边沿触发:同SV中的@
- wait_ptrigger电平触发
2.4 示例代码
(1)transaction&uvm_callback
定义了一个transaction类型edata
定义ecb继承于uvm_event_callback注册肯定跑不掉
- 回调函数的定义与实现
- 回调函数只能是pre_trigger,post_trigger
- 形参data解释:触发时可以传入某些数据
(2)comp1对event1由全局pool进行的例化
通过全局Pool进行例化
e1=uvm_event_pool::get_gobal("e1");
- event pool里面有e1:直接拿到一个句柄
- event pool里面没有e1:帮助创建一个名字是e1的句柄
task run_phase()中的要点:
- edata d = new()
- e1.trigger(d);//把数据传入triggered
- 把callback与event1做个关联
e1.add_callback(cb)
(3)comp2&env
e1.wait_triiger_data(tmp)
:等待被触发同时等待一个数据过来
- tmp默认obj类型
void`($cast(d, tmp)):tmp进行父类转子类的转化
e1.wait_triiger()
:直接等待被触发
(4)总结
2.5 应用场景总结
- uvm_event的使用场景
- uvm_event的使用场景
- uvm_event什么时候使用到
- obj与comp的同步
- comp之间的同步
- seq与dri之间的同步
- seq之间的同步
3 第二组类:uvm_barrier, uvm_barrier_pool
学习内容:第二组类:
- uvm_barrier
- uvm_barrier_pool
3.1 进程同步与uvm_barrier&uvm_barrier_pool
P1:SV中多线程的同步
P2:UVM的组件独立,SV方法收到作用域限制
P3:uvm_barrier解决多个组件同步协调,uvm_barrier_pool全局管理uvm_barrier
P4:继承关系同uvm_event_pool
3.2 uvm_barrier_pool&uvm_event_pool继承于uvm_object_string_pool
3.3 阈值
可设置阈值threshold
等待线程不少于阈值时触发全体线程中的等待
3.4 部分总结
- wait_for()进行等待
- set_threshold()设置触发阈值
3.5 代码示例
(1)comp1&comp2及其获得b句柄
- b.wait_for()
(2)env
env1做了一个裁判员
(3)结果与总结
4 正式进入uvm_callback
之前都是稍微提到组件或obj的回调方法,以及uvm_event_callback,今天我们正式分析uvm_callback机制
4.1 回调的作用
第一段,回调的好处
- 另一种同步方式
- 方便里类的封装复用
第二三四段,如何实现封闭的包扩展新方法
- 类的继承
- uvm覆盖机制
- callback,无需继承何添加新方法,只需要后期定义
4.2 之前学习过什么uvm_callback?
学过uvm_event_callback
学过uvm_object提供了一些callback方法供用户们定义:
1 |
|
默认情况下,这些回调函数do_xxx是定义为空的
如果用户执行了uvm_object::copy()函数,那么在该函数执行末尾会自动执行 uvm_object::do_copy()
do_copy()是copy,的回调函数,uvm_object会在copy()的执行尾端勾住(hook) callback 函数即do_copy()
如果用户自定义了这些回调函数,就可以在对应函数执行结束后再执行扩展后的回调方法
通过这个新添加的类,使得函数回调有了顺序和继承性
关于顺序和继承性的实现,UVM是通过两个相关类uvm_callback_iter和uvm_callbacks #(T, CB)来实现的
如何定义这些callback类:
UVM是通过两个相关类uvm_callback_iter和uvm_callbacks #(T, CB)来实现的
uvm_callback_iter
uvm_callbacks #(T, CB)
4.3 代码示例
(1)trans数据类以及callback定义
- trans数据类
- obj注册
- 定义cb1
- obj注册
- 虚函数,名称随便起
- 定义cb2继承于cb1
- override do_trans
你可以在callback里面定义任何你想定义的函数名称:这里我们定义了do_trans函数
(2)comp1定义
- 定义comp1
- 注册(关联)comp1与cb1两个类的关系,方便之后检查(其实也可以不写,类型不同时无法提醒警告,参考4.4节)
uvm_register_cb(comp1, cb1)
- run_phase中插入callback
- 插入callbacks:
uvm_do_callback(comp1, cb1, do_trans(d))
- 参数解释:我在comp1里面调用cb1类型的callback,callback方法名为do_trans(d),d为传入参数
- 插入callbacks:
- 注册(关联)comp1与cb1两个类的关系,方便之后检查(其实也可以不写,类型不同时无法提醒警告,参考4.4节)
(3)env与输出结果
- 构造函数
- 例化comp1,cb1,cb2
- build_phase
- 添加callbacks进行绑定:
uvm_callbacks # (comp1)::add(组件实例句柄, callback实例句柄1)
- 实现callback与comp1进行绑定
- 添加callbacks进行绑定:
uvm_callbacks # (comp1)::add(组件实例句柄, callback实例句柄2)
- 实现callback与comp1进行绑定
- cb2没有注册为什么添加到m_cb2到c1可以?:因为cb2继承cb1,一旦发生继承关系你不需要再进行绑定
- 添加callbacks进行绑定:
comp1的run_phase最终执行顺序:
- run_phase原来部分程序
- cb1.do_trans(d)
- cb2.do_trans(d)
三个步骤:
①注册你的callback
②绑定以及插入callback
③添加callback
4.4 总结:结对子
UVMcallback与SVcallback没区别,建议使用UVMcallback,更为标准化
部分函数总结
- 组件创建时注册:
uvm_register_cb(组件类名, callback类名)
组件对应位置插入:
uvm_do_callback(组件类名, callback类名, callback内回调方法名(回调传入数据参数))
环境中添加:
uvm_callbacks # (组件类名)::add(组件实例句柄, callback实例句柄)
控制回调函数的层次(了解):
`uvm_do_callbacks_exit_on(T,CB,METHOD,VAL)
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!