blob: 414134f2abf0bf81eceeb857ef85c546b4ad09fc [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// ---------------------------------------------
// Alert sender receiver interface monitor
// ---------------------------------------------
class alert_monitor extends dv_base_monitor#(
.ITEM_T (alert_seq_item),
.CFG_T (alert_agent_cfg),
.COV_T (alert_agent_cov)
);
`uvm_component_utils(alert_monitor)
bit under_ping_rsp;
uvm_analysis_port #(alert_seq_item) alert_port;
`uvm_component_new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
alert_port = new("alert_port", this);
endfunction : build_phase
//TODO: currently only support sync mode
//TODO: add support for signal int err and reset
virtual task run_phase(uvm_phase phase);
fork
alert_thread(phase);
ping_thread(phase);
reset_thread(phase);
join_none
endtask : run_phase
// TODO: placeholder to support reset
virtual task reset_thread(uvm_phase phase);
forever begin
@(negedge cfg.vif.rst_n);
@(posedge cfg.vif.rst_n);
end
endtask : reset_thread
virtual task ping_thread(uvm_phase phase);
alert_seq_item req;
bit ping_p;
forever @(cfg.vif.monitor_cb) begin
if (ping_p != cfg.vif.monitor_cb.alert_rx.ping_p) begin
phase.raise_objection(this);
under_ping_rsp = 1;
req = alert_seq_item::type_id::create("req");
req.alert_type = PingTrans;
fork
begin : isolation_fork
fork
begin : wait_ping_timeout
repeat (cfg.ping_timeout_cycle) @(cfg.vif.monitor_cb);
req.timeout = 1'b1;
end
begin : wait_ping_handshake
cfg.vif.wait_alert();
req.alert_handshake_sta = AlertReceived;
cfg.vif.wait_ack();
req.alert_handshake_sta = AckReceived;
cfg.vif.wait_alert_complete();
req.alert_handshake_sta = AlertComplete;
under_ping_rsp = 0;
// TODO: if now another alert triggered, will both sample the ack signal?
cfg.vif.wait_ack_complete();
req.alert_handshake_sta = AckComplete;
end
join_any
disable fork;
end : isolation_fork
join
`uvm_info("alert_monitor", $sformatf("[%s]: handshake status is %s",
req.alert_type.name(), req.alert_handshake_sta.name()), UVM_HIGH)
alert_port.write(req);
phase.drop_objection(this);
under_ping_rsp = 0;
end
ping_p = cfg.vif.monitor_cb.alert_rx.ping_p;
end
endtask : ping_thread
virtual task alert_thread(uvm_phase phase);
alert_seq_item req;
bit alert_p;
forever @(cfg.vif.monitor_cb) begin
if (!alert_p && cfg.vif.monitor_cb.alert_tx.alert_p === 1'b1 && !under_ping_rsp) begin
phase.raise_objection(this);
req = alert_seq_item::type_id::create("req");
req.alert_type = AlertTrans;
req.alert_handshake_sta = AlertReceived;
alert_port.write(req);
fork
begin : isolation_fork
fork
begin : alert_timeout
repeat (cfg.ping_timeout_cycle) @(cfg.vif.monitor_cb);
req.timeout = 1'b1;
end
begin : wait_alert_handshake
cfg.vif.wait_ack();
req.alert_handshake_sta = AckReceived;
cfg.vif.wait_alert_complete();
req.alert_handshake_sta = AlertComplete;
cfg.vif.wait_ack_complete();
req.alert_handshake_sta = AckComplete;
end
join_any
disable fork;
end : isolation_fork
join
`uvm_info("alert_monitor", $sformatf("[%s]: handshake status is %s",
req.alert_type.name(), req.alert_handshake_sta.name()), UVM_HIGH)
alert_port.write(req);
phase.drop_objection(this);
end
alert_p = cfg.vif.monitor_cb.alert_tx.alert_p;
end
endtask : alert_thread
endclass : alert_monitor