I need to connect a module output to it's input controlled by uvm_driver
.
I see it this way.
----- ---------------------
| MON |---->|uvm_tlm_analysis_fifo|
----- ---------------------
^ |
| |
------------- | ------- |
| |---------->| slave | v
| DUT | ------- --------
| |<---------------------| master |
------------- --------
I tried the following.
typedef class seq_item extends uvm_sequence_item;
typedef class driver extends uvm_driver(seq_item);
class agent extends uvm_agent;
`uvm_component_utils(agent)
uvm_analysis_port#(seq_item) ap;
uvm_tlm_analysis_fifo#(seq_item) fifo;
driver drv;
function new(string name, uvm_component parent);
super.new(name,parent);
endfunction: new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
ap = new("ap", this);
fifo= new("fifo",this);
drv = driver::type_id::create("driver", this);
endfunction: build_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
ap.connect(fifo.analysis_export);
drv.seq_item_port.connect(fifo.get_peek_export);
endfunction: connect_phase
task main_phase(uvm_phase phase);
seq_item trans;
phase.raise_objection(this);
repeat(5) begin
trans = seq_item::type_id::create("inTrans");
assert(trans.randomize());
ap.write(trans);
end
phase.drop_objection(this);
endtask
endclass: agent
Here Minimal, Reproducible Example.
`include "uvm_macros.svh"
package t;
import uvm_pkg::*;
class seq_item extends uvm_sequence_item;
`uvm_object_utils(seq_item)
rand bit [31:0] data;
function new(string name = "seq_item");
super.new(name);
endfunction: new
endclass: seq_item
class driver extends uvm_driver#(seq_item);
`uvm_component_utils(driver)
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction: new
task main_phase(uvm_phase phase);
fork
super.main_phase(phase);
join_none
forever begin
seq_item_port.get_next_item(req);
`uvm_info(get_type_name(),$psprintf("Got item with data: %h",req.data),UVM_NONE);
seq_item_port.item_done();
end
endtask: main_phase
endclass: driver
class test extends uvm_test;
`uvm_component_utils(test)
uvm_analysis_port#(seq_item) ap;
uvm_tlm_analysis_fifo#(seq_item) fifo;
driver drv;
function new(string name, uvm_component parent);
super.new(name,parent);
endfunction: new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
ap = new(.name("apb_ap"), .parent(this));
fifo= new("fifo",this);
drv = driver ::type_id::create(.name("driver"), .parent(this) );
endfunction: build_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
ap.connect(fifo.analysis_export);
drv.seq_item_port.connect(fifo.get_peek_export);
endfunction: connect_phase
task main_phase(uvm_phase phase);
seq_item trans;
phase.raise_objection(this);
repeat(5) begin
trans = seq_item::type_id::create("inTrans");
assert(trans.randomize());
ap.write(trans);
end
phase.drop_objection(this);
endtask
endclass: test
endpackage
module top();
import uvm_pkg::*;
import t::*;
initial begin
run_test();
end
endmodule
It's generates following errors.
** Error: (vsim-7065) 5.sv(51): Illegal assignment to class mtiUvm.uvm_pkg::uvm_port_base #(class mtiUvm.uvm_pkg::uvm_sqr_if_base #(class work.t::seq_item, class work.t::seq_item)) from class mtiUvm.uvm_pkg::uvm_get_peek_imp #(class work.t::seq_item, class mtiUvm.uvm_pkg::uvm_tlm_fifo_base #(class work.t::seq_item))
# Time: 0 ns Iteration: 0 Region: /t File: 5.sv
# ** Error: (vsim-8754) 5.sv(51): Actual input arg. of type 'class mtiUvm.uvm_pkg::uvm_get_peek_imp #(class work.t::seq_item, class mtiUvm.uvm_pkg::uvm_tlm_fifo_base #(class work.t::seq_item))' for formal 'provider' of 'connect' is not compatible with the formal's type 'class mtiUvm.uvm_pkg::uvm_port_base #(class mtiUvm.uvm_pkg::uvm_sqr_if_base #(class work.t::seq_item, class work.t::seq_item))'.
As I get, I can't connect fifo to master's seq_item_port
. Is there a way to implement such scheme? If driver can really get items just from sequencer, how to manually write items from sequencer to seq_item_port
?
As I suspected, I can't implement questions scheme without sequencer. So result scheme will be follow:
----- ---------
| MON |---->|sequencer|
----- | ------|
^ | | fifo |
| ---------
------------- | ------- |
| |-------->| slave | v
| DUT | ------- --------
| |<-----------------| master |
------------- --------
Question was how make sequencer write to seq_item_export without running a sequence. To achieve this, as pointed in answer above I was needed to implement get_next_item
task in a custom sequencer class like this:
class fifo_sequencer#(type REQ=uvm_sequence_item,RSP=REQ) extends uvm_sequencer#(REQ,RSP);
`uvm_component_param_utils(fake_sequencer#(REQ,RSP))
uvm_tlm_analysis_fifo#(REQ) fifo;
function new(string name, uvm_component parent);
super.new(name, parent);
fifo = new("fifo", this);
endfunction
task get_next_item(output REQ t);
fifo.get_peek_export.get(t);
endtask
function void item_done(RSP item = null);
if (item != null) begin
seq_item_export.put_response(item);
end
endfunction
endclass
Note that in addition to get_next_item task
, item_done function
must also be implemented (or you may get an Item_done() called with no outstanding requests
fatal_error).
Thus Minimal, Reproducible Example will transfer into:
`include "uvm_macros.svh"
package t;
import uvm_pkg::*;
class seq_item extends uvm_sequence_item;
`uvm_object_utils(seq_item)
rand bit [31:0] data;
function new(string name = "seq_item");
super.new(name);
endfunction: new
endclass: seq_item
class driver extends uvm_driver#(seq_item);
`uvm_component_utils(driver)
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction: new
task main_phase(uvm_phase phase);
fork
super.main_phase(phase);
join_none
forever begin
seq_item_port.get_next_item(req);
`uvm_info(get_type_name(),$psprintf("Got item with data: %h",req.data),UVM_NONE);
seq_item_port.item_done();
end
endtask: main_phase
endclass: driver
class fifo_sequencer#(type REQ=uvm_sequence_item,RSP=REQ) extends uvm_sequencer#(REQ,RSP);
`uvm_component_param_utils(fifo_sequencer#(REQ,RSP))
uvm_tlm_analysis_fifo#(REQ) fifo;
function new(string name, uvm_component parent);
super.new(name, parent);
fifo = new("fifo", this);
endfunction
task get_next_item(output REQ t);
fifo.get_peek_export.get(t);
endtask
function void item_done(RSP item = null);
if (item != null) begin
seq_item_export.put_response(item);
end
endfunction
endclass
class test extends uvm_test;
`uvm_component_utils(test)
uvm_analysis_port#(seq_item) ap;
driver drv;
fifo_sequencer#(seq_item) sqr;
function new(string name, uvm_component parent);
super.new(name,parent);
endfunction: new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
ap = new("apb_ap", this);
sqr = fifo_sequencer#(seq_item) ::type_id::create("sequencer", this);
drv = driver ::type_id::create("driver", this);
endfunction: build_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
ap.connect(sqr.fifo.analysis_export);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction: connect_phase
task main_phase(uvm_phase phase);
seq_item trans;
phase.raise_objection(this);
repeat(5) begin
trans = seq_item::type_id::create("inTrans");
assert(trans.randomize());
ap.write(trans);
end
phase.drop_objection(this);
endtask
endclass: test
endpackage
module top();
import uvm_pkg::*;
import t::*;
initial begin
run_test();
end
endmodule