news 2026/1/19 5:34:38

52. How to use uvm_printer

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
52. How to use uvm_printer

UVM Printer:从“手动打印”到“自动格式化”的进化

🎯 课程目标:20分钟掌握UVM对象打印的艺术

今天我要教你UVM中最酷的调试工具——uvm_printer。这就像从“手写简历”到“专业排版软件”的进化,让你的调试输出变得美观又专业!

📋 第一部分:问题的根源——传统打印的痛点

传统方式的痛苦经历

想象你要记录员工的个人信息:

// ❌ 传统方式:每个类都要自己写打印函数class Employee;string name;intage;string department;intsalary;// 每个类都要写这样的函数!functionvoiddisplay();$display("name=%s, age=%0d, department=%s, salary=%0d",name,age,department,salary);endfunction endclass class Manager extends Employee;intteam_size;// 子类还要重写,而且要调用super.display()!functionvoiddisplay();super.display();$display("team_size=%0d",team_size);endfunction endclass// 如果再有Manager的子类,又要重写...

传统方式的问题

  1. 重复劳动:每个类都要写打印函数
  2. 格式混乱:每个人写法不一样
  3. 维护噩梦:修改字段要改多个地方
  4. 没有层次:嵌套对象打印很麻烦

🖨️ 第二部分:UVM Printer的三种专业格式

UVM提供了三种现成的打印格式,就像Word的三种视图:

1. 表格打印机(默认)—— Excel表格视图

---------------------------------------- Name Type Size Value ---------------------------------------- obj my_data - @1013 data integral 8 'h5a addr integral 8 'h1 format format - @1022 header integral 4 'hb footer integral 3 'h0

2. 树形打印机—— 文件夹树状视图

obj: (my_data@1013) { data: 'h5a addr: 'h1 format: (format@1022) { header: 'hb footer: 'h0 } }

3. 线性打印机—— 单行紧凑视图

obj: (my_data@1013) { data: 'h5a addr: 'h1 format: (format@1022) { header: 'hb footer: 'h0 } }

🛠️ 第三部分:两种使用方法(简单vs灵活)

方法1:使用宏(简单快捷,推荐!)

// 步骤1:用宏注册字段class Employee extends uvm_sequence_item;string name;intage;string department;intsalary;// 使用uvm_field_*宏注册字段`uvm_object_utils_begin(Employee)`uvm_field_string(name,UVM_ALL_ON)// 注册字符串`uvm_field_int(age,UVM_ALL_ON)// 注册整数`uvm_field_string(department,UVM_ALL_ON)`uvm_field_int(salary,UVM_ALL_ON)`uvm_object_utils_end functionnew(string name="Employee");super.new(name);endfunction// 注意:不需要写print()函数!endclass// 步骤2:直接使用print()方法initial begin Employee emp=Employee::type_id::create("emp");emp.name="张三";emp.age=30;emp.department="研发部";emp.salary=50000;// 打印!自动格式化!emp.print();// 使用默认表格打印机emp.print(uvm_default_tree_printer);// 使用树形打印机emp.print(uvm_default_line_printer);// 使用线性打印机end

方法2:使用do_print()函数(灵活控制)

class Manager extends Employee;intteam_size;bit has_budget_approval;`uvm_object_utils(Manager)functionnew(string name="Manager");super.new(name);endfunction// 自定义打印函数virtual functionvoiddo_print(uvm_printer printer);// 1. 先打印父类的字段super.do_print(printer);// 2. 添加本类的字段printer.print_int("team_size",team_size,$bits(team_size));// 3. 格式化特殊字段printer.print_string("budget_approval",has_budget_approval?"有":"无");endfunction endclass

🎛️ 第四部分:打印机旋钮(高级控制)

UVM Printer提供了丰富的控制选项,就像相机的各种设置:

class PrinterConfigurator;functionvoidconfigure_printer();// 获取默认打印机uvm_table_printer printer=uvm_default_table_printer;// 1. 控制显示深度(嵌套层次)printer.knobs.depth=2;// 只显示2层嵌套// 2. 是否显示类型列printer.knobs.type_name=0;// 不显示Type列// 3. 是否显示大小列printer.knobs.size=0;// 不显示Size列// 4. 缩进控制printer.knobs.indent=4;// 缩进4个空格(默认2)// 5. 显示完整名称(包含路径)printer.knobs.full_name=1;// 显示obj.data而不是data// 6. 十六进制前缀printer.hex_radix="0x";// 用0x代替'h// 7. 是否显示对象引用IDprinter.knobs.reference=0;// 不显示@1013这样的ID// 8. 设置最大宽度printer.knobs.max_width=120;// 每行最大120字符endfunction endclass

🔄 第五部分:嵌套对象的处理

情况1:简单嵌套(用宏自动处理)

class Department;string name;intemployee_count;`uvm_object_utils_begin(Department)`uvm_field_string(name,UVM_ALL_ON)`uvm_field_int(employee_count,UVM_ALL_ON)`uvm_object_utils_end endclass class Company;string name;Department dept;// 嵌套对象`uvm_object_utils_begin(Company)`uvm_field_string(name,UVM_ALL_ON)`uvm_field_object(dept,UVM_ALL_ON)// 注意:用_object不是_int`uvm_object_utils_end functionnew(string name="Company");super.new(name);dept=Department::type_id::create("dept");endfunction endclass

