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)循环会持续执行,不会再等待事件触发。
具体问题拆解
- 任务调用时机错误:
run_main_tcms()在时钟下降沿触发后立即调用sample_data(),此时任务直接启动,不会等待rd_trig_i事件。 - 循环逻辑脱离事件约束:
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
相关产品推荐
相关产品推荐

