可结合 uvm_do分析 来看此文章~~
好了,开始正题~~~
driver:
seq_item_port.get_next_item(req);
$cast(rsp,req.clone());
drive_one_pkt(req);
rsp.set_id_info(req);//回response 一定要加上这句!!!
seq_item_port.put(rsp);
seq_item_port.item_done();
-------------------------------------------------------------------------------------------------
Q: uvm_driver中get()与get_next_item()的区别
A: get()中调用了item_done(), 而get_next_item没有;
------------------------------------------------------------------------------------------------
class uvm_driver #(type REQ=uvm_sequence_item,
type RSP=REQ) extends uvm_component;
uvm_seq_item_pull_port #(REQ, RSP) seq_item_port;
uvm_seq_item_pull_port #(REQ, RSP) seq_item_prod_if; // alias
uvm_analysis_port #(RSP) rsp_port;
REQ req;
RSP rsp;
function new (string name, uvm_component parent);
super.new(name, parent);
seq_item_port = new("sqr_pull_port", this);
rsp_port = new("rsp_port", this);
seq_item_prod_if = seq_item_port;
endfunction // new
------------------------------------------------------------------------------------------------
在agent中将调用driver.seq_item_port.connect(sequencer.seq_item_export)将两个port连接
这样,driver中seq_item_port.put(rsp)实际是调用seq_item_export的put函数。
------------------------------------------------------------------------------------------------
sequencer:
//通过在seq_item_export new时获取sequencer的handle
class uvm_sequencer #(type REQ=uvm_sequence_item, RSP=REQ)
extends uvm_sequencer_param_base #(REQ, RSP);
typedef uvm_sequencer #( REQ , RSP) this_type;
bit sequence_item_requested;
bit get_next_item_called;
`uvm_component_param_utils(this_type)
uvm_seq_item_pull_imp #(REQ, RSP, this_type) seq_item_export;
function new (string name, uvm_component parent=null);
super.new(name, parent);
seq_item_export = new ("seq_item_export", this);
endfunction
endclass
------------------------------------------------------------------------------------------------
class uvm_seq_item_pull_imp #(type REQ=int, type RSP=REQ, type IMP=int)
extends uvm_port_base #(uvm_sqr_if_base #(REQ, RSP));
// Function: new
`UVM_IMP_COMMON(`UVM_SEQ_ITEM_PULL_MASK, "uvm_seq_item_pull_imp",IMP)
`UVM_SEQ_ITEM_PULL_IMP(m_imp, REQ, RSP, t, t)
endclass
------------------------------------------------------------------------------------------------
`define UVM_IMP_COMMON(MASK,TYPE_NAME,IMP) \
local IMP m_imp; \
function new (string name, IMP imp); \
super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); \
m_imp = imp; \
m_if_mask = MASK; \
endfunction \
`UVM_TLM_GET_TYPE_NAME(TYPE_NAME)
------------------------------------------------------------------------------------------------
`define UVM_SEQ_ITEM_PULL_IMP(imp, REQ, RSP, req_arg, rsp_arg) \
task get_next_item(output REQ req_arg); imp.get_next_item(req_arg); endtask \
task try_next_item(output REQ req_arg); imp.try_next_item(req_arg); endtask \
function void item_done(input RSP rsp_arg = null); imp.item_done(rsp_arg); endfunction \
task wait_for_sequences(); imp.wait_for_sequences(); endtask \
function bit has_do_available(); return imp.has_do_available(); endfunction \
function void put_response(input RSP rsp_arg); imp.put_response(rsp_arg); endfunction \
task get(output REQ req_arg); imp.get(req_arg); endtask \
task peek(output REQ req_arg); imp.peek(req_arg); endtask \
task put(input RSP rsp_arg); imp.put(rsp_arg); endtask
------------------------------------------------------------------------------------------------
task uvm_sequencer :: put (RSP t);
put_response(t);
endtask
------------------------------------------------------------------------------------------------
function void uvm_sequencer_param_base :: put_response (RSP t);
uvm_sequence_base sequence_ptr;
if (t == null) begin
uvm_report_fatal("SQRPUT", "Driver put a null response", UVM_NONE);
end
m_last_rsp_push_front(t);
m_num_rsps_received++;
// Check that set_id_info was called
if (t.get_sequence_id() == -1) begin
`ifndef CDNS_NO_SQR_CHK_SEQ_ID
uvm_report_fatal("SQRPUT", "Driver put a response with null sequence_id", UVM_NONE);
`endif
return;
end
sequence_ptr = m_find_sequence(t.get_sequence_id());
if (sequence_ptr != null) begin
// If the response_handler is enabled for this sequence, then call the response handler
if (sequence_ptr.get_use_response_handler() == 1) begin
sequence_ptr.response_handler(t);
return;
end
sequence_ptr.put_response(t);
end
else begin
uvm_report_info("Sequencer",
$sformatf("Dropping response for sequence %0d, sequence not found. Probable cause: sequence exited or has been killed",
t.get_sequence_id()));
end
endfunction
------------------------------------------------------------------------------------------------
//在driver 中调用 set_id_info 设置当前transaction的transaction id 和 sequence id;
function void set_id_info(uvm_sequence_item item);
if (item == null) begin
uvm_report_fatal(get_full_name(), "set_id_info called with null parameter", UVM_NONE);
end
this.set_transaction_id(item.get_transaction_id());
this.set_sequence_id(item.get_sequence_id());
endfunction
------------------------------------------------------------------------------------------------
//sequence 向sequencer发出请求时(wait_for_granted task),通过调用set_sequence_id找到當前sequence 的sequence id。
在finish_item中通過調用send_request為當前transaction設定transaction_id.
function void uvm_sequencer_param_base :: send_request(uvm_sequence_base sequence_ptr,
uvm_sequence_item t,
bit rerandomize = 0);
REQ param_t;
if (sequence_ptr == null) begin
uvm_report_fatal("SNDREQ", "Send request sequence_ptr is null", UVM_NONE);
end
if (sequence_ptr.m_wait_for_grant_semaphore < 1) begin
uvm_report_fatal("SNDREQ", "Send request called without wait_for_grant", UVM_NONE);
end
sequence_ptr.m_wait_for_grant_semaphore--;
if ($cast(param_t, t)) begin
if (rerandomize == 1) begin
if (!param_t.randomize()) begin
uvm_report_warning("SQRSNDREQ", "Failed to rerandomize sequence item in send_request");
end
end
if (param_t.get_transaction_id() == -1) begin
param_t.set_transaction_id(sequence_ptr.m_next_transaction_id++);
end
m_last_req_push_front(param_t);
end else begin
uvm_report_fatal(get_name(),$sformatf("send_request failed to cast sequence item"), UVM_NONE);
end
param_t.set_sequence_id(sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1));
t.set_sequencer(this);
if (m_req_fifo.try_put(param_t) != 1) begin
uvm_report_fatal(get_full_name(),
$sformatf("Sequencer send_request not able to put to fifo, depth; %0d", m_req_fifo.size()), UVM_NONE);
end
m_num_reqs_sent++;
// Grant any locks as soon as possible
grant_queued_locks();
endfunction
------------------------------------------------------------------------------------------------
function void set_sequence_id(int id);// from uvm_sequence_item
m_sequence_id = id;
endfunction
------------------------------------------------------------------------------------------------
function int get_sequence_id();
return (m_sequence_id);
endfunction