UVM验证入门(1)-uvm是什么

109 阅读11分钟

引言:UVM是什么?

  从字面意思来看UVM(Universal Verification Methodology)就是通用验证方法学;从具象概念来看UVM是一个用SystemVerilog编写的类库,它提供了很多预定义的类和方法,用于构建验证环境;从抽象概念来看,UVM是一种验证方法学,它提供了一套完整的验证框架和最佳实践,指导如何构建可重用、可扩展的验证环境。

1. 概述

  UVM是一个基于SystemVerilog的验证方法学框架,它提供了一套完整的类库最佳实践指南,用于构建模块化、可重用和可扩展的验证环境。   对于复杂的芯片设计,UVM通过标准化、自动化和可重用,解决了传统验证方式效率低下、容易出错、难以协作的痛点,已成为芯片验证行业不可或缺的基石。

UVM的核心价值

  • 标准化 - 统一的验证架构和编码风格
  • 可重用性 - 组件级、环境级、测试级的重用
  • 可维护性 - 清晰的层次结构和配置机制

2. UVM发展历程

时间方法学特点局限性
2000年前定向测试简单直接不可重用、难以维护
2000-2007eRM/VMM早期方法学语言特定、不够统一
2007-2011OVM多语言支持双标准并存
2011至今UVM行业统一标准学习曲线较陡

  UVM的前身是OVM,由Mentor和Candence于2008年联合发布。2010年,Accellera(Systemverilog Verilog语言标准最初的制定者)把OVM才能作为标准,并在此基础上着手退出新一代验证方法学UVM。   2010年5月,Accellera推出了UVM1.0EA,EA就是early adoption。   2011年2月,UVM1.0正式版本发布。   2011年6月,UVM1.1版本发布,修正了1.0版本中的大量问题。   2011年12月,UVM1.1a发布。   2012年5月,UVM1.1b发布。   2012年10月,UVM1.1c发布。   2013年3月,UVM1.1d发布。   2014年6月,UVM1.2发布,引入了新的方法、丰富了某些宏。   2017年12月,IEEE 1800.2发布,基于UVM1.2,提供了更严格的规范、支持寄存器动态地址映射,并简化了回调机制。   2020年3月,更新了IEEE 1800.2,显著的性能提升和功能增强,是目前广泛推荐使用的稳定版本。

3. 为什么是UVM

  在UVM之前,芯片验证面临巨大挑战:

  • 设计复杂度爆炸:SoC芯片集成数十亿晶体管,功能极其复杂。
  • 验证效率低下:传统的定向测试方法需要大量人力,且难以覆盖所有场景。
  • 代码不可重用:模块级验证代码无法用于系统级,新项目需要重写大量代码。
  • 协作困难:没有统一标准,不同工程师写的验证环境风格迥异,难以理解和维护。

  UVM的诞生就是为了解决这些问题,它融合了之前OVM、VMM等方法的优点,并由Accellera组织标准化,现已成为数字芯片验证领域的事实标准。

4. 典型的UVM验证平台结构

在这里插入图片描述

4.1 核心组件职责分解

4.1.1 test - 测试顶层控制器

核心职责:

  • 验证环境的最高层级管理者
  • 测试场景的入口点和协调中心
  • 配置管理的决策者
class base_test extends uvm_test;
    // 构建测试环境、配置参数、启动测试序列
    virtual function void build_phase(uvm_phase phase);
        env = my_env::type_id::create("env", this);
    endfunction
endclass

4.1.2 env - 验证环境容器

核心职责:

  • 验证组件的集成容器
  • 组件间连接的架构师
  • 环境级配置的承载者
