经常会看到在sequence和virtual sequence中,使用了宏`uvm_declare_p_sequencer。那么,为什么我们要使用p_sequencer呢?
class base_vseq extends uvm_sequence;
function new(string name="base_vseq");
super.new(name);
endfunction
`uvm_object_utils(base_vseq)
`uvm_declare_p_sequencer(uart_ctrl_virtual_sequencer)
endclass
从继承的关系上,uvm_sequence_item->uvm_sequence_base->uvm_sequence,uvm_sequence_item中有一个成员变量m_sequencer(喂喂喂,怎么说m_sequencer了?嗯嗯,别急,往后看),当我们在test的run_phase中start一个sequence的时候,其实就是给m_sequencer赋值了,把我们环境的sequencer赋给m_sequencer。m_sequencer是不带parameter的。
class uvm_sequence_item extends uvm_transaction;
local int m_sequence_id = -1;
protected bit m_use_sequence_info;
protected int m_depth = -1;
protected uvm_sequencer_base m_sequencer;
把宏`uvm_declare_p_sequencer展开看,就是把m_sequencer赋值给了p_sequencer,当然了,m_sequncer所指向的对象,一定要是p_sequencer或者p_sequencer的子类,否者cast函数会报错的。
`define uvm_declare_p_sequencer(SEQUENCER) \
SEQUENCER p_sequencer;\
virtual function void m_set_p_sequencer();\
super.m_set_p_sequencer(); \
if( !$cast(p_sequencer, m_sequencer)) \
`uvm_fatal("DCLPSQ", \
$sformatf("%m %s Error casting p_sequencer, please verify that this sequence/sequence item is intended to execute on this type of sequencer", get_full_name())) \
endfunction
那么,费了这么多事,要做什么呢?其实就是传递配置。因为sequence和component不一样,component是在build_phase环节就有了,而sequence是在run_phase阶段才会第一次出现,sequence想要去从环境上拿到配置信息,一定要通过它的m_sequencer,但是m_sequencer是不带parameter的,和我们start的时候一定不match,所以UVM就事先在定义sequence的时候,把p_sequencer这个带parameter的sequencer准备好,方便后面的使用。
virtual task body();
response_queue_error_report_disabled = 1;
start_addr = `TX_FIFO_REG;
while (num_of_wr) begin
`uvm_info(get_type_name(), $sformatf("Starting %0d Writes...", num_of_wr), UVM_LOW)
for (int i = 0; i < num_of_wr; i++) begin
if (p_sequencer.tful) begin
num_of_wr -= i;
`uvm_info("UART_APB_SEQLIB", $sformatf("Breaking from apb_to_uart_wr since tfifo is not empty yet, pending num_of_wr = %d", num_of_wr), UVM_LOW)
#10000;
break;
end
`uvm_do_with(req,
{ req.addr == start_addr;
req.direction == APB_WRITE;
req.delay == del; } )
#200;
if (i == num_of_wr - 1)
num_of_wr = 0;
end
end
endtask
上面这段代码就是sequence的片段,可以看到直接访问了p_sequencer的变量tful,如果写成m_sequencer.tful,是一定不成的。