情况2:复杂嵌套(自定义控制)

class ComplexCompany;string name;Department departments[3];// 对象数组!`uvm_object_utils_begin(ComplexCompany)`uvm_field_string(name,UVM_ALL_ON)// 注意:数组需要特殊处理`uvm_object_utils_end functionnew(string name="ComplexCompany");super.new(name);foreach(departments[i])departments[i]=Department::type_id::create($sformatf("dept[%0d]",i));endfunction virtual functionvoiddo_print(uvm_printer printer);super.do_print(printer);// 手动打印数组foreach(departments[i])begin printer.print_object($sformatf("departments[%0d]",i),departments[i]);end endfunction endclass

🧪 第六部分:实战完整示例

示例:打印完整的组织结构

// 1. 基础员工类(用宏)class BaseEmployee extends uvm_sequence_item;string id;string name;intage;`uvm_object_utils_begin(BaseEmployee)`uvm_field_string(id,UVM_ALL_ON)`uvm_field_string(name,UVM_ALL_ON)`uvm_field_int(age,UVM_ALL_ON|UVM_DEC)`uvm_object_utils_end functionnew(string name="BaseEmployee");super.new(name);endfunction endclass// 2. 经理类(继承+自定义)class Manager extends BaseEmployee;intteam_size;BaseEmployee team_members[5];// 管理5个员工`uvm_object_utils_begin(Manager)`uvm_field_int(team_size,UVM_ALL_ON|UVM_DEC)// 注意:数组不在宏中处理`uvm_object_utils_end functionnew(string name="Manager");super.new(name);foreach(team_members[i])team_members[i]=BaseEmployee::type_id::create($sformatf("member_%0d",i));endfunction virtual functionvoiddo_print(uvm_printer printer);// 先打印基类字段super.do_print(printer);// 打印本类字段printer.print_int("team_size",team_size,$bits(team_size),UVM_DEC);// 控制嵌套深度:只打印一层printer.knobs.depth=1;// 打印数组foreach(team_members[i])beginif(team_members[i]!=null)begin printer.print_object($sformatf("team_members[%0d]",i),team_members[i]);end end endfunction endclass// 3. 测试代码class PrinterTest extends uvm_test;Manager ceo;uvm_table_printer custom_printer;virtual functionvoidbuild_phase(uvm_phase phase);super.build_phase(phase);// 创建CEO对象ceo=Manager::type_id::create("ceo");ceo.id="CEO001";ceo.name="张总裁";ceo.age=45;ceo.team_size=5;// 创建自定义打印机custom_printer=new();configure_printer(custom_printer);endfunction virtual taskrun_phase(uvm_phase phase);phase.raise_objection(this);// 方法1:默认打印(表格格式)`uvm_info("TEST","=== 默认表格打印机 ===",UVM_LOW)ceo.print();// 方法2:树形打印`uvm_info("TEST","=== 树形打印机 ===",UVM_LOW)ceo.print(uvm_default_tree_printer);// 方法3:自定义打印机`uvm_info("TEST","=== 自定义打印机 ===",UVM_LOW)ceo.print(custom_printer);phase.drop_objection(this);endtask functionvoidconfigure_printer(uvm_table_printer printer);// 精简配置:只显示名称和值printer.knobs.size=0;// 不显示大小列printer.knobs.type_name=0;// 不显示类型列printer.knobs.indent=4;// 缩进4个空格printer.knobs.depth=2;// 显示2层深度printer.knobs.full_name=1;// 显示完整名称printer.hex_radix="";// 不使用十六进制前缀endfunction endclass

📊 第七部分:输出对比展示

默认表格打印机输出:

---------------------------------------- Name Type Size Value ---------------------------------------- ceo Manager - @1013 id string 3 CEO001 name string 6 张总裁 age integral 32 45 team_size integral 32 5 team_members[0] Employee - @1022 id string 0 name string 0 age integral 32 0 team_members[1] Employee - @1023 ...

树形打印机输出:

ceo: (Manager@1013) { id: CEO001 name: 张总裁 age: 45 team_size: 5 team_members[0]: (Employee@1022) { id: name: age: 0 } team_members[1]: (Employee@1023) { ... } }

自定义打印机输出:

-------------------------- Name Value -------------------------- ceo - ceo.id CEO001 ceo.name 张总裁 ceo.age 45 ceo.team_size 5 ceo.team_members[0] - ...(深度控制为2,所以只显示一层)

🔧 第八部分:实用调试技巧

技巧1:条件打印

