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

验证方法与判定标准

运行仿真后,观察输出日志。判定通过的三个条件:

  1. seq_simple生效:driver打印3条data=0x?? delay=1~5的记录,data为随机值。
  2. seq_burst生效:driver打印5条data=0xa5 delay=0的记录。
  3. 停止机制生效:仿真结束前出现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()演示停止机制,仿真才能正常结束。