1. 所有派生自UVM_component及其派生类的类都应当使用uvm_component_utils宏注册。好处之一就是,其main_phase就可以自动运行了。
2. Driver中往往只是while循环,进行驱动,不做其他的事儿,因此实现driver,就是实现其main_phase.
3. Raise_objection与drop_objection成对出现,在raise之前不能有消耗时间的语句。
4. 为了避免对代码绝对路径的引用,使用interface,而在类中,是无法声明interface,因此使用 virtual interface.
i. 然而如何将不同class类中的interface连接到一起?在class的 build phase中使用config db机制,即可get。而set则需要在initial 语句中,调用config db 进行set interface
ii. 此外,build phase是函数,不消耗时间,与main phase不同。
iii. config_db也可以传递其他的变量的值。如var,counter等等。
5. Transaction,在平台中流动的一个数据包。其由uvm_sequence_item派生而来,注册类的时候使用的是uvm_object_utils,是有生命周期的,用完了就挂掉了。
6. Uvm_env中包括所有的uvm组件的环境,如driver,scoreboard等,因此在调用run_test()语句进行启动时,只需要实例化uvm_env即可。因为不允许run_test()多个组件。
7. 在uvm_env中如何实例化组件?在其build phase,通过调用type_name::type_id:creat方式,生成各个组件。
8. Monitor扩展自uvm_monitor,这个类似于driver,也需要virtual interface,利用接口收集到的数据,转化成新的transaction。
9. 因为driver与monitor的代码高度相似,可以将他们封装到一个agent中,同样, agent扩展自uvm_agent。在uvm_agent中声明driver和monitor,在agent的build phase根据is_active变量判断是否生成driver。本质原因还是因为在结果检查端的agent不需要driver。
1. 在env中就要声明两个agent,一个在入口,一个再出口,在env的build phase,通过type_name::type_id:creat方式创建两个agent,然后对agent中的is_active进行赋值。
2. 因此当env先实例化,然后再实例化agent时,agent中的driver就会按照is_active的值,一个agent有,一个agent没有driver。
10. 如果不在build phase创建component,那么唯二的方法就是在new函数中,调用type_name::type_id:creat创建实例。而如果想要同样的效果,即is_active变量来确定是否生成driver,则需要在new函数中,在type_name::type_id:creat之前,调用config_db get来获取is_active的值。
11. Reference model 用于模仿dut的行为,扩展自uvm_component, 在其中会声明两个port,uvm_blocking_get_port与uvm_analysis_port,一个用于获取数据,一个用于发送数据,获取的数据是在i_agent中的monitor。即在env中可以声明一个uvm_tlm_analysis_fifo类型的fifo,i_agent中的发送数据端和model中的获取数据端连接到这个fifo上。 那么i_agent中的发送数据端如何连接呢?可以在i_agent中不做任何操作,直接在i_agent中声明一个ap,然后将monitor中的ap连接到这个ap上,即子ap指到父ap的ap上,即可。
12. 最后需要增加scoreboard,scoreboard要做的就是期望数据和实际数据的比对。因此scoreboard中要做两个获取数据的port。Scoreboard的程序主要负责将expect 的数据存入fifo,(因为c model程序生成结果比较快,如果慢的另说),每次来一个actual数据就比对一次。而compare的程序可以写在transaction类中,这样直接调用类中的function进行比较即可。
13. 在声明class类的transaction时,为了不用重写copy,compare等函数,可以选择将transaction中的数据声明为`uvm_field_int类型,这样就就可以调用uvm中已经封装好的函数,copy,compare,paket_bytes进行打包。
14. Sequence扩展自uvm_sequence,也是有生命周期的,使用uvm_object_utils宏注册到factory中。
15. Sequence中其主要作用的是body,在body中,负责创建transaction并发送,发送可以使用1)uvm do 2)start item, finish item即可将数据发送。
16. 分析driver机制:driver中seq_item_export.get_next_item获得transaction,按照时序发送出去后,调用seq_item_export.item_done, 用于通知sequencer,这个数据已经发送完毕,应当产生下一个transaction。另外:seq的seq_item_export与driver的seq_item_port是在env中的connect phase连接到一起的
17. 如何显式的指定哪个sequencer发送哪个sequence呢?可以在env的main phase中实例化sequence,并调用sequence的start,在start的传参中传入i_agt_sqr,即指定哪个sequencer发送合格sequence。
18. 注意在这个前后也是要发送raise,drop objection的。这个我认为可以反复调用start多次调用一个sequence。
19. 使用默认的方式 default sequence,这个是在env的build phase或者initial 中,直接调用uvm_config_db#(uvm_object_wrapper)::set(this,”uvm_test_top.i_agt.sqr.main_phase”,”default_sequence”,my_sequence::type_id::get())直接用这个方式指定哪个sequence被哪个sequencer发送,则sequencer默认的会发送这个sequence。
20. 最终,引入base_test。之前都是讲env作为环境的顶层,实际上,应当将扩展自base_test的类作为环境的顶层,在my_test中声明env,并在build_phase中,调用my_env::type_id::creat语句进行creat,创建了这个之后,调用uvm_config_db指定哪个sequencer跑sequence。参见Page53。
21. 在tb_top.sv中调用initial语句,一是run_test(“test的名字”) 二是调用uvm_config_db将virtual interface传送给各个模块的interface。
22. 然而,如果存在多个tests,如何区分不同的tests呢?使用在initial中调用run_test(tests名字)的方式比较麻烦,因而可以在命令中使用+UVM_TEST_NAME=tests名字的方式方式进行简化。
2. Driver中往往只是while循环,进行驱动,不做其他的事儿,因此实现driver,就是实现其main_phase.
3. Raise_objection与drop_objection成对出现,在raise之前不能有消耗时间的语句。
4. 为了避免对代码绝对路径的引用,使用interface,而在类中,是无法声明interface,因此使用 virtual interface.
i. 然而如何将不同class类中的interface连接到一起?在class的 build phase中使用config db机制,即可get。而set则需要在initial 语句中,调用config db 进行set interface
ii. 此外,build phase是函数,不消耗时间,与main phase不同。
iii. config_db也可以传递其他的变量的值。如var,counter等等。
5. Transaction,在平台中流动的一个数据包。其由uvm_sequence_item派生而来,注册类的时候使用的是uvm_object_utils,是有生命周期的,用完了就挂掉了。
6. Uvm_env中包括所有的uvm组件的环境,如driver,scoreboard等,因此在调用run_test()语句进行启动时,只需要实例化uvm_env即可。因为不允许run_test()多个组件。
7. 在uvm_env中如何实例化组件?在其build phase,通过调用type_name::type_id:creat方式,生成各个组件。
8. Monitor扩展自uvm_monitor,这个类似于driver,也需要virtual interface,利用接口收集到的数据,转化成新的transaction。
9. 因为driver与monitor的代码高度相似,可以将他们封装到一个agent中,同样, agent扩展自uvm_agent。在uvm_agent中声明driver和monitor,在agent的build phase根据is_active变量判断是否生成driver。本质原因还是因为在结果检查端的agent不需要driver。
1. 在env中就要声明两个agent,一个在入口,一个再出口,在env的build phase,通过type_name::type_id:creat方式创建两个agent,然后对agent中的is_active进行赋值。
2. 因此当env先实例化,然后再实例化agent时,agent中的driver就会按照is_active的值,一个agent有,一个agent没有driver。
10. 如果不在build phase创建component,那么唯二的方法就是在new函数中,调用type_name::type_id:creat创建实例。而如果想要同样的效果,即is_active变量来确定是否生成driver,则需要在new函数中,在type_name::type_id:creat之前,调用config_db get来获取is_active的值。
11. Reference model 用于模仿dut的行为,扩展自uvm_component, 在其中会声明两个port,uvm_blocking_get_port与uvm_analysis_port,一个用于获取数据,一个用于发送数据,获取的数据是在i_agent中的monitor。即在env中可以声明一个uvm_tlm_analysis_fifo类型的fifo,i_agent中的发送数据端和model中的获取数据端连接到这个fifo上。 那么i_agent中的发送数据端如何连接呢?可以在i_agent中不做任何操作,直接在i_agent中声明一个ap,然后将monitor中的ap连接到这个ap上,即子ap指到父ap的ap上,即可。
12. 最后需要增加scoreboard,scoreboard要做的就是期望数据和实际数据的比对。因此scoreboard中要做两个获取数据的port。Scoreboard的程序主要负责将expect 的数据存入fifo,(因为c model程序生成结果比较快,如果慢的另说),每次来一个actual数据就比对一次。而compare的程序可以写在transaction类中,这样直接调用类中的function进行比较即可。
13. 在声明class类的transaction时,为了不用重写copy,compare等函数,可以选择将transaction中的数据声明为`uvm_field_int类型,这样就就可以调用uvm中已经封装好的函数,copy,compare,paket_bytes进行打包。
14. Sequence扩展自uvm_sequence,也是有生命周期的,使用uvm_object_utils宏注册到factory中。
15. Sequence中其主要作用的是body,在body中,负责创建transaction并发送,发送可以使用1)uvm do 2)start item, finish item即可将数据发送。
16. 分析driver机制:driver中seq_item_export.get_next_item获得transaction,按照时序发送出去后,调用seq_item_export.item_done, 用于通知sequencer,这个数据已经发送完毕,应当产生下一个transaction。另外:seq的seq_item_export与driver的seq_item_port是在env中的connect phase连接到一起的
17. 如何显式的指定哪个sequencer发送哪个sequence呢?可以在env的main phase中实例化sequence,并调用sequence的start,在start的传参中传入i_agt_sqr,即指定哪个sequencer发送合格sequence。
18. 注意在这个前后也是要发送raise,drop objection的。这个我认为可以反复调用start多次调用一个sequence。
19. 使用默认的方式 default sequence,这个是在env的build phase或者initial 中,直接调用uvm_config_db#(uvm_object_wrapper)::set(this,”uvm_test_top.i_agt.sqr.main_phase”,”default_sequence”,my_sequence::type_id::get())直接用这个方式指定哪个sequence被哪个sequencer发送,则sequencer默认的会发送这个sequence。
20. 最终,引入base_test。之前都是讲env作为环境的顶层,实际上,应当将扩展自base_test的类作为环境的顶层,在my_test中声明env,并在build_phase中,调用my_env::type_id::creat语句进行creat,创建了这个之后,调用uvm_config_db指定哪个sequencer跑sequence。参见Page53。
21. 在tb_top.sv中调用initial语句,一是run_test(“test的名字”) 二是调用uvm_config_db将virtual interface传送给各个模块的interface。
22. 然而,如果存在多个tests,如何区分不同的tests呢?使用在initial中调用run_test(tests名字)的方式比较麻烦,因而可以在命令中使用+UVM_TEST_NAME=tests名字的方式方式进行简化。