1.核心基类(uvm_object)
- UVM的类最初都是从
uvm_void
(虚类)继承而来,继承于uvm_void
的两个子类为uvm_object
和uvm_port_base
。 - uvm_object的核心方法主要提供与数据操作相关的服务:copy、clone、compare、print、pack/unpack。
- 域的自动化。使得注册UVM类的同时可以声明会参与到上述copy等操作的成员变量。
`uvm_object_utils_begin(class_name)
`uvm_field_int(xx, UVM_ALL_ON)
`uvm_field_enum(e_class, e_inst, UVM_ALL_ON)
`uvm_field_string(xx, UVM_ALL_ON)
`uvm_object_utils_end
1)拷贝
- copy默认已经创建好了对象,只需对数据进行拷贝;clone则会自动创建对象并进行数据拷贝再返回目标对象的句柄。如果成员包括句柄,则拷贝时会额外创建新的对象,将句柄指向该对象。
- 在执行拷贝时默认进行的是深拷贝,即会执行
copy()
和do_copy()【回调函数】
。
2)比较
- 默认的比较器最大输出的错误比较信息为1,即只要发生错误就不会进行后续的比较。
uvm_default_comparer.show_max=xx
可以更改最大输出的错误比较信息。- 实际上,默认情况 下
uvm_pkg
中例化了很多相关的全局数据操作配置成员,如uvm_default_printer
、uvm_default_packer
等
3)打印
uvm_default_printer
为默认的打印设置,指向了uvm_default_table_printer
- 其余还有
uvm_default_tree/line_printer
- 如果用户自定义一些打印属性则可通过修改
uvm_printer::knob
中的成员来定制打印格式。
4)打包和解包
- pack将自动化声明后的域打包成比特流。
- unpack与pack相反。将串行数据解包变为原有各自的域。
- UVM环境中较少使用,但当与外界环境例如SystemC发生大规模数据传递或者UVM与FPGA emulator之间进行数据交换时,该方法则可能会用到。
2.phase机制
- UVM在验证环境构建时引入phase机制,清晰地将UVM仿真阶段层次化
phase | 函数/任务 | 执行顺序 |
---|
build | 函数 | 自顶向下 |
connect | 函数 | 自底向上 |
end_of_elaboration | 函数 | 自底向上 |
start_of_simulation | 函数 | 自底向上 |
run | 任务 | 自底向上 |
extract | 函数 | 自底向上 |
check | 函数 | 自底向上 |
report | 函数 | 自底向上 |
final | 函数 | 自顶向下 |
- 只有uvm_component及其继承于uvm_component的子类,才会按照phase机制将上面的九个phase先后执行完毕。
- 其中只有run_phase是task(可以完成一些等待、激励、采样等耗时的任务);build_phase和final_phase的执行顺序为自顶向下,其余的均为自底向上。仿真实例如下:
- run_phase又对应于12个分支phase(并行关系)。
pre/-/post
_reset/config/main/shutdown
1)UVM编译和运行顺序
- 在加载硬件模型调用仿真器之前,需完成编译和建模阶段。
- 在开始仿真之前,分别执行硬件的always/initial语句、UVM的调用测试方法run_test()和run_phase之前的几个phase。
- 开始仿真后,执行run_phase()或者对应细分的12个phase。
- 结束仿真后,执行剩余的extract、report等phase。
2)UVM仿真开始
- 通过由
uvm_pkg
提供的全局函数run_test()
来指定运行哪一个uvm_test
,指定的test将被例化并指定为顶层的组件。一般而言,run_test()
可以在合适的module/program中调用。 - 用户也可通过在仿真时传递参数
+UVM_TESTNAME=<test_name>
来指定仿真时调用的uvm_test
。
3)UVM世界的“诞生”
- UVM顶层类
uvm_root
继承于uvm_component
,提供了run_test()
等方法作为UVM世界的核心角色。 - 在
uvm_pkg
中有且只有1个uvm_root
所例化的对象即uvm_top
。通过uvm_top
调用run_test(test_name)
涉及如下初始化过程:
①获取正确的test_name
②初始化objection机制
③创建uvm_test_top实例
④调用phase控制方法
⑤等待所有phase执行结束
⑥报告总结和结束仿真
3)UVM仿真结束
- 利用objection挂起机制控制仿真结束。
uvm_objection
类提供了一种供所有component和sequence共享的计数器。
task run_phase(uvm_phase phase);
`phase.raise_objection(this);
...
`phase.drop_objection(this);
endtask
- 如果进入run_phase()后并没有马上挂起objection,则不会继续运行run_phase()而是转入extract_phase()。
3.config机制
- UVM提供
uvm_config_db
配置类,可以传递①virtual interface
,②单一变量值,③配置对象(config object)。
uvm_config_db#(T)::set(uvm_component cntxt, string inst_name, string field_name, T value);
uvm_config_db#(T)::get(uvm_component cntxt, string inst_name, string field_name, inout T value);
1)interface传递
- 接口传递需要在
run_test()
之前,保证在进入build_phase
之前virtual interface
已经被传递到了uvm_config_db
中。
uvm_config_db#(virtual uvm_config_if)::set(uvm_root::get(), "uvm_test_top.*", "vif", if0);
uvm_config_db#(virtual uvm_config_if)::get(this, "", "vif", vif);
2)单一变量传递
uvm_config_db#(int)::set(this, "c1", "var1", 10);
uvm_config_db#(int)::get(this, "", "var1", var1);
3)object传递
- 可以将每个组件的变量加以整合,放置到
uvm_object
中再进行传递。
uvm_config_db#(uvm_object)::set(this, "c1", "cfg", cfg1);
...
uvm_config_fb#(uvm_object)::get(this, "", "cfg", tmp);
void'($cast(cfg, tmp));
4)总结
- 使用
set()/get()
方法时传递的参数应该上下保持一致,否则需使用$cast()
完成类型转换。 - 应尽量确保set方法在相关配置组件创建前调用,这是因为只有先完成配置,相关组件在例化前可以得到配置值进而正确地例化。
- 传递的参数可以使用
*
通配符来表示任意的层次。
4.消息管理
1)消息方法
function void uvm_report_info(string id, string message, int verbosity = UVM_MEDIUM, string filename = "", int line = 0);
function void uvm_report_warning(string id, string message, int verbosity = UVM_MEDIUM, string filename = "", int line = 0);
function void uvm_report_error(string id, string message, int verbosity = UVM_LOW, string filename = "", int line = 0);
function void uvm_report_fatal(string id, string message, int verbosity = UVM_NONE, string filename = "", int line = 0);
- 其中
verbosity
冗余度于消息处理中的过滤直接相关。冗余度的设置如果低于过滤的开关,那么该消息会打印出来,否则不会被打印出来。重要程度由高到低依次为UVM_NONE/LOW/MEDIUM/HIGH/FULL/DEBUG
。
2)消息处理
- 消息处理的方式是同消息的严重级别对应的。当然用户也可自定义的修改。
严重级别 | 默认处理方式 |
---|
UVM_INFO | UVM_DISPLAY |
UVM_WARNING | UVM_DISPLAY |
UVM_ERROR | UVM_DISPLAY / UVM_COUNT |
UVM_FATAL | UVM_DISPLAY / UVM_EXIT |
- 此外还有
NO_ACTION
、UVM_LOG
、UVM_CALL_HOOK
、UVM_STOP
等处理方式。
3)消息机制
- 可以通过
uvm_report_object
类提供的方法自定义配置消息处理方式。该类是间于uvm_object
类与uvm_component
类之间的中间类,主要功能是完成消息的打印和管理。 - 消息处理是由
uvm_report_handler
类来完成的,每个uvm_report_object
类中都有一个handler
实例。 - 所有
uvm_report_handler
实例也都依赖于uvm_pkg
中的uvm_report_server
唯一实例,但该实例并没有作为全局变量直接暴露给用户,需要通过uvm_report_server::get_server()
自行调用。
4)回调函数
report_hook()
函数通过结合消息处理时的UVM_CALL_HOOK
参数,结合用户自定义的回调函数实现不同的配置。- 调用回调函数时首先调用
report_hook()
函数,然后按照severity级别来选择更细致的回调函数report_SEVERITY_hook()
。
set_report_severity_action(UVM_ERROR, UVM_DISPLAY | UVM_CALL_HOOK);
set_report_verbosity_level_hier(UVM_LOW);
uvm_report_error("RUN", "error1", UVM_LOW);
uvm_root::get().set_report_id_verbosity_hier("BUILD", UVM_NONE);