class SmartPrinter;// 只在需要时打印详细信息functionvoiddebug_print(uvm_object obj,bit verbose=0);if(verbose)begin// 详细模式:用树形打印机,显示所有细节uvm_tree_printer printer=new();printer.knobs.depth=-1;// 显示所有深度obj.print(printer);endelsebegin// 简洁模式:用自定义表格打印机uvm_table_printer printer=new();printer.knobs.size=0;printer.knobs.type_name=0;obj.print(printer);end endfunction endclass

技巧2:打印部分字段

class SelectivePrinter extends uvm_printer;// 自定义打印机,只打印感兴趣的字段virtual functionvoidprint_field(string name,uvm_object value);// 只打印名字包含"id"或"name"的字段if(name.find("id")>=0||name.find("name")>=0)begin super.print_field(name,value);end// 其他字段忽略不打印endfunction endclass

技巧3:实时切换打印机

class DynamicPrinterTest extends uvm_test;// 在仿真过程中动态切换打印机virtual taskrun_phase(uvm_phase phase);uvm_object obj=get_test_object();// 阶段1:正常模式(表格)`uvm_info("PHASE","阶段1:正常模式",UVM_LOW)obj.print();// 阶段2:发现异常,切换到详细模式if(check_error())begin `uvm_warning("DEBUG","发现异常,切换到详细模式")obj.print(uvm_default_tree_printer);end// 阶段3:深度调试模式if(need_deep_debug())begin uvm_table_printer debug_printer=new();debug_printer.knobs.depth=-1;// 无限深度debug_printer.knobs.full_name=1;obj.print(debug_printer);end endtask endclass

📋 第九部分:快速参考表

uvm_field_* 宏类型

适用类型示例
uvm_field_int整数类型uvm_field_int(age, UVM_ALL_ON)
uvm_field_string字符串uvm_field_string(name, UVM_ALL_ON)
uvm_field_object对象uvm_field_object(dept, UVM_ALL_ON)
uvm_field_enum枚举uvm_field_enum(color_t, color, UVM_ALL_ON)
uvm_field_array数组uvm_field_array(ids, UVM_ALL_ON)

打印机旋钮速查

旋钮作用常用值
depth打印深度-1=无限,0=顶层,1=1层嵌套
size是否显示大小列0=不显示,1=显示
type_name是否显示类型列0=不显示,1=显示
full_name是否显示完整名称0=只显示字段名,1=显示obj.field
indent缩进空格数2(默认),4(常用)
reference是否显示对象ID0=不显示,1=显示,2=特殊格式

打印方法对比

方法优点缺点适用场景
宏注册简单,自动不够灵活90%的常规场景
do_print()灵活,可控制需要写代码复杂对象,特殊需求
混合使用兼顾两者稍复杂既有常规字段又有特殊需求

💡 最终总结:UVM Printer的使用哲学

UVM Printer让你的调试输出从"原始数据"变成"结构化信息":

传统打印的痛点: 📝 每个类都要写打印函数 🎨 格式五花八门 🔍 难以阅读嵌套结构 ⚙️ 无法控制输出细节 UVM Printer的优势: 📊 三种专业格式可选 🔄 自动处理继承和嵌套 🎛️ 丰富的控制选项 💾 一致的输出格式

记住这个使用策略

简单对象用宏,复杂对象用do_print;
日常调试用表格,分析结构用树形,紧凑查看用线性;
默认设置先尝试,特殊需求调旋钮。

现在你已经掌握了UVM Printer的所有技巧!在你的下一个项目中:

  1. 新类设计:使用宏注册字段,一劳永逸
  2. 调试阶段:根据需求切换不同打印机
  3. 问题定位:使用深度控制和过滤器
  4. 团队协作:统一打印机配置,保持日志一致

你会发现,专业的打印输出能让调试效率提升数倍!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/12 4:48:31

Cobalt Strike(简称 CS)专业的红队安全测试工具

Cobalt Strike(简称 CS)是一款专业的红队安全测试工具,核心用于模拟真实网络攻击,实现目标主机控制、权限提升、横向渗透等操作,是企业安全演练中常用的工具之一。以下是它的核心功能和基础使用流程(结合你…

作者头像 李华
网站建设 2025/12/31 23:21:49

全网最全继续教育AI论文工具TOP10测评

全网最全继续教育AI论文工具TOP10测评 2025年继续教育AI论文工具测评背景与评测维度 随着人工智能技术的快速发展,AI写作工具在学术研究和继续教育领域的应用日益广泛。然而,面对市场上琳琅满目的产品,如何选择一款真正适合自身需求的工具&am…

作者头像 李华
网站建设 2025/12/31 23:08:14

2025必备!8个AI论文软件,助研究生搞定毕业论文!

2025必备!8个AI论文软件,助研究生搞定毕业论文! AI 工具正在重塑论文写作的未来 随着人工智能技术的不断进步,越来越多的研究生开始借助 AI 工具来提升论文写作效率。无论是开题报告、文献综述还是数据分析,AI 工具都能…

作者头像 李华