uvm实战-学习笔记
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
《UVM实战(卷1)》学习笔记
看了第1/2/3/4/5/6/8/9.1这几个章节。
第一章是综述,第二章是一个具体的例子,学习笔记从第三章相关内容开始。
我个人觉得UVM重要的部分(特点的部分):
1)factory机制(overrideconfig_db)
2)TLM传递
3)phase机制
4)sequence-sequencer以及virtualseq/sqr
内容中的截图基本来自于UVM源代码、书自带的例子和《uvm1.1应用指南及源代码分析》这个PDF里的。
需要结合书(
第3
也uvm_void
常用的
是
item,当发现有
常用的
transaction-level向signal-level的转换。
uvm_driver需要参数(REQRSP),比uvm_component增加了几个成员。
重要的是seq_item_port和req/rsp.(src/comps/uvm_driver.svh)
monitor/scoreboard派生自uvm_monitor和uvm_scoreboard,但是uvm_monitor和uvm_scoreboard并没有在uvm_component基础上做扩展。
src/comps/uvm_monitor.svh
因为
driver和
env
macro
1)对于
2)对于
对于
`uvm_component_utils(类名)
uvm_component里的成员也可以像uvm_object里成员一样,用field_automation机制。
field_automation机制:
对于uvm_object派生类来说,field_automation机制让对象自动有的copycompareprintpackunpack等函数,简化了实现uvm_component派生类里一些function/task的工作量
对于uvm_component派生类来说,field_automation机制最重要的是可以在build_phase中自动获取
uvm_config_db#()::set()的数值(必须加super.build_phase(phase))----也就是不用写uvm_config_db#()::get()
注意:field_automation的macro的类型要和uvm_config_db的参数类型一致:
如下示例代码,field_intvsuvm_config_db#(bit[47:0])这个时候super.build_phase()是不起作用的。
想要起作用的话,需要用
clone=new+copy 源代码中可以看到clone 函数一上来会做一次create ,然后调copy 函数
src/base/uvm_object.svh
3.2UVM 的树形结构
uvm_component 的new/create 要注意第一个参数是名字,第二个参数是parent 指针。
UVM 真正的树根是“uvm_top ”.根据上面这个树结构,可以看出一个个component 的parent 是什么。
uvm_top 的parent 是null 。
当一个component 在实例化的时候,如果parent 参数设成null ,那么parent 参数会被仿真器自动设置成uvm_root 的实例uvm_top.
在6.6.1章节里也提到了,sequence 在uvm_config_db#()::get ()的时候,第一个参数设成“null ”,实际就是 0/1两种情况
1
有217bit 中
bit0✍✍packbit9UVM_ALL_ON 是‘
UVM_ALL_ON|UVM_NO_PACK 这样就会忽略掉packbit
这个ps 的更合理一些。
然后crc_error 是
3.4UVM打印信息控制
get_report_verbosity_level()
set_report_verbosity_level(UVM_HIGH)只对当前调用的component起作用
set_report_verbosity_level_hier(UVM_HIGH)对当前及下面所有的component起作用
simv+UVM_VERBOSITY=UVM_HIGH命令行方式------我觉得用这个就可以了
重载打印信息:
set_report_severity_override(UVM_WARNING,UVM_ERROR);
上述函数都是在connect_phase及后面的phase使用
设置UVM_ERROR到达一定数量结束仿真
设置在
都是4
set的
1)
2)
3)
调用set
config_db(6.6.1章节)。
使用如下函数调试config_db
check_config_usage()print_config(1/0)这两个函数在connect_phase函数中调
simv+UVM_CONFIG_DB_TRACE
注意:第二个参数设置错误不会报错!!-------config_db机制务必要注意参数的书写。
第4章UVM中的TLM1.0通信
TLM是TransactionLevelModeling缩写
这章要搞清楚portexportimpfifo以及几种操作function/task和对应component中要实现的function/task
下面的箭头方向都是控制流的方向,不是数据流方向。
我觉得作为一个VMM用户会觉得TLM有点难理解,总想用VMM_CHANNEL去套,结果把自己搞晕。
像port等其实是调imp所在component的task/function.
我看UVM源代码里有一个uvm_seq_item_pull_port的class,它的基类是uvm_port_base.在uvm_driver的成员seq_item_port就是这个类型的。
与它对应的是uvm_seq_item_pull_imp,uvm_sequencer的成员seq_item_export 就是这种类型。
在my_agent.sv中会connect它们。
4.2端口互连
port是动作的发起者,export是动作接收者,但是需要以一个imp来结束。
;而
完以后,
之分
)。
transport 连接用connect函数实现,从名字就可以看出来,这个必须在connect_phase中调。
4.3通信方式
这节应该是本章重点。
实际使用中用analysis_port✍analysis_imp还是port✍tlm_analysis_fifo✍port可以根据实际情况自己决定。
analysis_port(analysis_export)可以连接多个imp(一对多的通信)✍✍put和get系列端口与相应imp的通信通常是一对一的(可以一对多,但是本书没有给出一对多的例子4.2.1章节有介绍)。
analysis_port(analysis_export)更像是一个广播
analysis_port(analysis_export)没有阻塞和非阻塞的概念。
它是一个广播,不等与它相连的其他端口的响应。
analysis_port(analysis_export)必须连的imp是analysis_imp.analysis_imp所在的component必须定义个write 的function---------注意:是function
代码示例:4.3.1示例代码的analysis_port文件夹
componentC和B的代码基本一致。
env的connect_phase函数里做connect:
component中有多个imp的时候,如何实现write函数?
4.3.2给的例子中,scoreboard有两个imp,分别从output_agent和reference-model的analysis_port获取transaction,然后做compare.这个时候需要用:
`uvm_analysis_imp_decl(_标记)这个macro,然后“write”函数变成“write_标记()”函数,analysis_port所在component不用变,还是调write()函数即可。
代码示例如下:
使用macro声明
来实现port
中直接
的时候用for循环。
第5章UVM验证平台的运行
5.1phase机制
所有的phase如下图:
中间绿色的是taskphase,两头青色的是functionphase
component的实例化是在build_phase中完成,object的实例化可以在任何phase完成。
functionphase中除了build_phase都是“自下而上”的执行----这里的上下是指的树结构中的上下。
-------build_phase 是“自上而下”
同层次的兄弟关系的component,buildphase执行顺序是根据new时候name的字典序–5.1.3章节
对于叔侄关系的component,buildphase执行顺序是深度优先。
例如前面UVM树中,“scb”和“i_agt.drv”,因为i_agt在scb前面,会执行完i_agt,然后drv\mon\sqr,然后o_agt,然后mon,然后才是scb。
所有component的同一个runtimephase是同时开始的。
-----也就是说会等其他component的上一个phase结束才开始当前phase。
super.build_phase(phase)一定要加,其他phase的super….可以不用加.
phase之间可以跳转。
例如在正常工作的时候,发生了的reset,那么应该是main_phase跳转到reset_phase.例如:5.1.7章节的示例代码
jump导致
1)在
2)
3)
控制
推荐在
5.2.2
注意用
给
在test的
objection
5.3
第6
sequencer
1)
2)需要
3)
4)启动sequence(一般在case的build_phase中)
上述变化反映到代码中,如图6.1.2章节的示例代码
下图中有两种方法实现my_sequencer
sequence的启动方式(3种):
1)在case的main_phase中:注意要设置cseq的staring_phase。
我觉得书上6-5代码清单里有两个地方写的不合理,一个是start的参数应该是sqr的路径,另外是少了设置starting_phase
2)注意在case的build_phase中
3)更推荐用下面这种方式:
sequence被启动后,会自动执行sequence的bodytask(以及pre_bodymid_bodypost_body)
在同一个sequencer上可以启动多个sequence,因为启动了多个,所以不能设置default_sequnce了,需要用上
面第一种方法来启动sequence.---------但是sequence的嵌套可以解决这个问题(上层sequence做default_sequence6.4章节)
sequence可以用uvm_do_priuvm_do_pri_with等macro来设置优先级priority,当一个sequencer上有多个sequence 的时候,这个优先级就有意义了。
优先级就带来sequencer的仲裁算法。
默认的仲裁算法是SEQ_ARB_FIFO(杨哥遵循陷入先出顺序,不考虑优先级),所以设置优先级以后,需要改变仲裁算法。
在case的main_phase中调函数set_arbitration()
前面提到的“嵌套sequence”也可以像上面这样来设置仲裁算法。
sequencer的操作:
lock()grab()获取独占权。
unlock()ungrab()释放独占权
is_relevant()设置sequence有效和无效。
返回值1有效,返回值0无效。
在
macro
除了
在两个,uvm_send
类似
可以嵌套。
sequence
通过上面的约束,上层sequence里可以约束下层sequence里transaction的成员:
sequence的参数代表了它的req和rsp的uvm_sequence_item派生类的类名。
如果需要发送不同uvm_sequence_item派生类的对象,那么需要把sequence、sequencer和driver参数声明成基类uvm_sequence_item。
由于是基类,所以在driver中seq_item_port.get_next_item(req)的时候要做$cast转换.因为sequence默认参数就是uvm_sequence_item,所以不用写。
6.4.3示例代码:
driver中的cast操作
实际的testbench中,很可能会在sequencer里加入一些成员变量,一般这种情况下要declarep_sequencer这个指针。
用macro–uvm_declare_p_sequencer(sequencer类名)在sequence中可以实现:6.4.4章节示例
问题:p_sequencer的声明macro是不是一直加着----直接写在base_sequence里比较好。
可以做一个base_sequence,需要p_sequencer的声明的话,写在base_sequence里,这样就不用每个sequence都声明p_sequencer指针了。
6.5virtualsequence
virtualsequence(virtualsequencer)是特色。
如下图所示:
系统级环境里可能有多个env,带来了多个sequencer/sequence,这样在case里不好维护。
实现一个virtualsequencer,里面包括指向各个sequencer的指针;而virtualsequence就像前面介绍的“sequence嵌套”一样实现。
由于virtualsequencer里有实际sequencer的指针,所以肯定不能用“typedefuvm_sequncer….”来实现。
同时,由于
base_test----所以
所谓“的6.5.3
base_test
case
的控制
sequence
虽然
在case,它的名
null和
6.6.1
在
6.6.3
sequencesequencerdriver的参数有两个:req类型和rsp类型,默认情况下rsp和req一样的类型。
当sequence 需要driver返回response的时候,就需要用到rsp了。
sequence中在uvm_domacro之后调get_reponse(rsp)task,而在driver中增加的代码较多:
6.7.1章节示例代码
get_reponse和put_response对应。
注意driver中必须有set_id_info函数。
put_response可以省略:需要item_done函数带rsp参数:seq_item_port.item_done(rsp)-----但是当有多次rsp的时候,就不能这么用了。
多次的时候只能是调多次get_reponse和put_response
get_response是一个阻塞的task,当sequence没有获取到driver返回的rsp的时候,会阻塞住sequence的body(),所以当driver不能及时返回rsp的时候,get_response✍✍put_response这个机制就有问题了。
UVM的解决方法是使用response_handler函数:
在pre_body()函数中use_reponse_handler()打开这个功能,然后重载response_handler(uvm_sequence_itemresponse)这个函数 一般需要$cast给sequence中的rsp成员.而sequence
的bodytask里就不用再调get_response了
6.7.3章节代码示例:
rsp和req的类型可以不同,这个时候注意sequencedriversequencer的参数
6.8sequencelibrary
sequencelibrary是一系列sequence的结合。
uvm_sequence_library本身是uvm_sequence的派生类。
实现sequence_library的时候要注意:
1)在
)
一个
使用是
可以使用
:6.8.4
第8
重点章节
UVM的virtual 的才行。
使用
1)
2)
3)
4)
也可以用类名字符串来代替原始类名::get_type()和重载类名::get_type()
set_type_override(原始类名字符串,重载类名字符串,replace)
set_inst_override(相对路径字符串,原始类名字符串,重载类名字符串)
直接使用factory这个全局变量的函数:
与上面的非常类似,只是把“相对路径字符串”变成“绝对路径字符串”,而且移到最后一个参数:
直接使用
factory
在build_phase
comp.print_override_info();
factory.debug_create_by_name();
factory.debug_create_byte_type();
factory.print();
uvm_root.print_topolofy();
可以重载uvm_sequence_itemuvm_sequenceuvm_component.都是在case的build_phase中调,而且都是直接用factory的方法
第9章UVM的代码重用
只给
uvm的
1)
2)
3)在
4)
5)从A
6)在
前面做这
9.1.4
精心整理。