`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg::*;
interface map_storage_if;
bit [31:0] value;
endinterface
class map_storage_backdoor extends uvm_reg_backdoor;
virtual map_storage_if vif;
function new(string name = "bd"); super.new(name); endfunction
virtual task write(uvm_reg_item rw);
do_pre_write(rw);
vif.value = rw.value[0];
rw.status = UVM_IS_OK;
do_post_write(rw);
endtask
virtual function void read_func(uvm_reg_item rw);
rw.value[0] = vif.value;
rw.status = UVM_IS_OK;
endfunction
endclass
class map_storage_reg extends uvm_reg;
uvm_reg_field low_byte, value, high_half;
function new(string name = "rg"); super.new(name, 32, UVM_NO_COVERAGE); endfunction
function void build();
low_byte = new("low_byte");
value = new("value");
high_half = new("high_half");
low_byte.configure(this, 8, 0, "RW", 0, 0, 1, 0, 1);
value.configure(this, 8, 8, "RW", 0, 0, 1, 0, 1);
high_half.configure(this, 16, 16, "RW", 0, 0, 1, 0, 1);
endfunction
endclass
class map_storage_block extends uvm_reg_block;
map_storage_reg rg;
function new(string name = "model"); super.new(name, UVM_NO_COVERAGE); endfunction
function void build(bit mapped = 1);
rg = new(); rg.configure(this); rg.build();
if (mapped) begin
default_map = create_map("map", 0, 4, UVM_LITTLE_ENDIAN, 1);
default_map.add_reg(rg, 0, "RW");
end
lock_model();
endfunction
endclass
class backdoor_map_observer extends uvm_report_catcher;
int map_warnings;
function new(string name = "observer"); super.new(name); endfunction
virtual function action_e catch();
if (get_severity() == UVM_WARNING && get_id() == "RegModel" &&
uvm_is_match("*is not contained within map 'Backdoor'*", get_message()))
map_warnings++;
return THROW;
endfunction
endclass
module backdoor_map_probe;
map_storage_if hw();
initial begin
map_storage_block model = new();
map_storage_block unmapped_model = new("unmapped_model");
map_storage_backdoor bd = new();
backdoor_map_observer observer = new();
uvm_status_e status;
uvm_reg_data_t value, full_value, mask, expected;
string scenario_names[8] = '{"reg_null", "reg_pseudo", "field_null", "field_real",
"reg_unmapped", "reg_real", "mirror_pseudo", "field_via_reg"};
model.build();
unmapped_model.build(0);
bd.vif = hw;
model.rg.set_backdoor(bd);
unmapped_model.rg.set_backdoor(bd);
uvm_report_cb::add(null, observer);
mask = '1;
mask >>= $bits(uvm_reg_data_t) - model.rg.value.get_n_bits();
for (int scenario = 0; scenario < 8; scenario++) begin
hw.value = 'h12345678;
void'(model.rg.predict(hw.value));
void'(unmapped_model.rg.predict(hw.value));
observer.map_warnings = 0;
$display("PROBE|begin|%s", scenario_names[scenario]);
case (scenario)
0: model.rg.read(status, value, UVM_BACKDOOR);
1: model.rg.read(status, value, UVM_BACKDOOR, uvm_reg_map::backdoor());
2: model.rg.value.read(status, value, UVM_BACKDOOR);
3: model.rg.value.read(status, value, UVM_BACKDOOR, model.default_map);
4: unmapped_model.rg.read(status, value, UVM_BACKDOOR);
5: model.rg.read(status, value, UVM_BACKDOOR, model.default_map);
6: begin
model.rg.mirror(status, UVM_CHECK, UVM_BACKDOOR, uvm_reg_map::backdoor());
value = model.rg.get_mirrored_value();
end
7: begin
model.rg.read(status, full_value, UVM_BACKDOOR);
value = (full_value >> model.rg.value.get_lsb_pos()) & mask;
end
endcase
expected = (scenario inside {2, 3, 7}) ? 'h56 : 'h12345678;
if (status != UVM_IS_OK || value != expected)
`uvm_fatal("BACKDOOR_MAP", "Read status/data mismatch")
// This fixture has RW fields and no concurrent hardware writer.
case (scenario)
0, 6: model.rg.write(status, 'h89abcdef, UVM_BACKDOOR);
1: model.rg.write(status, 'h89abcdef, UVM_BACKDOOR, uvm_reg_map::backdoor());
2: model.rg.value.write(status, 'hab, UVM_BACKDOOR);
3: model.rg.value.write(status, 'hab, UVM_BACKDOOR, model.default_map);
4: unmapped_model.rg.write(status, 'h89abcdef, UVM_BACKDOOR);
5: model.rg.write(status, 'h89abcdef, UVM_BACKDOOR, model.default_map);
7: begin
model.rg.read(status, full_value, UVM_BACKDOOR);
if (status != UVM_IS_OK) `uvm_fatal("BACKDOOR_MAP", "RMW read failed")
full_value = (full_value & ~(mask << model.rg.value.get_lsb_pos())) |
((uvm_reg_data_t'('hab) & mask) << model.rg.value.get_lsb_pos());
model.rg.write(status, full_value, UVM_BACKDOOR);
end
endcase
expected = (scenario inside {2, 3, 7}) ? 'h1234ab78 : 'h89abcdef;
if (status != UVM_IS_OK || hw.value != expected)
`uvm_fatal("BACKDOOR_MAP", "Write status/hardware mismatch")
if (scenario == 6) begin
model.rg.mirror(status, UVM_CHECK, UVM_BACKDOOR, uvm_reg_map::backdoor());
if (status != UVM_IS_OK) `uvm_fatal("BACKDOOR_MAP", "Mirror failed")
end
if (((scenario == 4) ? unmapped_model.rg.get_mirrored_value() :
model.rg.get_mirrored_value()) != expected)
`uvm_fatal("BACKDOOR_MAP", "Mirror value mismatch")
$display("REVIEW|%s_warnings|%0d", scenario_names[scenario], observer.map_warnings);
$display("REVIEW|%s_data_ok|1", scenario_names[scenario]);
end
$display("REVIEW|done|1");
$finish;
end
endmodule