class my_env extends uvm_env;
    my_agent    agent;
    my_scoreboard scb;
    my_coverage cov;
    my_virtual_sequencer v_sqr;
    
    // 1. 构建验证环境的所有组件
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        agent = my_agent::type_id::create("agent", this);
        scb = my_scoreboard::type_id::create("scb", this);
        cov = my_coverage::type_id::create("cov", this);
        v_sqr = my_virtual_sequencer::type_id::create("v_sqr", this);
    endfunction
    
    // 2. 连接所有组件间的通信端口
    virtual function void connect_phase(uvm_phase phase);
        // 连接monitor到scoreboard和coverage
        agent.monitor.analysis_port.connect(scb.analysis_export);
        agent.monitor.analysis_port.connect(cov.analysis_export);
        
        // 连接virtual sequencer到physical sequencer
        v_sqr.data_sqr = agent.sequencer;
    endfunction
    
    // 3. 环境级配置分发
    virtual function void configure();
        agent.is_active = UVM_ACTIVE;  // 设置agent工作模式
    endfunction
endclass

4.1.3 agent - 接口功能包

核心职责:

  • 特定接口验证功能的完整封装
  • 工作模式的统一管理
  • 协议相关组件的集中管理
class my_agent extends uvm_agent;
    my_sequencer sqr;
    my_driver    drv;
    my_monitor   mon;
    
    uvm_analysis_port #(my_transaction) analysis_port;
    
    // 1. 根据配置创建组件(ACTIVE/PASSIVE模式)
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        mon = my_monitor::type_id::create("mon", this);
        
        if (is_active == UVM_ACTIVE) begin
            sqr = my_sequencer::type_id::create("sqr", this);
            drv = my_driver::type_id::create("drv", this);
        end
    endfunction
    
    // 2. 连接ACTIVE模式下的组件
    virtual function void connect_phase(uvm_phase phase);
        // 连接driver和sequencer
        if (is_active == UVM_ACTIVE)
            drv.seq_item_port.connect(sqr.seq_item_export);
            
        // 将monitor的分析端口代理到agent级别
        analysis_port = mon.analysis_port;
    endfunction
    
    // 3. 协议特定的配置管理
    bit collect_coverage = 1;
    int bus_width = 32;
endclass

4.1.4 driver - 信号驱动器

核心职责:

  • Transaction到信号时序的转换器
  • 总线协议的具体实现者
  • 与Sequencer的请求响应协调者
class my_driver extends uvm_driver #(my_transaction);
    virtual my_interface vif;
    
    // 1. 从sequencer获取transaction
    virtual task run_phase(uvm_phase phase);
        forever begin
            seq_item_port.get_next_item(req);  // 从sequencer获取激励
            drive_transaction(req);           // 驱动到DUT
            seq_item_port.item_done();        // 告知完成
        end
    endtask
    
    // 2. 实现具体的协议时序
    virtual task drive_transaction(my_transaction tr);
        // 按照总线协议将transaction转换为信号时序
        vif.data <= tr.data;
        vif.addr <= tr.addr;
        vif.valid <= 1'b1;
        
        @(posedge vif.clk);
        while (!vif.ready) @(posedge vif.clk);
        
        vif.valid <= 1'b0;
        `uvm_info("DRV", $sformatf("Drived transaction: addr=0x%0h, data=0x%0h", 
                  tr.addr, tr.data), UVM_HIGH)
    endtask
    
    // 3. 处理背压和流控制
    virtual task handle_backpressure();
        // 实现背压处理逻辑
    endtask
endclass

4.1.5 monitor - 信号级监视器

核心职责:

  • 接口信号的被动观察者
  • 信号到时序的反向转换器
  • 验证数据的采集分发中心
class my_monitor extends uvm_monitor;
    virtual my_interface vif;
    uvm_analysis_port #(my_transaction) analysis_port;
    
    // 1. 持续监控接口信号
    virtual task run_phase(uvm_phase phase);
        forever begin
            my_transaction tr;
            collect_transaction(tr);     // 采集信号并转换为transaction
            analysis_port.write(tr);     // 分发到所有订阅者
        end
    endtask
    
    // 2. 协议解析和事务重建
    virtual task collect_transaction(output my_transaction tr);
        tr = my_transaction::type_id::create("tr");
        
        // 等待事务开始
        @(posedge vif.clk iff vif.valid);
        
        // 采集地址相位
        tr.addr = vif.addr;
        
        // 采集数据相位
        do begin
            @(posedge vif.clk);
            tr.data = vif.data;
        end while (vif.valid && !vif.last);
        
        `uvm_info("MON", $sformatf("Captured transaction: addr=0x%0h", tr.addr), UVM_HIGH)
    endtask
    
    // 3. 协议覆盖率收集(可选)
    covergroup protocol_cg;
        // 协议特定的覆盖率点
    endgroup
