当前位置: 首页 > java >正文

UVM验证—第二课(一):核心基类阶段机制

目录

1. 核心基类

1.1 uvm_object

1.2 域的自动化(filed automation)

1.3 copy和clone

1.4 compare

1.5 print

1.6 pack&unpack

2. phase机制

2.1 概述

2.2 运行阶段机制

2.3 执行顺序

2.3.1 不同 phase 在同一个 component 中的执行顺序

2.3.2 相同 phase 的在 uvm 树形结构的执行顺序

2.3.3 相同 phase 在 uvm 树形结构中的同级组件的执行顺序

2.4 objection 机制 

1. 核心基类

1.1 uvm_object

  • UVM世界中的类最初都是从一个uvm void根类(root class)继承来的,而实际上这个类并没有成员变量和方法。
  • uvm_void只是一个虚类(virtual class),还在等待将来继承于它的子类去开垦。在继承于uvm_void的子类中,有两个类,一个为uvm_object类,另外一个为uvm_port_base类。
  • 在UVM世界的类库地图中除过事务接口(transaction interface)类继承于uvm_port base,其它所有的类都是从uvm_object类一步步继承而来的。

  • 从uvm_object提供的方法和相关的宏操作来看,它的核心方法主要提供与数据操作的相关服务:
    • Copy
    • Clone
    • Compare
    • Print
    • Pack/Unpack
  • 在SV模块的学习中,我们懂得了什么是句柄拷贝和对象拷贝。因此,无论是copy或者clone,都需要确保在操作的过程中,需要有source object和target object。

