How can we verify a memory whose address location is swapped

///

import uvm_pkg::*;
`include “uvm_macros.svh”

// Interface and Top Module (unchanged from previous example)
interface mem_if (input logic clk, reset_n);
logic write_en;
logic read_en;
logic [3:0] addr;
logic [7:0] data_in;
logic [7:0] data_out;
clocking cb @(posedge clk);
output write_en, read_en, addr, data_in;
input data_out;
endclocking
endinterface

// Sequence Item
class mem_seq_item extends uvm_sequence_item;
rand logic [3:0] addr;
rand logic [7:0] data;
rand bit write_en;
rand bit read_en;
uvm_object_utils_begin(mem_seq_item) uvm_field_int(addr, UVM_ALL_ON)
uvm_field_int(data, UVM_ALL_ON) uvm_field_int(write_en, UVM_ALL_ON)
uvm_field_int(read_en, UVM_ALL_ON) uvm_object_utils_end
function new(string name = “mem_seq_item”);
super.new(name);
endfunction
endclass

// Sequence
class mem_sequence extends uvm_sequence #(mem_seq_item);
`uvm_object_utils(mem_sequence)
function new(string name = “mem_sequence”);
super.new(name);
endfunction
task body();
mem_seq_item item;
repeat(2) begin
item = mem_seq_item::type_id::create(“item”);
start_item(item);
assert(item.randomize() with {write_en == 1; read_en == 0; addr == 5; data == 8’hAA;});
finish_item(item);
start_item(item);
assert(item.randomize() with {write_en == 0; read_en == 1; addr == 6;});
finish_item(item);
end
endtask
endclass

// Driver
class mem_driver extends uvm_driver #(mem_seq_item);
uvm_component_utils(mem_driver) virtual mem_if vif; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); if (!uvm_config_db#(virtual mem_if)::get(this, "", "mem_vif", vif)) uvm_fatal(“DRV”, “Could not get vif”)
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
forever begin
mem_seq_item item;
seq_item_port.get_next_item(item);
@(vif.cb);
vif.cb.write_en <= item.write_en;
vif.cb.read_en <= item.read_en;
vif.cb.addr <= item.addr;
vif.cb.data_in <= item.data;
@(vif.cb);
seq_item_port.item_done();
end
endtask
endclass

// Sequencer
class mem_sequencer extends uvm_sequencer #(mem_seq_item);
`uvm_component_utils(mem_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass

// Agent
class mem_agent extends uvm_agent;
`uvm_component_utils(mem_agent)
mem_driver driver;
mem_sequencer sequencer;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
driver = mem_driver::type_id::create(“driver”, this);
sequencer = mem_sequencer::type_id::create(“sequencer”, this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
driver.seq_item_port.connect(sequencer.seq_item_export); // Connect driver to sequencer
endfunction
endclass

// Environment
class mem_env extends uvm_env;
`uvm_component_utils(mem_env)
mem_agent agent;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent = mem_agent::type_id::create(“agent”, this);
endfunction
endclass

// Test
class mem_test extends uvm_test;
`uvm_component_utils(mem_test)
mem_env env;
virtual mem_if vif;

function new(string name = “mem_test”, uvm_component parent = null);
super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = mem_env::type_id::create(“env”, this);
if (!uvm_config_db#(virtual mem_if)::get(this, “”, “mem_vif”, vif))
`uvm_fatal(“TEST”, “Could not get vif”)
uvm_config_db#(virtual mem_if)::set(this, “env.agent.driver”, “mem_vif”, vif);
endfunction

task run_phase(uvm_phase phase);
mem_sequence seq;
phase.raise_objection(this);
seq = mem_sequence::type_id::create(“seq”);
seq.start(env.agent.sequencer); // Start the sequence on the sequencer
#100;
// Back Door Read
uvm_info("TEST", "Performing Back Door Read", UVM_LOW) begin logic [7:0] read_val; read_val = tb.mem_inst.mem[5]; $display("Back Door Read: addr=5, value=%h (expected AA)", read_val); end // Back Door Write uvm_info(“TEST”, “Performing Back Door Write”, UVM_LOW)
begin
tb.mem_inst.mem[6] = 8’hBB;
$display(“Back Door Write: addr=6, value=BB”);
end
// Front Door Read (already handled by sequence)
@(vif.cb);
$display(“Front Door Read: addr=6, value=%h (expected BB)”, vif.cb.data_out);
#100;
phase.drop_objection(this);
endtask
endclass

module tb;
logic clk, reset_n;
mem_if mem_vif(clk, reset_n);
simple_memory mem_inst (.clk(clk), .reset_n(reset_n), .write_en(mem_vif.write_en),
.read_en(mem_vif.read_en), .addr(mem_vif.addr),
.data_in(mem_vif.data_in), .data_out(mem_vif.data_out));

initial begin
clk = 0;
forever #5 clk = ~clk;
end
initial begin
reset_n = 0;
#20 reset_n = 1;
end
initial begin
uvm_config_db#(virtual mem_if)::set(null, “uvm_test_top”, “mem_vif”, mem_vif);
run_test(“mem_test”);
end
initial begin
$dumpfile(“dump.vcd”);
$dumpvars;
end
endmodule

///
///
//DESIGN

module simple_memory (
input logic clk,
input logic reset_n,
input logic write_en, // Write enable
input logic read_en, // Read enable
input logic [3:0] addr, // 4-bit address (16 locations)
input logic [7:0] data_in, // 8-bit data input
output logic [7:0] data_out // 8-bit data output
);
logic [7:0] mem [0:15]; // Memory array (16 locations, 8-bit each)

always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
for (int i = 0; i < 16; i++) mem[i] <= 8’h00;
data_out <= 8’h00;
end else begin
if (write_en) begin
mem[addr] <= data_in; // Front door write
end
if (read_en) begin
data_out <= mem[addr]; // Front door read
end
end
end
endmodule

///

Here i gave a code that gives idea about how back door reads and front door writes vice versa happens!!!

I don’t believe this is the solution. You cannot check any storage place of a real memory. Have in mind you have a memory of size 1TB. You are unable to ckeck all storage places in a reasonable time. And using a hierarchical path and considering this as ‘backdoor’ is a bad approach. Even using uvm_hdl_read is not a good approach because it needs also a hierarchical path. I#d recommend to spend effort on investigating the address decoder, that it generates the right values on the address pins.

That is under the assumption that

The correctness of the output of the address decoder ↔ the correctness of the output of the memory.

is always true.

If there is a case such that the output of the decoder is correct, but the output of the memory is wrong, that doesn’t work. Although it is unlikely.