uvm里如何插入断点_1 UVM学习笔记--phase机制(转)

本文详细介绍了UVM中的phase机制,包括build、connect、end_of_elaboration、start_of_simulation、run、extract、check、report和final等函数任务,以及新增的12个task phase。UVM的phase按照特定顺序自动化运行,支持同步和跳转。文章还探讨了function phase和task phase的区别,以及如何在不同phase中添加代码以执行特定任务。此外,还提到了phase的调试技巧,如使用UVM_PHASE_TRACE标志和设置verbosity。最后,文章提供了示例代码以展示phase的执行顺序。
摘要由CSDN通过智能技术生成

先来看一看,UVM的phase有哪些?

phase

函数/任务

执行顺序

功能

典型应用

build

函数

自顶向下

创建和配置测试平台的结构

创建组件和寄存器模型,设置或者获取配置

connect

函数

自底向上

建立组件之间的连接

连接TLM/TLM2的端口,连接寄存器模型和adapter

end_of_elaboration

函数

自底向上

测试环境的微调

显示环境结构,打开文件,为组件添加额外配置

start_of_simulation

函数

自底向上

准备测试环境的仿真

显示环境结构,设置断点,设置初始运行的配置值

run

任务

自底向上

激励设计

提供激励、采集数据和数据比较,与OVM兼容

extract

函数

自底向上

从测试环境中收集数据

从测试平台提取剩余数据,从设计观察最终状态

check

函数

自底向上

检查任何不期望的行为

检查不期望的数据

report

函数

自底向上

报告测试结果

报告测试结果,将结果写入到文件中

final

函数

自顶向下

完成测试活动结束仿真

关闭文件,结束联合仿真引擎

1.UVM phase 概览

UVM采用phase机制来自动化运行testbench各个仿真过程。UVM phase支持显示或隐式的同步方案,运行过程中的线程控制和跳转。用户只要把代码填入对应的phase,这些代码就会自动在正确的时间执行。各个phase执行顺序如下图所示:

image.png

相较于OVM,UVM新增了12个小的task phase,如下图:

image.png

其中run_phase和uvm新增加的12个小phase是并行执行的。

2 按是否消耗仿真时间,所有phase可以分成两大类

<1> function phase:不消耗仿真时间,而其也可分成两大类:

a. 继承自uvm_bottomup_phase, 在UVM component树中,自下而上的执行, 如connect_phase

b. 继承自uvm_topdown_phase, 在UVM component树中,自上而下执行, 如build_phase

<2> task phase:消耗仿真时间的,也称动态运行(run-time)phase.

下图是各个phase的继承关系,从中可以看出

image.png

自上而下(top-down) function phase:build和final phase。

自下而上(bottom-up)f unction phase: connect, end_of_elaboration,start_of_simulation, extract, check, report。

task phase: run_phase以及其他12个小phase: pre_reset, reset_phase, post_reset, pre_configure, configure, post_configure,

pre_main, main, post_main, pre_shutdown, shutdown, post_shutdown, 如下图:

image.png

3 task phase的同步

一个UVM验证平台有许多component组成,每个component都有自己的run_phase,以及从pre_reset 到post_shuddown的12个小phase。只有所有component的一个小task phase 完成,整个仿真平台才开始下一个小task phase的执行。 各个component的run_phase之间,以及run_phase于最后一个小phase--post_shutdown_phase之间,都有这样的同步。

image.png

4. super.xxx_phase

除了super.build_phase,其他super.xxx_phase几乎没做任何事情,因此,除了build_phase,其他phase可不必加super.xxx_phase.

在super.build_phase中,主要完成自动获取config_db中参数的功能,如果自定义的component无需获取任何参数,也可省略。

5. phase的跳转

默认情况下各phase是从上到下按时间顺序执行,但可以自定义做必要的跳转,如在main_phase执行过程中,突然遇到reset信号被置起,可以用jump()实现从mian_phase到reset_phase的跳转:

phase.jump(uvm_reset_phase::get())

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

跳转的限制

不能跳转到build到start_of_function的function phase, 也不能跳转到run_phase. 从pre_reset_phase后的所有phase都可以作为jump()的参数。 除了向前跳转,也可向后跳转。除了向run-time phase跳转,甚至可以向final_phase等function phase跳转。

phase的调试

在命令行加UVM_PHASE_TRACE,可以将进入和退出个phase的信息打印到log中。

+UVM_PHASE_TRACE

在指定phase设置verbosity:

+uvm_set_verbosity=,,,

例如:simv +uvm_set_verbosity=uvm_test_top.env.mdl,my_model,UVM_NONE,main +UVM_TESTNAME=my_case0 +UVM_PHASE_TRACE -l tmp.log

注意,其中参数 不需要phase后缀,如上面例子将uvm_test_top.env.mdl的main_phase中打印的信息屏蔽掉,命令行里用的是+uvm_set_verbosity=uvm_test_top.env.mdl,my_model,UVM_NONE,main 。

设置timeout时间

1. 通过命令行: +UVM_TIMEOUT=,

如 +UVM_TIMEOUT="300ns, YES"

2.通过在base test中使用set_timeout(): uvm_top.set_timeout(500ns,0);

必要时需要修改宏定义:`define UVM_DEFAULT_TIMEOUT 9200s

————————————————

版权声明:本文为CSDN博主「wonder_coole」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/wonder_coole/java/article/details/90443373

code

关于执行的顺序,可以从下面这段简单的例码中得到佐证:

module common_phase_order;

import uvm_pkg::*;

`include "uvm_macros.svh"

class subcomp extends uvm_component;

`uvm_component_utils(subcomp)

function new(string name, uvm_component parent);

super.new(name, parent);

endfunction

function void build_phase(uvm_phase phase);

`uvm_info("build_phase", "", UVM_LOW)

endfunction

function void connect_phase(uvm_phase phase);

`uvm_info("connect_phase", "", UVM_LOW)

endfunction

function void end_of_elaboration_phase(uvm_phase phase);

`uvm_info("end_of_elaboration_phase", "", UVM_LOW)

endfunction

function void start_of_simulation_phase(uvm_phase phase);

`uvm_info("start_of_simulation_phase", "", UVM_LOW)

endfunction

task run_phase(uvm_phase phase);

`uvm_info("run_phase", "", UVM_LOW)

endtask

function void extract_phase(uvm_phase phase);

`uvm_info("extract_phase", "", UVM_LOW)

endfunction

function void check_phase(uvm_phase phase);

`uvm_info("check_phase", "", UVM_LOW)

endfunction

function void report_phase(uvm_phase phase);

`uvm_info("report_phase", "", UVM_LOW)

endfunction

function void final_phase(uvm_phase phase);

`uvm_info("final_phase", "", UVM_LOW)

endfunction

endclass

class topcomp extends subcomp;

subcomp c1, c2;

`uvm_component_utils(topcomp)

function new(string name, uvm_component parent);

super.new(name, parent);

endfunction

function void build_phase(uvm_phase phase);

`uvm_info("build_phase", "", UVM_LOW)

c1 = subcomp::type_id::create("c1", this);

c2 = subcomp::type_id::create("c2", this);

endfunction

endclass

class test1 extends uvm_test;

topcomp t1;