1.2 域的自动化(filed automation)

  • UVM通过域的自动化,使得用户在注册UVM类的同时也可以声名今后会参与到对象复制、克隆、打印等操作的成员变量。
  • uvm_field_int(变量名,FLAG)      除了int,还有real,enum(enum名称,实例名,FLAG),object,event,string
    动态数组 uvm_field_array_enum,int,object,string
    静态数组 uvm_field_sarray_enum,int,object,string
    队列 uvm_field_queue_enum,int,object,string
    联合数组 uvm_field_aa_int_string(ARG,FLAG)   aa_object_string,aa_object_int等      aa后面第一个是存储数据类型,第二个是索引类型
  • UVM_DEFAULT和UVM_ALL_ON表示将所有的数据操作方式都打开。UVM推荐使用UVM_DEFAULT将全部数据操作方法打开
  class box extends uvm_object;int volume = 120;color_t color = WHITE;string name = "box";`uvm_object_utils_begin(box)`uvm_field_int(volume, UVM_ALL_ON)`uvm_field_enum(color_t, color, UVM_ALL_ON)`uvm_field_string(name, UVM_ALL_ON)`uvm_object_utils_endfunction new(string name="box");super.new(name);this.name = name;endfunctionendclass

1.3 copy和clone

  1. copy 和 clone 的基本区别
    • copy 方法:默认使用已经创建好的对象,仅对数据进行拷贝。也就是说,它利用现有的对象实例,将源对象的数据复制到这个已有对象中。
    • clone 方法:会自动创建新对象,并对 source object(源对象)进行数据拷贝,然后返回 target object(目标对象)句柄。即它会先新建一个对象,再把源对象的数据复制到新对象中,最后返回新对象的引用。
  2. 数据复制的共性
    无论是 copy 还是 clone,都需要对数据进行复制操作。这是它们的核心功能,确保目标对象能够拥有与源对象相同或经过特定处理的数据。
  3. 包含句柄的数据成员拷贝问题
    当数据成员包含句柄时,在拷贝过程中存在疑问:是只拷贝该成员句柄本身,还是额外创建新的对象,并拷贝该句柄指向的对象。这是因为句柄本质上是指向某个对象的引用,直接拷贝句柄可能导致多个对象共享同一个目标对象,而创建新对象并拷贝指向对象的内容则可以避免这种情况,实现数据的独立性和隔离性。
  4. copy 的深拷贝示例
    从示例可以看出,在进行 copy 时,默认进行的是深拷贝(deep copy),即会执行 copy() 和 do_copy() 方法。深拷贝会递归地复制对象及其所引用的所有对象,确保目标对象与源对象在内存中是完全独立的,修改其中一个不会影响另一个。

copy代码

module object_copy2; // 定义一个模块名为 object_copy2,作为测试平台使用import uvm_pkg::*; // 导入 UVM 标准包中的所有内容,以便在模块中使用 UVM 类和方法`include "uvm_macros.svh" // 包含 UVM 的宏定义文件,用于支持如 `uvm_object_utils 等宏typedef enum {RED, WHITE, BLACK} color_t; // 定义枚举类型 color_t,包含三种颜色:RED、WHITE、BLACK// 定义 ball 类,继承自 uvm_object,表示一个球类对象class ball extends uvm_object;int diameter = 10; // 直径,默认值为 10color_t color = RED; // 颜色,默认为 RED// 使用 UVM 工厂机制注册 ball 类,并开始声明字段`uvm_object_utils_begin(ball)`uvm_field_int(diameter, UVM_DEFAULT) // 注册 diameter 字段,采用默认处理方式(复制、比较等)`uvm_field_enum(color_t, color, UVM_NOCOPY) // 注册 color 字段,但禁止复制操作`uvm_object_utils_end// 构造函数,创建 ball 实例时调用function new(string name="ball");super.new(name); // 调用父类 uvm_object 的构造函数endfunction// 自定义 do_copy 方法,用于控制对象拷贝行为virtual function void do_copy(uvm_object rhs);ball b;$cast(b, rhs); // 将 rhs 转换为 ball 类型$display("ball::do_copy entered.."); // 打印进入 do_copy 的提示信息if(b.diameter <= 20) begindiameter = 20; // 如果源对象直径小于等于 20,则目标对象直径设置为 20endendfunctionendclass// 定义 box 类,继承自 uvm_object,表示一个盒子类对象class box extends uvm_object;int volume = 120; // 体积,默认值为 120color_t color = WHITE; // 颜色,默认为 WHITEstring name = "box"; // 名字,默认为 "box"ball b; // 包含一个 ball 对象的实例// 使用 UVM 工厂机制注册 box 类,并开始声明字段`uvm_object_utils_begin(box)`uvm_field_int(volume, UVM_ALL_ON) // 注册 volume 字段,启用所有操作(复制、比较、打印等)`uvm_field_enum(color_t, color, UVM_ALL_ON) // 注册 color 字段,启用所有操作`uvm_field_string(name, UVM_ALL_ON) // 注册 name 字段,启用所有操作`uvm_field_object(b, UVM_SHALLOW) // 注册 ball 对象 b,使用浅拷贝策略`uvm_object_utils_end// 构造函数,创建 box 实例时调用function new(string name="box");super.new(name); // 调用父类 uvm_object 的构造函数this.name = name; // 设置当前对象的名字b = new(); // 创建 ball 子对象实例endfunctionendclass// 声明两个 box 类的实例 b1 和 b2box b1, b2;initial beginb1 = new("box1"); // 创建 box1 实例b1.volume = 80; // 设置 box1 的体积为 80b1.color = BLACK; // 设置 box1 的颜色为 BLACKb1.b.color = WHITE; // 设置 box1 中 ball 的颜色为 WHITEb2 = new(); // 创建新的 box 实例 b2b2.copy(b1); // 使用 copy 方法将 b1 的内容复制到 b2b2.name = "box2"; // 修改 b2 的名字为 "box2"$display("%s", b1.sprint()); // 打印 b1 的内容(包括自身及其子对象)$display("%s", b2.sprint()); // 打印 b2 的内容(注意 b 是浅拷贝,指向同一个 ball 对象)endendmodule

输出结果: 

ball::do_copy entered..
-----------------------------------
Name          Type      Size  Value
-----------------------------------
box1          box       -     @336
  volume      integral  32    'h50
  color       color_t   32    BLACK
  name        string    4     box1
  b           ball      -     @337
    diameter  integral  32    'ha 
    color     color_t   32    WHITE
-----------------------------------

-----------------------------------
Name          Type      Size  Value
-----------------------------------
box           box       -     @338
  volume      integral  32    'h50
  color       color_t   32    BLACK
  name        string    4     box2
  b           ball      -     @340
    diameter  integral  32    'h14
    color     color_t   32    RED 
