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

class action_item extends uvm_sequence_item;
  `uvm_object_utils(action_item)
  rand int value;
  function new(string name="action_item"); super.new(name); endfunction
endclass
class action_derived_item extends action_item;
  `uvm_object_utils(action_derived_item)
  function new(string name="action_derived_item"); super.new(name); endfunction
endclass
class action_seqr extends uvm_sequencer#(action_item);
  int last_priority;
  function new(string name, uvm_component parent); super.new(name,parent); endfunction
  virtual task wait_for_grant(uvm_sequence_base sequence_ptr,
                             int item_priority=-1, bit lock_request=0);
    last_priority=item_priority;
    super.wait_for_grant(sequence_ptr,item_priority,lock_request);
  endtask
endclass
class consumer_link;
  action_seqr consumer_seqr;
endclass
class action_sequence extends uvm_sequence#(action_item);
  action_seqr target_seqr;
  consumer_link cons_if=new();
  int expected_value, expected_priority;
  bit check_value;
  action_seqr expected_seqr;
  action_item saved;
  int identity_checks;
  function new(string name="action_sequence"); super.new(name); endfunction
  function void expect_transfer(action_seqr sqr, int priority_value, bit constrained);
    expected_seqr=sqr;
    expected_priority=priority_value;
    check_value=constrained;
    expected_value=42;
  endfunction
  task body();
    action_seqr local_seqr;
    if (!$cast(local_seqr, get_sequencer())) $fatal(1,"sequencer type");
    cons_if.consumer_seqr=target_seqr;
    expect_transfer(local_seqr, 100, 0);
`ifdef REVIEW_UVM20
    `uvm_do(req)
`else
    `uvm_do(req)
`endif
    expect_transfer(local_seqr, 37, 0);
`ifdef REVIEW_UVM20
    `uvm_do(req, get_sequencer(), 37)
`else
    `uvm_do_pri(req, 37)
`endif
    expect_transfer(local_seqr, 100, 1);
`ifdef REVIEW_UVM20
    `uvm_do(req, get_sequencer(), -1, {value==42;})
`else
    `uvm_do_with(req, {value==42;})
`endif
    expect_transfer(local_seqr, 37, 1);
`ifdef REVIEW_UVM20
    `uvm_do(req, get_sequencer(), 37, {value==42;})
`else
    `uvm_do_pri_with(req, 37, {value==42;})
`endif
    expect_transfer(target_seqr, 100, 0);
`ifdef REVIEW_UVM20
    `uvm_do(req, target_seqr)
`else
    `uvm_do_on(req, target_seqr)
`endif
    expect_transfer(target_seqr, 37, 0);
`ifdef REVIEW_UVM20
    `uvm_do(req, target_seqr, 37)
`else
    `uvm_do_on_pri(req, target_seqr, 37)
`endif
    expect_transfer(target_seqr, 100, 1);
`ifdef REVIEW_UVM20
    `uvm_do(req, target_seqr, -1, {value==42;})
`else
    `uvm_do_on_with(req, target_seqr, {value==42;})
`endif
    expect_transfer(target_seqr, 37, 1);
`ifdef REVIEW_UVM20
    `uvm_do(req, target_seqr, 37, {value==42;})
`else
    `uvm_do_on_pri_with(req, target_seqr, 37, {value==42;})
`endif
    expect_transfer(target_seqr, 100, 0);
`ifdef REVIEW_UVM20
    `uvm_do(req, cons_if.consumer_seqr)
`else
    `uvm_do_seq(req, cons_if)
`endif
    expect_transfer(target_seqr, 100, 1);
`ifdef REVIEW_UVM20
    `uvm_do(req, cons_if.consumer_seqr, -1, {value==42;})
`else
    `uvm_do_seq_with(req, cons_if, {value==42;})
`endif
`ifdef REVIEW_UVM20
    `uvm_create(req, target_seqr)
`else
    `uvm_create_on(req, target_seqr)
`endif
    saved=req; req.value=42; expect_transfer(target_seqr, 100, 1);
`ifdef REVIEW_UVM20
    `uvm_send(req)
`else
    `uvm_send(req)
`endif
    if (req!=saved) $fatal(1,"send recreated object");
    identity_checks++;
`ifdef REVIEW_UVM20
    `uvm_create(req, cons_if.consumer_seqr)
`else
    `uvm_create_seq(req, cons_if)
`endif
    saved=req; req.value=42; expect_transfer(target_seqr, 37, 1);
`ifdef REVIEW_UVM20
    `uvm_send(req, 37)
`else
    `uvm_send_pri(req, 37)
`endif
    if (req!=saved) $fatal(1,"send recreated object");
    identity_checks++;
`ifdef REVIEW_UVM20
    `uvm_create(req, target_seqr)
`else
    `uvm_create_on(req, target_seqr)
