`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg::*;
class bus_item extends uvm_sequence_item;
`uvm_object_utils(bus_item)
bit write;
int unsigned address;
int unsigned data;
function new(string name = "bus_item"); super.new(name); endfunction
endclass
class base_object extends uvm_object;
`uvm_object_utils(base_object)
function new(string name = "base_object"); super.new(name); endfunction
endclass
class derived_object extends base_object;
`uvm_object_utils(derived_object)
function new(string name = "derived_object"); super.new(name); endfunction
endclass
class probe_callback extends uvm_callback;
int calls;
function new(string name = "probe_callback"); super.new(name); endfunction
virtual function void observed(); calls++; endfunction
endclass
class bus_driver extends uvm_driver#(bus_item);
`uvm_component_utils(bus_driver)
`uvm_register_cb(bus_driver, probe_callback)
int unsigned memory[int unsigned];
int transfers;
function new(string name, uvm_component parent); super.new(name, parent); endfunction
task run_phase(uvm_phase phase);
bus_item request;
forever begin
seq_item_port.get_next_item(request);
if (request.write) memory[request.address] = request.data;
else request.data = memory.exists(request.address) ? memory[request.address] : 0;
transfers++;
`uvm_do_callbacks(bus_driver, probe_callback, observed())
$display("REVIEW_BUS|%0d|%0h|%08h", request.write, request.address, request.data);
seq_item_port.item_done();
end
endtask
endclass
class register_adapter extends uvm_reg_adapter;
`uvm_object_utils(register_adapter)
function new(string name = "register_adapter"); super.new(name); endfunction
function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
bus_item item = bus_item::type_id::create("item");
item.write = rw.kind == UVM_WRITE;
item.address = rw.addr;
item.data = rw.data;
return item;
endfunction
function void bus2reg(uvm_sequence_item bus, ref uvm_reg_bus_op rw);
bus_item item;
if (!$cast(item, bus)) `uvm_fatal("ADAPTER", "Wrong bus item")
rw.kind = item.write ? UVM_WRITE : UVM_READ;
rw.addr = item.address;
rw.data = item.data;
rw.status = UVM_IS_OK;
endfunction
endclass
class wide_register extends uvm_reg;
`uvm_object_utils(wide_register)
uvm_reg_field field;
function new(string name = "wide_register"); super.new(name, 64, UVM_NO_COVERAGE); endfunction
function void build();
field = uvm_reg_field::type_id::create("field");
field.configure(this, 64, 0, "RW", 0, 0, 1, 1, 0);
endfunction
endclass
class register_block extends uvm_reg_block;
`uvm_object_utils(register_block)
wide_register value;
function new(string name = "register_block"); super.new(name, UVM_NO_COVERAGE); endfunction
function void build();
value = wide_register::type_id::create("value");
value.configure(this);
value.build();
default_map = create_map("map", 'h100, 4, UVM_LITTLE_ENDIAN, 1);
default_map.add_reg(value, 'h20, "RW");
lock_model();
endfunction
endclass
class child_sequence extends uvm_sequence#(bus_item);
`uvm_object_utils(child_sequence)
static int parent_ok;
function new(string name = "child_sequence"); super.new(name); endfunction
task body();
bus_item item = bus_item::type_id::create("item");
parent_ok = get_parent_sequence() != null;
start_item(item);
item.write = 1; item.address = 'h40; item.data = 'hcafe;
finish_item(item);
endtask
endclass
class parent_sequence extends uvm_sequence#(bus_item);
`uvm_object_utils(parent_sequence)
function new(string name = "parent_sequence"); super.new(name); endfunction
task body();
child_sequence child = child_sequence::type_id::create("child");
child.start(m_sequencer, this);
endtask
endclass
class automatic_sequence extends uvm_sequence#(bus_item);
`uvm_object_utils(automatic_sequence)
static int runs;
function new(string name = "automatic_sequence"); super.new(name); endfunction
task body(); runs++; endtask
endclass
class legacy_sequence extends uvm_sequence#(bus_item);
`uvm_object_utils(legacy_sequence)
static int runs;
function new(string name = "legacy_sequence"); super.new(name); endfunction
task body(); runs++; endtask
endclass
class matrix_test extends uvm_test;
`uvm_component_utils(matrix_test)
uvm_sequencer#(bus_item) sequencer, wrapper_sequencer, instance_sequencer, legacy_sequencer;
bus_driver driver;
probe_callback callback;
register_block model;
register_adapter adapter;
string phases;
int config_value;
bit factory_ok;
function new(string name, uvm_component parent); super.new(name, parent); endfunction
function void build_phase(uvm_phase phase);
base_object created;
derived_object derived;
automatic_sequence instance_sequence;
super.build_phase(phase);
phases = "build";
uvm_config_db#(int)::set(this, "", "value", 42);
if (!uvm_config_db#(int)::get(this, "", "value", config_value))
`uvm_fatal("CONFIG", "Missing config")
base_object::type_id::set_type_override(derived_object::get_type());
created = base_object::type_id::create("created");
factory_ok = $cast(derived, created);
sequencer = new("sequencer", this);
wrapper_sequencer = new("wrapper_sequencer", this);
instance_sequencer = new("instance_sequencer", this);
legacy_sequencer = new("legacy_sequencer", this);
driver = bus_driver::type_id::create("driver", this);
callback = new();
uvm_callbacks#(bus_driver, probe_callback)::add(driver, callback);
model = register_block::type_id::create("model");
model.build();
adapter = register_adapter::type_id::create("adapter");
uvm_config_db#(uvm_object_wrapper)::set(this, "wrapper_sequencer.main_phase", "default_sequence", automatic_sequence::get_type());
instance_sequence = automatic_sequence::type_id::create("instance_sequence");
uvm_config_db#(uvm_sequence_base)::set(this, "instance_sequencer.main_phase", "default_sequence", instance_sequence);
uvm_config_db#(string)::set(this, "legacy_sequencer", "default_sequence", "legacy_sequence");
endfunction
function void connect_phase(uvm_phase phase);
phases = {phases, ">connect"};
driver.seq_item_port.connect(sequencer.seq_item_export);
model.default_map.set_sequencer(sequencer, adapter);
model.default_map.set_auto_predict(1);
endfunction
task run_phase(uvm_phase phase);
parent_sequence sequence_value;
uvm_status_e status;
uvm_reg_data_t data;
phase.raise_objection(this);
phases = {phases, ">run"};
sequence_value = parent_sequence::type_id::create("sequence_value");
sequence_value.start(sequencer);
model.value.write(status, 64'h01234567_89abcdef, UVM_FRONTDOOR, model.default_map);
$display("REVIEW|reg_write_status|%0d", status);
model.value.read(status, data, UVM_FRONTDOOR, model.default_map);
$display("REVIEW|reg_read_status|%0d", status);
$display("REVIEW|reg_read_data|%016h", data);
$display("REVIEW|reg_mirror_data|%016h", model.value.get_mirrored_value());
#10;
$display("REVIEW|objection_total|%0d", phase.get_objection().get_objection_total());
phase.drop_objection(this);
endtask
function void extract_phase(uvm_phase phase);
phases = {phases, ">extract"};
endfunction
function void report_phase(uvm_phase phase);
phases = {phases, ">report"};
$display("REVIEW|phase_order|%s", phases);
$display("REVIEW|config_value|%0d", config_value);
$display("REVIEW|factory_override|%0d", factory_ok);
$display("REVIEW|sequence_parent|%0d", child_sequence::parent_ok);
$display("REVIEW|phase_default_sequences|%0d", automatic_sequence::runs);
$display("REVIEW|legacy_default_sequence|%0d", legacy_sequence::runs);
$display("REVIEW|callback_calls|%0d", callback.calls);
$display("REVIEW|bus_transfers|%0d", driver.transfers);
$display("REVIEW|done|1");
endfunction
endclass
module feature_matrix;
initial run_test("matrix_test");
initial begin #10000; $fatal(1, "Review timeout"); end
endmodule