-----------------------------------

  • 新添加了一个类ball,并且在box中例化了一个ball的对象。在拷贝过程中,box的其它成员都正常拷贝了,但对于box:b的拷贝则通过了ball的深拷贝方式进行。
  • 即先执行自动拷贝copy(),来拷贝允许拷贝的域,由于ball::color不允许拷贝,所以只拷贝了ball::diameter。
  • 接下来,再执行do_copy()函数,这个函数是需要用户定义的回调函数(callback function),即在copy(执行完后会执行do_copy()。
  • 如果用户没有定义该函数,那么则不会执行额外的数据操作。从ball::do_copy(函数可以看到,如果被拷贝对象的diameter小于20,那么则将自身的diameter设置为20。因此,最后对象b2.b的成员与b1.b的成员数值不同。

1.4 compare

compare 比较 b2.compare(b1) 比较失败返回0,有不同立即返回,不会在比较后续的数据,如果有多个不同,只会报错第一个不同

1.5 print

  • uvm_default printer = uvm_default_line_printer; b1.print();
  • uvm_default _printer = uvm_default_tree_printer ; b1.print() ;
  • uvm_default_tree_printer:可以将对象按照树状结构打印。
  • uvm_default_line_printer : 可以将对象数据打印到一行上面。
  • uvm_default_table_printer : 可以将对象按照表格的方式打印。
  • uvm_default_printer: UVM环境默认的打印设置,该句柄默认指向了uvm_default_table_printer。

1.6 pack&unpack

  • tr.pack_bytes(data_q)   将所有字段打包成byte流,放入data_q中
  • unpack_bytes  将一个byte流逐一恢复到某个类的实例中  按照`uvm_field_int注册时的顺序从上到下依次打包
  • pack()    unpack()  将所有字段打包成bit流
  • pack_ints()  unpack_ints()   将所有字段打包成int(4个byte,或者dword)流

2. phase机制

2.1 概述

  • SV的验证环境构建中,我们可以发现,传统的硬件设计模型在仿真开始前,已经完成例化和连接了;而SV的软件部分对象例化则需要在仿真开始后执行
  • 虽然对象例化通过调用构建函数new()来实现,但是单单通过new()函数无法解决一个重要问题,那就是验证环境在实现层次化时,如何保证例化的先后关系,以及各个组件在例化后的连接。
  • 此外如果需要实现高级功能,例如在顶层到底层的配置时,SV也无法在底层组件例化之前完成对底层的配置逻辑。
  • 因此UVM在验证环境构建时,引入了phase机制,通过该机制我们可以很清晰地将UVM仿真阶段层次化。
  • 这里的层次化,不单单是各个phase的先后执行顺序,而且处于同一phase中的层次化组件之间的phase也有先后关系。

2.2 运行阶段机制

phase 阶段执行机制是 UVM 定义的一套代码执行的规范,规定了在相同组件中,在 UVM 树形结构中以及在不同组件中代码的运行顺序。
  1. 构造阶段(Construction phase):在此阶段,验证环境的各个组件被创建并连接。包括创建和配置模型、生成各种信号和时钟,还有其他必要的前期准备工作。
  2. 配置阶段(configuration phase):在此阶段,各个组件的配置参数被设置,各种需要的连接关系建立起来。这些配置和连接可以通过 UVM 自带的配置机制进行设置。
  3. 主阶段(Main phase):在此阶段,主要进行测试的执行过程。此阶段使用各种事务 transaction)进行通信,发送和接收交互信息,执行具体的测试功能,包括输入和输出数据的处理、引发事件等。
  4. 收尾阶段(Shutdown phase):在此阶段,进行一些清理工作,释放资源,存储统计信息和自检等。通常,这个阶段运行在主测试程序结束之后,以确保所有的资源被正确释放。

2.3 执行顺序

UVM phase根据是否消耗时间分为 function phase 和 task phase,function phase 和task phase 都是 UVM 平台自动执行的。

2.3.1 不同 phase 在同一个 component 中的执行顺序

不同 phase 在同一个 component 中是按照自顶而下的执行顺序进行执行的,也就是说从 build_phase 开始,按照从上往下的顺序进行执行

注意:实验中 run_phase 与 12 task phase 是平行执行的。

2.3.2 相同 phase 的在 uvm 树形结构的执行顺序

相同 phase 的在 uvm 树形结构的执行顺序分为两种情况:自上而下和自下而上。
  • 自上而下执行的 phase 有:build_phasefinal_phase
  • 自 下 而 上 执 行 的 phase 有 : connect_phase end_of_elaboration_phase start_of_simulation_phasereset phaseconfiguration phaserun_phasemain phaseshutdown phase extact_phasecheck_phasereport_phase

2.3.3 相同 phase uvm 树形结构中的同级组件的执行顺序

相同 phase uvm 树形结构中的同级组件的执行顺序是按照字典的顺序执行的。
  • 如 driver 与 monitor,它们的执行顺序是按照字典序的,这里的字典序是依据 new 时指定的名字,例如有两个 agent,有一个 agent new 的名字为 a_agent,另一个 agent new 的名字为 b_agent,那么最先执行的是 a_agent 里的 build_phase 再是 b_agent build_phase
  • 同样的 dadd_driverdadd_imonitor, dadd_sequencer 是同级的 component,在 agent new 的名字为 drv,imon,sqrbuild_phase 执行的顺序是 dadd_driver,dadd_imonitor,dadd_sequencer

2.4 objection 机制 

  • UVM 通过 phase objection 机制来控制验证平台的关闭。在每个 phase 中,UVM会检查是否有 objection 被提起(raise_objection),如果有,那么等待这个 objection 被撤销(drop_objection)后停止仿真,如果没有则马上结束当前 phase
  • raise_objectiondrop_objection 要成双成对出现了,注意:raise_objection 必须放在 main_phase 第一个消耗仿真时间的语句之前。
  • object 机制会遍历所有 component 里的 phase objection 是否被撤销,如果全部被 撤销才能进入下一个 phase

例如下图所示,在执行到 task reset_phase 中会等到 component A,component Bcomponent C objection 全部被撤销之后才能进入 configure phase。

objection 机制的好处在于可有效的控制平台的执行和关闭,提高了验证平台的灵活性和可控性

http://www.xdnf.cn/news/14072.html

相关文章:

  • Deepseek+python - 自动图表生成
  • Arduino学习-红外感应
  • 聊一聊 - 如何写好README文档
  • ABB 216EA61B HESG448230R1/G
  • OpenLayers 图层叠加控制
  • Windows10搭建FTP服务器
  • python中的zip函数
  • Python的格式化输入输出
  • 深入理解 @JsonGetter:精准掌控前端返回数据格式!
  • cpp 绑定方案大比拼
  • SpringBoot实现权限管理系统完整指南(附源码)
  • 【Code】COP FOR THE STRUCTURAL USE OF STEEL 2011 (2023 Edition)
  • SDPA(Scaled Dot-Product Attention)详解
  • CE 标志新门槛:智能门锁 EN 18031 认证合规路径与成本分析
  • 分布式锁模板工具类
  • 2025企业级BI产品评测和推荐
  • 在 WinForms 中制作无边框窗体通过鼠标拖动移动和调整大小,难点是我窗体上被标题栏和状态栏dock之后很难选中
  • 短视频矩阵系统开发实战:PHP实现SaaS独立部署
  • deepimagej-plugin开源程序是用于运行深度学习模型的 ImageJ 插件
  • 【解决方案】Kali 2022.3修复仓库密钥一键安装docker,docker compose
  • 开发环境与生产环境的 yml 文件与配置
  • 1分钟理解FreeRtos中的信号量知识
  • LeetCode - 387. 字符串中的第一个唯一字符
  • 一个简单的torch-cuda demo
  • Acrobat 首选项配置:从注册表到锁定机制
  • 【MPC】模型预测控制笔记 (2):约束MPC
  • C语言预处理命令详解
  • 第9章 表达式和运算符 笔记 待完善
  • 如何运营一个专业的体育比分网站
  • 2025年06月13日Github流行趋势