news 2026/4/18 9:20:57

11. UVM Test [uvm_test]

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
11. UVM Test [uvm_test]

现在,你已经准备好学习UVM的“总指挥”了——uvm_test。它是整个验证工厂的最高指挥官,负责设定任务、调配资源并下令开工。

简单来说,uvm_test不是一个具体的测试动作,而是一个可配置、可重用的“测试方案”或“作战计划”。它不直接驱动信号,而是通过配置环境、启动不同的“作战指令”(序列)来验证DUT的不同功能。

🎯 Test的本质:一个可执行的“验证方案”

你可以把验证计划(Verification Plan)里的一条条功能点(Feature)想象成需要攻克的“战略目标”。一个uvm_test就是一个针对其中一个战略目标的完整作战计划。它包含:

  • 作战环境:需要哪些“部队”(Agent)参与。
  • 部队配置:各部队用什么“装备”、以什么“模式”(主动/被动)作战。
  • 作战指令:具体的进攻顺序和策略(Sequence)。
  • 战果评估:如何判断目标是否达成(通过Scoreboard等检查)。

🏗️ 编写一个UVM Test的四步核心流程

下图展示了创建一个“作战计划”(Test)从搭建指挥部到下达作战指令的完整流程:

第一步:建立指挥部
你的 Test 类需要从uvm_test继承,并进行工厂注册。注意,它虽然不叫uvm_component,但本质上是一个顶级组件

class my_base_test extends uvm_test;`uvm_component_utils(my_base_test)// 使用组件宏注册functionnew(string name=“my_base_test”,uvm_component parent=null);super.new(name,parent);endfunction// ... 后续步骤写在这里endclass

第二步:组建与配置部队 (核心)
build_phase中,你需要:

  1. 创建环境(env)和配置对象(cfg)
  2. 为配置对象赋值(如设置工作模式、获取虚拟接口等)。
  3. 通过uvm_config_db将配置对象“下发”到环境中的具体Agent
virtual functionvoidbuild_phase(uvm_phase phase);super.build_phase(phase);// 1. 创建m_env=my_env::type_id::create(“m_env”,this);m_cfg=my_cfg::type_id::create(“m_cfg”);// 2. 配置if(!uvm_config_db #(virtual dut_if)::get(this,“”,“dut_vif”,m_cfg.vif))`uvm_error(“CFG”,“Interface not found!)m_cfg.is_active=UVM_ACTIVE;// 3. 下发uvm_config_db #(my_cfg)::set(this,“m_env.m_agent”,“cfg”,m_cfg);endfunction

第三步:战前检阅(调试)
end_of_elaboration_phase中,所有组件已创建并连接好。此时打印拓扑结构,可以清晰地看到你搭建的整个“部队编制”是否正确。

virtual functionvoidend_of_elaboration_phase(uvm_phase phase);uvm_top.print_topology();// 打印出完整的UVM组件树endfunction

第四步:下达作战指令(核心)
run_phase(这是一个task,会消耗仿真时间)中,你需要:

  1. 申请作战时间:通过raise_objection(this)防止仿真立刻结束。
  2. 创建并启动主序列:这是测试的灵魂,决定了要发送什么数据。
  3. 结束作战:序列执行完毕后,drop_objection(this)
virtual taskrun_phase(uvm_phase phase);my_main_sequence main_seq;super.run_phase(phase);// 好习惯phase.raise_objection(this);main_seq=my_main_sequence::type_id::create(“main_seq”);main_seq.start(m_env.v_sqr);// 通常启动在虚拟序列器上phase.drop_objection(this);endtask

🚀 如何“启动”一个Test:两种方式

Test 的启动不是在你代码里调用一个函数,而是在顶层模块(tb_top)的initial块中,通过run_test()这个全局任务来“召唤”。

方式一:代码内指定(不灵活)

initial beginrun_test(“my_base_test”);// 固定运行 my_base_testend

方式二(推荐):命令行指定

initial beginrun_test();// 参数为空,从命令行获取end

然后在仿真时通过命令行指定:

# 使用不同的 +UVM_TESTNAME 来运行不同的测试,无需重新编译!<simulator_command>+UVM_TESTNAME=my_base_test<simulator_command>+UVM_TESTNAME=test_feature_a<simulator_command>+UVM_TESTNAME=test_stress

这是UVM框架灵活性的重要体现,一定要掌握。

🔄 衍生测试:实现极致的重用

这是UVM测试策略最强大的地方。你不需要为每个功能点从头写一个Test,而是通过继承来复用和调整。

假设你有一个验证寄存器读写功能的测试reg_test

