`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg::*;
class lifecycle_catcher extends uvm_report_catcher;
int overflow, phase_error;
function new(); super.new("catcher"); endfunction
function action_e catch();
if (uvm_is_match("*Response queue overflow*", get_message())) begin
overflow++; return CAUGHT;
end
if (get_id() inside {"UVM/SEQ/LOCK_DEPR", "UVM/SEQ/SP/GET", "UVM/SEQ/SP/SET", "UVM/GET_TO_LOCK_DAP/SAG"}) begin
phase_error++; return CAUGHT;
end
return THROW;
endfunction
endclass
class lifecycle_sequence extends uvm_sequence#(uvm_sequence_item);
bit hold_after_grant, granted, route_lock, locked;
uvm_sequencer_base other;
function new(string name="seq"); super.new(name); endfunction
function void overflow_now();
uvm_sequence_item response = new("response");
set_response_queue_depth(0);
put_response(response);
endfunction
task body();
if (route_lock) begin
lock(other); locked = 1; wait(0);
end else begin
req = new("req");
start_item(req);
granted = 1;
if (hold_after_grant) wait(0);
finish_item(req);
end
endtask
endclass
module lifecycle_probe;
initial begin
lifecycle_catcher catcher = new();
lifecycle_sequence controls = new("controls"), routing = new("routing");
lifecycle_sequence bad = new("bad"), good = new("good");
uvm_sequencer#(uvm_sequence_item) primary = new("primary", null);
uvm_sequencer#(uvm_sequence_item) other = new("other", null);
uvm_sequencer#(uvm_sequence_item) retry_sqr = new("retry", null);
uvm_sequence_item received;
uvm_phase phase_a = uvm_run_phase::get(), phase_b = uvm_reset_phase::get(), locked_phase;
bit completed;
uvm_report_cb::add(null, catcher);
$display("REVIEW|default_response_disabled|%0d", controls.get_response_queue_error_report_disabled());
controls.overflow_now();
$display("REVIEW|default_overflow_errors|%0d", catcher.overflow);
catcher.overflow = 0;
controls.set_response_queue_error_report_disabled(0);
controls.overflow_now();
$display("REVIEW|explicit_overflow_errors|%0d", catcher.overflow);
controls.set_starting_phase(phase_a);
locked_phase = controls.get_starting_phase();
controls.set_starting_phase(phase_b);
locked_phase = controls.get_starting_phase();
$display("REVIEW|locked_phase_preserved|%0d", locked_phase == phase_a);
$display("REVIEW|locked_phase_error|%0d", catcher.phase_error > 0);
routing.route_lock = 1;
routing.other = other;
fork routing.start(primary); join_none
wait(routing.locked);
routing.kill();
#1;
$display("REVIEW|cross_sequencer_lock_after_kill|%0d", other.is_grabbed());
bad.hold_after_grant = 1;
fork : retry_workers
bad.start(retry_sqr, null, 200);
good.start(retry_sqr, null, 100);
begin
#1;
retry_sqr.get_next_item(received);
retry_sqr.item_done();
completed = 1;
end
begin wait(bad.granted); bad.kill(); end
join_none
#5;
$display("REVIEW|retry_after_grant_kill|%0d", completed);
good.kill();
disable retry_workers;
$display("REVIEW|done|1");
$finish;
end
initial begin #50; $fatal(1, "lifecycle timeout"); end
endmodule