`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg::*;

class push_item extends uvm_sequence_item;
  int value;
  function new(string name="item"); super.new(name); endfunction
endclass
class push_catcher extends uvm_report_catcher;
  int full_errors;
  function new(); super.new("push_catcher"); endfunction
  function action_e catch();
    if (get_id() == "SQRSNDREQGNI") begin
      full_errors++;
      // Keep observing after the known fatal; this is test instrumentation only.
      return CAUGHT;
    end
    return THROW;
  endfunction
endclass
class push_sequence extends uvm_sequence#(push_item);
  bit completed;
  function new(string name="seq"); super.new(name); endfunction
  task body();
    for (int i=1; i<=2; i++) begin
      req = new(); req.value = i;
      start_item(req); finish_item(req);
    end
    completed = 1;
  endtask
endclass
class push_sink extends uvm_component;
  uvm_blocking_put_imp#(push_item,push_sink) input_port;
  int values[$];
  function new(string name, uvm_component parent);
    super.new(name,parent); input_port = new("input_port",this);
  endfunction
  task put(push_item item); values.push_back(item.value); #1; endtask
endclass
class repaired_push_sequencer extends uvm_push_sequencer#(push_item);
  function new(string name, uvm_component parent); super.new(name,parent); endfunction
  task run_phase(uvm_phase phase);
    push_item item;
    if (!$test$plusargs("MIGRATED")) super.run_phase(phase);
    else forever begin
`ifdef REVIEW_UVM20
      m_safe_select_item(0,item);
      sequence_item_requested = 0;
      // Consume the request peeked by m_safe_select_item before selecting again.
      if (!m_req_fifo.try_get(item)) `uvm_fatal("PUSH_DRAIN", "No selected item")
`else
      m_select_sequence();
      m_req_fifo.get(item);
`endif
      req_port.put(item);
      m_wait_for_item_sequence_id = item.get_sequence_id();
      m_wait_for_item_transaction_id = item.get_transaction_id();
    end
  endtask
endclass
class push_test extends uvm_test;
  `uvm_component_utils(push_test)
  repaired_push_sequencer sqr;
  push_sink sink;
  function new(string name, uvm_component parent); super.new(name,parent); endfunction
  function void build_phase(uvm_phase phase);
    super.build_phase(phase); sqr = new("sqr",this); sink = new("sink",this);
  endfunction
  function void connect_phase(uvm_phase phase); sqr.req_port.connect(sink.input_port); endfunction
  task run_phase(uvm_phase phase);
    push_sequence sequence_value = new();
    push_catcher catcher = new();
    uvm_report_cb::add(sqr,catcher);
    phase.raise_objection(this);
    fork sequence_value.start(sqr); join_none
    #10;
    $display("REVIEW|push_count|%0d", sink.values.size());
    $display("REVIEW|push_first|%0d", sink.values.size() > 0 ? sink.values[0] : -1);
    $display("REVIEW|push_second|%0d", sink.values.size() > 1 ? sink.values[1] : -1);
    $display("REVIEW|sequence_completed|%0d", sequence_value.completed);
    $display("REVIEW|request_fifo_full_errors|%0d", catcher.full_errors);
    sequence_value.kill();
    $display("REVIEW|done|1");
    phase.drop_objection(this);
  endtask
endclass
module push_probe;
  initial run_test("push_test");
endmodule
