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?
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:
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
.pready
for both read and write transactions, but it does not.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.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:
apb_mod
module port signals.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.