`uvm_component_utils(test1)

function new(string name, uvm_component parent);

super.new(name, parent);

endfunction

function void build_phase(uvm_phase phase);

t1 = topcomp::type_id::create("t1", this);

endfunction

endclass

initial begin

//t1 = new("t1", null);

run_test("test1");

end

endmodule

输出结果:

UVM_INFO @ 0: reporter [RNTST] Running test test1...

UVM_INFO @ 0: uvm_test_top.t1 [build_phase]

UVM_INFO @ 0: uvm_test_top.t1.c1 [build_phase]

UVM_INFO @ 0: uvm_test_top.t1.c2 [build_phase]

UVM_INFO @ 0: uvm_test_top.t1.c1 [connect_phase]

UVM_INFO @ 0: uvm_test_top.t1.c2 [connect_phase]

UVM_INFO @ 0: uvm_test_top.t1 [connect_phase]

UVM_INFO @ 0: uvm_test_top.t1.c1 [end_of_elaboration_phase]

UVM_INFO @ 0: uvm_test_top.t1.c2 [end_of_elaboration_phase]

UVM_INFO @ 0: uvm_test_top.t1 [end_of_elaboration_phase]

UVM_INFO @ 0: uvm_test_top.t1.c1 [start_of_simulation_phase]

UVM_INFO @ 0: uvm_test_top.t1.c2 [start_of_simulation_phase]

UVM_INFO @ 0: uvm_test_top.t1 [start_of_simulation_phase]

UVM_INFO @ 0: uvm_test_top.t1.c1 [run_phase]

UVM_INFO @ 0: uvm_test_top.t1.c2 [run_phase]

UVM_INFO @ 0: uvm_test_top.t1 [run_phase]

UVM_INFO @ 0: uvm_test_top.t1.c1 [extract_phase]

UVM_INFO @ 0: uvm_test_top.t1.c2 [extract_phase]

UVM_INFO @ 0: uvm_test_top.t1 [extract_phase]

UVM_INFO @ 0: uvm_test_top.t1.c1 [check_phase]

UVM_INFO @ 0: uvm_test_top.t1.c2 [check_phase]

UVM_INFO @ 0: uvm_test_top.t1 [check_phase]

UVM_INFO @ 0: uvm_test_top.t1.c1 [report_phase]

UVM_INFO @ 0: uvm_test_top.t1.c2 [report_phase]

UVM_INFO @ 0: uvm_test_top.t1 [report_phase]

UVM_INFO @ 0: uvm_test_top.t1 [final_phase]

UVM_INFO @ 0: uvm_test_top.t1.c1 [final_phase]

UVM_INFO @ 0: uvm_test_top.t1.c2 [final_phase]

从这个例子可以看出,上面的九个phase,对于一个测试环境的声明周期而言,是有固定的执行先后顺序的;同时,对于处于同一个phase的组件之间,执行也会按照层次的顺序或者自顶向下、或者自底向上来执行。这个简单的环境中,顶层测试组件test1中,例化了一个t1组件,而t1组件内又进一步例化了c1和c2组件。从执行的打印结果来看,需要注意的地方有:

对于build phase,执行顺序按照自顶向下,这符合验证结构建设的逻辑。因为只有先创建高层的组件,才会创建空间来容纳低层的组件。

只有uvm_component及其继承与uvm_component的子类,才会按照phase机制将上面九个phase先后执行完毕。

上面介绍的九个phase中,常用的phase包括build、connect、run和report,它们分别完成了组件的建立、连接、运行和报告。这些phase在uvm_component中通过_phase的后缀完成了虚方法的定义,比如build_phase()中可以定义一些例化组件和配置的任务。在这九个phase中,只有run_phase方法是一个可以耗时的任务,这意味着该方法中可以完成一些等待、激励、采样的任务。对于其它phase对应的方法,都是函数,必须即时返回(0耗时)。

在run_phase中,用户如果要完成测试,则通常需要经历下面的激励序列:

上电

复位

寄存器配置

主要测试内容

等待DUT完成测试

一种简单的方式是,用户在run_phase中完成上面所有的激励;另外一种方式,如果可以将上面的几种典型的序列分到不同的区间,让对应的激励按区搁置的话,也能让测试更有层次。因此,run_phase又可以分为下面的12个phase:

pre_reset_phase

reset_phase

post_reset_phase

pre_configure_phase

configure_phase

post_configure_phase

pre_main_phase

main_phase

post_main_phase

pre_shutdown_phase

shutdown_phase

post_shutdown_phase

上面的12个phase的执行顺序也是前后排列的。那么这12个phase与run_phase是什么关系呢?我们通过这段例码来看看:

module uvm_phase_order;

import uvm_pkg::*;

`include "uvm_macros.svh"

class test1 extends uvm_test;

`uvm_component_utils(test1)

function new(string name, uvm_component parent);

super.new(name, parent);

endfunction

function void start_of_simulation_phase(uvm_phase phase);

`uvm_info("start_of_simulation", "", UVM_LOW)

endfunction

task run_phase(uvm_phase phase);

phase.raise_objection(this);

`uvm_info("run_phase", "entered ..", UVM_LOW)

#1us;

`uvm_info("run_phase", "exited ..", UVM_LOW)

phase.drop_objection(this);

endtask

task reset_phase(uvm_phase phase);

`uvm_info("reset_phase", "", UVM_LOW)

endtask

task configure_phase(uvm_phase phase);

`uvm_info("configure_phase", "", UVM_LOW)

endtask

task main_phase(uvm_phase phase);

`uvm_info("main_phase", "", UVM_LOW)

endtask

task shutdown_phase(uvm_phase phase);

`uvm_info("shutdown_phase", "", UVM_LOW)

endtask

function void extract_phase(uvm_phase phase);