`endif
    saved=req; req.value=42; expect_transfer(target_seqr, 100, 0);
`ifdef REVIEW_UVM20
    `uvm_rand_send(req)
`else
    `uvm_rand_send(req)
`endif
    if (req!=saved) $fatal(1,"send recreated object");
    identity_checks++;
`ifdef REVIEW_UVM20
    `uvm_create(req, cons_if.consumer_seqr)
`else
    `uvm_create_seq(req, cons_if)
`endif
    saved=req; req.value=42; expect_transfer(target_seqr, 37, 0);
`ifdef REVIEW_UVM20
    `uvm_rand_send(req, 37)
`else
    `uvm_rand_send_pri(req, 37)
`endif
    if (req!=saved) $fatal(1,"send recreated object");
    identity_checks++;
`ifdef REVIEW_UVM20
    `uvm_create(req, target_seqr)
`else
    `uvm_create_on(req, target_seqr)
`endif
    saved=req; req.value=42; expect_transfer(target_seqr, 100, 1);
`ifdef REVIEW_UVM20
    `uvm_rand_send(req, -1, {value==42;})
`else
    `uvm_rand_send_with(req, {value==42;})
`endif
    if (req!=saved) $fatal(1,"send recreated object");
    identity_checks++;
`ifdef REVIEW_UVM20
    `uvm_create(req, cons_if.consumer_seqr)
`else
    `uvm_create_seq(req, cons_if)
`endif
    saved=req; req.value=42; expect_transfer(target_seqr, 37, 1);
`ifdef REVIEW_UVM20
    `uvm_rand_send(req, 37, {value==42;})
`else
    `uvm_rand_send_pri_with(req, 37, {value==42;})
`endif
    if (req!=saved) $fatal(1,"send recreated object");
    identity_checks++;
  endtask
endclass

`ifdef REVIEW_UVM20
class action_factory extends uvm_factory;
  uvm_default_factory delegate = new();
  virtual function void register(uvm_object_wrapper obj); delegate.register(obj); endfunction
  virtual function void set_inst_override_by_type(uvm_object_wrapper original_type, uvm_object_wrapper override_type, string full_inst_path);
    delegate.set_inst_override_by_type(original_type, override_type, full_inst_path);
  endfunction
  virtual function void set_inst_override_by_name(string original_type_name, string override_type_name, string full_inst_path);
    delegate.set_inst_override_by_name(original_type_name, override_type_name, full_inst_path);
  endfunction
  virtual function void set_type_override_by_type(uvm_object_wrapper original_type, uvm_object_wrapper override_type, bit replace=1);
    delegate.set_type_override_by_type(original_type, override_type, replace);
  endfunction
  virtual function void set_type_override_by_name(string original_type_name, string override_type_name, bit replace=1);
    delegate.set_type_override_by_name(original_type_name, override_type_name, replace);
  endfunction
  virtual function uvm_object create_object_by_type(uvm_object_wrapper requested_type, string parent_inst_path="", string name="");
    return delegate.create_object_by_type(requested_type, parent_inst_path, name);
  endfunction
  virtual function uvm_component create_component_by_type(uvm_object_wrapper requested_type, string parent_inst_path="", string name, uvm_component parent);
    return delegate.create_component_by_type(requested_type, parent_inst_path, name, parent);
  endfunction
  virtual function uvm_object create_object_by_name(string requested_type_name, string parent_inst_path="", string name="");
    return delegate.create_object_by_name(requested_type_name, parent_inst_path, name);
  endfunction
  virtual function uvm_component create_component_by_name(string requested_type_name, string parent_inst_path="", string name, uvm_component parent);
    return delegate.create_component_by_name(requested_type_name, parent_inst_path, name, parent);
  endfunction
  virtual function void debug_create_by_type(uvm_object_wrapper requested_type, string parent_inst_path="", string name="");
    delegate.debug_create_by_type(requested_type, parent_inst_path, name);
  endfunction
  virtual function void debug_create_by_name(string requested_type_name, string parent_inst_path="", string name="");
    delegate.debug_create_by_name(requested_type_name, parent_inst_path, name);
  endfunction
  virtual function uvm_object_wrapper find_override_by_type(uvm_object_wrapper requested_type, string full_inst_path);
    return delegate.find_override_by_type(requested_type, full_inst_path);
  endfunction
  virtual function uvm_object_wrapper find_override_by_name(string requested_type_name, string full_inst_path);
    return delegate.find_override_by_name(requested_type_name, full_inst_path);
  endfunction
  virtual function uvm_object_wrapper find_wrapper_by_name(string type_name);
    return delegate.find_wrapper_by_name(type_name);
  endfunction
  virtual function void print(int all_types=1); delegate.print(all_types); endfunction
virtual function bit is_type_name_registered(string type_name);
  return delegate.is_type_name_registered(type_name);
endfunction
virtual function bit is_type_registered(uvm_object_wrapper obj);
  return delegate.is_type_registered(obj);
endfunction
virtual function void set_type_alias(string alias_type_name,
                                     uvm_object_wrapper original_type);
  delegate.set_type_alias(alias_type_name, original_type);
endfunction
virtual function void set_inst_alias(string alias_type_name,
                                     uvm_object_wrapper original_type,
                                     string full_inst_path);
  delegate.set_inst_alias(alias_type_name, original_type, full_inst_path);
endfunction
endclass
`endif
class action_server extends uvm_default_report_server;
virtual function string compose_report_message(
    uvm_report_message report_message, string report_object_name = "");
  return {"[team] ",
          super.compose_report_message(report_message, report_object_name)};
