接前面的问题,仿真停在0时刻,可以从后往前来推这个问题。
driver是直接与物理接口相连的组件,主要的行为主要体现在main_phase()中
class my_driver extends uvm_driver;
........
task my_driver::main_phase(phase):
super.main_phase(phase)
forever begin
seq_item_port.get_next_item(req);
.....
seq_item_port.item_done();
end
endtask
....
endclass
seq_item_port 并不会再my_driver的成员变量中出现,它在uvm_driver类中。它是用于连接driver和sequencer的一个端口。driver要想驱动总线发送数据首先要从这个端口获得transaction,如代码中的get_next_item。因此一旦物理总线上没有出现数据首先检查,driver是否收到了来自sequencer的激励。
sequencer的结构非常简单,当driver要驱动数据,向sequencer申请一个item,sequencer会把相应的sequence发送给driver。
一个简单的sequence主要的行为在body()中。
class my_sequence extends uvm_sequence #(my_transaction)
.......
virtual task body();
if(starting_phase != null)
starting_phapse.raise_objection(this);
repeat(10) begin
`uvm_do(m_trans)
end
#100;
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask
endclass
当sequence启动起来后,会自动执行body方法,`uvm_do宏每执行一次就会向uvm_sequencer发送一个transaction,它产生一个trans是不消耗仿真时间的,将trans传给sequencer也不消耗时间,但是driver需要消耗时间完成一个trans的驱动,只有当driver调用item_done之后,一次uvm_do宏才算执行完毕,进入下一个uvm_do的执行。当所有的uvm_do执行完毕之后,driver会停在get_next_item。
drop_objection之后,就会进入$finish(),结束整个仿真。
////////////////////////////////////////////////////////////////////////////////////////////////
需要注意的是:如果想要执行一些耗费时间的代码,至少要在此phase下raise一次objection,这个结论只适用于run_time的phase。如果没有任何objection被raise,消耗时间的代码将不会被执行,直接跳到下一个phase,例如曾经碰到过这样一个问题。在driver中main_phase之前reset_phase中将dut的信号进行reset,需要在reset_phase中单独raise_objection,否则reset_phase不会被执行,因为sequence中的raise_objection只是针对了driver中的main_phase。
////////////////////////////////////////////////////////////////////////////////////////////////
my_sequence中的raise_objection和drop_objection是属于phase的一个函数,但是uvm_sequence是一个uvm_object,而phase是属于component的一个概念。因此用starting_phase != null来判断。starting_phase实际上是uvm_sequence指向phase的一个指针,当sequencer在main_phase中启动default_sequence时,sequencer就将phase赋值给sequence中的这个指针,从而满足了starting_phase!= null的这个条件。
那么sequence是如何启动的,一般由手动启动和自动启动两种方法。一般都是使用自动启动的方法。
class my_test extends uvm_test;
.......
function void my_test::build_phase(uvm_phase phase);
super.build_phase(phase);
uvm_config_db#(uvm_object_wrapper)::set(this,'env.i_agt.sqr.main_phase','default_sequence',my_sequence::type_id::get());
endfunction
endclass
config_db的set语句就是通知sequencer,让其在运行到main_phase的时候自动启动前面定义的my_sequence,就是这里让sequence自动启动了。如果在这里把default_sequence定义为sequence_1,那么就会自动启动sequence_1。因此一旦发现sequence没有进入body的部分,说明sequence没有启动起来,一定是config_db的问题。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请
点击举报。