I am trying to learn UVM by writing a wishbone master.
My test finishes without executing “seq_item_port.get_next_item (req);” and consequently “get_and_drive()” in the driver class.
The test case does not hang; it just doesn’t do anything that is coded in the driver class.
How do I fix this?
Thanks!
class wb_driver extends uvm_driver #(wb_transaction);
protected virtual wb_if vif;
`uvm_component_utils (wb_driver)
function new (string name, uvm_component parent);
super.new (name, parent);
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual wb_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF",{"virtual interface must be set for: ", get_full_name(),".vif"});
endfunction: build_phase
virtual task run_phase (uvm_phase phase);
get_and_drive ();
endtask : run_phase
// get_and_drive
virtual protected task get_and_drive ();
@ (posedge vif.arst);
@ (posedge vif.ref_clk);
forever begin
seq_item_port.get_next_item (req);
drive_transfer (req);
seq_item_port.item_done ();
end
endtask : get_and_drive
// drive_transfer
virtual protected task drive_transfer (wb_transaction trans);
// write
if (trans.we == 1) begin
@ (posedge vif.ref_clk);
vif.we <= 1'b1;
vif.adr <= trans.adr;
vif.cyc <= 1'b1;
vif.stb <= 1'b1;
vif.dout <= trans.dout;
@ (posedge vif.ref_clk);
while (vif.ack == 0) @ (posedge vif.ref_clk)
vif.we <= 1'bx;
vif.adr <= 'hx;
vif.cyc <= 1'b0;
vif.stb <= 1'bx;
vif.dout <= 'hx;
end
// read
else if (trans.we == 0) begin
@ (posedge vif.ref_clk);
vif.we <= 1'b0;
vif.adr <= trans.adr;
vif.cyc <= 1'b1;
vif.stb <= 1'b1;
@ (posedge vif.ref_clk);
while (vif.ack == 0) @ (posedge vif.ref_clk)
vif.we <= 1'bx;
vif.adr <= 'hx;
vif.cyc <= 1'b0;
vif.stb <= 1'bx;
vif.dout <= 'hx;
trans.din <= vif.din;
end
endtask : drive_transfer
endclass: wb_driver
class wb_sequencer extends uvm_sequencer# (wb_transaction);
`uvm_component_utils (wb_sequencer)
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction : new
endclass: wb_sequencer
class wb_transaction extends uvm_sequence_item;
`uvm_object_utils (wb_transaction)
typedef enum {READ=1, WRITE=0} read_write_enum;
rand read_write_enum read_write;
rand bit [7:0] adr;
rand bit [7:0] dout;
rand bit [7:0] sel;
rand bit cyc;
rand bit stb;
rand bit we;
bit [7:0] din;
bit ack;
bit err;
bit rty;
constraint we_c
{
(read_write == WRITE) -> (we == 1);
(read_write == READ) -> (we == 0);
}
// constructor
function new (string name = "wb_transaction");
super.new (name);
sel = 0;
endfunction: new
function void do_copy (uvm_object rhs);
wb_transaction rhs_;
if (!$cast(rhs_, rhs)) begin
uvm_report_error("do_copy:", "Cast failed");
return;
end
super.do_copy (rhs);
read_write = rhs_.read_write ;
adr = rhs_.adr;
dout = rhs_.dout;
sel = rhs_.sel;
cyc = rhs_.cyc;
stb = rhs_.stb;
we = rhs_.we;
din = rhs_.din;
ack = rhs_.ack;
err = rhs_.err;
rty = rhs_.rty;
endfunction: do_copy
function bit do_compare (uvm_object rhs, uvm_comparer comparer);
wb_transaction rhs_;
if(!$cast(rhs_, rhs)) begin
return 0;
end
if (!super.do_compare (rhs, comparer)) begin
return 0;
end
endfunction: do_compare
function string convert2string ();
string s;
s = super.convert2string();
$sformat(s, "%s\n read_write \t%0d\n adr \t%0h\n dout \t%0h\n din \t%0h\n we \t%0h\n cyc \t%0h\n stb \t%0h\n", s, read_write, adr, dout, din, we, cyc, stb);
return s;
endfunction: convert2string
function void do_print (uvm_printer printer);
if (printer.knobs.sprint == 0) begin
$display (convert2string());
end
else begin
printer.m_string = convert2string();
end
endfunction: do_print
endclass: wb_transaction
`ifndef WB_TB_SV
`define WB_TB_SV
`include "wb_seq_lib.sv"
class wb_tb extends uvm_env;
`uvm_component_utils (wb_tb)
wb_env wb_env0;
function new (string name, uvm_component parent=null);
super.new (name, parent);
endfunction : new
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
wb_env0 = wb_env::type_id::create ("wb_env0", this);
endfunction : build_phase
endclass : wb_tb
`endif
`include "wb_tb.sv"
class wb_base_test extends uvm_test;
`uvm_component_utils (wb_base_test)
wb_tb wb_tb0;
uvm_table_printer printer;
function new (string name = "wb_base_test", uvm_component parent=null);
super.new (name,parent);
endfunction : new
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
uvm_config_db#(int)::set(this, "*", "recording_detail", UVM_FULL);
wb_tb0 = wb_tb::type_id::create("wb_tb0", this);
printer = new ();
printer.knobs.depth = 3;
endfunction : build_phase
function void end_of_elaboration_phase (uvm_phase phase);
`uvm_info(get_type_name(),
$psprintf ("Printing the test topology :\n%s", this.sprint(printer)), UVM_LOW)
endfunction : end_of_elaboration_phase
task run_phase (uvm_phase phase);
super.run_phase(phase);
endtask : run_phase
endclass : wb_base_test
class test_write extends wb_base_test;
`uvm_component_utils (test_write)
function new (string name = "test_write", uvm_component parent=null);
super.new (name,parent);
endfunction : new
virtual function void build_phase (uvm_phase phase);
uvm_config_db# (uvm_object_wrapper)::set(this, "wb_tb0.wb_env0.sequencer.run_phase", "default_sequence", write_seq::type_id::get());
super.build_phase (phase);
endfunction : build_phase
local bit once = 1;
task main_phase(uvm_phase phase);
if (once) begin
once = 0;
phase.raise_objection (this);
#1us;
phase.drop_objection (this);
end
endtask
endclass : test_write
virtual class wb_base_sequence extends uvm_sequence #(wb_transaction);
function new (string name="wb_base_seq");
super.new (name);
endfunction
virtual task pre_body ();
if (starting_phase!=null) begin
`uvm_info(get_type_name(),
$sformatf("%s pre_body() raising %s objection",
get_sequence_path(),
starting_phase.get_name()), UVM_MEDIUM);
starting_phase.raise_objection(this);
end
endtask
virtual task post_body ();
if (starting_phase!=null) begin
`uvm_info(get_type_name(),
$sformatf("%s post_body() dropping %s objection",
get_sequence_path(),
starting_phase.get_name()), UVM_MEDIUM);
starting_phase.drop_objection(this);
end
endtask
endclass: wb_base_sequence
class write_seq extends wb_base_sequence;
function new (string name="write_seq");
super.new (name);
endfunction
`uvm_object_utils (write_seq)
virtual task body ();
repeat (1) begin
//`uvm_create (req)
//`uvm_rand_send_with (req, {req.we == 1;})
`uvm_do_with(req, {req.we == 1;})
end
endtask
endclass: write_seq
package wb_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
typedef uvm_config_db#(virtual wb_if) wb_vif_config;
typedef virtual wb_if wb_vif;
`include "wb_transaction.sv"
`include "wb_sequencer.sv"
`include "wb_driver.sv"
`include "wb_agent.sv"
`include "wb_env.sv"
endpackage: wb_pkg
interface wb_if;
logic ref_clk;
logic rst;
logic[2:0] adr;
logic[7:0] din;
logic[7:0] dout;
logic cyc;
logic stb;
logic we;
logic[7:0] sel;
logic ack;
logic inta;
logic arst;
endinterface: wb_if
class wb_env extends uvm_env;
`uvm_component_utils (wb_env)
wb_agent wb_agent0;
function new (string name, uvm_component parent);
super.new (name, parent);
endfunction : new
function void build_phase (uvm_phase phase);
string inst_name;
super.build_phase (phase);
wb_agent0 = wb_agent::type_id::create (inst_name, this);
endfunction : build_phase
endclass: wb_env
class wb_agent extends uvm_agent;
protected uvm_active_passive_enum is_active = UVM_ACTIVE;
`uvm_component_utils (wb_agent)
wb_driver driver;
wb_sequencer sequencer;
function new (string name, uvm_component parent);
super.new (name, parent);
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase (phase);
if (get_is_active() == UVM_ACTIVE) begin
sequencer = wb_sequencer::type_id::create("sequencer", this);
driver = wb_driver::type_id::create("driver", this);
end
endfunction: build_phase
function void connect_phase (uvm_phase phase);
if (is_active == UVM_ACTIVE) begin
driver.seq_item_port.connect (sequencer.seq_item_export);
end
endfunction : connect_phase
endclass : wb_agent
`include "wb_pkg.sv"
`include "i2c_master_top.v"
`include "i2c_if.sv"
`include "wb_if.sv"
module i2c_tb_top;
import uvm_pkg::*;
import wb_pkg::*;
`include "wb_test_lib.sv"
wb_if vif();
i2c_if i2c_if0(vif.ref_clk);
i2c_master_top i2c_top (
// wishbone interface
.wb_clk_i (vif.ref_clk),
.wb_rst_i (1'b0),
.arst_i (vif.arst),
.wb_adr_i (vif.adr[2:0]),
.wb_dat_i (vif.dout [7:0]),
.wb_dat_o (vif.din [7:0]),
.wb_we_i (vif.we),
.wb_stb_i (vif.stb),
.wb_cyc_i (vif.cyc),
.wb_ack_o (vif.ack),
.wb_inta_o (vif.inta),
// i2c signals
.scl_pad_i (i2c_if0.scl),
.scl_pad_o (i2c_if0.scl0_o),
.scl_padoen_o (i2c_if0.scl0_oen),
.sda_pad_i (i2c_if0.sda),
.sda_pad_o (i2c_if0.sda0_o),
.sda_padoen_o (i2c_if0.sda0_oen)
);
initial begin
uvm_config_db#(virtual wb_if)::set(uvm_root::get(), "*", "vif", vif);
run_test ();
end
initial begin
vif.ref_clk <= 1'b1;
vif.arst <= 1'b1;
vif.we <= 1'b0;
vif.cyc <= 1'b0;
vif.stb <= 1'b0;
vif.dout <= 8'h0;
vif.adr <= 3'h0;
#20;
vif.arst = 1'b0;
@(posedge vif.ref_clk);
vif.arst = 1'b1;
end
always
#50 vif.ref_clk <= ~vif.ref_clk;
initial begin
$vcdpluson (0, i2c_tb_top);
end
endmodule