0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

UVM设计模式之访问者模式

rfdqdzdg 来源:IC Verification Club 2023-08-11 09:28 次阅读

访问者模式

Visitor Pattern:允许一个或者多个操作应用到一组对象上,解耦操作和对象本身。换言之,如果component的数据结构是比较稳定的,但其是易于变化的,那么使用访问者模式是个不错的选择。

常见的访问者模式有五种角色:

(1) Vistor(抽象访问者):为该对象结构中具体元素角色声明一个访问操作接口

(2) ConcreteVisitor(具体访问者):每个具体访问者都实现了Vistor中定义的操作。

(3) Element(抽象元素):定义了一个accept操作,以Visitor作为参数

(4) ConcreteElement(具体元素):实现了Element中的accept()方法,调用Vistor的访问方法以便完成对一个元素的操作。

(5) ObjectStructure(对象结构):可以是组合模式,也可以是集合;能够枚举它包含的元素;提供一个接口,允许Vistor访问它的元素。

举例:老师教学反馈得分大于等于85分或者学生成绩大于等于90分,则可以获得优秀奖;如果老师论文数目大于等于2、学生论文数目大于等于1,则可以获得1万元的现金。在这个例子中,老师和学生就是Element,他们的数据结构稳定不变。从上面的描述中,我们发现,对数据结构的操作是多变的,一会儿评选成绩,一会儿评选科研,这样就适合使用访问者模式来分离数据结构和操作。

两种操作,class GradeSelection class ResearchSelection 重写实现 visit()函数

wKgZomTVjwWAXK5iAAP4jI4N2fo731.jpg

class Teacher class Studnet中调用 visitor.visit(),不需要特别指明哪一种操作。

wKgaomTVjwWABPsSAATFa5DiKuA798.jpg

wKgZomTVjwWAPhBgAAPaxF8B9gc262.jpg

访问者模式适用于对一组结构固定的组件统一地加入一个新的操作,如上例,将student1,student2,teacher1,teacher2这四个共同属性(都继承于Element)的组件,加入ObjectStructure中,此例中的组件关系是前后线性的关系,依次加入element_q队列中。当需要对所有组件执行researchselection操作时,ObjectStructure调用accept(researchselection)即可,会自动遍历各个组件执行这个researchselection的操作。如果需要切换其他操作,只需更改ObjectStructure中accept的参数即可。添加新的操作也很方便,不需要更改组件,只需要在外部重写visitor()函数,具有很好的扩展性,实现组件与操作的解耦。

UVM_PHASE

UVM的环境具有明确的结构,各个组件统一继承于uvm_component, 组成 ** tree structure** 。每个子类component重写各个phase函数,每个component中的phase函数相当于visitor(),很符合使用访问者模式的条件。但是uvm的phase机制实现和上述介绍的示例还有很大区别,component中的phase是在自身内部实现的,而不是放在类外部;对于执行同一个phase,树形结构中的component不是简单的依次执行,有top-down,down-top和并行执行;对于同一个componet中的phase, 有不消耗时间的function phase, 也有消耗时间的task phase, 有依次执行的,也有并列执行的(run_phase和12个run-time phase)。所以存在两个维度,一个uvm_component的维度,根据单例模式中的parent-child关系构建了树状结构;一个phase维度,将每个phase以node的形式放入domain中,统一调度。UVM还支持objection机制,drain_time,timeout,多domain,进程同步,phase的jump,phase_debug等操作,所以简单的访问者模式无法满足要求。

下面根据源码对uvm_phase从这两个维度分析:

1. phase的执行顺序

在第二篇,提到了uvm_root中函数run_test()根据工厂模式创建testcase的实例。接下来run_test()调用uvm_phase中的静态函数m_run_phase()开始执行各个phase。这里用到了SV内建的class process,提供了精细控制进程的方法。

uvm_domain调用静态函数get_common_domain(), 从名字上可以看到这是获得一个domain。uvm_domain继承于uvm_phase,是phase的一个容器。

