blob: 472081425ad73080594fe3d4d2e40e986aa9c349 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
class dv_base_monitor #(type ITEM_T = uvm_sequence_item,
type REQ_ITEM_T = ITEM_T,
type RSP_ITEM_T = ITEM_T,
type CFG_T = dv_base_agent_cfg,
type COV_T = dv_base_agent_cov) extends uvm_monitor;
`uvm_component_param_utils(dv_base_monitor #(ITEM_T, CFG_T, COV_T))
CFG_T cfg;
COV_T cov;
// Indicates activity on the interface, driven only within the `monitor_ready_to_end()` task.
protected bit ok_to_end = 1;
// Used to ensure we run the watchdog exactly once at the end of the run phase. Cleared at start
// of run phase. Set once watchdog_ok_to_end has been started at the end of the run_phase.
protected bit phase_ready_to_end_invoked = 0;
// Analysis port for the collected transfer.
uvm_analysis_port #(ITEM_T) analysis_port;
// item will be sent to this port for seq when req phase is done (last is set)
uvm_analysis_port #(REQ_ITEM_T) req_analysis_port;
// item will be sent to this port for seq when rsp phase is done (rsp_done is set)
uvm_analysis_port #(RSP_ITEM_T) rsp_analysis_port;
`uvm_component_new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
analysis_port = new("analysis_port", this);
req_analysis_port = new("req_analysis_port", this);
rsp_analysis_port = new("rsp_analysis_port", this);
endfunction
virtual task run_phase(uvm_phase phase);
fork
collect_trans(phase);
join
endtask
// collect transactions forever
virtual protected task collect_trans(uvm_phase phase);
`uvm_fatal(`gfn, "this method is not supposed to be called directly!")
endtask
// UVM callback which is invoked during phase sequencing.
virtual function void phase_ready_to_end(uvm_phase phase);
if (!phase.is(uvm_run_phase::get())) return;
if (phase_ready_to_end_invoked) return;
phase_ready_to_end_invoked = 1;
fork
monitor_ready_to_end();
watchdog_ok_to_end(phase);
join_none
endfunction
// Ensures that ok_to_end when asserted, stays asserted for 1 ok_to_end_delay_ns period.
//
// If ok_to_end de-asserts before the watchdog expires, it waits for it to assert again
// and restarts the timer. This ensures that there is sufficient drain time to allow the
// simulation to end gracefully. It raises and drops the objection at the appropriate times.
virtual task watchdog_ok_to_end(uvm_phase run_phase);
bit objection_raised;
bit watchdog_done;
uint watchdog_restart_count = 1;
forever begin
if (!objection_raised) begin
`uvm_info(`gfn, "watchdog_ok_to_end: raising objection", UVM_MEDIUM)
run_phase.raise_objection(this, {`gfn, " objection raised"});
objection_raised = 1'b1;
end
// Start the timer only when ok_to_end is asserted.
wait (ok_to_end);
`uvm_info(`gfn, $sformatf("watchdog_ok_to_end: starting the timer (count: %0d)",
watchdog_restart_count++), UVM_MEDIUM)
fork
begin: isolation_fork
fork
begin
watchdog_done = 1'b0;
#(cfg.ok_to_end_delay_ns * 1ns);
watchdog_done = 1'b1;
end
wait (!ok_to_end);
join_any
disable fork;
end: isolation_fork
join
// If ok_to_end stayed high throughout the watchdog timer expiry, then drop the objection.
if (ok_to_end && watchdog_done) begin
`uvm_info(`gfn, "watchdog_ok_to_end: dropping objection", UVM_MEDIUM)
run_phase.drop_objection(this, {`gfn, " objection dropped"});
objection_raised = 1'b0;
// Wait for ok_to_end to de-assert again in future.
wait (!ok_to_end);
end
end
endtask
// Asserts/de-asserts ok_to_end to indicate bus activity.
//
// This task is invoked in a forked thread within `phase_ready_to_end()`, which is callback
// invoked by UVM at the end of the phase. The forked thread does not join. Hence, the extended
// monitor needs to override this function and assert ok_to_end based on the activity on the bus
// (assert it when idle, de-assert when its not) in a forever loop.
virtual task monitor_ready_to_end();
endtask
endclass