Hi all,
based on the discussion in https://community.cadence.com/cadence_technology_forums/f/functional-verification/38665/run_phase-doesn-t-update-sv-interface-signals I have extended the testbench with uvm_agent, but sequencing cannot be bound properly.
DUT interface, DUT and testbench are in the thread above. I am trying to test a very simple counter to learn UVM environment.
My UVM package looks like as follows.
I get the compilation error at Incisive 15.22.
ncvlog: *E,NOTCLM (tb_pkg.sv,120|52): seq_item_port is not a class item.
seq.start (m_env.m_seqr);
The problem is the "run_phase" function in uvm_test which complains that the object cannot be found. Where should I move the seq_item_port? To the agent or to the sequencer? And how?
Sorry this might be stupid question but I couldnt figure out how to do it, because on web most examples are simple so that there is no need to use uvm_agent.
Any help appreciated.
`include "uvm_macros.svh"
// www.youtube.com/watch
package my_pkg;
import uvm_pkg::*;
// Transaction (for constrain random value generation)
class my_transaction extends uvm_sequence_item;
`uvm_object_utils (my_transaction)
rand logic [7:0] load_val;
constraint c_load_val { load_val > 10 ; load_val < 20; }
function new(string name = "");
super.new(name);
endfunction
function void do_copy (uvm_object rhs);
my_transaction tx;
$cast(tx, rhs);
load_val = tx.load_val;
endfunction
endclass : my_transaction
// Sequencer (to create sequences, to be called by the driver)
typedef uvm_sequencer #(my_transaction) my_sequencer;
class my_sequence extends uvm_sequence #(my_transaction);
`uvm_object_utils(my_sequence)
function new (string name = "");
super.new(name);
endfunction
task body;
if (starting_phase != null)
starting_phase.raise_objection(this);
repeat (8)
begin
req = my_transaction::type_id::create("req");
start_item(req);
if (!req.randomize()) `uvm_error ("", "randomize failed");
finish_item (req);
end
if (starting_phase != null)
starting_phase.drop_objection(this);
endtask : body
endclass: my_sequence
// Driver
class my_driver extends uvm_driver #(my_transaction);
`uvm_component_utils (my_driver)
// this is the DUT interface, mostly instantiated in the driver
virtual dut_if dut_vi;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
if (! uvm_config_db #(virtual dut_if)::get(this, "", "dut_if", dut_vi))
`uvm_error ("", "uvm_config_db::get failed");
endfunction
task run_phase(uvm_phase phase);
forever
begin
seq_item_port.get_next_item(req);
@(posedge dut_vi.i_clk);
$display ("run_phase!!");
dut_vi.i_load_en <= '1;
// dut_vi.i_load_val <= $urandom;
dut_vi.i_load_val = req.load_val;
seq_item_port.item_done();
end
endtask
endclass: my_driver
// Agent
class my_agent extends uvm_agent;
my_sequencer m_seqr;
my_driver m_driv;
`uvm_component_utils(my_agent)
// constructor
function new (string name, uvm_component parent);
super.new (name, parent);
endfunction : new
// build phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (get_is_active() == UVM_ACTIVE) begin
m_driv = my_driver::type_id::create("m_driv", this);
m_seqr = my_sequencer::type_id::create("m_seqr", this);
end
endfunction : build_phase
function void connect_phase(uvm_phase phase);
if (get_is_active() == UVM_ACTIVE) begin
m_driv.seq_item_port.connect(m_seqr.seq_item_port);
end
endfunction : connect_phase
endclass : my_agent
// Environment
class my_env extends uvm_env;
`uvm_component_utils (my_env)
// my_sequencer m_seqr;
// my_driver m_driv;
my_agent m_agt;
// Constructor - informs parent this class
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction : new
function void build_phase(uvm_phase phase);
// m_seqr = my_sequencer::type_id::create("m_seqr", this);
// m_driv = my_driver::type_id::create("m_driv", this);
m_agt = my_agent::type_id::create("m_agt", this);
endfunction : build_phase
// if connect_phase is empty, then no need to instantiate it :-)
// function void connect_phase(uvm_phase phase);
// m_driv.seq_item_port.connect(m_seqr.seq_item_export);
// endfunction : connect_phase
endclass
// driver is instantiated in the test
class my_test extends uvm_test;
`uvm_component_utils (my_test)
// decl member
my_env m_env;
// standard code for all components
// must it be a virtual function?
function new (string name, uvm_component parent);
super.new (name, parent);
endfunction
// Factory method call "create" in UVM is used
// we extend the functionality of m_env
function void build_phase(uvm_phase phase);
m_env = my_env::type_id::create("m_env", this);
endfunction
// only task phase (contains sim time)
task run_phase(uvm_phase phase);
/* // from now on the test is busy
phase.raise_objection(this);
// we consume some time
#200;
// one of 4 macros, others: `uvm_warning, `uvm_error, `uvm_fatal
// UVM_MEDIUM - verbosity level: UVM_INFO,
`uvm_info("", "Hello world", UVM_MEDIUM);
// I'm finished, test is over
phase.drop_objection(this); */
my_sequence seq;
seq = my_sequence::type_id::create("seq");
if(!seq.randomize() ) `uvm_error ("", "run_phase::seq.randomize failed");
seq.starting_phase = phase;
seq.start (m_env.m_seqr);
endtask
endclass: my_test
endpackage : my_pkg