1. 构建基础UVM测试平台并测量仿真时间
任务目标
搭建一个最小可运行的UVM测试平台,包含driver、monitor、scoreboard三个核心组件,驱动一个简单的接口信号,运行一个基本测试,并通过仿真器的运行时选项测量仿真时间,记录该时间作为后续性能优化实验的基线。
环境依赖
需要支持UVM-1.2的仿真器(如VCS、QuestaSim、Xcelium)。以下代码基于QuestaSim 2023.3验证,使用-c命令行模式运行。无需额外安装库,UVM源码随仿真器分发。
完整实现
// file: tb_top.sv
`include "uvm_macros.svh"
import uvm_pkg::*;
// 接口:简单数据通路
interface simple_if(input bit clk);
logic [7:0] data;
logic valid;
logic ready;
clocking cb @(posedge clk);
output data, valid;
input ready;
endclocking
modport DRIVER (clocking cb, output data, valid);
modport MONITOR (input data, valid, ready);
endinterface
// 事务对象
class transaction extends uvm_sequence_item;
rand bit [7:0] data;
`uvm_object_utils_begin(transaction)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "transaction");
super.new(name);
endfunction
endclass
// 序列:产生10个随机事务
class base_seq extends uvm_sequence #(transaction);
`uvm_object_utils(base_seq)
function new(string name = "base_seq");
super.new(name);
endfunction
task body();
repeat(10) begin
transaction tx = transaction::type_id::create("tx");
start_item(tx);
finish_item(tx);
end
endtask
endclass
// Driver:驱动接口
class driver extends uvm_driver #(transaction);
`uvm_component_utils(driver)
virtual simple_if vif;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
@(vif.cb);
vif.cb.data <= req.data;
vif.cb.valid <= 1;
do @(vif.cb); while (!vif.cb.ready);
vif.cb.valid <= 0;
seq_item_port.item_done();
end
endtask
endclass
// Monitor:采样接口
class monitor extends uvm_monitor;
`uvm_component_utils(monitor)
virtual simple_if vif;
uvm_analysis_port #(transaction) ap;
function new(string name, uvm_component parent);
super.new(name, parent);
ap = new("ap", this);
endfunction
task run_phase(uvm_phase phase);
forever begin
@(posedge vif.valid);
begin
transaction tx = transaction::type_id::create("tx");
tx.data = vif.data;
ap.write(tx);
@(negedge vif.valid);
end
end
endtask
endclass
// Scoreboard:比较收发数据
class scoreboard extends uvm_scoreboard;
`uvm_component_utils(scoreboard)
uvm_analysis_imp #(transaction, scoreboard) imp;
transaction expected_q[$];
int match_count;
function new(string name, uvm_component parent);
super.new(name, parent);
imp = new("imp", this);
endfunction
function void write(transaction tx);
if (expected_q.size() > 0) begin
transaction exp = expected_q.pop_front();
if (exp.data == tx.data)
match_count++;
else
`uvm_error("SCB", $sformatf("Mismatch: exp=%0d got=%0d", exp.data, tx.data))
end
endfunction
task run_phase(uvm_phase phase);
// 从driver端获取期望数据(通过analysis port连接)
endtask
endclass
// 环境
class env extends uvm_env;
`uvm_component_utils(env)
driver d;
monitor m;
scoreboard s;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
d = driver::type_id::create("d", this);
m = monitor::type_id::create("m", this);
s = scoreboard::type_id::create("s", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// 将driver的seq_item_port连接到sequencer(此处用隐式sequencer)
// 实际连接在test中完成
endfunction
endclass
// 测试
class base_test extends uvm_test;
`uvm_component_utils(base_test)
env e;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
e = env::type_id::create("e", this);
// 设置虚接口
if (!uvm_config_db#(virtual simple_if)::get(this, "*", "vif", e.d.vif))
`uvm_fatal("CFG", "Virtual interface not found")
if (!uvm_config_db#(virtual simple_if)::get(this, "*", "vif", e.m.vif))
`uvm_fatal("CFG", "Virtual interface not found")
endfunction
task run_phase(uvm_phase phase);
base_seq seq;
seq = base_seq::type_id::create("seq");
phase.raise_objection(this);
seq.start(e.d.seq_item_port);
#100ns;
phase.drop_objection(this);
endtask
endclass
// 顶层模块
module tb_top;
bit clk;
always #5 clk = ~clk;
simple_if vif(clk);
initial begin
uvm_config_db#(virtual simple_if)::set(null, "*", "vif", vif);
run_test("base_test");
end
// 驱动时钟和复位
initial begin
vif.ready = 1;
vif.valid = 0;
vif.data = 0;
end
endmodule
运行方式
# 编译(QuestaSim)
vlog -sv -uvm tb_top.sv
# 运行并测量仿真时间
vsim -c -uvm -do "run -all; quit" work.tb_top
# 仿真结束后,终端会输出UVM报告摘要,其中包含仿真时间
验证方法与判定标准
运行后观察以下输出:
- UVM报告显示
UVM_INFO,无UVM_ERROR或UVM_FATAL; - Scoreboard的
match_count等于10(可通过在report_phase中添加打印确认); - 仿真时间记录:QuestaSim在
run -all结束后,终端会显示Break at或Time:信息,记录该时间值作为基线。例如:Break at /tb_top.sv line 120, Time: 215 ns中的215 ns即为本次仿真的总仿真时间。
判定通过条件:UVM报告无错误且scoreboard匹配计数为10,同时记录下仿真时间数值作为后续实验的基线参考。
常见问题
- 若出现
Fatal: Virtual interface not found,检查uvm_config_db的路径匹配是否正确; - 若仿真挂起,检查driver中握手信号是否死锁——本设计中
ready恒为1,不会出现该问题; - 仿真时间测量以QuestaSim终端输出的
Time:字段为准,不同仿真器输出格式略有差异,但均会显示总仿真时间。