理解 uvm_monitor 是掌握UVM“观察-反馈”回路的关键。如果说 driver 是工厂里将图纸变成零件的 “机械臂”,那么 monitor 就是安装在流水线上的“高清摄像头”和“传感器”

它不参与驱动,只负责被动地、默默地观察 DUT接口上的信号,并将看到的一切翻译成高级的“事务”(Transaction),然后广播给所有关心的人(如记分板、覆盖率收集器)。

📡 Monitor的核心角色:被动的“观察者与翻译官”

下图清晰展示了 uvm_monitor 在验证平台中的数据流角色及其内部工作流程:
在这里插入图片描述

核心职责:实现 “信号级”回到“事务级”的逆向翻译。它需要知道,在特定的时钟沿,当 validready 信号同时为高时,addrdata 线上的值就构成了一个有效的传输事务。

🛠️ 创建一个标准Monitor:四步法

以下是一个可直接套用的APB总线监视器模板,代码中的注释详细解释了每个步骤:

// 1. 定义监视器类,通常不需要参数化(除非特殊需要)
class apb_monitor extends uvm_monitor; // 注意继承自 uvm_monitor
    `uvm_component_utils(apb_monitor)

    // 2. 声明关键部件
    // 2.1 虚拟接口:观察信号的“探头”
    virtual apb_interface vif;
    // 2.2 分析端口:广播数据的“电视台”。这是Monitor最独特的标志!
    uvm_analysis_port #(apb_transaction) ap;

    // 2.3 配置开关(可选,但很专业)
    bit checks_enable = 1; // 是否进行基础协议检查
    bit coverage_enable = 1; // 是否采样覆盖率

    function new(string name = "apb_monitor", uvm_component parent = null);
        super.new(name, parent);
    endfunction

    // 3. Build Phase:构建部件并获取虚拟接口
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        // 3.1 实例化分析端口(必须!)
        ap = new(“ap”, this);
        // 3.2 从config_db获取虚拟接口(和driver获取的是同一个)
        if (!uvm_config_db #(virtual apb_interface)::get(this, “”, “vif”, vif)) begin
            `uvm_fatal(“MON_CFG”, “无法获取虚拟接口!监视器将失明。”)
        end
    endfunction

    // 4. Run Phase (一个task):核心监控循环
    virtual task run_phase(uvm_phase phase);
        apb_transaction trans; // 用于暂存捕捉到的事务
        super.run_phase(phase);

        // 初始化:可以等待复位释放等
        wait (vif.preset_n == 1);

        forever begin
            trans = apb_transaction::type_id::create(“trans”); // 创建新事务对象

            // 4.1 捕捉一个完整的事务(这是协议相关的核心逻辑)
            capture_transfer(trans);

            // 4.2 (可选)进行基础协议检查
            if (checks_enable) begin
                perform_protocol_checks(trans);
            end

            // 4.3 (可选)采样覆盖率
            if (coverage_enable) begin
                trans.cg.sample(); // 假设事务类内定义了覆盖率组cg
            end

            // 4.4 最重要的一步:通过分析端口广播事务
            `uvm_info(get_type_name(), $sformatf(“监听到事务:%s”, trans.convert2string()), UVM_HIGH)
            ap.write(trans); // 所有连接了这个端口的组件都会立即收到trans的拷贝
        end
    endtask

    // 5. 协议相关的捕捉任务(需要你根据协议具体实现)
    virtual task capture_transfer(output apb_transaction t);
        // 示例:等待APB传输开始(PSEL变高)
        @(posedge vif.pclk iff vif.psel === 1‘b1);

        t.paddr = vif.paddr;
        t.pwrite = vif.pwrite;
        if (vif.pwrite) begin
            t.pwdata = vif.pwdata;
        end

        // 等待ENABLE信号,完成传输
        @(posedge vif.pclk iff vif.penable === 1‘b1);
        if (!t.pwrite) begin
            t.prdata = vif.prdata; // 捕捉读数据
        end
        @(negedge vif.penable); // 等待传输结束
    endtask

    virtual function void perform_protocol_checks(apb_transaction t);
        // 例如:检查地址是否对齐等基础协议违规
        if (t.paddr[1:0] != 2‘b00) begin
            `uvm_warning(“PROT_ERR”, $sformatf(“地址未对齐:0x%0h”, t.paddr))
        end
    endfunction
endclass

🔌 Monitor的灵魂:uvm_analysis_port

这是Monitor区别于Driver最显著的特征,也是UVM实现松耦合、高内聚架构的核心。

  • 作用:它是一个广播端口。Monitor不关心谁在听,它只负责在事务发生时“喊一嗓子”(ap.write(trans))。
  • 连接:在**上一级容器(如agentenv)的connect_phase**中,将Monitor的ap连接到其他组件的analysis_exportanalysis_imp
    // 在 my_agent 或 my_env 的 connect_phase 中
    virtual function void connect_phase(uvm_phase phase);
        // 将monitor的端口连接到scoreboard的出口
        m_monitor.ap.connect(m_scoreboard.ap_export);
        // 可以同时连接到覆盖率收集器
        m_monitor.ap.connect(m_coverage.analysis_export);
    endfunction
    
  • 优势:Scoreboard、Coverage Collector等订阅者完全独立于Monitor。你可以轻松增加或移除订阅者,而无需修改Monitor的代码

⚙️ 工作模式与Agent的关系

无论其父agentUVM_ACTIVE 还是 UVM_PASSIVEmonitor 永远都会被创建和运行

  • ACTIVE 模式中,Agent包含driver + sequencer + monitor,Monitor用于观察自己驱动的结果(回环检查)。
  • PASSIVE 模式中,Agent仅包含monitor,用于观察其他主体驱动的接口,进行协议合规性检查或系统级数据流追踪。

💎 最佳实践与高级技巧

  1. 保持被动与轻量:Monitor绝不驱动任何信号。其内部的协议检查也应是被动断言,只报告违规,不干预运行。
  2. 分离关注点:将高级功能检查(如数据一致性)留给scoreboard,Monitor只做最基础的、与协议时序强相关的检查。
  3. 处理复杂协议:对于多通道、流水线协议(如AXI),可以在run_phase中**fork多个并行的线程**,分别监视不同通道,最后再汇聚成一个完整事务广播出去。
  4. 使用配置开关:像示例中那样,为checks_enablecoverage_enable提供开关,可以通过uvm_config_db在测试层动态关闭,便于调试和提升仿真性能。
  5. 事务对象创建:务必在循环内为每个新事务创建新的对象type_id::create),避免覆盖前一个事务的数据。

总结uvm_monitor 是验证平台的眼睛和耳朵。一个设计良好的Monitor,通过analysis_port将原始的物理世界与智能的分析世界解耦,是构建自动化、可复用验证环境的基石。

你的下一步:请为你之前的my_transaction和虚拟接口,创建一个my_monitor。暂时忽略复杂的协议捕捉,只需在run_phase中每隔几个时钟周期,就创建一个新事务,并给它的字段赋予任意值,然后通过ap.write()广播出去。最后,在你的my_agent中实例化它,并将其ap端口连接到你的my_scoreboard。当你看到Scoreboard能接收到Monitor发出的事务时,你就打通了UVM的另一条核心数据流 DUT信号 -> Monitor -> Scoreboard

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