1

Here is my code on EDA Playground.

`include "uvm_macros.svh"
import uvm_pkg::*;
//////////////////////transaction class//////////////////////
class transaction extends uvm_sequence_item;
 `uvm_object_utils( transaction )
 rand bit [7 : 0] paddr;
 rand bit [7 : 0] pwdata;
 bit [7 : 0] prdata;
 rand bit pwrite;
 
 function new(string name = "transaction");
 super.new(name);
 endfunction 
 
 constraint c_paddr { 
 paddr inside {8'hF0, 8'hE0, 8'hE1, 8'hE2, 8'hE3, 8'hD0, 8'hD1, 8'hD2, 8'hD3};
 }
endclass
//////////////////////Driver//////////////////////
class driver extends uvm_driver #(transaction);
 `uvm_component_utils(driver)
 
 virtual top_if vif;
 transaction tr;
 
 function new(string name = "driver", uvm_component parent = null);
 super.new(name, parent);
 endfunction 
 
 virtual function void build_phase(uvm_phase phase);
 super.build_phase(phase);
 if(!uvm_config_db#(virtual top_if)::get(this, "", "vif", vif))
 `uvm_error("DRV", "Error getting Interface Handle")
 endfunction 
 
 /////write data to dut -> psel -> pen 
 
 virtual task write();
 @(posedge vif.pclk);
 vif.paddr <= tr.paddr;
 vif.pwdata <= tr.pwdata;
 vif.pwrite <= 1'b1;
 vif.psel <= 1'b1;
 @(posedge vif.pclk);
 vif.penable <= 1'b1;
 `uvm_info("DRV", $sformatf("Mode :Write | WDATA : %0d ADDR : %0d", vif.pwdata, vif.paddr), UVM_NONE); 
 
 @(posedge vif.pclk);
 vif.psel <= 1'b0;
 vif.penable <= 1'b0;
 endtask 
 
 ////read data from dut 
 virtual task read();
 @(posedge vif.pclk);
 vif.paddr <= tr.paddr;
 vif.pwrite <= 1'b0;
 vif.psel <= 1'b1;
 @(posedge vif.pclk);
 vif.penable <= 1'b1;
 `uvm_info("DRV", $sformatf("Mode :Read | WDATA : %0d ADDR : %0d RDATA : %0d", vif.pwdata, vif.paddr, vif.prdata), UVM_NONE);
 @(posedge vif.pclk);
 vif.psel <= 1'b0;
 vif.penable <= 1'b0;
 tr.prdata = vif.prdata;
 
 endtask 
 
 /////////////////////////////////////////
 
 virtual task run_phase (uvm_phase phase);
 bit [7:0] data;
 vif.presetn <= 1'b1;
 vif.psel <= 0;
 vif.penable <= 0;
 vif.pwrite <= 0;
 vif.paddr <= 0;
 vif.pwdata <= 0;
 forever begin
 seq_item_port.get_next_item (tr);
 if (tr.pwrite)
 begin
 write();
 end
 else 
 begin 
 read();
 end
 seq_item_port.item_done ();
 end
 endtask 
endclass
 
 
 
//////////////////////Monitor//////////////////////
 class monitor extends uvm_monitor;
 `uvm_component_utils( monitor )
 uvm_analysis_port #(transaction) mon_ap;
 virtual top_if vif;
 
 function new(string name="my_monitor", uvm_component parent);
 super.new(name, parent);
 endfunction : new
 
 virtual function void build_phase(uvm_phase phase);
 super.build_phase (phase);
 mon_ap = new("mon_ap", this);
 if(! uvm_config_db#(virtual top_if)::get (this, "", "vif", vif))
 `uvm_error("DRV", "Error getting Interface Handle")
 endfunction : build_phase
 
 virtual task run_phase(uvm_phase phase);
 fork
 forever begin
 @(posedge vif.pclk);
 if(vif.psel && vif.penable && vif.presetn) begin
 transaction tr = transaction::type_id::create("tr");
 tr.paddr = vif.paddr;
 tr.pwrite = vif.pwrite;
 if (vif.pwrite)
 begin
 tr.pwdata = vif.pwdata;
 @(posedge vif.pclk);
 `uvm_info("MON", $sformatf("Mode : Write | WDATA : %0d ADDR : %0d", vif.pwdata, vif.paddr), UVM_NONE);
 end
 else
 begin
 @(posedge vif.pclk);
 tr.prdata = vif.prdata;
 `uvm_info("MON", $sformatf("Mode : Read | WDATA : %0d ADDR : %0d RDATA : %0d", vif.pwdata, vif.paddr, vif.prdata), UVM_NONE); 
 end
 mon_ap.write(tr);
 end 
 end
 join_none
 endtask 
endclass
 
 
 
//////////////////////scoreboard//////////////////////
class sco extends uvm_scoreboard;
`uvm_component_utils(sco)
 uvm_analysis_imp#(transaction,sco) recv;
 bit [7:0] arr [1024];
 bit [7:0] temp;
 
 function new(input string inst = "sco", uvm_component parent = null);
 super.new(inst,parent);
 endfunction
 
 virtual function void build_phase(uvm_phase phase);
 super.build_phase(phase);
 recv = new("recv", this);
 endfunction
 
 virtual function void write(transaction tr);
 
 if(tr.pwrite == 1'b1)
 begin
 arr[tr.paddr] = tr.pwdata;
 `uvm_info("SCO", $sformatf("DATA Stored | Addr : %0d Data :%0d", tr.paddr, tr.pwdata), UVM_NONE)
 end
 else
 begin
 
 temp = arr[tr.paddr]; 
 if( temp == tr.prdata)
 `uvm_info("SCO", $sformatf("Test Passed -> Addr : %0d Data :%0d", tr.paddr, temp), UVM_NONE)
 else
 `uvm_error("SCO", $sformatf("Test Failed -> Addr : %0d Data :%0d", tr.paddr, temp))
 
 end
 $display("----------------------------------------------------------------"); 
 endfunction
endclass
 
 
//////////////////////Agent//////////////////////
class agent extends uvm_agent;
`uvm_component_utils(agent)
function new(input string inst = "agent", uvm_component parent = null);
super.new(inst,parent);
endfunction
 driver d;
 uvm_sequencer#(transaction) seqr;
 monitor m;
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
 d = driver::type_id::create("d",this);
 m = monitor::type_id::create("m",this);
 seqr = uvm_sequencer#(transaction)::type_id::create("seqr", this); 
endfunction
virtual function void connect_phase(uvm_phase phase);
 super.connect_phase(phase);
 d.seq_item_port.connect(seqr.seq_item_export);
endfunction
endclass
 
 
//////////////////////RAL Model//////////////////////
/////////// Status Register//////////////
///////// s_reg Registers//////////////
class status_reg extends uvm_reg;
 `uvm_object_utils(status_reg)
 rand uvm_reg_field status;
 rand uvm_reg_field producer;
 rand uvm_reg_field consumer;
 function new(string name = "status_reg");
 super.new(name, 8, UVM_NO_COVERAGE);
 endfunction
 function void build();
 status = uvm_reg_field::type_id::create("status");
 producer = uvm_reg_field::type_id::create("producer");
 consumer = uvm_reg_field::type_id::create("consumer");
 //(reg, bitwidth, lsb, access, volatile, reselVal, hasReset, isRand, fieldAccess)
 status.configure(this, 1, 0, "RW", 0, 0, 1, 1, 1);
 producer.configure(this, 1, 1, "RW", 0, 0, 1, 1, 1);
 consumer.configure(this, 1, 2, "RW", 0, 0, 1, 1, 1);
 endfunction
endclass
////////////Status register block////////////////
class status_reg_block extends uvm_reg_block;
 `uvm_object_utils(status_reg_block)
 status_reg s_reg0;
 status_reg s_reg1;
 
 uvm_reg_map status_reg_map;
 
 function new(string name = "status_reg_block");
 super.new(name, UVM_NO_COVERAGE);
 endfunction
 virtual function void build();
 s_reg0 = status_reg::type_id::create("s_reg0");
 s_reg0.configure(this);
 s_reg0.build();
 
 s_reg1 = status_reg::type_id::create("s_reg1");
 s_reg1.configure(this);
 s_reg1.build();
 
 status_reg_map = create_map("status_reg_map", 8'hF0, 1, UVM_LITTLE_ENDIAN);
 status_reg_map.add_reg(s_reg0, 'h00, "RW");
 status_reg_map.add_reg(s_reg1, 'h01, "RW");
 endfunction
endclass
//////////////////Duplicate Register//////////////
///////////// control register///////////////////////
class ctrl_d_reg extends uvm_reg;
 `uvm_object_utils(ctrl_d_reg)
 
 rand uvm_reg_field d_enb_field;
 rand uvm_reg_field d_enable_field;
 rand uvm_reg_field d_r_w_field;
 
 function new(string name = "ctrl_d_reg");
 super.new(name, 8, UVM_NO_COVERAGE);
 endfunction
 function void build();
 d_enb_field = uvm_reg_field::type_id::create("d_enb_field");
 d_enable_field = uvm_reg_field::type_id::create("d_enable_field");
 d_r_w_field = uvm_reg_field::type_id::create("d_r_w_field");
 
 d_enb_field.configure( this, 1, 0, "RW", 0, 0, 1, 1, 1);
 d_enable_field.configure( this, 1, 1, "RW", 0, 0, 1, 1, 1);
 d_r_w_field.configure( this, 1, 2, "RW", 0, 0, 1, 1, 1);
 endfunction
 
endclass
///////////// d_reg registers///////////////////////
class data_reg extends uvm_reg;
 `uvm_object_utils(data_reg)
 
 rand uvm_reg_field data_reg_field;
 
 function new(string name = "data_reg");
 super.new(name, 8, UVM_NO_COVERAGE);
 endfunction
 function void build();
 data_reg_field = uvm_reg_field::type_id::create("data_reg_field");
 data_reg_field.configure(this, 8, 0, "RW", 0, 0, 1, 1, 1);
 endfunction
 
endclass
//////////Data register 0 block/////////////
class data_reg_0_block extends uvm_reg_block;
 `uvm_object_utils(data_reg_0_block)
 
 ctrl_d_reg enable_0;
 data_reg baud_rate_0;
 data_reg trans_count_0;
 data_reg sl_address_0;
 
 uvm_reg_map data_reg_0_map;
 
 function new(string name = "data_reg_0_block");
 super.new(name, UVM_NO_COVERAGE);
 endfunction
 virtual function void build();
 enable_0 = ctrl_d_reg::type_id::create("enable_0");
 baud_rate_0 = data_reg::type_id::create("baud_rate_0");
 trans_count_0 = data_reg::type_id::create("trans_count_0");
 sl_address_0 = data_reg::type_id::create("sl_address_0");
 
 enable_0.build();
 baud_rate_0.build();
 trans_count_0.build();
 sl_address_0.build();
 
 enable_0.configure(this);
 baud_rate_0.configure(this);
 trans_count_0.configure(this);
 sl_address_0.configure(this);
 
 //check the address 00,01,02,03 and what is this below 4
 data_reg_0_map = create_map("data_reg_0_map", 8'hE0, 1, UVM_LITTLE_ENDIAN);
 data_reg_0_map.add_reg(enable_0, 'h00, "RW");
 data_reg_0_map.add_reg(baud_rate_0, 'h01, "RW");
 data_reg_0_map.add_reg(trans_count_0, 'h02, "RW");
 data_reg_0_map.add_reg(sl_address_0, 'h03, "RW");
 endfunction
endclass
//////////Data register 1 block/////////////
class data_reg_1_block extends uvm_reg_block;
 `uvm_object_utils(data_reg_1_block)
 
 ctrl_d_reg enable;
 data_reg baud_rate;
 data_reg trans_count;
 data_reg sl_address;
 
 uvm_reg_map data_reg_1_map;
 
 function new(string name = "data_reg_1_block");
 super.new(name, UVM_NO_COVERAGE);
 endfunction
 virtual function void build();
 enable = ctrl_d_reg::type_id::create("enable");
 baud_rate = data_reg::type_id::create("baud_rate");
 trans_count = data_reg::type_id::create("trans_count");
 sl_address = data_reg::type_id::create("sl_address");
 
 enable.build();
 baud_rate.build();
 trans_count.build();
 sl_address.build();
 
 enable.configure(this);
 baud_rate.configure(this);
 trans_count.configure(this);
 sl_address.configure(this);
 
 data_reg_1_map = create_map("data_reg_1_map", 8'hD0, 1, UVM_LITTLE_ENDIAN);
 data_reg_1_map.add_reg(enable, 'h00, "RW");
 data_reg_1_map.add_reg(baud_rate, 'h01, "RW");
 data_reg_1_map.add_reg(trans_count, 'h02, "RW");
 data_reg_1_map.add_reg(sl_address, 'h03, "RW");
 endfunction
endclass
/////////////Ping pong register block///////////////////
class ping_pong_reg_block extends uvm_reg_block;
 `uvm_object_utils(ping_pong_reg_block)
 
 status_reg_block status_regs;
 data_reg_0_block d_reg_0;
 data_reg_1_block d_reg_1;
 
 uvm_reg_map ping_pong_reg_map;
 
 function new(string name = "ping_pong_reg_block");
 super.new(name, UVM_NO_COVERAGE);
 endfunction
 function void build();
 status_regs = status_reg_block::type_id::create("status_regs");
 d_reg_0 = data_reg_0_block::type_id::create("d_reg_0");
 d_reg_1 = data_reg_1_block::type_id::create("d_reg_1");
 
 status_regs.configure(this);
 d_reg_0.configure(this);
 d_reg_1.configure(this);
 
 status_regs.build();
 d_reg_0.build();
 d_reg_1.build();
 
 ping_pong_reg_map = create_map("ping_pong_reg_map", 8'hD0, 1, UVM_LITTLE_ENDIAN);
 ping_pong_reg_map.add_submap(d_reg_1.data_reg_1_map, 'h00);
 ping_pong_reg_map.add_submap(d_reg_0.data_reg_0_map, 'h10);
 ping_pong_reg_map.add_submap(status_regs.status_reg_map,'h20);
 
 lock_model();
 endfunction
endclass
 
 
 
//////////////////////Adapter//////////////////////
class top_adapter extends uvm_reg_adapter;
 `uvm_object_utils (top_adapter)
 function new (string name = "top_adapter");
 super.new (name);
 endfunction
 
 function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
 transaction tr; 
 tr = transaction::type_id::create("tr");
 
 tr.pwrite = (rw.kind == UVM_WRITE) ? 1'b1 : 1'b0;
 tr.paddr = rw.addr;
 if(tr.pwrite) tr.pwdata =rw.data;
 if(!tr.pwrite) tr.prdata=rw.data;;
 //tr.pwdata = rw.data;
 return tr;
 endfunction
 
 function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
 transaction tr;
 
 assert($cast(tr, bus_item));
 rw.kind = (tr.pwrite == 1'b1) ? UVM_WRITE : UVM_READ;
 rw.data = (tr.pwrite == 1'b1) ? tr.pwdata : tr.prdata;
 rw.addr = tr.paddr;
 //rw.data = tr.prdata;
 rw.status = UVM_IS_OK;
 endfunction
endclass
//////////////////////Environment//////////////////////
class env extends uvm_env;
 `uvm_component_utils(env)
 
 agent agent_inst;
 ping_pong_reg_block regmodel; 
 top_adapter adapter_inst;
 
 uvm_reg_predictor #(transaction) predictor_inst;
 
 sco s; 
 
 function new(string name = "env", uvm_component parent);
 super.new(name, parent);
 endfunction : new
 function void build_phase(uvm_phase phase);
 super.build_phase(phase);
 agent_inst = agent::type_id::create("agent_inst", this);
 s = sco::type_id::create("s", this);
 
 regmodel = ping_pong_reg_block::type_id::create("regmodel", this);
 regmodel.build();
 
 predictor_inst = uvm_reg_predictor#(transaction)::type_id::create("predictor_inst", this);
 adapter_inst = top_adapter::type_id::create("adapter_inst",, get_full_name());
 
 endfunction 
 function void connect_phase(uvm_phase phase);
 agent_inst.m.mon_ap.connect(s.recv);
 agent_inst.m.mon_ap.connect(predictor_inst.bus_in);
 
 regmodel.ping_pong_reg_map.set_sequencer( .sequencer(agent_inst.seqr), .adapter(adapter_inst) );
 regmodel.ping_pong_reg_map.set_base_addr(8'hD0);
 
 predictor_inst.map = regmodel.ping_pong_reg_map;
 predictor_inst.adapter = adapter_inst;
 endfunction 
endclass 
//////////////////////Sequences//////////////////////
class data_reg_wr extends uvm_sequence;
 `uvm_object_utils(data_reg_wr)
 ping_pong_reg_block regmodel;
 
 function new (string name = "data_reg_wr"); 
 super.new(name); 
 endfunction
 
 task body; 
 uvm_status_e status;
 bit [7:0] wdata; 
 
 wdata = $urandom(5);
 regmodel.d_reg_0.baud_rate_0.write(status, wdata);
 regmodel.d_reg_1.baud_rate.write(status, wdata);
 endtask
endclass
class data_reg_rd extends uvm_sequence;
 `uvm_object_utils(data_reg_rd)
 ping_pong_reg_block regmodel;
 
 function new (string name = "data_reg_rd"); 
 super.new(name); 
 endfunction
 
 task body; 
 uvm_status_e status;
 bit [7:0] rdata;
 
 regmodel.d_reg_0.baud_rate_0.read(status, rdata);
 //`uvm_info("SEQ", $sformatf("rData %0d",rdata), UVM_NONE)
 regmodel.d_reg_1.baud_rate.read(status, rdata);
 endtask
endclass
//////////////////////Test//////////////////////
class test extends uvm_test;
 `uvm_component_utils(test)
 function new(input string inst = "test", uvm_component c);
 super.new(inst, c);
 endfunction
 env e;
 data_reg_wr wr_seq;
 data_reg_rd rd_seq;
 virtual function void build_phase(uvm_phase phase);
 super.build_phase(phase);
 e = env::type_id::create("env", this);
 
 wr_seq = data_reg_wr::type_id::create("wr_seq");
 rd_seq = data_reg_rd::type_id::create("rd_seq");
 endfunction
 virtual task run_phase(uvm_phase phase);
 phase.raise_objection(this);
 `uvm_info("TEST", "Starting Write Sequence", UVM_MEDIUM)
 wr_seq.regmodel = e.regmodel;
 wr_seq.start(e.agent_inst.seqr);
 `uvm_info("TEST", "Starting Read Sequence", UVM_MEDIUM)
 rd_seq.regmodel = e.regmodel;
 rd_seq.start(e.agent_inst.seqr);
 phase.drop_objection(this);
 phase.phase_done.set_drain_time(this, 200);
 endtask
endclass
//////////////////////TB//////////////////////
module tb; 
 top_if vif();
 
 apb_mod dut(vif.pclk, 
 vif.presetn, 
 vif.paddr, 
 vif.psel, 
 vif.penable, 
 vif.pwrite, 
 vif.pwdata, 
 vif.pready, 
 vif.prdata, 
 vif.pwakeup, 
 vif.pslverr, 
 vif.enable_O, 
 vif.r_w_O, 
 vif.buad_rate_O, 
 vif.trans_count_O, 
 vif.sl_address_O,
 ); // Added missing connection
 
 initial begin
 vif.pclk <= 0;
 end
 always #10 vif.pclk = ~vif.pclk;
 
 initial begin
 uvm_config_db#(virtual top_if)::set(null, "*", "vif", vif);
 run_test("test");
 end
 
 initial begin
 $dumpfile("dump.vcd");
 $dumpvars;
 end
endmodule
 
 
 
 

The above code is the testbench that I have written for this DUT:

module apb_mod #(parameter BW = 8, CSR_no = 4)(
 //////// APB signals ////////
 input wire pclk, /// clock
 input wire presetn, /// active low synchronous reset
 input wire [BW-1:0] paddr, /// address
 input wire psel, /// peripheral select
 input wire penable, /// peripheral enable
 input wire pwrite, /// peripheral write
 input wire [BW-1:0] pwdata, /// peripheral data
 output wire pready, /// peripheral ready
 output wire [BW-1:0] prdata, /// peripheral read data
 input wire pwakeup, /// peripheral wakeup
 output wire pslverr, 
 
 ////////// dummy UART CSRs in ping pong //////////
 input wire done,
 output wire enable_O, 
 output wire r_w_O,
 output wire [3:0] buad_rate_O,
 output wire [3:0] trans_count_O,
 output wire [3:0] sl_address_O
);
 
 ////////////// APB REGs ////////
 reg [2:0] state, next_state; 
 reg pready_reg;
 reg pslverr_reg;
 reg [BW-1:0] prdata_reg;
 
 ////////////////// pingpong Registers //////
 reg [7:0] s_reg [1:0]; 
 reg [7:0] d_reg_0[3:0]; 
 reg [7:0] d_reg_1[3:0]; 
 
 /////////////// states of APB /////////////////////
 localparam IDLE = 3'b000, SETUP = 3'b001, ACCESS = 3'b010; /// states of APB 
 
 ///////////////////////// uart C S R regs //////////
 reg enable_O_reg; 
 reg r_w_O_reg; 
 reg [3:0] buad_rate_O_reg;
 reg [3:0] trans_count_O_reg;
 reg [3:0] sl_address_O_reg;
 
 /////////////////////// assignment /////////////////////////////
 assign enable_O = enable_O_reg;
 assign r_w_O = r_w_O_reg;
 assign buad_rate_O = buad_rate_O_reg; 
 assign trans_count_O = trans_count_O_reg;
 assign sl_address_O = sl_address_O_reg;
 assign prdata = prdata_reg;
 assign pslverr = pslverr_reg;
 
 always @(posedge pclk) begin 
 if (!presetn) begin
 s_reg[0][0] <= 1; // s_status
 s_reg[0][1] <= 0; // producer
 s_reg[0][2] <= 0; // consumer
 d_reg_0[0][0] <= 0; // enb_0
 d_reg_1[0][0] <= 0; // enb_1
 state <= IDLE;
 pslverr_reg <= 0;
 end else begin
 state <= next_state;
 end
 end
 
 always @(*) begin
 if (s_reg[0][2] == 0) begin
 enable_O_reg = d_reg_0[0][1]; 
 r_w_O_reg = d_reg_0[0][2]; 
 buad_rate_O_reg = d_reg_0[1];
 trans_count_O_reg = d_reg_0[2];
 sl_address_O_reg = d_reg_0[3];
 end else if (s_reg[0][2] == 1) begin
 enable_O_reg = d_reg_1[0][1]; 
 r_w_O_reg = d_reg_1[0][2]; 
 buad_rate_O_reg = d_reg_1[1];
 trans_count_O_reg = d_reg_1[2];
 sl_address_O_reg = d_reg_1[3]; 
 end else begin
 enable_O_reg = d_reg_0[0][1]; 
 r_w_O_reg = d_reg_0[0][2]; 
 buad_rate_O_reg = d_reg_0[1];
 trans_count_O_reg = d_reg_0[2];
 sl_address_O_reg = d_reg_0[3];
 end
 end
 
 always @(posedge pclk) begin
 if (done) begin
 if (d_reg_0[0][0] == 1 & d_reg_1[0][0] == 0) begin
 d_reg_0[0][0] <= 0;
 s_reg[0][2] <= 0;
 end else if (d_reg_0[0][0] == 0 & d_reg_1[0][0] == 1) begin
 d_reg_1[0][0] <= 0;
 s_reg[0][2] <= 1;
 end else begin
 s_reg[0][2] <= 0; 
 end
 end
 end
 
 always @(posedge pclk) begin
 if (penable) begin
 if (pwrite) begin 
 case (s_reg[0][1])
 1'b0: begin
 if (paddr == 8'hf0)
 s_reg[0][1] <= pwdata[0];
 else begin
 d_reg_0[paddr] <= pwdata;
 s_reg[0][2] <= 1;
 s_reg[0][0] <= 0;
 end
 end
 1'b1: begin
 if (paddr == 8'hf0)
 s_reg[0][1] <= pwdata[0];
 else begin
 d_reg_1[paddr] <= pwdata;
 s_reg[0][2] <= 0;
 s_reg[0][0] <= 0;
 end
 end
 default: begin 
 d_reg_0[paddr] <= pwdata;
 s_reg[0][0] <= 1; 
 pslverr_reg <= 1;
 end
 endcase
 end else begin
 prdata_reg <= (paddr[7:4] == 4'hf) ? s_reg[0][2:0] :
 (paddr[7:4] == 4'he) ? d_reg_0[paddr[3:0]] : d_reg_1[paddr[3:0]];
 end
 end
 end
 
 always @(*) begin 
 case (state)
 IDLE: next_state = psel ? SETUP : IDLE;
 SETUP: next_state = penable ? ACCESS : SETUP;
 ACCESS: next_state = (psel && pready) ? SETUP : (!psel ? IDLE : ACCESS);
 default: next_state = IDLE;
 endcase 
 end
endmodule
//////////////////////Interface//////////////////////
interface top_if ();
 logic [7 : 0]paddr; // 8-bit
 logic [7 : 0]pwdata; // 8-bit
 logic [7 : 0]prdata; // 8-bit
 logic pwrite; // 1-bit
 logic psel; // 1-bit
 logic penable; // 1-bit
 logic presetn; // 1-bit
 logic pclk; // 1-bit
 logic pslverr; // 1-bit
 logic pwakeup; // 1-bit
 logic pready; // 1-bit
 logic enable_O; // 1-bit
 logic r_w_O; // 1-bit
 
 logic [3:0] buad_rate_O; // 4-bit
 logic [3:0]trans_count_O;// 4-bit
 logic [3:0]sl_address_O; // 4-bit
endinterface

I'm not able to read the data (using the read function) that I have written into the environment (using the write function).

The following log shows the output of the program
UVM_INFO testbench.sv(584) @ 0: uvm_test_top \[TEST\] Starting Write Sequence
UVM_INFO testbench.sv(51) @ 30: uvm_test_top.env.agent_inst.d \[DRV\] Mode :Write | WDATA : 187 ADDR : 225
UVM_INFO testbench.sv(135) @ 70: uvm_test_top.env.agent_inst.m \[MON\] Mode : Write | WDATA : 187 ADDR : 225
UVM_INFO testbench.sv(177) @ 70: uvm_test_top.env.s \[SCO\] DATA Stored | Addr : 225 Data :187
-
UVM_INFO testbench.sv(51) @ 90: uvm_test_top.env.agent_inst.d \[DRV\] Mode :Write | WDATA : 187 ADDR : 209
UVM_INFO testbench.sv(588) @ 110: uvm_test_top \[TEST\] Starting Read Sequence
UVM_INFO testbench.sv(135) @ 130: uvm_test_top.env.agent_inst.m \[MON\] Mode : Write | WDATA : 187 ADDR : 209
UVM_INFO testbench.sv(177) @ 130: uvm_test_top.env.s \[SCO\] DATA Stored | Addr : 209 Data :187
-
UVM_INFO testbench.sv(68) @ 150: uvm_test_top.env.agent_inst.d \[DRV\] Mode :Read | WDATA : 187 ADDR : 225 RDATA : x
UVM_INFO testbench.sv(141) @ 190: uvm_test_top.env.agent_inst.m \[MON\] Mode : Read | WDATA : 187 ADDR : 225 RDATA : x
UVM_ERROR testbench.sv(187) @ 190: uvm_test_top.env.s \[SCO\] Test Failed -\> Addr : 225 Data :187
-
UVM_INFO testbench.sv(68) @ 210: uvm_test_top.env.agent_inst.d \[DRV\] Mode :Read | WDATA : 187 ADDR : 209 RDATA : x
UVM_INFO testbench.sv(141) @ 250: uvm_test_top.env.agent_inst.m \[MON\] Mode : Read | WDATA : 187 ADDR : 209 RDATA : x
UVM_ERROR testbench.sv(187) @ 250: uvm_test_top.env.s \[SCO\] Test Failed -\> Addr : 209 Data :187
-

Here I'm expecting the data to be read and show it as "Test Passed", but the data written isn't found in the prdata register at all. What could be the problem, and how do I fix it?

toolic
62.9k21 gold badges81 silver badges130 bronze badges
asked Feb 10, 2025 at 8:02
0

1 Answer 1

0

Since you named the DUT module apb_mod, I am assuming your goal is for the design to act as an AMBA APB slave and the testbench as an APB master.

If that is the case, then there are a few mistakes that I can see by inspection:

  • The DUT should drive the pready output, but it does not. The APB protocol requires the design to drive this signal for all transactions. In simulation, it will always be z.
  • The testbench must sample pready for both read and write transactions, but it does not.
  • The transaction class declares prdata as a 2-state type (bit) which is assigned to a 4-state type (logic) in the driver class. You should add code to the driver to display a message (either a uvm_info or a uvm_error) when this conversion from x/z to 0 occurs.
  • It is misleading to display WDATA for a "Read" transaction because the write data is irrelevant. In the monitor and driver, it is much more useful to display the transaction data instead of the interface data. It is good practice to add a display function to the transaction class, then just call that in the monitor and driver.

You should debug the problem using waveforms; it is insufficient to rely solely on the log output to debug the problem. This will narrow your problem down to either a DUT or a testbench bug. In waveforms:

  • Prove that the write occurred on the apb_mod module port signals.
  • If that looks good, prove that the register was written with the correct data. If not, then there is a design bug.

If you update the question with your link to EDA Playground, you will get more detailed help. That is far too much code for anyone to copy and get running.


Now that you updated the question with your link to EDA Playground, I can run the simulation. In waveforms, I see that apb_mod.prdata is unknown (x) for the whole simulation. This is the reason you see "RDATA : x" in your log file.

I also see that apb_mod.presetn is 1 for the whole simulation. This means that the testbench did not properly reset the design. You need to start the simulation with presetn=0, then after a couple clock cycles, set it to 1.

In your driver, create a reset task. Also create a reset sequence and call it before your write sequence.

answered Feb 10, 2025 at 12:06
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.