`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg::*;
interface storage_if;
bit [31:0] value;
endinterface
class storage_backdoor extends uvm_reg_backdoor;
virtual storage_if vif;
function new(string name = "storage_backdoor");
super.new(name);
endfunction
virtual task write(uvm_reg_item rw);
do_pre_write(rw);
if (vif == null) rw.status = UVM_NOT_OK;
else begin
vif.value = rw.value[0];
rw.status = UVM_IS_OK;
end
do_post_write(rw);
endtask
virtual function void read_func(uvm_reg_item rw);
if (vif == null) rw.status = UVM_NOT_OK;
else begin
rw.value[0] = vif.value;
rw.status = UVM_IS_OK;
end
endfunction
endclass
class storage_reg extends uvm_reg;
uvm_reg_field value;
function new(string name = "storage_reg");
super.new(name, 32, UVM_NO_COVERAGE);
endfunction
function void build();
value = new("value");
value.configure(this, 32, 0, "RW", 0, 0, 1, 0, 1);
endfunction
endclass
class storage_block extends uvm_reg_block;
storage_reg rg;
function new(string name = "storage_block");
super.new(name, UVM_NO_COVERAGE);
endfunction
function void build();
rg = new(); rg.configure(this); rg.build();
default_map = create_map("map", 0, 4, UVM_LITTLE_ENDIAN, 1);
default_map.add_reg(rg, 0, "RW");
lock_model();
endfunction
endclass
class backdoor_observer extends uvm_reg_cbs;
int before_write, after_write, before_read, after_read;
function new(string name = "observer"); super.new(name); endfunction
virtual task pre_write(uvm_reg_item rw); before_write++; endtask
virtual task post_write(uvm_reg_item rw); after_write++; endtask
virtual task pre_read(uvm_reg_item rw); before_read++; endtask
virtual task post_read(uvm_reg_item rw); after_read++; endtask
endclass
module backdoor_binding_probe;
storage_if hw();
initial begin
storage_block model = new();
storage_backdoor bd = new();
backdoor_observer observer = new();
uvm_status_e status;
uvm_reg_data_t value;
model.build();
bd.vif = hw;
model.rg.set_backdoor(bd);
uvm_callbacks#(uvm_reg_backdoor, uvm_reg_cbs)::add(bd, observer);
$display("REVIEW|backdoor_identity|%0d", model.rg.get_backdoor() == bd);
model.rg.write(status, 'h12345678, UVM_BACKDOOR);
if (status != UVM_IS_OK) `uvm_fatal("BACKDOOR", "Write failed")
if (hw.value != 'h12345678) `uvm_fatal("BACKDOOR", "Hardware mismatch")
$display("REVIEW|write_ok|%0d", status == UVM_IS_OK);
$display("REVIEW|hardware|%08h", hw.value);
// Discard observer counts for any read performed by the RAL write path.
observer.before_read = 0; observer.after_read = 0;
hw.value = 'h89abcdef;
model.rg.read(status, value, UVM_BACKDOOR);
if (status != UVM_IS_OK || value != 'h89abcdef)
`uvm_fatal("BACKDOOR", "Read failed")
$display("REVIEW|read_ok|%0d", status == UVM_IS_OK);
$display("REVIEW|read_value|%08h", value[31:0]);
$display("REVIEW|mirror|%08h", model.rg.get_mirrored_value());
$display("REVIEW|write_callbacks|%0d:%0d", observer.before_write, observer.after_write);
$display("REVIEW|read_callbacks|%0d:%0d", observer.before_read, observer.after_read);
bd.vif = null;
model.rg.read(status, value, UVM_BACKDOOR);
$display("REVIEW|missing_interface_rejected|%0d", status == UVM_NOT_OK);
$display("REVIEW|done|1");
$finish;
end
endmodule