You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Specman中事件未触发但监视器提前采样,求问题原因

问题:监视器未等待BFM事件触发就直接执行采样

我的BFM通过rd_trig_o事件端口在drive_packet执行完成后触发事件,代码如下:

unit collector_bfm_u like uvm_bfm {
    !p_smp : collector_smp_u;
    !p_drv : collector_driver_u;
    !pkt : collector_packet_s;
    p : collector_data;
    port_num : uint (bits:2);
    event clk_e is rise (p_smp.clk_in$) @sim;
    rd_addr_o : out buffer_port of addr_t is instance;
    rd_trig_o : out event_port is instance; 
    keep rd_addr_o.buffer_size() == 4;
    !rd_address_fifo : deque of (addr_t);

    run() is  {
        rd_address_fifo = new;
        start run_main_tcms();
    };

    run_main_tcms() @clk_e is {
        --wait true (p_smp.rst_in$ == 0); //  wait till reset is negated
        wait delay(10);
        message(LOW,"out of reset!!!");
        all of {
            {request_and_drive_packet()};
            {send_rd_address()};
        }
    };

    request_and_drive_packet() @clk_e is {
        while (TRUE) {
            pkt = p_drv.get_next_item();
            drive_packet( pkt );
            emit p_drv.item_done;
        };
    };

    drive_packet(req: collector_packet_s) @clk_e is {
        var signal_name : string;
        p_smp.i_we_b[port_num]$ = req.we_b;
        p_smp.i_addr_b[port_num]$ = req.addr_b;
        rd_address_fifo.push(req.addr_b);
        emit rd_trig_o$;
    };

监视器的sample_data()本应等待rd_trig_i事件触发后再执行采样,代码如下:

unit collector_monitor_u like uvm_monitor {
    !p_smp : collector_smp_u;
    event clk_e is fall (p_smp.clk_in$) @sim;
    port_num : uint (bits:2);
    rd_data_o : out buffer_port of data_t is instance;
    rd_trig_i : in event_port is instance;
    keep rd_data_o.buffer_size() == 4;
    
    run() is  {
        start run_main_tcms();
    };
    
    run_main_tcms() @clk_e is {
            sample_data();
    };
        
    sample_data() @rd_trig_i$ is {
        var rd_data: bit;
        var data_value: data_t;

        while (TRUE) do {
            wait cycle;
            rd_data = p_smp.i_we_b[port_num]$;
            if (rd_data == 0) {
                data_value = p_smp.o_q_b[port_num]$;
                rd_data_o.put(data_value);
                outf("read data = %d \n", data_value);
            }
        }
    };  
    
};

已在agent中完成事件端口绑定:

keep bind(bfm.rd_trig_o, mon.rd_trig_i);

但仿真时监视器未等待事件触发就直接采样,请问问题出在哪?


原因及解决方法

核心问题:sample_data()的触发逻辑错误

你在run_main_tcms()里直接调用了sample_data(),而sample_data()的@rd_trig_i$修饰符只作用于任务的入口点——一旦任务被调用进入后,内部的while(TRUE)循环会持续执行,不会再等待事件触发。

具体问题拆解

  1. 任务调用时机错误:run_main_tcms()在时钟下降沿触发后立即调用sample_data(),此时任务直接启动,不会等待rd_trig_i事件。
  2. 循环逻辑脱离事件约束:sample_data()里的while(TRUE)循环仅在第一次进入时等待rd_trig_i事件,但循环内部的wait cycle只是等待时钟周期,不会再检查事件触发条件。

修正方案

方案1:让每次采样都等待事件触发

修改sample_data(),将事件等待放在循环内部,确保每次采样前都等待BFM的事件:

sample_data() is {
    var rd_data: bit;
    var data_value: data_t;

    while (TRUE) do {
        @rd_trig_i$; // 每次循环都等待事件触发
        wait cycle;
        rd_data = p_smp.i_we_b[port_num]$;
        if (rd_data == 0) {
            data_value = p_smp.o_q_b[port_num]$;
            rd_data_o.put(data_value);
            outf("read data = %d \n", data_value);
        }
    }
};  

同时调整run_main_tcms(),无需绑定时钟,直接启动任务即可:

run_main_tcms() is {
    sample_data();
};

方案2:保持任务入口的事件触发,单次采样后退出

如果要保留@rd_trig_i$在任务入口,需要让任务每次触发后只执行一次采样,再由事件重新触发任务:

run_main_tcms() is {
    while(TRUE) do {
        sample_data(); // 每次事件触发后执行一次采样,返回后等待下一次事件
    }
};
        
sample_data() @rd_trig_i$ is {
    var rd_data: bit;
    var data_value: data_t;

    wait cycle;
    rd_data = p_smp.i_we_b[port_num]$;
    if (rd_data == 0) {
        data_value = p_smp.o_q_b[port_num]$;
        rd_data_o.put(data_value);
        outf("read data = %d \n", data_value);
    }
};  

额外检查点

  • 验证BFM的事件是否正确发射:在drive_packet中添加打印语句,确认emit rd_trig_o$确实在预期时机执行。
  • 确认事件端口绑定无误:检查bind语句中的实例名、端口名是否拼写正确,避免绑定失效。

内容的提问来源于stack exchange,提问作者zg71

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 16:25:26