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

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

3天内不再提示

行为型设计模式在UVM中的应用有哪些呢?

rfdqdzdg 来源:IC Verification Club 2023-08-07 10:19 次阅读

模板模式

Template method patttern: 在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。

模板模式的使用很简单,就是 继承 + 重写 的配合使用。在父类中定义一函数XXX(), 里面封装了函数 pre_XXX()和函数 post_XXX(), 当执行函数XXX()时,会自动执行 pre_XXX(), post_XXX(), 相当于在父类中固定了这种执行流程,pre_XXX() -> XXX() -> post_XXX()。pre_XXX(), post_XXX()扩展了XXX()的功能。子类继承父类,根据需求重写。pre_XXX(), post_XXX()相当于hook, 也可以广义的称为回调函数,但是和回调函数仍有区别,在下一节具体阐述。

UVM中常见:

squence中的start()前后插入pre_start(),post_start(), body()前后的pre_body(), post_body();

uvm_object中copy()被调用会自动执行do_copy(), compare()中的do_compare(), print()中的do_print(), pack()中的do_pack(), unpack()中的do_unpack()。

phase中的pre_xxx_phase, post_xxx_phase

SV调用randomize()自动调用pre_randomize(), post_randomize()。

这里就不在一一列举和代码展示了,

策略模式

Strategy Pattern: 定义一种算法类,将每个算法分别封装起来,让它们可以相互替换。算法调用者只需包含抽象算法的类然后调用算法,算法的具体实现被独立出来,保持主体的结构稳定。

策略模式让具体算法独立于算法的调用者,这里的算法指一个具体的行为,具备多态特性,可以实现重写,算法的调用可以简单理解为一个函数被调用。策略模式其实就是 组合 + 多态 的配合使用。

在第一篇中,提到了composition这个单词,也就是组合,合成的意思。相对于继承(Inheritance),合成使用了“有”(has-a)的关系,继承使用了“是”(is-a)的关系。对于抽象算法的实现,可以联系到第一篇中提到的interface class, 一种面向接口编程的特性。

下面将 composition 和 interface class两种结合起来,使用Systemverilog编写一个简单的策略模式的示例:

1. car 两个子类,sedan轿车和truck卡车,都需要请求加油。

2. 抽象类add_oil_behavior_interface, 两个子类 add_gasoline add_diesel 是一种 add_oil “算法” 不同的实现,一个加汽油,一个加柴油。

3. 在testbench中,通过set_oil_type将实例对象传入。类的多态,调用add_oil, 根据对象调用实际“算法”。

4e4ad46e-3446-11ee-9e74-dac502259ad0.png

上面的例子通过策略模式构建,似乎有些繁琐,通过if else判断是卡车还是轿车选择加什么油,更简单明了。但是这里仅仅使用了一种车加油的“特征”,如果有更多种类的车,更多特征,比如载人数量,车身颜色,组件型号等,使用if else对各种类型的车做归类将使代码难以维护。如果卡车有一天加了汽油,只需要set_oil_type(add_gasoline_h)就可以完成,通过if else编写的代码显然hardcoding了。

上述代码还不够make sense,无路是汽车还是卡车,当被创建时,应该有一个default的默认加油方式,所以可以改写如下:

在汽车或者卡车被创建时,就指定一种加油方式。line20将卡车切换成加汽油,line24再切换成加柴油时,报错。因为变量被 protected 修饰,不可以在类外部调用。

4e9ffde0-3446-11ee-9e74-dac502259ad0.png

UML图:

4ef69e2a-3446-11ee-9e74-dac502259ad0.png

所以策略模式的 “策略” 体现在对算法的调用和算法的实现的解耦,我们把“算法”(具体函数处理)封装到一个抽线类中,在调用类中声明这个抽象类(这便是composition,调用类可以使用抽象类的方法),对抽象类实现或者重写成多个子类,调用类调用算法时,根据内部抽象类句柄指向的具体的子类对象,调用子类对象的”算法“(多态)。

策略模式很实用,在纯软件编程中非常常见。在UVM源码中也应用到了策略模式,比如default_sequence和uvm_callback。UVM中使用的策略模式和纯软件编程中所总结的策略模式稍有不同,但核心是一样的,通过 “ 组合 + 多态” 的方式,实现对算法的调用和算法的实现的解耦。

default_sequence

构建用例创建的sequence继承于uvm_sequence, 继承关系如图:

4f22f36c-3446-11ee-9e74-dac502259ad0.png

