This is from one of the examples in verification academy. Can any one tell why is the read data different?
package bidirect_bus_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
// Bus sequence item
class bus_seq_item extends uvm_sequence_item;
// Request fields
rand logic[31:0] addr;
rand logic[31:0] write_data;
rand bit read_not_write;
rand int delay;
// Response fields
bit error;
logic[31:0] read_data;
`uvm_object_utils(bus_seq_item)
function new(string name = "bus_seq_item");
super.new(name);
endfunction
constraint at_least_1 { delay inside {[1:20]};}
constraint align_32 {addr[1:0] == 0;}
function void do_copy(uvm_object rhs);
bus_seq_item rhs_;
if (!$cast(rhs_, rhs)) begin
`uvm_fatal("do_copy", "cast failed, check types");
end
addr = rhs_.addr;
write_data = rhs_.write_data;
read_not_write = rhs_.read_not_write;
delay = rhs_.delay;
error = rhs_.error;
read_data = rhs_.read_data;
endfunction: do_copy
function bit do_compare(uvm_object rhs, uvm_comparer comparer);
bus_seq_item rhs_;
do_compare = $cast(rhs_, rhs) &&
super.do_compare(rhs, comparer) &&
addr == rhs_.addr &&
write_data == rhs_.write_data &&
read_not_write == rhs_.read_not_write &&
delay == rhs_.delay &&
error == rhs_.error &&
read_data == rhs_.read_data;
endfunction: do_compare
function string convert2string();
return $sformatf("%s\n addr:\t%0h\n write_data:\t%0h\n read_not_write:\t%0b\n delay:\t%0d\n error:\t%0b\n read_data:\t%0h",
super.convert2string(), addr, write_data, read_not_write, delay, error, read_data);
endfunction: convert2string
function void do_print(uvm_printer printer);
printer.m_string = convert2string();
endfunction: do_print
function void do_record(uvm_recorder recorder);
super.do_record(recorder);
`uvm_record_field("addr", addr);
`uvm_record_field("write_data", write_data);
`uvm_record_field("read_not_write", read_not_write);
`uvm_record_field("delay", delay);
`uvm_record_field("error", error);
`uvm_record_field("read_data", read_data);
endfunction: do_record
endclass: bus_seq_item
// Bidirectional driver - uses:
//
// get_next_item() to get the next instruction item
// item_done() to indicate that the driver has finished with the item
//
class bidirect_bus_driver extends uvm_driver #(bus_seq_item);
`uvm_component_utils(bidirect_bus_driver)
bus_seq_item req;
local virtual bidirect_bus_driver_bfm m_bfm;
function new(string name = "bidirect_bus_driver", uvm_component parent = null);
super.new(name, parent);
endfunction
function void set_bfm(virtual bidirect_bus_driver_bfm bfm);
m_bfm = bfm;
endfunction: set_bfm
task run_phase(uvm_phase phase);
m_bfm.wait_for_reset();
forever begin
seq_item_port.get_next_item(req); // Start processing req item
m_bfm.drive(req);
seq_item_port.item_done(); // End of req item
end
endtask: run_phase
endclass: bidirect_bus_driver
class bidirect_bus_sequencer extends uvm_sequencer #(bus_seq_item);
`uvm_component_utils(bidirect_bus_sequencer)
function new(string name = "bidirect_bus_sequencer", uvm_component parent = null);
super.new(name, parent);
endfunction
endclass: bidirect_bus_sequencer
// Bus sequence, which shows how the req object contains the result at the end
// of the control handshake with the driver via the sequencer
//
class bus_seq extends uvm_sequence #(bus_seq_item);
`uvm_object_utils(bus_seq)
bus_seq_item req;
int error_count = 0;
rand int limit = 15; // Controls the number of iterations
logic[31:0] mem[32'h0100_0000:32'h0100_001C] = '{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
function new(string name = "bus_seq");
super.new(name);
endfunction
task body;
req = bus_seq_item::type_id::create("req");
repeat (limit) begin
start_item(req);
// The address is constrained to be within the address of the GPIO function
// within the DUT, The result will be a request item for a read or a write
assert(req.randomize() with {addr inside {[32'h0100_0000:32'h0100_001C]};});
finish_item(req);
// The req handle points to the object that the driver has updated with response data
`uvm_info("seq_body", req.convert2string(), UVM_LOW);
if(req.read_not_write == 1) begin
if (mem[req.addr] == req.read_data) begin
`uvm_info("seq_body", "READ WRITE MATCH", UVM_LOW)
end
else begin
error_count++;
`uvm_error("body", "READ WRITE ERROR")
end
end
else begin
mem[req.addr] = req.write_data;
end
end
endtask: body
endclass: bus_seq
// Test class which instantiates, builds and connects the sequencer and the driver
//
class bidirect_bus_test extends uvm_test;
`uvm_component_utils(bidirect_bus_test)
bus_seq test_seq;
bidirect_bus_driver m_driver;
bidirect_bus_sequencer m_sequencer;
function new(string name = "bidirect_bus_test", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
m_driver = bidirect_bus_driver::type_id::create("m_driver", this);
m_sequencer = bidirect_bus_sequencer::type_id::create("m_sequencer", this);
endfunction: build_phase
function void connect_phase(uvm_phase phase);
virtual bidirect_bus_driver_bfm bfm;
m_driver.seq_item_port.connect(m_sequencer.seq_item_export);
if (!uvm_config_db #(virtual bidirect_bus_driver_bfm)::get(this, "", "top_hdl.bidirect_bus_drv", bfm)) begin
`uvm_fatal("connect_phase", "uvm_config_db #(virtual bidirect_bus_driver_bfm)::get(...) failed");
end
m_driver.set_bfm(bfm);
endfunction: connect_phase
task run_phase(uvm_phase phase);
test_seq = bus_seq::type_id::create("test_seq");
phase.raise_objection(this, "Starting test_seq");
test_seq.start(m_sequencer);
phase.drop_objection(this, "Finished test_seq");
endtask: run_phase
function void report_phase(uvm_phase phase);
if(test_seq.error_count == 0) begin
`uvm_info("** UVM TEST PASSED **", $sformatf("No Read Write mismatches"), UVM_LOW)
end
else begin
`uvm_error("** UVM TEST FAILED **", $sformatf("Read Write mismatches"))
end
endfunction
endclass: bidirect_bus_test
endpackage: bidirect_bus_pkg
// Top level test bench module
module top_tb;
import uvm_pkg::*;
import bidirect_bus_pkg::*;
// UVM start up:
initial begin
run_test("bidirect_bus_test");
end
endmodule: top_tb
module top_hdl;
bus_if BUS();
gpio_if GPIO();
bidirect_bus_driver_bfm bidirect_bus_drv(
.clk (BUS.clk),
.resetn (BUS.resetn),
.addr (BUS.addr),
.write_data (BUS.write_data),
.rnw (BUS.rnw),
.valid (BUS.valid),
.ready (BUS.ready),
.read_data (BUS.read_data),
.error (BUS.error)
);
bidirect_bus_slave DUT(.bus(BUS), .gpio(GPIO));
// Free running clock
initial begin
BUS.clk = 0;
forever begin
#10 BUS.clk = ~BUS.clk;
end
end
// Reset
initial begin
BUS.resetn = 0;
repeat (3) begin
@(posedge BUS.clk);
end
BUS.resetn = 1;
end
initial begin
uvm_pkg::uvm_config_db #(virtual bidirect_bus_driver_bfm)::set(null, "uvm_test_top", $psprintf("%m.bidirect_bus_drv") , bidirect_bus_drv);
end
endmodule: top_hdl
interface bus_if;
logic clk;
logic resetn;
logic[31:0] addr;
logic[31:0] write_data;
logic rnw;
logic valid;
logic ready;
logic[31:0] read_data;
logic error;
endinterface: bus_if
interface gpio_if;
logic[255:0] gp_op;
logic[255:0] gp_ip;
logic clk;
endinterface: gpio_if
interface bidirect_bus_driver_bfm (
input logic clk,
input logic resetn,
output logic [31:0] addr,
output logic [31:0] write_data,
output logic rnw,
output logic valid,
input logic ready,
input logic [31:0] read_data,
input logic error
);
import bidirect_bus_pkg::*;
initial begin
valid <= 0;
rnw <= 1;
end
task wait_for_reset();
@(posedge resetn);
endtask: wait_for_reset
task drive(bus_seq_item req);
repeat (req.delay) begin // Delay between bus transactions
@(posedge clk);
end
valid <= 1;
addr <= req.addr;
rnw <= req.read_not_write;
if (req.read_not_write == 0) begin
write_data <= req.write_data;
end
while (ready != 1) begin
@(posedge clk);
end
// At end of the pin level bus transaction
// Copy response data into the req fields:
if (req.read_not_write == 1) begin
req.read_data = read_data; // Copy read data response
end
req.error = error; // Copy bus error response status
valid <= 0; // End the pin level bus transaction
endtask: drive
endinterface: bidirect_bus_driver_bfm
// DUT - A semi-real GPIO interface with a scratch RAM
module bidirect_bus_slave(interface bus, interface gpio);
logic[1:0] delay;
always @(posedge bus.clk) begin
if (bus.resetn == 0) begin
delay <= 0;
bus.ready <= 0;
gpio.gp_op <= 0;
end
if (bus.valid == 1) begin // Valid cycle
if (bus.rnw == 0) begin // Write
if (delay == 2) begin
bus.ready <= 1;
delay <= 0;
if (bus.addr inside{[32'h0100_0000:32'h0100_001C]}) begin // GPO range - 8 words or 255 bits
case (bus.addr[7:0])
8'h00: gpio.gp_op[31:0] <= bus.write_data;
8'h04: gpio.gp_op[63:32] <= bus.write_data;
8'h08: gpio.gp_op[95:64] <= bus.write_data;
8'h0c: gpio.gp_op[127:96] <= bus.write_data;
8'h10: gpio.gp_op[159:128] <= bus.write_data;
8'h14: gpio.gp_op[191:160] <= bus.write_data;
8'h18: gpio.gp_op[223:192] <= bus.write_data;
8'h1c: gpio.gp_op[255:224] <= bus.write_data;
endcase
bus.error <= 0;
end
else begin
bus.error <= 1; // Outside valid write address range
end
end
else begin
delay <= delay + 1;
bus.ready <= 0;
end
end
else begin // Read cycle
if (delay == 3) begin
bus.ready <= 1;
delay <= 0;
if (bus.addr inside{[32'h0100_0000:32'h0100_001C]}) begin // GPO range - 8 words or 255 bits
case (bus.addr[7:0])
8'h00: bus.read_data <= gpio.gp_op[31:0];
8'h04: bus.read_data <= gpio.gp_op[63:32];
8'h08: bus.read_data <= gpio.gp_op[95:64];
8'h0c: bus.read_data <= gpio.gp_op[127:96];
8'h10: bus.read_data <= gpio.gp_op[159:128];
8'h14: bus.read_data <= gpio.gp_op[191:160];
8'h18: bus.read_data <= gpio.gp_op[223:192];
8'h1c: bus.read_data <= gpio.gp_op[255:224];
endcase
bus.error <= 0;
end
else if (bus.addr inside{[32'h0100_0020:32'h0100_003C]}) begin // GPI range - 8 words or 255 bits - read only
case (bus.addr[7:0])
8'h20: bus.read_data <= gpio.gp_ip[31:0];
8'h24: bus.read_data <= gpio.gp_ip[63:32];
8'h28: bus.read_data <= gpio.gp_ip[95:64];
8'h2c: bus.read_data <= gpio.gp_ip[127:96];
8'h30: bus.read_data <= gpio.gp_ip[159:128];
8'h34: bus.read_data <= gpio.gp_ip[191:160];
8'h38: bus.read_data <= gpio.gp_ip[223:192];
8'h3c: bus.read_data <= gpio.gp_ip[255:224];
endcase
bus.error <= 0;
end
else begin
bus.error <= 1;
end
end
else begin
delay <= delay + 1;
bus.ready <= 0;
end
end
end
else begin
bus.ready <= 0;
bus.error <= 0;
delay <= 0;
end
end
endmodule: bidirect_bus_slave