comon_domain调用add函数依次加入不消耗时间的function phase, 一共9个。第一个uvm_build_phase::get()获得build_phase的实例,uvm_build_phase和uvm_root一样采用了单例模式,所以全局只有一个build_phase,通过 uvm_build_phaes::get()获得。所以我们平常在不同component中的wKgZomTVjwWAGfyNAAADG_EH5-w724.jpg传入的phase,其实指向的都是那个唯一的uvm_build_phaes::get() 实例。其他phase也一样,实例全局唯一。

add()函数实现了将不同phase以node的形式加入,node有predecessor,successor的概念,构成链表结构。类似component中parent,child的关系,构成树状结构。根据add加入的顺序,组织了先后顺序。所以connect_phase_node的predecessor是build_phase_node, successor是end_of_elaboration_phase.

get_uvm_domain()获得另一个domain:uvm_domain。uvm_domain中加入的是task phase, 一共12个。然后common_domain再将uvm_domain和run_phase同时加入,实现rum_phase和12个小phase组成的run-time phase并行执行。

到此,各个phase的执行顺序就固定了。如果没有单独创建domain,那么只有common_domain和uvm_domain这两个domain会被默认创建。结构如下:

wKgaomTVjwWAAe5uAAAujlqzaBQ086.jpg

回到m_run_phases(), 有一个forever begin ... end一直循环从m_phae_hopper.get()获得phase执行exectute_phase()。最开始m_phase_hopper( 一个放入uvm_phase类型的mailbox)放入的是common domain,common domain执行完毕后,会将successor build phase 放入m_phase_hopper中;在forever循环中m_phae_hopper.get()获得build phase,执行完build phase最后会放入build phase的successor connect phase,直到遍历完所有phase。

wKgaomTVjwWAcRRiAAbbZswg0Wg714.jpg

2. component的执行顺序

接上面,phase.execute_phase()的具体实现会根据不同的uvm_phase_type和uvm_phase_state走不同的分支。
uvm_build_phase, uvm_final_phase继承于uvm_topdown_phase, 其余function phase继承于uvm_downtop_phase, task phase继承于uvm_task_phase。

对于build_phase, 函数exectue_phase会调用m_imp.traverse(top,this,UVM_PHASE_EXECUTING), traverse()函数在uvm_topdown_phase中定义,build_phase从top to down的执行顺序也是在这里实现的。

最开始traverse传入的是top,也就是最顶层uvm_root,②处调用get_first_child获得uvm_test_top(在之前的run_test中已被创建),递归调用traverse函数,执行ph.execute(uvm_test_top, phase), 实际调用的是comp.build_phase, 也就是uvm_test_top的 builde_phase()。builde_phase会创建uvm_test_top的child env。执行完ph.exectute,再次执行traverse函数,此时传入的component是env, 执行env的build_phase,创建env的child agt。一直递归循环,实现所有component的创建。

对于继承uvm_downtop_phase的phase,则是从底部开始循环。相比uvm_topdowun_phase,将递归函数traverse放在ph.execute前面,便实现了down to top的顺序。

对于继承uvm_task_phase的函数,虽然递归函数traverse放在ph.execut前面,也是down to top的顺序,但是fork ... join_none让不同component的同一种phase函数在不同process上同时执行,实际效果是一块同时运行的。

所以对于component中phase的执行遍历,是根据调用递归函数遍历child完成的。在uvm_root中的find()函数,也是递归调用函数完成遍历。

wKgZomTVjwWAS7mgAAS-62PXmPY160.jpg

uvm objection

uvm objection涉及对进程的控制,先介绍一下systemverilog提供的class process。(计算机体系中的进程,线程和内核的调度有关,而仿真平台是跑在仿真软件上的,由 simulation kernel进行调度 (IEEE 4.Scheduling semantics clause) 按照时间片执行,以下进程,线程不做区分,统一叫做进程)

SV中的fork相关函数可以创建新的进程,但是对于进程的管理, 只有 wait fork, disable identifier, disable fork这些。其他语言中一般都有专门管理进程的操作方法,比如python中的multiprocessing模块。所以SV中加入了一个class process,提供了更精细的进程管理。class process并不可以用于创建进程,只可以在initial begin ..end,always,fork等创建进程的语句中通过process::self()获取该进程;status()获得进程状态,kill()终止进程及子进程,suspend()挂起进程,resume()恢复进程,srandom(int seed)设置进程的随机种子。

