UVM实战指南(4)

2019-08-30 16:37

4.4 uvm_component类

所有的UVM验证环境的组件,包括环境和测试项都是直接或者间接由uvm_component类继承而来。此类是一个准静态类,只能在仿真开始的时候创建(构建[build]阶段). 从此类继承的用户自定义类继承了许多内建的自动化功能。

注意: 一般来说,通过从某个方法学构建的一系列类继承来设计自己的类,这系列类本身都是由uvm_component继承而来。由于提供各种功能的类都是由此类派生,理解uvm_component类是非常重要的。

下面章节描述uvm_component类的一些功能,以及如何使用。关键功能是: ? ? ? ? ?

Phasing and execution control 阶段(phase)执行控制 Hierarchy information functions 层次信息功能 Configuration methods 配置方法 Factory convenience methods 工厂方法 Hierarchical reporting control 层次化汇报控制

4.4.1 仿真阶段控制方法

在Verilog/VHDL类似的硬件描述语言中,在仿真开始之前静态构建各个实例的层次结构,保证了在跑仿真之前,所有的实例都连接存在且正确连接。在Systemverilog中,类对象是在运行时被创建,这就引出一些问题:什么时候进行传输交易产生和执行比较安全?什么时候能够确保所有的UVM组件都已经被创建?可以连接什么TLM端口?

尽管每个开发者都能够设计各自的同步方式,SystemVerilog UVM类库提供了一系列的阶段(phase)方法进行环境同步,而不需要事先设计计划。这些阶段给用户提供了一些钩子,实现在关键的时间点执行一些逻辑。比如,如果需要在仿真结束的时候执行检查逻辑,可以扩展check()阶段方法,在其中嵌入执行代码。那么这些代码在仿真过程中将会在想要的时间点被执行。除了run阶段方法之外,剩下所有的内建阶段方法的执行是在零时间内完成。请参考UVM类参考手册中的uvm_phase文档获得更多的信息。

从高层次来看,已有的阶段方法是(以仿真执行的顺序):

new() — 尽管他不是一个UVM阶段函数,但是组件的构造函数是组件被创建生成时第一个执行的函数。uvm_component构造函数包含两个参数:一个字符串name参数代表组件的名称,以及一个对组件父亲的引用。建议不要使用构造函数参数的缺省值,这样可以保证用户提供有意义的名字和父类。构造函数格式如下: class street extends uvm_component; `uvm_component_utils(street)

function new(string name, uvm_component parent); super.new(name, parent); endfunction : new endclass : street

技巧:关于构造函数的使用指南 ?

所有的组件类型的构造函数必须使用名称参数和父类参数。因为工厂需要提供名称参数和父类参数来构建组件。 ? ? ?

不要使用缺省参数,以确保用户必须给这两个参数提供有意义的值 使用简洁,意思清晰的名称

对于组件数组,名字使用索引:agent[index], 比如 env.agent[0].monitor, env.agent[1].monitor,等等

build()—第一个UVM阶段方法是build()方法,对每个组件会自顶向下自动调用。此方法可以对子组件进行配置,然后创建子组件。由于构造函数不是完全多态的,因此我们使用此方法来构建在构造函数中没有被创建的子组件。 因为build()方法是自顶向下调用,所以父类的构造配置将在子类build()方法之前完成。 一些关于build()使用指南: ?

每个build()的实现必须先调用super.build(), 除非此组件明确关闭了自动配置功能。调用super.build()会通过apply_config_settings方法调用来完成更新组件的配置域。尽管不建议使用,父组件可以显式的在parent.build()中调用子组件的build(). 调用super.build()确保了build()不被调用两次。 ?

在build()中分配子组件,而不是在构造函数中分配子组件。这样可以允许组件在分配层次结构之前可以配置。由于构造函数不是多态的,所以除非在build()函数中来创建结构,否则一个继承类不可能改变结构。 ? ? ?

如果组件在build()阶段之后被分配,UVM将会报错。 子组件的配置需要在build()方法中,子组件被创建之前完成。

如果通过重载build方法来改变组件的结构,此时不能够调用super.build(),因为这会导致父类的build被执行。如果你仍然想要uvm_component的build()方法的行为,可以通过调用uvm_component::build()来完成,这个方式会直接跳过父类的build方法。 . class my_derived_comp extends mycomp;

function new(string name, uvm_component parent); super.new(name,parent); endfunction function void build();

uvm_component::build(); //不调用super.build() ...//做其他事情 endfunction endclass

connect()—此阶段在build()之后执行。由于所有的子组件在build()阶段自顶向下都被创建,用户可以认定在connect()被调用的时候,所有组件的拓扑结构都已经成功创建. 此方法用来做事物级建模(TLM)的连接, 指针引用的赋值,以及虚拟接口(virtual interface)的赋值。

end_of_elaboration()— end_of_elaboration()阶段确保所有的连接,所有的引用都在connect阶段完成。在end_of_elaboration阶段执行之前,UVM完成了所有的TLM绑定,因此在此阶段,所有的端口绑定都已经建立,可以被访问使用。

start_of_simulation()—此阶段提供了一个机制来避免仿真0时刻各个组件之间的互相依赖。组件在此阶段初始化,确保在run阶段开始的时候,一切都已经正确初始化。

run()—run()阶段是唯一的一个耗时间的阶段,它定义了组件运行时的主要功能。由于它被定义为任务(task)类型,所以可以消耗仿真时间。当组件从run任务返回时,并不代表run阶段结束。有可能其内部创建的进程还在继续执行。run阶段是通过global_stop_request()任务来完成。此任务在发生超时,或者在对象机制使用的时候调用进程终止方法。

extract()—此阶段用来在仿真结束,,在检查校验阶段之前,提取仿真的结果。此阶段可以用来收集断言错误的个数,覆盖率,以及DUT内部讯号和寄存器的值,组件内部变量值,组件的统计信息及其他信息。此阶段执行不耗时间(消耗0时间),是一个函数调用。调用方式是自底向上。(译者补充:从叶子(leaf)组件的extract函数开始调用,深度优先)

check()—在前阶段(extract阶段)得到了重要的仿真结果,check阶段对结果进行分析判断,以此决定整个仿真的最终结论。此阶段也是一个0执行时间的函数调用,自底向上调用。 report()—此阶段最后执行,用来将结果输出到文件或者屏幕。此阶段是一个0执行时间的函数,自底向上调用。

尽管所有这些钩子方法在uvm_component以及他的子类中定义,只需要实现用到的相关(阶段)函数/任务(不需要全部实现). 组件不需要对子组件使用`uvm_field_object宏,组件在被创建的时候总是被提供其父组件,从而构建了所有组件的层次结构。 仿真阶段和层次构造的例子在后面给出:

4.4.2 层次信息函数

在仿真时,组件树是静态的。组件对层次信息非常注意,可以查询其父类,子类,以及他们在层次结构中的位置。相关的uvm_component成员函数如下:

? ?

get_parent()—返回父组件句柄,如果没有,返回null

get_full_name()—返回此对象的完整层次结构名字.缺省实现是将层次结构中的父类和其叶子对象相拼接。

? get_child(string_name)—根据参数名字返回子组件的句柄

以下例子演示了UVM仿真的阶段控制,以及组件的层次信息方法的使用。包含了street, city, state的组合。并演示了get_child(), get_parent(), 以及get_full_name()的功能。不建议使用new()来创建对象。请参考62页的\工厂\章节。 实例4-5: uvm_component仿真阶段控制以及层次信息相关方法 此例子演示了组件层次,包括州,城市,街道等对象实例。注意构造函数以及build(),run(), end_of_elaboration()阶段函数/任务的使用。用户通过阶段钩子函数/任务来完成想要的功能。从run_test()出发,各阶段开始按步骤自动开始执行。此例子也展示了get_child(), get_parent()和get_full_name()函数得到层次信息的功能 1. 2. 3. 4. 5. 6. 7. 8. 9.

module test; import uvm_pkg::*; `include \

class street extends uvm_component; `uvm_component_utils(street)

function new(string name, uvm_component parent); super.new(name, parent); endfunction : new task run ();

10. `uvm_info(\ 11. endtask : run 12. endclass : street

13. class city extends uvm_component; 14. street Main_St;

15. `uvm_component_utils(city)

16. function new(string name, uvm_component parent); 17. super.new(name, parent); 18. endfunction : new

19. function void build(); // note that we allocate in the build() 20. super.build();

21. Main_St = street::type_id::create(\

22. endfunction : build 23. task run();

24. uvm_component child, parent; 25. string pr, ch;

26. child = get_child(\ 27. parent = get_parent(); 28. pr = parent.get_full_name(); 29. ch = child.get_name();

30. `uvm_info(get_type_name(), $psprintf(\Child:%s\ 31. endtask : run 32. endclass : city

33. class state extends uvm_component; 34. city Capital_city;

35. `uvm_component_utils(state)

36. function new(string name, uvm_component parent); 37. super.new(name, parent); 38. endfunction : new 39. function void build(); 40. super.build();

41. Capital_city = city::type_id::create(\ 42. endfunction : build

43. function void end_of_elaboration(); 44. this.print();

45. endfunction : end_of_elaboration 46. endclass : state

47. state Florida = state::type_id::create(\ 48. state New_York = state::type_id::create(\ 49. // Start UVM Phases 50. initial run_test();

51. initial #100 global_stop_request(); 52. endmodule : test

第4行:street类定义。由于street没有子组件,所以不需要build()方法。new()和build()方法仅仅调用super.new()和super.build().【补充说明:如果没有定义build()方法,将会调用父类中的build方法,也就是super.build()方法。这是虚函数的特点:如果有就用自己的,如果没有,就用父类的】

第9行:run()方法打印一些信息


UVM实战指南(4).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:《苹果树上的外婆》整本书读书规划

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: