///
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!!!