日常记录(43)phase、seq部分
phase的
跳转
在drv中,phase.jump控制了跳转。当线程中发现了复位信号,则跳转到reset相位(task_phase族中的)。
可跳转的phase包括12个动态运行的phase(task_phase)以及随后的phase(不包括和task_phase并行运行的run_phase)
task my_driver::main_phase(uvm_phase phase); `uvm_info("driver", "main phase", UVM_LOW) fork while(1) begin seq_item_port.get_next_item(req); drive_one_pkt(req); seq_item_port.item_done(); end begin @(negedge vif.rst_n); phase.jump(uvm_reset_phase::get()); end join endtask
调试
+UVM_PHASE_TRACE
超时退出
uvm_set_timeout(500ns, 0)
超时时间和是否能被覆盖。
run_phase与task_phase
task_phase进行raise后,可使得run_phase进行运行(由其它task_phase控制)。
而run_phase本身raise并不能使得task_phase运行。
phase的drain_time
在drop_objection之前延时一定的时间。
phase.phase_done.set_drain_time(this, 200);
调试与显示更多
+UVM_OBJECTION_TRACE
以下是seq的raise与drop完整。第二个参数为打印信息中括号里显示的字符串,第三个为raise和drop的数量。
class case0_sequence extends uvm_sequence #(my_transaction); my_transaction m_trans; function new(string name= "case0_sequence"); super.new(name); endfunction virtual task body(); if(starting_phase != null) starting_phase.raise_objection(this, "case0 objection", 2); #10000; if(starting_phase != null) starting_phase.drop_objection(this, "case0 objection", 2); endtask `uvm_object_utils(case0_sequence) endclass
domain概念
在不同的comp中,domain将不同的task_phase过程进行了分隔。
默认情况下,所有comp位于相同名为common_domain域中,task_phase中的各个phase同步
使用以下实例,可创建domain,set过程中第二个参数hier默认为1,表示继承。
domain实现不同后,jump过程只能在各自的domain中。
class B extends uvm_component; uvm_domain new_domain; `uvm_component_utils(B) function new(string name, uvm_component parent); super.new(name, parent); new_domain = new("new_domain"); endfunction virtual function void connect_phase(uvm_phase phase); set_domain(new_domain); endfunction extern virtual task reset_phase(uvm_phase phase); extern virtual task post_reset_phase(uvm_phase phase); extern virtual task main_phase(uvm_phase phase); extern virtual task post_main_phase(uvm_phase phase); endclass
时间域
61页,4.4节
NBA域
NBA events region
The NBA (nonblocking assignment update) region holds the events to be evaluated after all the Inactive events are processed
NBA(非阻塞赋值更新)区域在处理完所有Inactive事件后,保存要评估的事件
Sequence
仲裁机制优先级
默认优先级为-1,优先级越高越先执行。
在main_phase中设置了仲裁算法。默认算法为FIFO,先入先出,不考虑优先级。
而STRICT表示按照优先级仲裁。STRICT_FIFO表示先按照优先级,相同则使用先入先出。
此外还有RANDOM、WEIGHTED等方式。(优先级也可在start处指定。)
`uvm_do_pri(m_trans, 100) `uvm_do_pri_with(m_trans, 200, {m_trans.pload.size < 500;}) env.i_agt.sqr.set_arbitration(SEQ_ARB_STRICT_FIFO);
LOCK机制
在seq中的task body内,进行lock操作后,阻断了其它seq的发送,使得sqr只处理当前的seq。当前的seq进行unlock后,恢复正常。
lock(); unlock();
GRAB机制
和lock相同,但是优先级更高。在sqr的处理过程中,比如之前提到的FIFO,有执行顺序。
seq的lock需要等待到fifo到达指定的lock位置后才可执行。而grab则无需该规则,进入fifo后打断fifo,直接生效。
grab(); ungrab();
seq的失效和有效
seq中,重载is_relevant函数,进行失效和有效的控制。无效时sqr不发出该seq的trans。
virtual function bit is_relevant(); if((num >= 3)&&(!has_delayed)) return 0; else return 1; endfunction
is_relevant应该与wait_for_relevant成对出现。当前seq失效后,等到其它所有seq执行完毕,
则进入到该seq的wait_for_relevant中。等待必须将seq无效的条件清除(否则进入该函数的死循环)。
virtual task wait_for_relevant(); #10000; has_delayed = 1; endtask
其它宏和函数
宏
uvm_do_on指定trans和sqr。
uvm_do_pri指定trans和优先级。
uvm_create创建trans
uvm_send发送trans
uvm_send_pri发送时候指定优先级
uvm_rand_send发送前进行随机化
任务
start_item和finish_item。在trans实例化后调用(参数为trans),可指定优先级,被封装在了uvm_do系列宏中。
pre_do在start_item前调用。参数is_item为1表示对seq操作,0为对trans操作。
mid_do在finish_item前调用。参数为seq_item
post_do在finish_item后调用。参数为seq_item
不同的trans相同的sqr
drv设置为了uvm_seq_item而不是trans(sqr需要同样的设置),这样。
class my_driver extends uvm_driver#(uvm_sequence_item);
在main_phase过程中,使用$cast即可判断是哪个trans
while(1) begin seq_item_port.get_next_item(req); if($cast(m_tr, req)) begin drive_my_transaction(m_tr); `uvm_info("driver", "receive a transaction whose type is my_transaction", UVM_MEDIUM) end else if($cast(y_tr, req)) begin drive_your_transaction(y_tr); `uvm_info("driver", "receive a transaction whose type is your_transaction", UVM_MEDIUM) end else begin `uvm_error("driver", "receive a transaction whose type is unknown") end seq_item_port.item_done(); end
m_sequencer和p_sequencer
m_sequencer为当前的seq启动时默认使用的sqr,如在实例化一个seq后,通过该seq的start函数启动,传入参数为m_sequencer。
m_sequencer本质为uvm_sequencer_item类型。有时候需要将其\$cast转换为sqr类型,则可以使用uvm_declare_p_sequencer的宏,其中参数为sqr。
然后在seq的task body中,引用p_sequencer,即为m_sequencer对应的sqr。
Le vent se lève! . . . il faut tenter de vivre!
Le vent se lève! . . . il faut tenter de vivre!