1. 搭建最小UVM测试平台

搭建最小UVM测试平台 学习卡片

任务目标

本案例将搭建一个最小可运行的UVM验证平台,用于验证一个8位加法器DUT。平台包含driver(驱动激励)、monitor(监测输出)和scoreboard(数据比对)三个核心组件,通过一个基础测试用例完成数据比对并报告结果。

环境依赖

需要支持UVM-1.2的仿真器(如VCS、QuestaSim),并确保UVM库已正确安装。以下代码基于UVM-1.2标准编写,使用SystemVerilog语言。

DUT设计(加法器)

// adder.sv - 8位加法器DUT
module adder(
    input  logic [7:0] a,
    input  logic [7:0] b,
    input  logic       cin,
    output logic [7:0] sum,
    output logic       cout
);
    assign {cout, sum} = a + b + cin;
endmodule

UVM验证平台完整代码

// uvmt_adder_pkg.sv - 最小UVM测试平台(单文件完整实现)
package uvmt_adder_pkg;
    import uvm_pkg::*;
    `include "uvm_macros.svh"

    // 事务对象
    class adder_transaction extends uvm_sequence_item;
        rand logic [7:0] a;
        rand logic [7:0] b;
        rand logic       cin;
        logic [7:0] sum;
        logic       cout;

        `uvm_object_utils_begin(adder_transaction)
            `uvm_field_int(a, UVM_ALL_ON)
            `uvm_field_int(b, UVM_ALL_ON)
            `uvm_field_int(cin, UVM_ALL_ON)
            `uvm_field_int(sum, UVM_ALL_ON)
            `uvm_field_int(cout, UVM_ALL_ON)
        `uvm_object_utils_end

        function new(string name = "adder_transaction");
            super.new(name);
        endfunction
    endclass

    // 序列:生成随机激励
    class adder_sequence extends uvm_sequence #(adder_transaction);
        `uvm_object_utils(adder_sequence)

        function new(string name = "adder_sequence");
            super.new(name);
        endfunction

        task body();
            repeat(10) begin
                adder_transaction tx = adder_transaction::type_id::create("tx");
                start_item(tx);
                assert(tx.randomize());
                finish_item(tx);
            end
        endtask
    endclass

    // Driver:驱动激励到DUT
    class adder_driver extends uvm_driver #(adder_transaction);
        `uvm_component_utils(adder_driver)
        virtual adder_if vif;

        function new(string name, uvm_component parent);
            super.new(name, parent);
        endfunction

        function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            if (!uvm_config_db#(virtual adder_if)::get(this, "", "vif", vif))
                `uvm_fatal("NOVIF", "virtual interface not found")
        endfunction

        task run_phase(uvm_phase phase);
            forever begin
                seq_item_port.get_next_item(req);
                vif.a   <= req.a;
                vif.b   <= req.b;
                vif.cin <= req.cin;
                @(posedge vif.clk);
                seq_item_port.item_done();
            end
        endtask
    endclass

    // Monitor:采集DUT输出
    class adder_monitor extends uvm_monitor;
        `uvm_component_utils(adder_monitor)
        virtual adder_if vif;
        uvm_analysis_port #(adder_transaction) mon_ap;

        function new(string name, uvm_component parent);
            super.new(name, parent);
        endfunction

        function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            if (!uvm_config_db#(virtual adder_if)::get(this, "", "vif", vif))
                `uvm_fatal("NOVIF", "virtual interface not found")
            mon_ap = new("mon_ap", this);
        endfunction

        task run_phase(uvm_phase phase);
            adder_transaction tx;
            forever begin
                @(posedge vif.clk);
                tx = adder_transaction::type_id::create("tx");
                tx.a   = vif.a;
                tx.b   = vif.b;
                tx.cin = vif.cin;
                tx.sum = vif.sum;
                tx.cout = vif.cout;
                mon_ap.write(tx);
            end
        endtask
    endclass

    // Scoreboard:数据比对
    class adder_scoreboard extends uvm_scoreboard;
        `uvm_component_utils(adder_scoreboard)
        uvm_analysis_imp #(adder_transaction, adder_scoreboard) analysis_imp;
        int match_count;
        int error_count;

        function new(string name, uvm_component parent);
            super.new(name, parent);
        endfunction

        function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            analysis_imp = new("analysis_imp", this);
            match_count = 0;
            error_count = 0;
        endfunction

        function void write(adder_transaction tx);
            logic [8:0] expected;
            expected = tx.a + tx.b + tx.cin;
            if ({tx.cout, tx.sum} == expected) begin
                match_count++;
                `uvm_info("SCB", $sformatf("MATCH: a=%0d b=%0d cin=%0d sum=%0d cout=%0d",
                    tx.a, tx.b, tx.cin, tx.sum, tx.cout), UVM_MEDIUM)
            end else begin
                error_count++;
                `uvm_error("SCB", $sformatf("MISMATCH: a=%0d b=%0d cin=%0d expected=%0d actual={%0d,%0d}",
                    tx.a, tx.b, tx.cin, expected, tx.cout, tx.sum))
            end
        endfunction

        function void report_phase(uvm_phase phase);
            `uvm_info("SCB", $sformatf("Scoreboard report: %0d matched, %0d errors",
                match_count, error_count), UVM_LOW)
        endfunction
    endclass

    // 环境
    class adder_env extends uvm_env;
        `uvm_component_utils(adder_env)
        adder_driver    driver;
        adder_monitor   monitor;
        adder_scoreboard scoreboard;

        function new(string name, uvm_component parent);
            super.new(name, parent);
        endfunction

        function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            driver     = adder_driver::type_id::create("driver", this);
            monitor    = adder_monitor::type_id::create("monitor", this);
            scoreboard = adder_scoreboard::type_id::create("scoreboard", this);
        endfunction

        function void connect_phase(uvm_phase phase);
            super.connect_phase(phase);
            driver.seq_item_port.connect(driver.seq_item_export); // 内部连接
            monitor.mon_ap.connect(scoreboard.analysis_imp);
        endfunction
    endclass

    // 测试基类
    class adder_base_test extends uvm_test;
        `uvm_component_utils(adder_base_test)
        adder_env env;

        function new(string name, uvm_component parent);
            super.new(name, parent);
        endfunction

        function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            env = adder_env::type_id::create("env", this);
        endfunction

        task run_phase(uvm_phase phase);
            adder_sequence seq = adder_sequence::type_id::create("seq");
            phase.raise_objection(this);
            seq.start(env.driver.seq_item_port);
            #100;
            phase.drop_objection(this);
        endtask

        function void report_phase(uvm_phase phase);
            if (env.scoreboard.error_count == 0)
                `uvm_info("TEST", "*** TEST PASSED ***", UVM_LOW)
            else
                `uvm_error("TEST", "*** TEST FAILED ***")
        endfunction
    endclass

    // 具体测试用例
    class adder_basic_test extends adder_base_test;
        `uvm_component_utils(adder_basic_test)

        function new(string name, uvm_component parent);
            super.new(name, parent);
        endfunction
    endclass
endpackage

接口定义与顶层模块

// adder_if.sv - 接口定义
interface adder_if(input logic clk);
    logic [7:0] a;
    logic [7:0] b;
    logic       cin;
    logic [7:0] sum;
    logic       cout;
endinterface

// top.sv - 顶层模块,连接DUT与UVM平台
module top;
    logic clk;
    initial clk = 0;
    always #5 clk = ~clk;

    adder_if vif(clk);
    adder dut(
        .a(vif.a), .b(vif.b), .cin(vif.cin),
        .sum(vif.sum), .cout(vif.cout)
    );

    initial begin
        uvm_config_db#(virtual adder_if)::set(null, "uvm_test_top.env.driver", "vif", vif);
        uvm_config_db#(virtual adder_if)::set(null, "uvm_test_top.env.monitor", "vif", vif);
        run_test("adder_basic_test");
    end
endmodule

编译与运行

# 使用QuestaSim示例(其他仿真器命令类似)
vlib work
vlog +incdir+$UVM_HOME/src $UVM_HOME/src/uvm_pkg.sv adder.sv adder_if.sv uvmt_adder_pkg.sv top.sv
vsim -c -do "run -all; quit" work.top

验证方法与通过标准

运行仿真后,观察UVM报告。通过标准为:

  • scoreboard报告显示10次比对全部MATCH,error_count为0;
  • 测试报告显示“TEST PASSED”;
  • UVM无FATAL或ERROR级别的报错。

若出现MISMATCH,说明DUT逻辑或平台连接有误,需检查接口信号连接和driver时序。

预期输出(确定性结果)

由于激励为随机生成,具体数值不可预测,但scoreboard的比对逻辑是确定性的:对于任意输入a、b、cin,期望输出恒为{cout, sum} = a + b + cin。因此只要DUT功能正确,所有事务必然比对通过,最终报告必然显示10次MATCH、0 errors,并打印“TEST PASSED”。