4. UVM序列生成与驱动
任务目标
在UVM验证环境中,定义复位序列与读写序列,通过sequencer将sequence item驱动至driver,实现不同激励的生成与发送。本案例聚焦sequence机制的最小可运行闭环,不涉及寄存器模型或协议细节。
环境依赖
需要UVM-1.2库(或等效实现),仿真器支持SystemVerilog(如VCS、QuestaSim)。以下代码为单个SV文件,可直接编译运行。
关键完整代码
// file: seq_drive_demo.sv
`include "uvm_macros.svh"
import uvm_pkg::*;
// 1. 定义sequence item(激励数据单元)
class my_item extends uvm_sequence_item;
rand bit [7:0] addr;
rand bit [7:0] data;
rand bit write; // 1=写, 0=读
`uvm_object_utils_begin(my_item)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_field_int(write, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "my_item");
super.new(name);
endfunction
endclass
// 2. 定义复位序列(只产生一个复位item)
class reset_seq extends uvm_sequence #(my_item);
`uvm_object_utils(reset_seq)
function new(string name = "reset_seq");
super.new(name);
endfunction
task body();
my_item item = my_item::type_id::create("item");
start_item(item);
item.addr = 0;
item.data = 0;
item.write = 0; // 复位读操作
finish_item(item);
endtask
endclass
// 3. 定义读写序列(产生多个随机读写item)
class rw_seq extends uvm_sequence #(my_item);
`uvm_object_utils(rw_seq)
function new(string name = "rw_seq");
super.new(name);
endfunction
task body();
repeat (5) begin
my_item item = my_item::type_id::create("item");
start_item(item);
if (!item.randomize())
`uvm_fatal(get_type_name(), "randomize failed")
finish_item(item);
end
endtask
endclass
// 4. 定义driver(接收item并打印)
class my_driver extends uvm_driver #(my_item);
`uvm_component_utils(my_driver)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
my_item item;
forever begin
seq_item_port.get_next_item(item);
// 模拟驱动到DUT接口(此处仅打印)
$display("[DRV] %s addr=%0h data=%0h",
item.write ? "WRITE" : "READ", item.addr, item.data);
seq_item_port.item_done();
end
endtask
endclass
// 5. 定义测试层:启动sequence并连接
class test_base extends uvm_test;
`uvm_component_utils(test_base)
my_driver drv;
uvm_sequencer #(my_item) sqr;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
drv = my_driver::type_id::create("drv", this);
sqr = uvm_sequencer #(my_item)::type_id::create("sqr", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction
task run_phase(uvm_phase phase);
reset_seq rseq;
rw_seq wseq;
phase.raise_objection(this);
// 先执行复位序列
rseq = reset_seq::type_id::create("rseq");
rseq.start(sqr);
// 再执行读写序列
wseq = rw_seq::type_id::create("wseq");
wseq.start(sqr);
#10ns;
phase.drop_objection(this);
endtask
endclass
// 6. 顶层模块
module top;
initial begin
run_test("test_base");
end
endmodule
运行方式
# 使用VCS编译运行
vcs -sverilog +incdir+$UVM_HOME/src seq_drive_demo.sv $UVM_HOME/src/uvm.sv -R -l run.log
# 或使用QuestaSim
vlog -sv seq_drive_demo.sv +incdir+$UVM_HOME/src $UVM_HOME/src/uvm.sv
vsim -c -do "run -all; quit" test_base
验证方法与判定标准
运行仿真后,观察终端输出。判定通过条件:
- 首先出现1行
[DRV] READ addr=0 data=0(来自复位序列); - 随后出现5行
[DRV] WRITE/READ addr=随机值 data=随机值(来自读写序列); - 仿真无UVM_ERROR或UVM_FATAL,正常退出。
预期输出示例(地址与数据为随机值,仅示意格式):
[DRV] READ addr=0 data=0
[DRV] WRITE addr=3c data=a5
[DRV] READ addr=7f data=12
[DRV] WRITE addr=1a data=ff
[DRV] READ addr=55 data=00
[DRV] WRITE addr=e2 data=8d
常见问题
- 编译报uvm_pkg找不到:确认UVM_HOME环境变量已设置,且编译命令中包含
+incdir+$UVM_HOME/src。 - 没有输出:检查run_test参数与test类名一致(此处为
"test_base"),且顶层模块中已调用run_test。 - objection机制:run_phase中必须raise/drop objection,否则仿真可能在sequence执行前结束。