endfunction
endclass

module manual_actions_probe;
  int transfers=0;
  action_sequence seq;
  task automatic consume(action_seqr sqr);
    action_item received;
    forever begin
      sqr.get_next_item(received);
      if (sqr!=seq.expected_seqr || received.get_sequencer()!=sqr ||
          received.get_parent_sequence()!=seq) $fatal(1,"request context mismatch");
      if (sqr.last_priority!=seq.expected_priority) $fatal(1,"priority mismatch");
      if (seq.check_value && received.value!=seq.expected_value) $fatal(1,"value mismatch");
      transfers++;
      sqr.item_done();
    end
  endtask
  initial begin
    action_seqr local_seqr=new("local_seqr",null), target_seqr=new("target_seqr",null);
    uvm_event ev=new("ev");
    action_item item=new("item"), saved_item;
    uvm_object saved_data;
    uvm_table_printer printer=new();
    string text;
    action_server server=new();
    uvm_report_message msg=uvm_report_message::new_report_message();
`ifdef REVIEW_UVM20
    action_factory factory_value=new();
    uvm_object obj;
    action_derived_item derived;
    uvm_packer p=new(), restored=new();
    bit unsigned state[];
    factory_value.register(action_item::get_type());
    factory_value.register(action_derived_item::get_type());
    if (!factory_value.is_type_registered(action_item::get_type()) ||
        !factory_value.is_type_name_registered("action_item") ||
        factory_value.is_type_name_registered("missing")) $fatal(1,"registration queries");
    factory_value.set_type_alias("item_alias",action_item::get_type());
    factory_value.set_inst_alias("scoped_alias",action_item::get_type(),"scope.item");
    factory_value.set_type_override_by_type(action_item::get_type(),action_derived_item::get_type());
    obj=factory_value.create_object_by_name("item_alias","scope","plain");
    if (!$cast(derived,obj)) $fatal(1,"type alias override");
    obj=factory_value.create_object_by_name("scoped_alias","scope","item");
    if (!$cast(derived,obj)) $fatal(1,"instance alias override");
    $display("REVIEW|factory_delegate|1");
    p.flush(); p.pack_field_int('h1234,16); p.get_packed_bits(state);
    restored.set_packed_bits(state);
    if (restored.unpack_field_int(16)!='h1234) $fatal(1,"packer state roundtrip");
    $display("REVIEW|packer_state_roundtrip|1");
`endif
    item.value=42;
    ev.trigger(item);
    saved_data=ev.get_trigger_data();
    if (!$cast(saved_item,saved_data)) $fatal(1,"event data type");
    ev.reset();
    if (saved_item!=item || saved_item.value!=42) $fatal(1,"event snapshot");
    $display("REVIEW|event_saved_data|1");
`ifdef REVIEW_UVM20
    if (ev.get_trigger_data()!=null) $fatal(1,"event reset default");
    ev.set_default_data(item); ev.trigger(); ev.reset();
    if (ev.get_trigger_data()!=item) $fatal(1,"event explicit default");
    $display("REVIEW|event_explicit_default|1");
`endif
    repeat(2) begin
`ifdef REVIEW_UVM20
      printer.flush();
`endif
      printer.print_field("value",32'h1234,32,UVM_HEX);
      text=printer.emit();
      if (text=="") $fatal(1,"empty printer output");
    end
    $display("REVIEW|printer_reuse|1");
    msg.set_id("ACTION"); msg.set_message("hello");
    text=server.compose_report_message(msg,"probe");
    if (text.substr(0,6)!="[team] ") $fatal(1,"custom server format");
    $display("REVIEW|server_format|1");
    seq=new(); seq.target_seqr=target_seqr;
    fork
      consume(local_seqr);
      consume(target_seqr);
    join_none
    seq.start(local_seqr);
    disable fork;
    if (transfers!=16 || seq.identity_checks!=6) $fatal(1,"macro coverage");
    $display("REVIEW|macro_mappings|15");
    $display("REVIEW|macro_transfers|%0d",transfers);
    $display("REVIEW|macro_existing_identity|%0d",seq.identity_checks);
    $display("REVIEW|done|1");
    $finish;
  end
  initial begin #100; $fatal(1,"manual action timeout"); end
endmodule