wKgaomTVj4CALdYIAAEIbLqVg_E132.png

uvm objection机制的源代码实现不再探究,总结需要注意的几点:

每个phase的实例是唯一的,每个phase在创建的时候,自动创建了属于这个phase的objection。

对于消耗时间的task phase,其中必须raise_objection, 才会执行,否者直接退出。

对于同一个phase,可以多次raise_objection, 但是raise_objection和drop_objection必须成对存在。只有raise数量等于dorp数量时才会退出这个phase。

raise_objection前面不可以有消耗时间的语句,也就是刚进入phase的0时刻,就需要检测到raise_objection, 否则直接退出这个phase。

对于run_phase和并行的12个task phase, 如果在run_phase中raise_objection,但是main_phase没有raise_obejection,那么main_phase直接退出。如果在main_phase有raise_obejection,run_phase没有raise_objection,run_phase也会执行。所以尽量run_phase和12个小phase不要同时使用,以免出错。

通过简单的代码使用process来实现一下UVM中的objection:

wKgZomTVjwWAENP5AARqjCWBZ8g517.jpg

do_monitor是一个无线循环,在driver_main_phase中控制objection的raise和drop。

如果line42加上时间延迟,则会直接退出main_phase,进入下一个phase. 如果注释掉line43行也是直接退出main_phase,进入下一个phase. 打印结果:wKgaomTVjwWATLxdAAATba_m2Ds400.jpg

如果加上line49, line51,main_phase则无法退出。打印结果:

wKgZomTVjwWAUiZZAAA-ljRw7AA642.jpg

uvm_visitor

UVM1.2中新加入了访问者模式的基础类,供使用者扩展使用:

wKgaomTVjwWAKXaQAADU-MZJQ_U947.jpg

uvm_visitor:提供了visit()方法,以及begin_v(),end_v()两个hook。

重写visit方法,简单的打印component的full_name.

wKgaomTVjwaAV5q7AAL93lM6eUY809.jpg

uvm_visitor_adapter:提供了accept函数,用于实现visitor和component的连接,并对每个component调用visti方法。

wKgZomTVjwaAVjYWAAJoT_UIhnk179.jpg

env中创建visitor, adapter的实例,accept传入的是env这个comonent,打印处uvm_test_top.env

wKgaomTVjwaAUyJpAAKGV5G3qHs181.jpg

对于component的组织调用顺序,用户可以自定义structure。UVM提供了三种sturcture, 对应的adapter,如下:

wKgZomTVjwWAKRriAAEwQB7-9ww049.jpg

使用的top to down的structure, 从上到下遍历component调用visit()函数:

wKgZomTVjwaAFHhqAAYGE2BylyQ650.jpg

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • UVM
    UVM
    +关注

    关注

    0

    文章

    181

    浏览量

    18973
  • 数据结构
    +关注

    关注

    3

    文章

    564

    浏览量

    39905
  • 设计模式
    +关注

    关注

    0

    文章

    53

    浏览量

    8597

原文标题:UVM设计模式 (六)访问者模式、uvm_phase、uvm objection、process control

