引言:UVM是什么?
从字面意思来看UVM(Universal Verification Methodology)就是通用验证方法学;从具象概念来看UVM是一个用SystemVerilog编写的类库,它提供了很多预定义的类和方法,用于构建验证环境;从抽象概念来看,UVM是一种验证方法学,它提供了一套完整的验证框架和最佳实践,指导如何构建可重用、可扩展的验证环境。
1. 概述
UVM是一个基于SystemVerilog的验证方法学框架,它提供了一套完整的类库和最佳实践指南,用于构建模块化、可重用和可扩展的验证环境。 对于复杂的芯片设计,UVM通过标准化、自动化和可重用,解决了传统验证方式效率低下、容易出错、难以协作的痛点,已成为芯片验证行业不可或缺的基石。
UVM的核心价值
- 标准化 - 统一的验证架构和编码风格
- 可重用性 - 组件级、环境级、测试级的重用
- 可维护性 - 清晰的层次结构和配置机制
2. UVM发展历程
| 时间 | 方法学 | 特点 | 局限性 |
|---|---|---|---|
| 2000年前 | 定向测试 | 简单直接 | 不可重用、难以维护 |
| 2000-2007 | eRM/VMM | 早期方法学 | 语言特定、不够统一 |
| 2007-2011 | OVM | 多语言支持 | 双标准并存 |
| 2011至今 | UVM | 行业统一标准 | 学习曲线较陡 |
UVM的前身是OVM,由Mentor和Candence于2008年联合发布。2010年,Accellera(Systemverilog Verilog语言标准最初的制定者)把OVM才能作为标准,并在此基础上着手退出新一代验证方法学UVM。 2010年5月,Accellera推出了UVM1.0EA,EA就是early adoption。 2011年2月,UVM1.0正式版本发布。 2011年6月,UVM1.1版本发布,修正了1.0版本中的大量问题。 2011年12月,UVM1.1a发布。 2012年5月,UVM1.1b发布。 2012年10月,UVM1.1c发布。 2013年3月,UVM1.1d发布。 2014年6月,UVM1.2发布,引入了新的方法、丰富了某些宏。 2017年12月,IEEE 1800.2发布,基于UVM1.2,提供了更严格的规范、支持寄存器动态地址映射,并简化了回调机制。 2020年3月,更新了IEEE 1800.2,显著的性能提升和功能增强,是目前广泛推荐使用的稳定版本。
3. 为什么是UVM
在UVM之前,芯片验证面临巨大挑战:
- 设计复杂度爆炸:SoC芯片集成数十亿晶体管,功能极其复杂。
- 验证效率低下:传统的定向测试方法需要大量人力,且难以覆盖所有场景。
- 代码不可重用:模块级验证代码无法用于系统级,新项目需要重写大量代码。
- 协作困难:没有统一标准,不同工程师写的验证环境风格迥异,难以理解和维护。
UVM的诞生就是为了解决这些问题,它融合了之前OVM、VMM等方法的优点,并由Accellera组织标准化,现已成为数字芯片验证领域的事实标准。
4. 典型的UVM验证平台结构
4.1 核心组件职责分解
4.1.1 test - 测试顶层控制器
核心职责:
- 验证环境的最高层级管理者
- 测试场景的入口点和协调中心
- 配置管理的决策者
class base_test extends uvm_test;
// 构建测试环境、配置参数、启动测试序列
virtual function void build_phase(uvm_phase phase);
env = my_env::type_id::create("env", this);
endfunction
endclass
4.1.2 env - 验证环境容器
核心职责:
- 验证组件的集成容器
- 组件间连接的架构师
- 环境级配置的承载者
class my_env extends uvm_env;
my_agent agent;
my_scoreboard scb;
my_coverage cov;
my_virtual_sequencer v_sqr;
// 1. 构建验证环境的所有组件
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent = my_agent::type_id::create("agent", this);
scb = my_scoreboard::type_id::create("scb", this);
cov = my_coverage::type_id::create("cov", this);
v_sqr = my_virtual_sequencer::type_id::create("v_sqr", this);
endfunction
// 2. 连接所有组件间的通信端口
virtual function void connect_phase(uvm_phase phase);
// 连接monitor到scoreboard和coverage
agent.monitor.analysis_port.connect(scb.analysis_export);
agent.monitor.analysis_port.connect(cov.analysis_export);
// 连接virtual sequencer到physical sequencer
v_sqr.data_sqr = agent.sequencer;
endfunction
// 3. 环境级配置分发
virtual function void configure();
agent.is_active = UVM_ACTIVE; // 设置agent工作模式
endfunction
endclass
4.1.3 agent - 接口功能包
核心职责:
- 特定接口验证功能的完整封装
- 工作模式的统一管理
- 协议相关组件的集中管理
class my_agent extends uvm_agent;
my_sequencer sqr;
my_driver drv;
my_monitor mon;
uvm_analysis_port #(my_transaction) analysis_port;
// 1. 根据配置创建组件(ACTIVE/PASSIVE模式)
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
mon = my_monitor::type_id::create("mon", this);
if (is_active == UVM_ACTIVE) begin
sqr = my_sequencer::type_id::create("sqr", this);
drv = my_driver::type_id::create("drv", this);
end
endfunction
// 2. 连接ACTIVE模式下的组件
virtual function void connect_phase(uvm_phase phase);
// 连接driver和sequencer
if (is_active == UVM_ACTIVE)
drv.seq_item_port.connect(sqr.seq_item_export);
// 将monitor的分析端口代理到agent级别
analysis_port = mon.analysis_port;
endfunction
// 3. 协议特定的配置管理
bit collect_coverage = 1;
int bus_width = 32;
endclass
4.1.4 driver - 信号驱动器
核心职责:
- Transaction到信号时序的转换器
- 总线协议的具体实现者
- 与Sequencer的请求响应协调者
class my_driver extends uvm_driver #(my_transaction);
virtual my_interface vif;
// 1. 从sequencer获取transaction
virtual task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req); // 从sequencer获取激励
drive_transaction(req); // 驱动到DUT
seq_item_port.item_done(); // 告知完成
end
endtask
// 2. 实现具体的协议时序
virtual task drive_transaction(my_transaction tr);
// 按照总线协议将transaction转换为信号时序
vif.data <= tr.data;
vif.addr <= tr.addr;
vif.valid <= 1'b1;
@(posedge vif.clk);
while (!vif.ready) @(posedge vif.clk);
vif.valid <= 1'b0;
`uvm_info("DRV", $sformatf("Drived transaction: addr=0x%0h, data=0x%0h",
tr.addr, tr.data), UVM_HIGH)
endtask
// 3. 处理背压和流控制
virtual task handle_backpressure();
// 实现背压处理逻辑
endtask
endclass
4.1.5 monitor - 信号级监视器
核心职责:
- 接口信号的被动观察者
- 信号到时序的反向转换器
- 验证数据的采集分发中心
class my_monitor extends uvm_monitor;
virtual my_interface vif;
uvm_analysis_port #(my_transaction) analysis_port;
// 1. 持续监控接口信号
virtual task run_phase(uvm_phase phase);
forever begin
my_transaction tr;
collect_transaction(tr); // 采集信号并转换为transaction
analysis_port.write(tr); // 分发到所有订阅者
end
endtask
// 2. 协议解析和事务重建
virtual task collect_transaction(output my_transaction tr);
tr = my_transaction::type_id::create("tr");
// 等待事务开始
@(posedge vif.clk iff vif.valid);
// 采集地址相位
tr.addr = vif.addr;
// 采集数据相位
do begin
@(posedge vif.clk);
tr.data = vif.data;
end while (vif.valid && !vif.last);
`uvm_info("MON", $sformatf("Captured transaction: addr=0x%0h", tr.addr), UVM_HIGH)
endtask
// 3. 协议覆盖率收集(可选)
covergroup protocol_cg;
// 协议特定的覆盖率点
endgroup
endclass
4.1.6 sequencer - 激励调度器
核心职责:
- 测试序列的执行调度器
- Driver请求的仲裁分配器
- 激励生成的流程控制器
class my_sequencer extends uvm_sequencer #(my_transaction);
// 1. 序列仲裁和调度
// (基础功能由UVM框架自动提供)
// 2. 支持多种仲裁算法
function new(string name, uvm_component parent);
super.new(name, parent);
set_arbitration(SEQ_ARB_FIFO); // 设置仲裁策略
endfunction
// 3. 序列执行控制
// - 自动处理sequence的start(), stop(), pause(), resume()
// - 管理sequence的层次结构
// - 协调多个并发sequence的执行
endclass
// Sequencer的使用主要通过Sequence控制
class my_sequence extends uvm_sequence #(my_transaction);
virtual task body();
// Sequencer协调这些transaction的发送
`uvm_do(req) // 自动创建、随机化、发送
`uvm_do_with(req, {data == 8'hFF;}) // 带约束的发送
`uvm_send(req) // 发送已存在的transaction
endtask
endclass
4.1.7 scoreboard - 结果检查器
核心职责:
- Scoreboard是UVM验证环境中负责检查DUT功能正确性的核心组件,它像裁判一样评判DUT的行为是否符合预期
- 验证DUT的功能正确性和数据完整性
- 通过比对实际输出与预期输出,发现设计缺陷
class my_scoreboard extends uvm_scoreboard;
// 1. 数据一致性检查 - 核心比对逻辑
virtual function void check_data_consistency(my_transaction input_tr, my_transaction output_tr);
// 比对输入和输出数据是否一致
if (input_tr.payload != output_tr.payload) begin
`uvm_error("DATA_MISMATCH",
$sformatf("Input payload 0x%0h != Output payload 0x%0h",
input_tr.payload, output_tr.payload))
end
// 检查数据完整性(CRC、校验和等)
if (output_tr.crc != calculate_expected_crc(output_tr)) begin
`uvm_error("CRC_ERROR", "Data corruption detected")
end
endfunction
// 2. 协议符合性检查
virtual function void check_protocol_compliance(my_transaction tr);
// 检查事务顺序是否正确
if (tr.sequence_num != expected_sequence_num) begin
`uvm_error("SEQ_ERROR",
$sformatf("Sequence number mismatch: got %0d, expected %0d",
tr.sequence_num, expected_sequence_num))
end
// 检查响应延迟是否符合规范
if (tr.response_latency > max_allowed_latency) begin
`uvm_warning("LATENCY_WARN", "Response latency exceeds specification")
end
endfunction
// 3. 参考模型比对
virtual function void compare_with_reference(my_transaction actual_tr);
my_transaction expected_tr;
// 从参考模型获取预期结果
expected_tr = reference_model.predict(actual_tr);
// 详细比对每个字段
if (!expected_tr.compare(actual_tr)) begin
`uvm_error("COMPARE_FAIL",
$sformatf("DUT output doesn't match reference model\nExpected: %s\nActual: %s",
expected_tr.convert2string(), actual_tr.convert2string()))
end
endfunction
// 4. 错误注入和异常处理测试
virtual function void check_error_handling();
// 验证DUT对错误条件的处理是否正确
if (error_condition_detected && !error_response_received) begin
`uvm_error("ERROR_HANDLING", "DUT failed to handle error condition properly")
end
endfunction
// 5. 性能指标统计
virtual function void collect_performance_metrics();
// 收集吞吐量、延迟等性能数据
total_transactions++;
total_latency += current_latency;
`uvm_info("PERF",
$sformatf("Average latency: %0d cycles, Throughput: %0d transactions/cycle",
total_latency / total_transactions, throughput), UVM_MEDIUM)
endfunction
endclass
4.2 UVM的核心机制
4.2.1 工厂模式(Factory Pattern)
工厂机制是UVM的核心特性,允许在不修改原始代码的情况下,动态地替换对象和组件的类型,提供了极大的灵活性和可重用性。
- 使用宏注册类型到工厂
- 通过工厂创建对象实例
- 支持运行时类型覆盖
// 1. 基类定义和注册
class base_transaction extends uvm_sequence_item;
`uvm_object_utils(base_transaction)
rand bit [7:0] data;
rand bit [7:0] addr;
function new(string name = "base_transaction");
super.new(name);
endfunction
endclass
// 2. 派生类定义和注册
class extended_transaction extends base_transaction;
`uvm_object_utils(extended_transaction)
rand bit [3:0] user_bits;
rand bit priority;
function new(string name = "extended_transaction");
super.new(name);
endfunction
endclass
// 3. 在测试中实现类型覆盖
class my_test extends uvm_test;
`uvm_component_utils(my_test)
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
// 使用工厂机制覆盖类型
base_transaction::type_id::set_type_override(
extended_transaction::get_type());
endfunction
virtual task run_phase(uvm_phase phase);
base_transaction tr;
phase.raise_objection(this);
// 工厂会自动创建extended_transaction实例
tr = base_transaction::type_id::create("tr");
`uvm_info("TEST", $sformatf("Created transaction type: %s",
tr.get_type_name()), UVM_LOW)
phase.drop_objection(this);
endtask
endclass
4.2.2 配置机制(Configuration)
配置机制提供了一种在UVM组件层次中传递配置信息的标准方法,使得测试可以灵活地配置验证环境,而无需修改环境代码。
- 使用uvm_config_db存储和检索配置信息
- 支持任意数据类型的配置
- 提供作用域和优先级控制
// 1. 配置对象定义
class bus_config extends uvm_object;
`uvm_object_utils(bus_config)
int bus_width = 32;
int max_burst_size = 16;
bit has_coverage = 1;
bit is_active = 1;
function new(string name = "bus_config");
super.new(name);
endfunction
endclass
// 2. 在测试中设置配置
class config_test extends uvm_test;
`uvm_component_utils(config_test)
bus_config cfg;
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
// 创建并配置配置对象
cfg = bus_config::type_id::create("cfg");
cfg.bus_width = 64;
cfg.max_burst_size = 32;
cfg.has_coverage = 0; // 为性能测试禁用覆盖率
// 将配置对象存储到config_db
uvm_config_db#(bus_config)::set(this, "env.agent*", "bus_cfg", cfg);
// 设置简单值类型的配置
uvm_config_db#(int)::set(this, "env.agent*", "verbosity", UVM_HIGH);
endfunction
endclass
// 3. 在Agent中获取配置
class my_agent extends uvm_agent;
`uvm_component_utils(my_agent)
bus_config cfg;
int verbosity;
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
// 从config_db获取配置对象
if (!uvm_config_db#(bus_config)::get(this, "", "bus_cfg", cfg)) begin
`uvm_error("CONFIG", "Failed to get bus_config from config_db")
cfg = bus_config::type_id::create("cfg"); // 创建默认配置
end
// 获取简单值配置
if (!uvm_config_db#(int)::get(this, "", "verbosity", verbosity)) begin
verbosity = UVM_MEDIUM; // 默认值
end
`uvm_info("AGENT", $sformatf("Bus width: %0d, Active: %0d",
cfg.bus_width, cfg.is_active), UVM_LOW)
endfunction
endclass
4.2.3 Phase机制
Phase机制将仿真过程分为多个有序的阶段,确保所有组件按照正确的顺序初始化和执行,提供了确定性的执行流程。
- 预定义的标准phase序列
- 每个phase在所有组件上同步执行
- 支持用户自定义phase
class my_component extends uvm_component;
`uvm_component_utils(my_component)
int data_value;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
// 1. Build Phase - 创建和配置子组件
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("PHASE", "Executing build_phase", UVM_LOW)
// 创建子组件、获取配置等
data_value = 100;
endfunction
// 2. Connect Phase - 连接组件间的端口
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
`uvm_info("PHASE", "Executing connect_phase", UVM_LOW)
// 连接TLM端口、分析端口等
endfunction
// 3. End of Elaboration Phase - 环境构建完成
virtual function void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
`uvm_info("PHASE", "Executing end_of_elaboration_phase", UVM_LOW)
// 打印环境拓扑结构等
endfunction
// 4. Start of Simulation Phase - 仿真开始前
virtual function void start_of_simulation_phase(uvm_phase phase);
super.start_of_simulation_phase(phase);
`uvm_info("PHASE", "Executing start_of_simulation_phase", UVM_LOW)
endfunction
// 5. Run Phase - 主要的仿真阶段
virtual task run_phase(uvm_phase phase);
`uvm_info("PHASE", "Executing run_phase", UVM_LOW)
phase.raise_objection(this);
// 主要的测试逻辑
#100;
`uvm_info("RUN", "Run phase activity completed", UVM_LOW)
phase.drop_objection(this);
endfunction
// 6. Extract Phase - 提取仿真结果
virtual function void extract_phase(uvm_phase phase);
super.extract_phase(phase);
`uvm_info("PHASE", "Executing extract_phase", UVM_LOW)
// 提取覆盖率数据、性能统计等
endfunction
// 7. Check Phase - 检查仿真结果
virtual function void check_phase(uvm_phase phase);
super.check_phase(phase);
`uvm_info("PHASE", "Executing check_phase", UVM_LOW)
// 检查错误、验证结果等
endfunction
// 8. Report Phase - 报告仿真结果
virtual function void report_phase(uvm_phase phase);
super.report_phase(phase);
`uvm_info("PHASE", "Executing report_phase", UVM_LOW)
// 生成最终报告
`uvm_info("REPORT", "Simulation completed successfully", UVM_LOW)
endfunction
endclass
4.2.3 TLM通信(Transaction Level Modeling)
TLM提供组件间事务级通信的标准接口,支持阻塞、非阻塞和分析通信模式,实现组件间的松耦合。
- 使用端口和接口定义通信协议
- 支持多种通信模式
- 提供事务级数据传递
// 1. 事务定义
class packet extends uvm_sequence_item;
`uvm_object_utils(packet)
rand bit [31:0] addr;
rand bit [31:0] data;
rand bit [1:0] command;
function new(string name = "packet");
super.new(name);
endfunction
endclass
// 2. 生产者组件
class producer extends uvm_component;
`uvm_component_utils(producer)
// 定义TLM端口
uvm_blocking_put_port #(packet) put_port;
uvm_analysis_port #(packet) analysis_port;
function new(string name, uvm_component parent);
super.new(name, parent);
put_port = new("put_port", this);
analysis_port = new("analysis_port", this);
endfunction
virtual task run_phase(uvm_phase phase);
packet pkt;
phase.raise_objection(this);
for (int i = 0; i < 3; i++) begin
pkt = packet::type_id::create($sformatf("pkt_%0d", i));
assert(pkt.randomize());
`uvm_info("PRODUCER", $sformatf("Sending packet: addr=0x%0h", pkt.addr), UVM_LOW)
// 阻塞方式发送到消费者
put_port.put(pkt);
// 广播方式发送到所有订阅者
analysis_port.write(pkt);
end
phase.drop_objection(this);
endtask
endclass
// 3. 消费者组件
class consumer extends uvm_component;
`uvm_component_utils(consumer)
// 定义TLM接口
uvm_blocking_put_imp #(packet, consumer) put_export;
uvm_analysis_imp #(packet, consumer) analysis_export;
int packet_count = 0;
function new(string name, uvm_component parent);
super.new(name, parent);
put_export = new("put_export", this);
analysis_export = new("analysis_export", this);
endfunction
// 实现阻塞put接口
virtual task put(packet pkt);
`uvm_info("CONSUMER", $sformatf("Received via put: addr=0x%0h, data=0x%0h",
pkt.addr, pkt.data), UVM_LOW)
packet_count++;
#10; // 模拟处理延迟
endtask
// 实现分析端口write接口
virtual function void write(packet pkt);
`uvm_info("CONSUMER", $sformatf("Received via analysis: addr=0x%0h",
pkt.addr), UVM_HIGH)
endfunction
endclass
// 4. 环境连接
class my_env extends uvm_env;
`uvm_component_utils(my_env)
producer prod;
consumer cons;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
prod = producer::type_id::create("prod", this);
cons = consumer::type_id::create("cons", this);
endfunction
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// 连接阻塞put端口
prod.put_port.connect(cons.put_export);
// 连接分析端口
prod.analysis_port.connect(cons.analysis_export);
endfunction
endclass
5. 典型工作流程
构建阶段: Test类启动,调用Factory创建并配置Env、Agent等所有组件。
连接阶段: 将所有组件的TLM端口连接起来,建立通信路径。
运行阶段:
-
Test启动一个或多个预先写好的Sequence。
-
Sequence在Sequencer上产生Transaction并发送给Driver。
-
Driver将Transaction转换为信号时序,驱动到DUT。
-
Monitor监控DUT输出,将信号转换回Transaction,并发送给Scoreboard和Coverage Collector。
-
Scoreboard进行数据比对,报告成功或错误。
-
Coverage Collector收集覆盖率数据。
检查与报告: 仿真结束后,分析日志和覆盖率报告,评估验证是否完成。
5. 总结
本文概括的介绍了UVM验证环境的基本组成,除了上述列举的组件和机制,一个健壮的UVM验证环境还会包含一些其他的细节,本系列后续文章将深入探讨每个UVM组件的详细用法、最佳实践和其他相关的知识。
下一篇:UVM验证入门(2)-uvm常用类的继承关系
参考文档:UVM_Cl ass_Reference_Manual_1.0.pdf