文章目录
- 前言
- [一、UVM 核心组件详解](#一、UVM 核心组件详解)
-
- [1. uvm_component](#1. uvm_component)
- [2. uvm_object](#2. uvm_object)
- [3. uvm_driver](#3. uvm_driver)
- [4. uvm_monitor](#4. uvm_monitor)
- [5. uvm_agent](#5. uvm_agent)
- [6. uvm_sequencer](#6. uvm_sequencer)
- [7. uvm_sequence](#7. uvm_sequence)
- [8. uvm_sequence_item](#8. uvm_sequence_item)
- [9. uvm_scoreboard](#9. uvm_scoreboard)
- [10. uvm_env](#10. uvm_env)
- [11. uvm_test](#11. uvm_test)
- 二、相互关系
- 三、综合示例
前言
UVM(Universal Verification Methodology)是一种广泛应用于硬件验证领域的标准方法学,旨在提高验证流程的可重用性和可扩展性。UVM 提供了一套预定义的类和方法,用于创建模块化、可重用的验证环境。
一、UVM 核心组件详解
UVM(Universal Verification Methodology)是一种广泛应用于硬件验证领域的标准方法学,旨在提高验证流程的可重用性和可扩展性。UVM 提供了一套预定义的类和方法,用于创建模块化、可重用的验证环境。以下是一些核心组件及其作用和相互关系的详细介绍:
1. uvm_component
uvm_component 是 UVM 中所有组件的基类,如 uvm_driver、uvm_monitor、uvm_agent、uvm_scoreboard 等。它支持层次结构、相位机制和报告机制。
- 层次结构:每个 uvm_component 实例都是 UVM 树形结构的节点,可以有多个子节点。
- 相位机制:组件可以参与 UVM 的相位机制,组织仿真过程中的不同阶段,如构建、连接、运行和清理。
- 报告机制:组件可以使用 UVM 的消息基础设施报告事件、警告和错误。
定义示例:
c
class my_component extends uvm_component;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
// 构建组件
endfunction
virtual function void connect_phase(uvm_phase phase);
// 连接组件
endfunction
endclass
2. uvm_object
uvm_object 是 UVM 中所有对象的基类,提供了字段自动化机制和身份鉴别方法。
- 字段自动化:提供 print、copy、pack 等方法。
- 身份鉴别:提供 get_name、get_type_name、get_full_name 等方法。
定义示例:
c
class my_object extends uvm_object;
function new(string name = "my_object");
super.new(name);
endfunction
virtual function void do_print(uvm_printer printer);
// 自定义打印方法
endfunction
endclass
3. uvm_driver
uvm_driver 负责将事务驱动到 DUT(Design Under Test)的接口上。它通常从 uvm_sequencer 获取事务,并将其转换为 DUT 可以理解的信号。
定义示例:
c
class my_driver extends uvm_driver #(my_transaction);
virtual my_interface vif;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
// 对 req 进行处理,发送事务到 DUT
vif.signal = req.data;
seq_item_port.item_done();
end
endtask
endclass
4. uvm_monitor
uvm_monitor 负责监视 DUT 的接口,并将事务捕获到事务对象中。它通常将捕获的事务发送到 uvm_scoreboard 或其他组件进行进一步处理。
定义示例:
c
class my_monitor extends uvm_monitor;
uvm_analysis_port #(my_transaction) item_collected_port;
virtual my_interface vif;
function new(string name, uvm_component parent);
super.new(name, parent);
item_collected_port = new("item_collected_port", this);
endfunction
virtual task run_phase(uvm_phase phase);
forever begin
// 监视 DUT 的接口并捕获事务
my_transaction trans = my_transaction::type_id::create("trans");
trans.data = vif.signal;
item_collected_port.write(trans);
end
endtask
endclass
5. uvm_agent
uvm_agent 是一个组合组件,通常包含一个 uvm_driver、一个 uvm_monitor 和一个 uvm_sequencer。它负责管理这些组件的交互,提供一个完整的验证接口。
定义示例:
c
class my_agent extends uvm_agent;
my_driver m_driver;
my_sequencer m_sequencer;
my_monitor m_monitor;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
m_driver = my_driver::type_id::create("m_driver", this);
m_sequencer = my_sequencer::type_id::create("m_sequencer", this);
m_monitor = my_monitor::type_id::create("m_monitor", this);
endfunction
virtual function void connect_phase(uvm_phase phase);
m_driver.seq_item_port.connect(m_sequencer.seq_item_export);
endfunction
endclass
6. uvm_sequencer
uvm_sequencer 负责管理事务的生成和发送。它从 uvm_sequence 获取事务,并将其发送到 uvm_driver。
定义示例:
c
class my_sequencer extends uvm_sequencer #(my_transaction);
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
7. uvm_sequence
uvm_sequence 用于生成事务序列。它可以生成单个事务或多个事务的序列,并将它们发送到 uvm_sequencer。
定义示例:
c
class my_sequence extends uvm_sequence #(my_transaction);
function new(string name = "my_sequence");
super.new(name);
endfunction
virtual task body();
`uvm_info(get_type_name(), "Executing my_sequence", UVM_LOW)
// 创建和发送事务
my_transaction trans = my_transaction::type_id::create("trans");
start_item(trans);
trans.randomize();
finish_item(trans);
endtask
endclass
8. uvm_sequence_item
uvm_sequence_item 是所有事务的基类。它定义了事务的基本结构和方法,可以被 uvm_sequence 和 uvm_driver 使用。
定义示例:
c
class my_transaction extends uvm_sequence_item;
rand int data;
function new(string name = "my_transaction");
super.new(name);
endfunction
virtual function void do_print(uvm_printer printer);
printer.print_field_int("data", data, $bits(data));
endfunction
endclass
9. uvm_scoreboard
uvm_scoreboard 用于验证 DUT 的行为是否正确。它通常接收来自 uvm_monitor 的事务,并进行比较和验证。
定义示例:
c
class my_scoreboard extends uvm_scoreboard;
uvm_analysis_imp #(my_transaction, my_scoreboard) item_collected_export;
function new(string name, uvm_component parent);
super.new(name, parent);
item_collected_export = new("item_collected_export", this);
endfunction
virtual function void write(my_transaction t);
// 处理接收到的事务
`uvm_info(get_type_name(), "Received transaction", UVM_LOW)
endfunction
endclass
10. uvm_env
uvm_env 是验证环境的顶层组件,通常包含多个 uvm_agent、uvm_scoreboard 和其他组件。它负责管理整个验证环境的构建和运行。
定义示例:
c
class my_env extends uvm_env;
my_agent m_agent;
my_scoreboard m_scoreboard;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
m_agent = my_agent::type_id::create("m_agent", this);
m_scoreboard = my_scoreboard::type_id::create("m_scoreboard", this);
endfunction
virtual function void connect_phase(uvm_phase phase);
// 连接 agent 和 scoreboard
m_agent.m_monitor.item_collected_port.connect(m_scoreboard.item_collected_export);
endfunction
endclass
11. uvm_test
uvm_test 是测试用例的顶层组件,通常包含一个 uvm_env 和多个 uvm_sequence。它负责启动验证过程,并管理测试的运行。
定义示例:
c
class my_test extends uvm_test;
my_env m_env;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
m_env = my_env::type_id::create("m_env", this);
endfunction
virtual task run_phase(uvm_phase phase);
my_sequence seq = my_sequence::type_id::create("seq");
phase.raise_objection(this);
seq.start(m_env.m_agent.m_sequencer);
phase.drop_objection(this);
endtask
endclass
二、相互关系
- uvm_test:作为测试的入口点,创建和配置 uvm_env 和 uvm_sequence。
- uvm_env:管理验证环境中的多个 uvm_agent、uvm_scoreboard 和其他组件。
- uvm_agent:包含 uvm_driver、uvm_monitor 和 uvm_sequencer,负责驱动和监视 DUT 的接口。
- uvm_driver:从 uvm_sequencer 获取事务并驱动到 DUT。
- uvm_monitor:监视 DUT 的接口并捕获事务,发送到 uvm_scoreboard。
- uvm_sequencer:管理事务的生成和发送,从 uvm_sequence 获取事务。
- uvm_sequence:生成事务序列,发送到 uvm_sequencer。
- uvm_sequence_item:定义事务的基本结构和方法。
- uvm_scoreboard:验证 DUT 的行为是否正确,接收来自 uvm_monitor 的事务。
相互关系
- uvm_test:
○ 包含 uvm_env:管理验证环境。
○ 包含 uvm_sequence:管理测试序列。
○ 启动验证过程:通过 run_phase 方法启动测试。 - uvm_env:
○ 包含多个 uvm_agent:管理多个验证接口。
○ 包含 uvm_scoreboard:验证 DUT 的行为。
○ 配置组件间通信:通过 connect_phase 方法连接组件。 - uvm_agent:
○ 包含 uvm_driver:驱动事务到 DUT。
○ 包含 uvm_monitor:监视 DUT 的接口。
○ 包含 uvm_sequencer:管理事务序列。
○ 连接组件:通过 connect_phase 方法连接 uvm_driver 和 uvm_sequencer。 - uvm_driver:
○ 从 uvm_sequencer 获取事务:通过 seq_item_port 获取事务。
○ 驱动事务到 DUT:将事务转换为 DUT 可以理解的信号。
5. uvm_monitor:
○ 监视 DUT 的接口:捕获 DUT 的信号并转换为事务对象。
○ 发送事务:将捕获的事务发送到 uvm_scoreboard 或其他组件。 - uvm_sequencer:
○ 从 uvm_sequence 获取事务:通过 start_item 和 finish_item 方法获取事务。
○ 发送事务到 uvm_driver:通过 seq_item_port 发送事务。 - uvm_sequence:
○ 生成事务序列:通过 start_item 和 finish_item 方法生成事务。
○ 发送事务到 uvm_sequencer:通过 start 方法启动序列。 - uvm_sequence_item:
○ 定义事务结构:提供事务的基本字段和方法。
○ 支持字段自动化:提供 print、copy、pack 等方法。 - uvm_scoreboard:
○ 接收事务:通过 uvm_analysis_port 接收事务。
○ 比较和验证:比较接收到的事务和参考模型的数据,判断 DUT 是否正确工作。 - uvm_object:
○ 字段自动化:提供 print、copy、pack 等方法。
○ 身份鉴别:提供 get_name、get_type_name、get_full_name 等方法。
三、综合示例
以下是一个综合示例,展示了如何使用这些核心组件构建一个简单的验证环境:
c
// my_transaction.sv
class my_transaction extends uvm_object;
rand int data;
rand bit [31:0] address;
function new(string name = "my_transaction");
super.new(name);
endfunction
constraint c_data { data > 0; }
constraint c_address { address < 1024; }
virtual function void do_print(uvm_printer printer);
super.do_print(printer);
printer.print_field_int("data", data, $bits(data));
printer.print_field_int("address", address, $bits(address));
endfunction
endclass
c
// my_driver.sv
class my_driver extends uvm_driver#(my_transaction);
virtual my_if vif;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "Cannot get virtual interface")
endfunction
virtual task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
vif.data = req.data;
vif.address = req.address;
seq_item_port.item_done();
end
endtask
endclass
c
// my_monitor.sv
class my_monitor extends uvm_monitor;
virtual my_if vif;
uvm_analysis_port#(my_transaction) analysis_port;
function new(string name, uvm_component parent);
super.new(name, parent);
analysis_port = new("analysis_port", this);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "Cannot get virtual interface")
endfunction
virtual task run_phase(uvm_phase phase);
forever begin
my_transaction trans = new();
trans.data = vif.data;
trans.address = vif.address;
analysis_port.write(trans);
end
endtask
endclass
c
// my_sequencer.sv
class my_sequencer extends uvm_sequencer#(my_transaction);
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
c
// my_agent.sv
class my_agent extends uvm_agent;
my_driver driver;
my_monitor monitor;
my_sequencer sequencer;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
driver = my_driver::type_id::create("driver", this);
monitor = my_monitor::type_id::create("monitor", this);
sequencer = my_sequencer::type_id::create("sequencer", this);
endfunction
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
driver.seq_item_port.connect(sequencer.seq_item_export);
endfunction
endclass
c
// my_scoreboard.sv
class my_scoreboard extends uvm_scoreboard;
uvm_tlm_fifo#(my_transaction) exp_fifo;
uvm_tlm_fifo#(my_transaction) act_fifo;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
exp_fifo = new("exp_fifo", this);
act_fifo = new("act_fifo", this);
endfunction
virtual task run_phase(uvm_phase phase);
my_transaction exp_trans, act_trans;
forever begin
exp_fifo.get(exp_trans);
act_fifo.get(act_trans);
if (exp_trans != act_trans) begin
`uvm_error("SB", "Transaction mismatch")
end
end
endtask
endclass
c
// my_env.sv
class my_env extends uvm_env;
my_agent agent;
my_scoreboard scoreboard;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent = my_agent::type_id::create("agent", this);
scoreboard = my_scoreboard::type_id::create("scoreboard", this);
endfunction
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
agent.monitor.analysis_port.connect(scoreboard.exp_fifo.analysis_export);
endfunction
endclass
c
// my_test.sv
class my_test extends uvm_test;
my_env env;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env", this);
endfunction
virtual task run_phase(uvm_phase phase);
my_sequence seq = my_sequence::type_id::create("seq");
seq.start(env.agent.sequencer);
endtask
endclass