Мне нужно подключить выход модуля к его входу, управляемому uvm_driver
.
Я вижу это так.
----- ---------------------
| MON |---->|uvm_tlm_analysis_fifo|
----- ---------------------
^ |
| |
------------- | ------- |
| |---------->| slave | v
| DUT | ------- --------
| |<---------------------| master |
------------- --------
Я попробовал следующее.
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
Вот минимальный, воспроизводимый пример.
`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
Это генерирует следующие ошибки.
** 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))'.
Как понимаю, не могу подключить fifo к мастеру seq_item_port
. Есть ли способ реализовать такую схему? Если драйвер действительно может получить элементы только из секвенсора, как вручную записать элементы из секвенсора в seq_item_port
?
Какая ошибка у вас была? вы не предоставили определения классов driver
и seq_item
.
@Serge, добавлен минимальный воспроизводимый пример и его ошибка. Содержимое классов seq_item и драйвера я ранее не уточнял, так как оно совершенно неактуально в данном вопросе и будет только отвлекать. seq_item может быть как сложным классом с кучей полей, так и пустой заготовкой, унаследованной от uvm_sequence_item. Драйвером может быть либо axi4_s_master_driver, либо просто драйвер, который вытаскивает seq_items и тут же вызывает item_done. Решение лежит где-то на уровне агента или среды.
Вам нужен uvm_sequencer
с seq_item_export
, чтобы подключиться к водителю seq_item_port
. У вас его нет.
Если вы хотите использовать путь fifo, вам нужно создать и подключить общий порт в классе драйвера.
Это сообщение, сгенерированное 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)
Насколько я вижу из этого, вам все равно нужно создать порт, а также собственную реализацию seq_item_export
с задачей передачи элементов последовательности между ними. Я думаю, что вы можете создать поддельный секвенсор, чтобы справиться с этим (и оставить драйвер в покое).
Да, я знаю про вариант подключения секвенсора к драйверу, но не знаю, как писать в порт секвенсора вручную (как отмечено в вопросе), т.к. при традиционном использовании секвенсоры стартуют на нем, а я не могу передавать данные из fifo в последовательность. Модифицировать драйвер тоже мне кажется плохой идеей, так как используется уже написанный мастер axi4_stream, а прелесть uvm в повторном использовании.
Как я и подозревал, я не могу реализовать схему вопросов без секвенсора. Таким образом, схема результата будет следующей:
----- ---------
| MON |---->|sequencer|
----- | ------|
^ | | fifo |
| ---------
------------- | ------- |
| |-------->| slave | v
| DUT | ------- --------
| |<-----------------| master |
------------- --------
Вопрос заключался в том, как заставить секвенсор записывать в seq_item_export без запуска последовательности. Для этого, как указано в ответе выше, мне нужно было реализовать задачу get_next_item
в пользовательском класс секвенсора следующим образом:
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
Обратите внимание, что в дополнение к get_next_item task
, item_done function
также должен быть реализован (иначе вы можете получить Item_done() called with no outstanding requests
fatal_error).
Таким образом, минимальный воспроизводимый пример перейдет в:
`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
что значит "не удается подключиться"? что ты пробовал?