Reputation: 289
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
?
Upvotes: 2
Views: 1243
Reputation: 289
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
Upvotes: 3
Reputation: 12354
You need a uvm_sequencer
with seq_item_export
to connect to the driver's seq_item_port
. You do not have one.
If you want to use the fifo path, you need to create and connect a generic port in the driver class.
This is a message generated by vcs:
Error-[ICTTFC] Incompatible complex type usage
Incompatible complex type usage in task or function call.
The following expression is incompatible with the formal parameter of the
function. The type of the actual is 'class uvm_pkg::uvm_get_peek_imp#(class
t::seq_item,class uvm_pkg::uvm_tlm_fifo_base#(class t::seq_item))', while
the type of the formal is 'class uvm_pkg::uvm_port_base#(class
uvm_pkg::uvm_sqr_if_base#(class t::seq_item,class t::seq_item))'.
Expression: this.fifo.get_peek_export
Source info: this.drv.seq_item_port.connect(this.fifo.get_peek_export)
As far as I can see from it, you still need to create a port as well as an implementation of your own seq_item_export
with a task of passing of sequence items between them. I think that you can create a fake sequencer to handle it (and leave the driver alone).
Upvotes: 1