endclass

4.1.6 sequencer - 激励调度器

核心职责:

  • 测试序列的执行调度器
  • Driver请求的仲裁分配器
  • 激励生成的流程控制器
class my_sequencer extends uvm_sequencer #(my_transaction);
    // 1. 序列仲裁和调度
    // (基础功能由UVM框架自动提供)
    
    // 2. 支持多种仲裁算法
    function new(string name, uvm_component parent);
        super.new(name, parent);
        set_arbitration(SEQ_ARB_FIFO);  // 设置仲裁策略
    endfunction
    
    // 3. 序列执行控制
    // - 自动处理sequence的start(), stop(), pause(), resume()
    // - 管理sequence的层次结构
    // - 协调多个并发sequence的执行
endclass

// Sequencer的使用主要通过Sequence控制
class my_sequence extends uvm_sequence #(my_transaction);
    virtual task body();
        // Sequencer协调这些transaction的发送
        `uvm_do(req)                    // 自动创建、随机化、发送
        `uvm_do_with(req, {data == 8'hFF;})  // 带约束的发送
        `uvm_send(req)                  // 发送已存在的transaction
    endtask
endclass

4.1.7 scoreboard - 结果检查器

核心职责:

  • Scoreboard是UVM验证环境中负责检查DUT功能正确性的核心组件,它像裁判一样评判DUT的行为是否符合预期
  • 验证DUT的功能正确性和数据完整性
  • 通过比对实际输出与预期输出,发现设计缺陷
class my_scoreboard extends uvm_scoreboard;
    // 1. 数据一致性检查 - 核心比对逻辑
    virtual function void check_data_consistency(my_transaction input_tr, my_transaction output_tr);
        // 比对输入和输出数据是否一致
        if (input_tr.payload != output_tr.payload) begin
            `uvm_error("DATA_MISMATCH", 
                $sformatf("Input payload 0x%0h != Output payload 0x%0h",
                         input_tr.payload, output_tr.payload))
        end
        
        // 检查数据完整性(CRC、校验和等)
        if (output_tr.crc != calculate_expected_crc(output_tr)) begin
            `uvm_error("CRC_ERROR", "Data corruption detected")
        end
    endfunction

    // 2. 协议符合性检查
    virtual function void check_protocol_compliance(my_transaction tr);
        // 检查事务顺序是否正确
        if (tr.sequence_num != expected_sequence_num) begin
            `uvm_error("SEQ_ERROR", 
                $sformatf("Sequence number mismatch: got %0d, expected %0d",
                         tr.sequence_num, expected_sequence_num))
        end
        
        // 检查响应延迟是否符合规范
        if (tr.response_latency > max_allowed_latency) begin
            `uvm_warning("LATENCY_WARN", "Response latency exceeds specification")
        end
    endfunction

    // 3. 参考模型比对
    virtual function void compare_with_reference(my_transaction actual_tr);
        my_transaction expected_tr;
        
        // 从参考模型获取预期结果
        expected_tr = reference_model.predict(actual_tr);
        
        // 详细比对每个字段
        if (!expected_tr.compare(actual_tr)) begin
            `uvm_error("COMPARE_FAIL", 
                $sformatf("DUT output doesn't match reference model\nExpected: %s\nActual: %s",
                         expected_tr.convert2string(), actual_tr.convert2string()))
        end
    endfunction

    // 4. 错误注入和异常处理测试
    virtual function void check_error_handling();
        // 验证DUT对错误条件的处理是否正确
        if (error_condition_detected && !error_response_received) begin
            `uvm_error("ERROR_HANDLING", "DUT failed to handle error condition properly")
        end
    endfunction

    // 5. 性能指标统计
    virtual function void collect_performance_metrics();
        // 收集吞吐量、延迟等性能数据
        total_transactions++;
        total_latency += current_latency;
        
        `uvm_info("PERF", 
            $sformatf("Average latency: %0d cycles, Throughput: %0d transactions/cycle",
                     total_latency / total_transactions, throughput), UVM_MEDIUM)
    endfunction
endclass

4.2 UVM的核心机制

4.2.1 工厂模式(Factory Pattern)

  工厂机制是UVM的核心特性,允许在不修改原始代码的情况下,动态地替换对象和组件的类型,提供了极大的灵活性和可重用性。

  • 使用宏注册类型到工厂
  • 通过工厂创建对象实例
  • 支持运行时类型覆盖
// 1. 基类定义和注册
class base_transaction extends uvm_sequence_item;
    `uvm_object_utils(base_transaction)
    
    rand bit [7:0] data;
    rand bit [7:0] addr;
    
    function new(string name = "base_transaction");
        super.new(name);
    endfunction
endclass

// 2. 派生类定义和注册
class extended_transaction extends base_transaction;
    `uvm_object_utils(extended_transaction)
    
    rand bit [3:0] user_bits;
    rand bit       priority;
    
    function new(string name = "extended_transaction");
        super.new(name);
    endfunction
endclass

// 3. 在测试中实现类型覆盖
class my_test extends uvm_test;
    `uvm_component_utils(my_test)
    
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        
        // 使用工厂机制覆盖类型
        base_transaction::type_id::set_type_override(
            extended_transaction::get_type());
    endfunction
    
    virtual task run_phase(uvm_phase phase);
        base_transaction tr;
        phase.raise_objection(this);
        
        // 工厂会自动创建extended_transaction实例
        tr = base_transaction::type_id::create("tr");
        `uvm_info("TEST", $sformatf("Created transaction type: %s", 
                  tr.get_type_name()), UVM_LOW)
        
        phase.drop_objection(this);
    endtask
endclass

4.2.2 配置机制(Configuration)

  配置机制提供了一种在UVM组件层次中传递配置信息的标准方法,使得测试可以灵活地配置验证环境,而无需修改环境代码。

  • 使用uvm_config_db存储和检索配置信息
  • 支持任意数据类型的配置
  • 提供作用域和优先级控制
// 1. 配置对象定义
class bus_config extends uvm_object;
    `uvm_object_utils(bus_config)
    
    int bus_width = 32;
    int max_burst_size = 16;
    bit has_coverage = 1;
    bit is_active = 1;
    
    function new(string name = "bus_config");
        super.new(name);
    endfunction
endclass

// 2. 在测试中设置配置
class config_test extends uvm_test;
    `uvm_component_utils(config_test)
    
    bus_config cfg;
    
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        
        // 创建并配置配置对象
        cfg = bus_config::type_id::create("cfg");
        cfg.bus_width = 64;
        cfg.max_burst_size = 32;
        cfg.has_coverage = 0;  // 为性能测试禁用覆盖率
        
        // 将配置对象存储到config_db
        uvm_config_db#(bus_config)::set(this, "env.agent*", "bus_cfg", cfg);
        
        // 设置简单值类型的配置
        uvm_config_db#(int)::set(this, "env.agent*", "verbosity", UVM_HIGH);
    endfunction
endclass

// 3. 在Agent中获取配置
class my_agent extends uvm_agent;
    `uvm_component_utils(my_agent)
    
    bus_config cfg;
    int verbosity;
    
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        
        // 从config_db获取配置对象
        if (!uvm_config_db#(bus_config)::get(this, "", "bus_cfg", cfg)) begin
            `uvm_error("CONFIG", "Failed to get bus_config from config_db")
            cfg = bus_config::type_id::create("cfg");  // 创建默认配置
        end
        
        // 获取简单值配置
        if (!uvm_config_db#(int)::get(this, "", "verbosity", verbosity)) begin
            verbosity = UVM_MEDIUM;  // 默认值
        end
        
        `uvm_info("AGENT", $sformatf("Bus width: %0d, Active: %0d", 
                  cfg.bus_width, cfg.is_active), UVM_LOW)
    endfunction
endclass

4.2.3 Phase机制

  Phase机制将仿真过程分为多个有序的阶段,确保所有组件按照正确的顺序初始化和执行,提供了确定性的执行流程。

  • 预定义的标准phase序列
  • 每个phase在所有组件上同步执行
  • 支持用户自定义phase
class my_component extends uvm_component;
    `uvm_component_utils(my_component)
    
    int data_value;
    
    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
    
    // 1. Build Phase - 创建和配置子组件
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        `uvm_info("PHASE", "Executing build_phase", UVM_LOW)
        
        // 创建子组件、获取配置等
        data_value = 100;
    endfunction
    
    // 2. Connect Phase - 连接组件间的端口
    virtual function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        `uvm_info("PHASE", "Executing connect_phase", UVM_LOW)
        
        // 连接TLM端口、分析端口等
    endfunction
    
    // 3. End of Elaboration Phase - 环境构建完成
    virtual function void end_of_elaboration_phase(uvm_phase phase);
        super.end_of_elaboration_phase(phase);
        `uvm_info("PHASE", "Executing end_of_elaboration_phase", UVM_LOW)
        
        // 打印环境拓扑结构等
    endfunction
    
    // 4. Start of Simulation Phase - 仿真开始前
    virtual function void start_of_simulation_phase(uvm_phase phase);
        super.start_of_simulation_phase(phase);
        `uvm_info("PHASE", "Executing start_of_simulation_phase", UVM_LOW)
    endfunction
    
    // 5. Run Phase - 主要的仿真阶段
    virtual task run_phase(uvm_phase phase);
        `uvm_info("PHASE", "Executing run_phase", UVM_LOW)
        phase.raise_objection(this);
        
        // 主要的测试逻辑
        #100;
        `uvm_info("RUN", "Run phase activity completed", UVM_LOW)
        
        phase.drop_objection(this);
    endfunction
    
    // 6. Extract Phase - 提取仿真结果
    virtual function void extract_phase(uvm_phase phase);
        super.extract_phase(phase);
        `uvm_info("PHASE", "Executing extract_phase", UVM_LOW)
        
        // 提取覆盖率数据、性能统计等
    endfunction
    
    // 7. Check Phase - 检查仿真结果
    virtual function void check_phase(uvm_phase phase);
        super.check_phase(phase);
        `uvm_info("PHASE", "Executing check_phase", UVM_LOW)
        
        // 检查错误、验证结果等
    endfunction
    
    // 8. Report Phase - 报告仿真结果
    virtual function void report_phase(uvm_phase phase);
        super.report_phase(phase);
        `uvm_info("PHASE", "Executing report_phase", UVM_LOW)
        
        // 生成最终报告
        `uvm_info("REPORT", "Simulation completed successfully", UVM_LOW)
    endfunction
endclass

4.2.3 TLM通信(Transaction Level Modeling)

  TLM提供组件间事务级通信的标准接口,支持阻塞、非阻塞和分析通信模式,实现组件间的松耦合。

  • 使用端口和接口定义通信协议
  • 支持多种通信模式
  • 提供事务级数据传递
// 1. 事务定义
class packet extends uvm_sequence_item;
    `uvm_object_utils(packet)
    
    rand bit [31:0] addr;
    rand bit [31:0] data;
    rand bit [1:0]  command;
    
    function new(string name = "packet");
        super.new(name);
    endfunction
endclass

// 2. 生产者组件
class producer extends uvm_component;
    `uvm_component_utils(producer)
    
    // 定义TLM端口
    uvm_blocking_put_port #(packet) put_port;
    uvm_analysis_port #(packet) analysis_port;
    
    function new(string name, uvm_component parent);
        super.new(name, parent);
        put_port = new("put_port", this);
        analysis_port = new("analysis_port", this);
    endfunction
    
    virtual task run_phase(uvm_phase phase);
        packet pkt;
        phase.raise_objection(this);
        
        for (int i = 0; i < 3; i++) begin
            pkt = packet::type_id::create($sformatf("pkt_%0d", i));
            assert(pkt.randomize());
            
            `uvm_info("PRODUCER", $sformatf("Sending packet: addr=0x%0h", pkt.addr), UVM_LOW)
            
            // 阻塞方式发送到消费者
            put_port.put(pkt);
            
            // 广播方式发送到所有订阅者
            analysis_port.write(pkt);
        end
        
        phase.drop_objection(this);
    endtask
endclass

// 3. 消费者组件
class consumer extends uvm_component;
    `uvm_component_utils(consumer)
    
    // 定义TLM接口
    uvm_blocking_put_imp #(packet, consumer) put_export;
    uvm_analysis_imp #(packet, consumer) analysis_export;
    
    int packet_count = 0;
    
    function new(string name, uvm_component parent);
        super.new(name, parent);
        put_export = new("put_export", this);
        analysis_export = new("analysis_export", this);
    endfunction
    
    // 实现阻塞put接口
    virtual task put(packet pkt);
        `uvm_info("CONSUMER", $sformatf("Received via put: addr=0x%0h, data=0x%0h", 
                  pkt.addr, pkt.data), UVM_LOW)
        packet_count++;
        #10;  // 模拟处理延迟
    endtask
    
    // 实现分析端口write接口
    virtual function void write(packet pkt);
        `uvm_info("CONSUMER", $sformatf("Received via analysis: addr=0x%0h", 
                  pkt.addr), UVM_HIGH)
    endfunction
endclass

// 4. 环境连接
class my_env extends uvm_env;
    `uvm_component_utils(my_env)
    
    producer prod;
    consumer cons;
    
    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
    
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        prod = producer::type_id::create("prod", this);
        cons = consumer::type_id::create("cons", this);
    endfunction
    
    virtual function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        
        // 连接阻塞put端口
        prod.put_port.connect(cons.put_export);
        
        // 连接分析端口
        prod.analysis_port.connect(cons.analysis_export);
    endfunction
endclass

5. 典型工作流程

构建阶段: Test类启动,调用Factory创建并配置Env、Agent等所有组件。

连接阶段: 将所有组件的TLM端口连接起来,建立通信路径。

运行阶段:

  • Test启动一个或多个预先写好的Sequence。

  • Sequence在Sequencer上产生Transaction并发送给Driver。

  • Driver将Transaction转换为信号时序,驱动到DUT。

  • Monitor监控DUT输出,将信号转换回Transaction,并发送给Scoreboard和Coverage Collector。

  • Scoreboard进行数据比对,报告成功或错误。

  • Coverage Collector收集覆盖率数据。

检查与报告: 仿真结束后,分析日志和覆盖率报告,评估验证是否完成。

5. 总结

  本文概括的介绍了UVM验证环境的基本组成,除了上述列举的组件和机制,一个健壮的UVM验证环境还会包含一些其他的细节,本系列后续文章将深入探讨每个UVM组件的详细用法、最佳实践和其他相关的知识。

下一篇:UVM验证入门(2)-uvm常用类的继承关系
参考文档:UVM_Cl ass_Reference_Manual_1.0.pdf