sequence不像component一样,没有被UVM赋予phase机制,sequence的运行需要“挂载”在sequencer上,一般有三种方式(UVM设计模式 (六)命令模式、三种sequence启动方式、start_item/finish_item、中介模式、virtual sequence):

1:采用default_sequence的方式启动

2. 直接调用sequence的start()函数启动

3. 在virtual sequence中调用uvm_do宏启动sequence

下面梳理下default_sequence中策略模式的应用:

1. 将case0_sequence“挂载”到sequencer上。

2. uvm_sequence_base中的虚函数start()调用了pre/post_start(), pre/post_body(),以及body()函数,这些函数都是虚函数,且没有定义任何操作。case0_sequence重写body()函数。

3. 当执行到main_phase()时,会执行uvm_sequencer_base中的start_phase_sequence()函数,uvm_config_db#() get::()获得case0_sequence的type_id, 然后调用factory的create_object_by_type创建case0_sequence的实例。(参考上一节工厂模式) $cast中的seq是uvm_sequence_base类型,多态。

4. 调用seq.start(), 执行body()函数的代码。

5. 只有使用default_sequence的方式启动,case0_sequence中starting_phase才不等于 null.

(只摘取了与策略模式有关的 code) +

4f536268-3446-11ee-9e74-dac502259ad0.png

default_sequence的方式启动,会调用seq.start()函数来运行body()函数的代码, 不同用例body()函数的实现不同,这里的body()就相当于策略模式中的“算法",将body()函数的实现放在子类sequence中重写,实现解耦。

不同之处是,UVM中通过 confid_db和facotry结合创建sequence,更灵活。抽象类使用的是virtual class而不是interface class,区别在第一篇中有阐述。UVM设计模式(一)

callback

在学习uvm_callback之前,先看一下如何用Systemverilog写一个简单的callback。

1. 抽象函数Driver_cbs定义了抽象函数pre_tx(), post_tx(),然后子类Driver_cbs_drop重写了pre_tx()函数,实现了每100个事务随机丢弃1个事务的功能。在class Driver中声明了这个抽象类的队列 cbs[$] 。

2. 在test中创建Driver_cbs_drop的实例对象,然后放入到cbs[$]这个队列中。可以放进去的原因是类的多态,父类句柄可以指向子类对象。

3. 遍历cbs[$]中放入的callback类,执行子类对象的pre_tx()函数。

源代码:《SystemVerilog 验证-测试平台编写指南》 8.7 :

4f9f4930-3446-11ee-9e74-dac502259ad0.png

上述的callback和策略模式的实现方式一样(组合 + 多态),在Driver类声明抽象类,然后调用抽象类中的函数,根据类的多态,实际调用的是子类重写过的函数。解耦pre_tx()函数的实现与调用,保持代码结构稳定,提高扩展性。

不同点在于callback定义的 pre_tx() 更像一个hook钩子,callback 常在VIP中使用,为了满足不同使用者的需求(在 driver中实现注错或者异常 ;在 monitor中收集功能覆盖率;或者实现控制 objection 的 raise/drop功能 ),设计VIP的人员需要留出这个hook供使用者根据业务需求自行定义,使用者不需要了解VIP driver的具体实现,只关心这个hook的实现。从这点来看,callback和上一节中的模板模式更接近,只不过实现方式不同,模板模式利用 继承+重写 实现。callbcak提供的hook相比模板模式提供的hook,扩展性和复用性更好,但是实现更复杂些。实际工作根据业务需求选择合适方式预留hook。

而纯软件中的策略模式是为了将一类算法归一抽象,然后分别实现。侧重于每一种算法的相互替代,使算法的变化独立于使用它们的客户端(这里的客户端指使用算法的代码)。通过解耦控制模块代码的复杂度和代码量,解决大量使用if-else分支判断逻辑。除此之外,策略模式还能满足开闭原则呢,添加新策略的时候,最小化、集中化的代码改动,减少引入bug的风险。

但是遵循第一篇中提到的KISS(Keep It Stupid Simple)原则,怎么简单怎么来,就是最好的设计,非得用策略模式,搞出n多类,反倒是一种过度设计。设计模式之美

uvm_callback

uvm_callback的大体结构与上一节提到的callbcak类似,具体实现细节不在列举(可参考《UVM1.1 应用指南及源码分析》- 19 callback机制源码分析 ),分析侧重日常调用以及策略模式的相关内容:

下图红框由VIP开发者或者平台搭建者完成,黄框为callback调用者完成。

1. 设计一个class A包含虚函数pre_tran()作为hook,供driver调用。typedef 将 A_pool 定义为 uvm_callbacks#(my_dirver, A) 类型的参数化的类。(class A相当于上节的 class Driver_cbs)

