4. 实现UVM序列机制
任务目标
在UVM验证环境中,定义多个sequence(激励序列),通过sequencer将sequence产生的transaction发送给driver,并演示如何控制sequence的启动(start)与停止(stop)。本案例聚焦于UVM序列机制的核心链路:sequence → sequencer → driver。
环境依赖
需要已安装支持UVM-1.2或IEEE 1800.2的仿真器(如VCS、QuestaSim、Xcelium)。以下代码基于UVM-1.2标准,使用标准UVM类库,无需额外IP。
关键完整代码
// file: uvm_sequence_demo.sv
`include "uvm_macros.svh"
import uvm_pkg::*;
// 1. 简单事务对象
class my_transaction extends uvm_sequence_item;
rand bit [7:0] data;
rand int delay;
`uvm_object_utils_begin(my_transaction)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_field_int(delay, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "my_transaction");
super.new(name);
endfunction
endclass
// 2. 两个不同的sequence
class seq_simple extends uvm_sequence #(my_transaction);
`uvm_object_utils(seq_simple)
function new(string name = "seq_simple");
super.new(name);
endfunction
task body();
my_transaction tx;
repeat(3) begin
tx = my_transaction::type_id::create("tx");
start_item(tx);
assert(tx.randomize() with { delay inside {[1:5]}; });
finish_item(tx);
end
endtask
endclass
class seq_burst extends uvm_sequence #(my_transaction);
`uvm_object_utils(seq_burst)
function new(string name = "seq_burst");
super.new(name);
endfunction
task body();
my_transaction tx;
repeat(5) begin
tx = my_transaction::type_id::create("tx");
start_item(tx);
assert(tx.randomize() with { data == 8'hA5; delay == 0; });
finish_item(tx);
end
endtask
endclass
// 3. 驱动driver
class my_driver extends uvm_driver #(my_transaction);
`uvm_component_utils(my_driver)
function new(string name = "my_driver", uvm_component* parent = null);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
my_transaction tx;
forever begin
seq_item_port.get_next_item(tx);
$display("[DRV] got data=0x%0h delay=%0d at time %0t", tx.data, tx.delay, $time);
#(tx.delay * 10ns); // 模拟驱动耗时
seq_item_port.item_done();
end
endtask
endclass
// 4. 环境与测试
class my_env extends uvm_env;
`uvm_component_utils(my_env)
my_driver drv;
uvm_sequencer #(my_transaction) sqr;
function new(string name = "my_env", uvm_component* parent = null);
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_transaction)::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
endclass
class my_test extends uvm_test;
`uvm_component_utils(my_test)
my_env env;
function new(string name = "my_test", uvm_component* parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env", this);
endfunction
task run_phase(uvm_phase phase);
seq_simple seq1;
seq_burst seq2;
phase.raise_objection(this);
// 启动seq1,发送3个随机事务
seq1 = seq_simple::type_id::create("seq1");
seq1.start(env.sqr);
// 启动seq2,发送5个固定事务
seq2 = seq_burst::type_id::create("seq2");
seq2.start(env.sqr);
// 演示停止:创建一个永不结束的sequence,然后调用kill()
begin
uvm_sequence #(my_transaction) killer_seq;
killer_seq = new("killer_seq");
fork
killer_seq.start(env.sqr);
join_none
#100ns;
killer_seq.kill();
$display("[TEST] killer_seq has been killed at time %0t", $time);
end
phase.drop_objection(this);
endtask
endclass
module top;
initial begin
run_test("my_test");
end
endmodule
运行方式
# 使用QuestaSim/VCS等仿真器编译运行
vlog -sv uvm_sequence_demo.sv +incdir+$UVM_HOME/src
vsim -c -do "run -all; quit" work.top
验证方法与判定标准
运行仿真后,观察输出日志。判定通过的三个条件:
- seq_simple生效:driver打印3条
data=0x?? delay=1~5的记录,data为随机值。 - seq_burst生效:driver打印5条
data=0xa5 delay=0的记录。 - 停止机制生效:仿真结束前出现
killer_seq has been killed消息,且仿真能正常退出(无挂起)。若killer_seq未被kill,仿真将因objection无法撤销而超时。
若以上三条均满足,说明sequence定义、sequencer路由、start启动和kill停止机制均工作正常。
关键点说明
start(sequencer)是启动sequence的标准入口,内部会执行body()任务。kill()用于强制终止一个正在执行的sequence,适用于需要提前结束激励的场景。- driver通过
get_next_item()/item_done()与sequencer握手,完成事务传递。 - 本案例中
killer_seq的body为空任务,因此会一直占用objection;通过kill()演示停止机制,仿真才能正常结束。