【15-UVM入门进阶2.P58】uvm_config_db遵循“先配置后例化”。 (1) SV里只能先例化对象,然后才能利用例化对象的层次化索引去传递变量/接口;而UVM里因为有了config_db机制,我们可以根据实际需求先把各层次类class的变量/接口get后丢到config_db的箱子里,各层次类class再去这个箱子对变量/接口set设置具体的value,进而达到“先配置再例化”的定制化。 (2) 【九大phase执行顺序】① 0时刻前,编译与链接(config_db在此时配置???);② 0时刻,always/initial块→调用顶层initial的run_test()→执行全局build_phase等4个phase;③ run时,执行run_phase;④ run后,执行extract_phase等4个phase。 (3) 先顶层set再底层get,然后build_phase里的comp1::type_id::create(),最后run_test()。 【UVM实验0】几个sv都是module模块里放着initial,只要compile→nonvopt→run -all,就能够执行initial里的内容。(难道因为module是硬件模块,所以run后就直接initial了?) 【UVM实验0】uvm_test_inst.sv的initial语块里的run_test(“top”)可以直接执行top这个类(class)!前提是包含该initial的module先import包含top类的test_pkg :: *。 【UVM实验0】只有继承于uvm_test的类,才有资格作为UVM验证环境的顶层。 【UVM实验1】vsim -novopt -classdebug +UVM_TESTNAME=object_create work.factory_mechanism work.factory_mechanism中的factory_mechanism是factory_mechanism_ref.sv中的模块名。 【UVM实验2】run_phase()里不用调用子一级的run,因为子一级的run本来就会有run_phase()去调用执行。例如:chnl_pkg.sv→class chnl_agent→task run_phase(),对比reg_pkg.sv→class reg_driver→task run_phase()。如下代码:
class chnl_agent extends uvm_agent;
. . .
task run_phase ( uvm_phase phase) ;
endtask
endclass: chnl_agent
【11-SV语言五】initial语块会等待fork…join结束完再退出仿真,但是路科说不会等待fork…join_any和fork…join_none执行完再退出仿真。通过QuestaSim仿真,发现initial语块同样会等待fork…join_any和fork…join_none执行完再退出仿真。
module initial_fork_join_none_order ;
initial begin
$display ( "@%0t: module starts" , $time ( ) ) ;
#10 $display ( "@%0t: after #10" , $time ( ) ) ;
fork
begin
#20 $display ( "@%0t: fork...join_none after #20" , $time ( ) ) ;
end
join_none
$display ( "@%0t: after fork...join_none" , $time ( ) ) ;
end
endmodule: initial_fork_join_none_order
【19-UVM入门进阶6-P35】如何让客户拓展封闭的包(如商用VIP)?① 通过类的继承+UVM的override机制;② 在VIP中某个class的某个方法func的前后预留方法接口,利用callback回调函数,在该方法func前后预留pre_callback()和post_callback(),可以配合external使用。 【UVM入门进阶实验3】如何在DVT eclipse里查看树状层次结构,QuestaSim的class instances实在不好用。 【UVM入门进阶6-视频7】TLM (Transaction Level Modeling)相对于mailbox的优势: (1)TLM除了具有mailbox的缓存功能外,还可以在一对多情况下initiator端用uvm_analysis_port/export/imp的方式去轮询target端内置的write()函数,通过其返回值去触发其他event; (2)TLM具有观察者模式(observer pattern)或叫广播模式,支持一对多的put,也可以允许“空发”,即get的imp数量为0,但是mailbox的REQ和RSP句柄只能成对出现,尽量要避免空句柄的现象; (3)在单端对单端的传输方式中,mailbox是利用层次化索引进行,各组件之间耦合较多,而TLM通过port/export/imp端口作中介,降低了各组件之间的粘度。 【20-UVM入门进阶7-P11】driver是initiator,sequencer是target,driver采用get模式(而不是put模式),有以下考虑: (1)如果是get模式,传输路径很通畅,即sequence item (from sequence)→sequencer→driver,效率很高;如果是put模式,sequencer发起put后,还需等待driver返回rsp允许发送,才能传输数据,效率低; (2)sequencer拥有仲裁特性,即允许多个sequence同时挂载到sequencer上。通过driver的get模式,sequencer只需要专注于仲裁,driver作为initiator只需要发出get请求,就可以通过sequencer拿到仲裁后的sequence item。 【20-UVM入门进阶7-P18】sequence挂载到sequencer上后,sequence就会自动执行body(),不用手动执行,类似于组件类的run_phase()。 【 20-UVM入门进阶7】小白第一年:(1)写sequence;(2)写test???【测试场景都放在sequence里写,test只是执行顶层virtual sequence的挂载并执行】。 【20-UVM入门进阶7-P18】虚拟类(virtual sequence) 【UVM实验4】driver里(包括chnl_pkg、fmt_pkg、reg_pkg)都是用的seq_item_port去get_next_item(req)和item_done(rsp),虽然名字一样都叫seq_item_port,但是由于有connect_phase,可以通过层次索引将需要握手的双方连接在一起,如下图: 【UVM实验4-reg_pkg_reg.sv】 ① uvm_sequence_item类 :包括rand型变量、constraint约束条件、field automation域自动化声明、new; ② uvm_sequence #(Type)类 :Type如uvm_sequence_item类的子类reg_trans ,包括rand型变量(赋值-1)、constraint约束条件(赋值-1)、field automation域自动化声明、宏uvm_declare_p_sequencer(放要挂载的sequencer)、body()【含uvm_sequence_item类的变量、`uvm_do_with(var, cstr)、可选项get_response()、其他握手传参的操作】; ③ uvm_sequencer #(Type)类 :Type如uvm_sequence_item类的子类reg_trans ,只需extends→utils注册→new创建; ④ uvm_driver #(Type)类 :Type如uvm_sequence_item类的子类reg_trans ,包括set_interface()【含有层次化包含的地方就会有set_interface(),如uvm_monitor,但是uvm_sequencer没有,它只需要通过TLM与uvm_driver子类通信即可,如driver.seq_item_port .connect(sequencer.seq_item_export ); 】、run_phase()【需要run()的地方就会有run_phase(),如uvm_monitor】。 【UVM实验4-reg_讲解1】UVM预定义函数create_item()在定义时就已经是uvm_sequence_item类(即父类),所以tmp在调用时,就是父类句柄(uvm_sequence_item)指向子类对象(bus_trans),因此每次create_item()都要$cast转化。
protected function uvm_sequence_item create_item
(
uvm_object_wrapper type_var,
uvm_sequencer_base l_sequencer,
string name
) ;
uvm_coreservice_t cs = uvm_coreservice_t:: get ( ) ;
uvm_factory factory= cs. get_factory ( ) ;
$cast ( create_item, factory. create_object_by_type ( type_var, this . get_full_name ( ) , name ) ) ;
create_item. set_item_context ( this , l_sequencer) ;
endfunction
【136-寄存器模型的常规方法1.mp4】00:00:10 详细介绍了register_model和reg_agent、DUT的交互过程,包括RGM里map产生uvm_reg_op类的reg,到adapter里通过reg2bus函数转化变成bus_trans,传输给reg_agent里的sequencer→driver,最后从interface给到DUT,当然还有bus2reg函数、predictor、auto_predict等细节。 【23-UVM入门进阶10】对Register Model寄存器模型 的深入理解:desired value 是用来先更新软件侧model对象的值,再利用该值更新硬件侧的actual value ,紧接着通过bus2reg的adapter去更新软件测model的mirror value 。desired value、actual value、mirror value都存放在各个uvm_reg_fielld子类里,uvm_reg_field是各个value的最小存放单元。 【26-UVM项目实战3】 (1)断言(assertion)不能修改设计行为,分为: ① 立即断言(immediate assertion) :非时序,如:assert (y==0) else flag=1;
; ②并行断言(concurrent assertion) :时序性的、带关键词property、与设计模块一起并行执行,如:property req_grant_prop
@( posedge clk) req ##2 gnt ##1 ! req ##0 ! gnt;
endproperty
assert property req_grant_prop else $error ( "Req Grant Protocal Violation" ) ;
并行断言必须要有时钟,功能类似于clocking块,可以采样得到稳定的设计信号变量,避免竞争。 (2)sequence 是用来表示在一个或多个时钟周期内的时序 描述(但却与uvm_sequence无关); 是property 的基本构建模块,并经过组合 来描述复杂的功能属性。 property 块可以直接包含sequence,复杂的property块也可以独立声明多个sequence。sequence s1;
@ ( posedge clk) a ##1 b ##1 c;
endsequence
sequence s2;
@ ( posedge clk) a ##1 c;
endsequence
property p1;
@ ( posedge clk) disable iff ( ! reset)
s1 | = > s2;
endproperty
sequence不能在class里声明(在module、interface、program、clocking块、package都可以),assert property不能在class里声明。 ==>建议:assertion只放在interface里声明!!! (3)蕴含(implication)操作符:如果property中左边的先行算子成立,那么property右边的后续算子才会被计算,分为::“成功”、“空成功”、“失败”三种情况。 ① 交叠蕴含操作符|-> :左边算子成立后,当前周期就执行右边算子;property p_req_ack;
@( posedge clk) mem_en | -> ( req ##2 ack) ;
endproperty: p_req_ack
② 非交叠蕴含操作符|=> :左边算子成立后,下一周期才执行右边算子。property p_req_ack;
@( posedge clk) mem_en |= > ( req ##2 ack) ;
endproperty: p_req_ack