2. class my_callback 继承 class A, 重写 task pre_tran()。(class my_callback相当于上节的class Driver_cbs_drop)

3. 在tc的connect_phase()中创建my_callback的对象,调用静态函数 A_pool::add(),完成对uvm_callbacks_base类中静态关联数组m_pool的赋值。(uvm_pool看成关联数组, uvm_queue看成队列, m_pool索引为object(drv), 值为存放uvm_callback(my_cb)的uvm_queue )( 此处的 uvm_queue相当于上节的 cbs[$] 队列,调用函数 add()相当于上节 cbs.push_back(dcd) 。)

(不同之处,UVM引入了 m_pool 这个关联数组作为 “池子“,可以存放 A类型的 callback, 也可以存放 B类型的 callback, 所以 A类型对应一个队列,B类型对应一个队列。此例中只用到了m_pool 。class uvm_typde_callbacks # (type T = uvm_object) 中还有一个静态变量 m_tw_cb_q ,当 A_pool :: add (null, my_cb),第一个参数为 null,则 my_cb放入m_tw_cb_q队列中。null则不指定具体 instance,表明该 callback对这个 type实例的对象都有效 。m_pool全局只有一个,而m_tw_cb_q则每个 type对应一个)

4. `uvm_register_cb宏展开,调用静态函数m_register_pair(), 完成callback与object的配对。试想,如果平台设计者设计了callback A 给driver使用 `uvm_register_cb(my_driver,A),callback B给monitor使用 `uvm_register_cb(my_monitor,B),以及其他很多callback。而使用者在调用callback时却在A_pool::add() 中误加入了类型B的callback, 编译仿真都正常进行,但是实际hook并没有被调用。幸运的是,会打印一个warning供使用者debug,帮助他及时发现前面的错误。

4fccc428-3446-11ee-9e74-dac502259ad0.png

5. `uvm_do_callbacks(T,CB,THIS,METHOD)展开后,创建uvm_callback_iter的实例,这个类提供的是iterator迭代器的功能,因为所有callback都放在了容器 m_pool 或 m_tw_cb_q 中,在此处调用的callback需要满足 uvm_object=my_driver, uvm_callback = A 的条件,需要对容器检索遍历获得。如上节单独的foreach循环无法满足要求,所以UVM提供了一个迭代器类专门负责此事。该示例中重复的过程如下:(此处对 uvm_queue的遍历相当于上节通过 foreach()对 cbs[$] 的遍历过程)

通过 m_get_q() 函数在 m_pool 中找到 和driver相对应的 callback uvm_queue(ref类型,赋值给get_first()函数中的q变量),然后在q队列中找到A类型的callback, 调用callback中的函数。然后重复执行上述步骤,直到 cb == null 结束。

uvm_queue中可能会放不同类型的callback,通过 $cast筛选出符合的类型。

如果使用 A_pool :: add (null, my_cb), 则是对m_tw_cb_q 队列的遍历,这里没有列出。

更多内容见:UVM设计模式 ( 五 ) 迭代器模式、Python/SV中的迭代器、uvm_callback_iter、scoreboard中的迭代器

+ (源代码UVM实战 9.1.4):

4fe34e64-3446-11ee-9e74-dac502259ad0.png

根据上述红色斜体的内容描述,UVM中的callback和SV中的callback使用思路一致,也是 组合 + 多态 的实现方式,和策略模式一样。通过UVM工厂模式的重写功能也可以实现callback的效果,选择哪种方式要根据实际场景。

扩展使用

在实际工作中,可以采用策略模式进行解耦,将那些经常变化的“内容”抽象出来,在外部分别实现。

下面列举DVCon上的两篇策略模式实际应用的文章:

2016 DVCon US : Design Patterns by Example for SystemVerilog Verification Environments Enabled by SystemVerilog 1800-2012

将PackBehavior和CheckBehaviro这两个"行为”从base_packet中拎出来,外部实现重写interface class, 构建了 v1_pack, v2_pack, v3_pack, Parity, Crc这几个类。

根据不同版本V1,V2,V3继承base_packet,创建v1_packet, v2_packet, v3_packet类,调用setPackBehaviro(), setCheckBehaviro()赋予不同的"行为“。

504401aa-3446-11ee-9e74-dac502259ad0.png

2019 DVCon INDIA : Using Software Design Patterns in Test Bench Development for a Multi-Layer Protocol

和上一篇类似,也是对packet中的pack_behaviro和check_behavior的操作。业务是DSI中的PHY layer。

50a5d06a-3446-11ee-9e74-dac502259ad0.png





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

    关注

    14

    文章

    1011

    浏览量

    83580
  • UVM
    UVM
    +关注

    关注

    0

    文章

    181

    浏览量

    19119
  • 解耦控制
    +关注

    关注

    0

    文章

    29

    浏览量

    10191
  • UML技术
    +关注

    关注

    0

    文章

    5

    浏览量

    1364
  • 迭代器
    +关注

    关注

    0

    文章

    43

    浏览量

    4296

原文标题:UVM设计模式 ( 四 ) 模板模式、策略模式、default_sequence、uvm_callback

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

收藏 人收藏

    评论

    相关推荐

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

    。可以不改变平台代码的基础上改变平台的行为,以产生不同类型的激励。平台可以不同的验证工程之间进行移植,善于利用uvm提供的各种机制。可以使验证平台具有极强的可重用性。
    发表于 01-21 16:00

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

    应用的过程,将uvm的组件封装起来,可以将这些封装的组件作为一个整体进行重用,进行芯片级或者是系统级验证的时候,往往会出现多个模块的验证。  此时,测试平台的结构会发生变化,图中
    发表于 01-22 15:32

    数字IC验证之“构成uvm测试平台的主要组件”(4)连载...

    的agent为agent的passive模式。  scoreboard积分板,它将会从两个地方获取数据,一个是参考模型发来的期望值,另一个是从slave agent发来的dut的输出值。积分板对这两个
    发表于 01-22 15:33

    什么是uvmuvm的特点哪些

    直观的印象,就是uvm验证平台,它是分层的结构。图中的每一个巨型框都代表着平台的一个构成元素。这些元素,我们称为平台组建,下面来简单的分析一下。从最底层上来看,agent 包含了driver,monitor和sequence
    发表于 02-14 06:46

    UVM sequence分层哪几种方式

    种请求下可以使用第一种分层方式,high-layer sequence依然使用low-layer sequencer进行驱动,同时对low-layer sequence进行更加精细化的控制
    发表于 04-11 16:37

    谈谈UVMuvm_info打印

    上有\`uvm_file和\`uvm_line的传参,它们定义如下:  `define uvm_file `__FILE__  `define uvm_line `__LINE__  
    发表于 03-17 16:41

    设计模式行为:策略模式

    策略模式(Strategy Pattern),一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于
    的头像 发表于 06-07 11:18 619次阅读
    设计<b class='flag-5'>模式</b><b class='flag-5'>行为</b><b class='flag-5'>型</b>:策略<b class='flag-5'>模式</b>

    设计模式行为:状态模式

    状态模式(State Pattern),类的行为是基于它的状态改变的。这种类型的设计模式属于行为
    的头像 发表于 06-07 11:20 561次阅读
    设计<b class='flag-5'>模式</b><b class='flag-5'>行为</b><b class='flag-5'>型</b>:状态<b class='flag-5'>模式</b>

    UVMuvm_config_db机制背后的大功臣

    本次讲一下UVMuvm_config_db,UVM中提供了一个内部数据库,可以在其中存储给定名称下的值,之后可以由其它TB组件去检索。
    的头像 发表于 06-20 17:28 1297次阅读

    如何用Verdi查看UVM环境的变量?

    我们常用的debug UVM的方法是通过打印log实现。有没有办法像 debug RTL代码一样将 UVM 变量拉到波形上看?答案是有的,下面让我们看看是怎么做到的。
    的头像 发表于 06-25 16:01 1578次阅读
    如何用Verdi查看<b class='flag-5'>UVM</b>环境<b class='flag-5'>中</b>的变量?

    UVMuvm_config_db机制背后的大功臣

    本次讲一下UVMuvm_config_db,UVM中提供了一个内部数据库,可以在其中存储给定名称下的值,之后可以由其它TB组件去检索。
    的头像 发表于 06-29 16:57 1178次阅读

    一文详解UVM设计模式

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

    行为设计模式UVM的应用

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

    迭代模式UVM的应用哪些

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

    UVM设计的sequence启动方式哪几种

    本篇介绍UVM的sequence,这是UVM中最基础的部分。对于前面介绍的uvm_callback, uvm_visitor等,很少被使用
    的头像 发表于 08-17 10:07 3881次阅读
    <b class='flag-5'>UVM</b>设计<b class='flag-5'>中</b>的sequence启动方式<b class='flag-5'>有</b>哪几种<b class='flag-5'>呢</b>?