文章出处:【微信号:数字芯片设计工程师,微信公众号:数字芯片设计工程师】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    如何判断访问者的浏览器是否打开了JAVASCRIPT功能?

    如何判断访问者的浏览器是否打开了JAVASCRIPT功能?作者:Hunte | 收录日期 : 2000-08-21   用这段代码就可以了
    发表于 01-11 09:33

    状态机模式与生产/消费模式的关系

    原来有些明白,但是现在又有点糊涂了 ,状态机模式和生产/消费模式之间到底有没有关系?有的话到底是什么样子的关系?求大神解释!!!!!
    发表于 03-04 11:37

    数字IC验证“什么是UVM”“UVM的特点”“UVM提供哪些资源”(2)连载中...

    会在一定范围内产生,减少无用的激励,提高效率。支持覆盖率驱动模式,根据当前覆盖率的情况,验证工程师可以决定下一步的验证内容,当覆盖率达到了一定的要求时,就可以宣告验证工作的完成。uvm验证平台,它具有很高的可重用性
    发表于 01-21 16:00

    数字IC验证“典型的UVM平台结构”(3)连载中...

    的passitage模式,从图中可以看出,每增加一个测试模块,平台中就会增加一个与相对应的agent,因为这些agent在测试单个模块的时候已经完成了,所以这里只需要将它们集成到一个env当中即可,这体现了uvm测试平台的可重
    发表于 01-22 15:32

    谈谈UVM中的uvm_info打印

    _action‘(UVM_NO_ACTION))。只有上述两都满足的情况下,才会返回1,也就是允许打印message。  uvm_report_info(ID, MSG, VERBOSITY,
    发表于 03-17 16:41

    配置Nginx访问日志

    每当处理客户请求时,Nginx都会在访问日志中生成一个新记录。每个事件记录都包含一个时间戳,并包含有关客户端和所请求资源的各种信息。访问日志可以显示访问者的位置,访问者
    的头像 发表于 05-24 09:59 1998次阅读

    嵌入式软件设计模式 好文值得收藏

    本文引用自本人公众号文章: 嵌入式开发中的两点编程思想   C语言也很讲究设计模式?一文讲透   包含如下: 01)C语言和设计模式(继承、封装、多态)   02)C语言和设计模式访问者
    的头像 发表于 06-20 09:09 1687次阅读

    四种方式来让您以简单模式访问迁移器

    在《库迁移系列 - 前言》中,主要介绍了什么是库迁移器。DigiPCBA专用的库迁移器界面会自动分析您所选择的本地库并将它们迁移到您登录的工作区,实现一键式解决方案。库迁移器可以提供极简的简单界面模式和高级模式两种模式,文中介绍
    的头像 发表于 08-05 10:05 697次阅读

    GoF设计模式访问者模式

    访问者模式的目的是,解耦数据结构和算法,使得系统能够在不改变现有代码结构的基础上,为对象新增一种新的操作。
    的头像 发表于 10-08 11:05 502次阅读

    设计模式访问者设计模式

    访问者设计模式是一种行为型设计模式,用于将算法与对象结构分离。它允许你在不改变对象结构的前提下定义新的操作。
    的头像 发表于 06-06 11:25 585次阅读

    设计模式行为型:访问者模式

    访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。
    的头像 发表于 06-07 15:11 550次阅读
    设计<b class='flag-5'>模式</b>行为型:<b class='flag-5'>访问者</b><b class='flag-5'>模式</b>

    一文详解UVM设计模式

    本篇是对UVM设计模式 ( 二 ) 参数化类、静态变量/方法/类、单例模式UVM_ROOT、工厂模式
    的头像 发表于 08-06 10:38 903次阅读
    一文详解<b class='flag-5'>UVM</b>设计<b class='flag-5'>模式</b>

    行为型设计模式UVM中的应用

    接下来介绍行为型设计模式UVM中的应用。
    的头像 发表于 08-09 14:01 407次阅读
    行为型设计<b class='flag-5'>模式</b>在<b class='flag-5'>UVM</b>中的应用

    迭代模式UVM中的应用有哪些

    行为型设计模式数量较多,上一篇介绍了模板模式和策略模式,下面对迭代模式进行介绍,挖掘其在UVM中的应用。
    的头像 发表于 08-14 17:15 388次阅读
    迭代<b class='flag-5'>模式</b>在<b class='flag-5'>UVM</b>中的应用有哪些

    设计模式中代理模式的使用场景

    官方定义: 代理模式 (Proxy Pattern) 是一种结构型设计模式,通过代理对象控制对原对象的访问,并允许在访问前或访问后做一些处理
    的头像 发表于 10-08 14:34 403次阅读
    设计<b class='flag-5'>模式</b>中代理<b class='flag-5'>模式</b>的使用场景