`uvm_info("extract_phase", "", UVM_LOW)

endfunction

endclass

initial begin

run_test("test1");

end

endmodule

输出结果:

UVM_INFO @ 0: reporter [RNTST] Running test test1...

UVM_INFO @ 0: uvm_test_top [start_of_simulation]

UVM_INFO @ 0: uvm_test_top [run_phase] entered ..

UVM_INFO @ 0: uvm_test_top [reset_phase]

UVM_INFO @ 0: uvm_test_top [configure_phase]

UVM_INFO @ 0: uvm_test_top [main_phase]

UVM_INFO @ 0: uvm_test_top [shutdown_phase]

UVM_INFO @ 1000000: uvm_test_top [run_phase] exited ..

UVM_INFO @ 1000000: uvm_test_top [extract_phase]

从这个例子可以看到,实际上,run_phase任务和上面细分的12个phase是并行进行的。在start_of_simulation_phase任务执行以后,run_phase和reset_phase开始执行,而在shutdown_phase执行完之后,需要等待run_phase执行完以后,才能进入extract_phase。关于执行的关系,可以从下面这张图中得出:

image.png

这里需要提醒用户的是,虽然run_phase与细分的12个phase是并行执行的,而12个phase也是按照先后顺序执行的。为了避免不必要的干扰,用户可以选择run_phase,或者12个phase中的若干来完成激励,但是请不要将它们混合起来使用,因为这样容易导致执行关系的不明确。

如果要进一步深入phase机制的话,我们首先需要清晰下面的概念:phase、schedule和domain。

phase即上面介绍的部分,特定的phase会完成特定的功能。

schedule包含phase的关联数组,即若干个phase会由schedule按照安排的顺序先后执行。

domain则内置一个schedule。

schedule类uvm_schedule和domain类uvm_domain均继承于uvm_phase。

上面首先介绍的9个phase,共同构成了common domain;而另外12个phase,则共同构成了uvm domain。无论是domain、还是phase,它们在UVM环境中都只生成一个唯一的对象。关于common domain和uvm domain的联系和区别是:

common domain无法被扩展或者取代,这是UVM phase机制的核心。也就是说,构成它的9个phase的顺序不能更改,也无法添加新的phase。同时,这一核心的domain也是为了与OVM的phase机制保持兼容,方便从OVM代码转换到UVM代码。

uvm domain则包含了上面的12个phase,其调度也是按照先后顺序执行的。对于这一部分,与common domain不同的是,它们的执行是与run_phase同时开始,并且最后共同结束的。同时,用户还可以自定义一些phase,添加到uvm domain中,设置好与其他phase执行的先后关系。

上面的common domain和uvm domain中包含的phase在uvm_pkg中例化的唯一phase实例群如下:

image

在详细介绍完UVM的各个phase,以及它们之间执行的顺序之后,读者可以结合之前硬件和软件的编译和例化部分,来统一理解UVM世界中的编译和运行顺序:

image

首先在加载硬件模型,调用仿真器之前,需要完成编译和建模阶段。

接下来,在开始仿真之前,会分别执行硬件的always/initial语句,以及UVM的调用测试方法run_test和几个phase,分别是build、connect、end_of_elaboration和start_of_simulation。

在开始仿真后,将会执行run_phase或者对应的12个细化phase。

在仿真结束后,将会执行剩余的phase,分别是extract、check、report和final。

对于使用phase机制,这里有一些建议:

避免使用reset_phase()、configure_phase()、main_phase()、shutdown_phase()和其它pre_/post_ phase。这12个phase尽管细化了run_phase(),但是也使得phase的跳转过为冗余,在将来的UVM版本中,这些phase将考虑被废除。为了控制reset、configure、main和shutdown各个阶段的任务调度和同步,用户可以考虑fork-join语句块,或者高级的同步方式,例如uvm_barrier和uvm_event。

避免phase的跳跃。实际上,用户可以指定个别组件的phase执行中,从phaseA跳跃到phaseC,而忽略了phaseB。但是这种方式不容易理解和调试,所以不建议使用这一特性。

避免自定义phase的使用。尽管uvm domain中允许用户自定义phase,并且规定新添加phase的执行顺序,但是目前的这一机制还不方便调试。用户应该尽量将置于新phase中的任务,剥离到新的任务中,并且在已有的phase中调用它们,完成任务调用的模块化。

从之前的例子和上面的图中,读者可以看到,UVM的环境建立和各个phase的先后调用的入口,都是从run_test()进入的。默认情况下,如果run_test()方法执行完毕,那么系统函数$finish则会被调用,来终止仿真。然而,有更多的方法来分别控制UVM仿真的开始和结束,我们接下来则分别介绍这些方法的应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值