// 1. 基础测试:搭建通用环境,启动基础序列class reg_test extends uvm_test;`uvm_component_utils(reg_test)reg_env m_env;reg_cfg m_cfg;virtual functionvoidbuild_phase(uvm_phase phase);super.build_phase(phase);m_env=reg_env::type_id::create(“m_env”,this);m_cfg=reg_cfg::type_id::create(“m_cfg”);m_cfg.reg_model=“RAL”;// 使用寄存器模型uvm_config_db #(reg_cfg)::set(this,*,“cfg”,m_cfg);endfunction virtual taskrun_phase(uvm_phase phase);base_reg_seq seq=base_reg_seq::type_id::create(“seq”);phase.raise_objection(this);seq.start(m_env.v_sqr);phase.drop_objection(this);endtask endclass// 2. 衍生测试A:复用环境,但更换更复杂的“作战指令”class test_reg_stress extends reg_test;// 关键:继承`uvm_component_utils(test_reg_stress)virtual taskrun_phase(uvm_phase phase);stress_reg_seq seq=stress_reg_seq::type_id::create(“seq”);// 更换序列phase.raise_objection(this);seq.start(m_env.v_sqr);// 环境 m_env 是从父类继承来的!phase.drop_objection(this);endtask endclass// 3. 衍生测试B:复用环境和序列,但调整“部队配置”class test_reg_passive extends reg_test;`uvm_component_utils(test_reg_passive)virtual functionvoidbuild_phase(uvm_phase phase);super.build_phase(phase);// 先调用父类,完成通用搭建m_cfg.is_active=UVM_PASSIVE;// 然后覆盖配置:将Agent设为被动模式endfunction endclass

⚠️ 核心要点与总结

概念说明关键点
uvm_test角色验证环境的总指挥和配置中心不直接干活,只负责“排兵布阵”。
配置下发通过uvm_config_db::setbuild_phase将配置对象(cfg)下发。实现环境行为的动态控制。
启动序列run_phasecreatestart序列。必须使用raise/drop_objection包裹。
运行方式通过run_test()++UVM_TESTNAME命令行参数实现不修改代码、不重新编译即可切换测试。
测试重用通过类继承创建衍生测试。重写build_phase以修改配置,或重写run_phase以更换主序列

给你的最终建议:
现在,请将你之前搭建的envagentsequence组合起来。

  1. 创建一个my_base_test,在build_phase中创建你的env
  2. run_phase中启动你的序列,并确保有raise/drop_objection
  3. tb_top中,使用run_test(“my_base_test”)启动仿真。
  4. 成功后,尝试用run_test()+ 命令行参数+UVM_TESTNAME=my_base_test的方式再次运行。
  5. 最后,创建一个衍生测试,仅仅更换另一个不同的序列,并通过命令行运行它。

当你成功运行起第一个由Test指挥的完整UVM环境时,你就真正打通了UVM从底层到顶层的任督二脉。

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

PMBOK第七版电子书资源:项目管理学习者的必备宝典 [特殊字符]

PMBOK第七版电子书资源&#xff1a;项目管理学习者的必备宝典 &#x1f680; 【免费下载链接】PMBOK第七版电子书资源 本仓库提供PMBOK&#xff08;项目管理知识体系指南&#xff09;第七版的英文版和中文版PDF电子书&#xff0c;以及详细的目录&#xff0c;方便用户快速查找和…

作者头像 李华
网站建设 2026/4/17 23:38:23

5分钟构建智能数据可视化仪表盘:Chart.js实战指南

5分钟构建智能数据可视化仪表盘&#xff1a;Chart.js实战指南 【免费下载链接】dropzone 项目地址: https://gitcode.com/gh_mirrors/dro/dropzone 还在为复杂的数据报表制作而头疼吗&#xff1f;想要快速创建美观的图表展示却不知从何入手&#xff1f;本文将带你使用C…

作者头像 李华
网站建设 2026/4/17 9:12:43

ESC/POS热敏打印在Android平台的企业级解决方案

ESC/POS热敏打印在Android平台的企业级解决方案 【免费下载链接】ESCPOS-ThermalPrinter-Android Useful library to help Android developpers to print with (Bluetooth, TCP, USB) ESC/POS thermal printer. 项目地址: https://gitcode.com/gh_mirrors/es/ESCPOS-ThermalP…

作者头像 李华
网站建设 2026/4/17 19:07:34

如何快速集成Android代码编辑器:Sora-Editor完整指南

如何快速集成Android代码编辑器&#xff1a;Sora-Editor完整指南 【免费下载链接】sora-editor A multifunctional Android code editor library. (aka CodeEditor) 项目地址: https://gitcode.com/gh_mirrors/so/sora-editor 想要在Android应用中集成一个功能强大的代码…

作者头像 李华
网站建设 2026/4/18 7:54:24

【Java毕设全套源码+文档】基于springboot的古风生活体验交流网站的设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华