*2.3.4_封装成agent

上一节在验证平台中加入monitor时,读者看到了driver和monitor之间的联系:两者之间的代码高度相似。其本质是因为二者处理的是同一种协议,在同样一套既定的规则下做着不同的事情。由于二者的这种相似性,UVM中通常将二者封装在一起,成为一个agent。因此,不同的agent就代表了不同的协议。



代码清单 2-33

文件:src/ch2/section2.3/2.3.4/my_agent.sv

4 class my_agent extends uvm_agent ;

5   my_driver drv;

6   my_monitor mon;

7

8   function new(string name, uvm_component parent);

9     super.new(name, parent);

10   endfunction

11

12   extern virtual function void build_phase(uvm_phase phase);

13   extern virtual function void connect_phase(uvm_phase phase);

14

15   `uvm_component_utils(my_agent)  //注意此处不需要分号

16 endclass

17

18

19 function void my_agent::build_phase(uvm_phase phase);

20   super.build_phase(phase);

21   if (is_active == UVM_ACTIVE) begin

22    drv = my_driver::type_id::create("drv", this);

23   end

24   mon = my_monitor::type_id::create("mon", this);

25 endfunction

26

27 function void my_agent::connect_phase(uvm_phase phase);

28   super.connect_phase(phase);

29 endfunction



所有的agent都要派生自uvm_agent类,且其本身是一个component,应该使用uvm_component_utils宏来实现factory注册。

这里最令人困惑的可能是build_phase中为何根据is_active这个变量的值来决定是否创建driver的实例。is_active是uvm_agent的一个成员变量,从UVM的源代码中可以找到它的原型如下:



代码清单 2-34

来源:UVM源代码

uvm_active_passive_enum is_active = UVM_ACTIVE;



而uvm_active_passive_enum是一个枚举类型变量,其定义为:



代码清单 2-35

来源:UVM源代码

typedef enum bit { UVM_PASSIVE=0, UVM_ACTIVE=1 } uvm_active_passive_enum;



这个枚举变量仅有两个值:UVM_PASSIVE和UVM_ACTIVE。在uvm_agent中,is_active的值默认为UVM_ACTIVE,在这种模式下,是需要实例化driver的。那么什么是UVM_PASSIVE模式呢?以本章的DUT为例,如图2-5所示,在输出端口上不需要驱动任何信号,只需要监测信号。在这种情况下,端口上是只需要monitor的,所以driver可以不用实例化。

在把driver和monitor封装成agent后,在env中需要实例化agent,而不需要直接实例化driver和monitor了:



代码清单 2-36

文件:src/ch2/section2.3/2.3.4/my_env.sv

4 class my_env extends uvm_env;

5

6   my_agent  i_agt;

7   my_agent  o_agt;

13   virtual function void build_phase(uvm_phase phase);

14     super.build_phase(phase);

15     i_agt = my_agent::type_id::create("i_agt", this);

16     o_agt = my_agent::type_id::create("o_agt", this);

17     i_agt.is_active = UVM_ACTIVE;

18     o_agt.is_active = UVM_PASSIVE;

19   endfunction

22 endclass



完成i_agt和o_agt的声明后,在my_env的build_phase中对它们进行实例化后,需要指定各自的工作模式是active模式还是passive模式。现在,整棵UVM树变为了如图2-6所示形式。

由于agent的加入,driver和monitor的层次结构改变了,在top_tb中使用config_db设置virtual my_if时要注意改变路径:



代码清单 2-37

文件:src/ch2/section2.3/2.3.4/top_tb.sv

48 initial begin

49    uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.i_agt.drv", "vif", input_if);

50    uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.i_agt.mon", "vif", input_if);

51    uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.o_agt.mon", "vif", output_if);

52 end



在加入了my_agent后,UVM的树形结构越来越清晰。

首先,只有uvm_component才能作为树的结点,像my_transaction这种使用uvm_object_utils宏实现的类是不能作为UVM树的结点的。

其次,在my_env的build_phase中,创建i_agt和o_agt的实例是在build_phase中;在agent中,创建driver和monitor的实例也是在build_phase中。

按照前文所述的build_phase的从树根到树叶的执行顺序,可以建立一棵完整的UVM树。

UVM要求UVM树最晚在build_phase时段完成,如果在build_phase后的某个phase实例化一个component:



class my_env extends uvm_env;

virtual function void build_phase(uvm_phase phase);

super.build_phase(phase);

endfunction

virtual task main_phase(uvm_phase phase);

i_agt = my_agent::type_id::create("i_agt", this);

o_agt = my_agent::type_id::create("o_agt", this);

i_agt.is_active = UVM_ACTIVE;

o_agt.is_active = UVM_PASSIVE;

endtask

endclass



如上所示,将在my_env的build_phase中的实例化工作移动到main_phase中,UVM会给出如下错误提示:



UVM_FATAL @ 0: i_agt [ILLCRT] It is illegal to create a component
(‘i_agt‘ under ‘uvm_test_top‘) after the build phase has ended.



那么是不是只能在build_phase中执行实例化的动作呢?答案是否定的。其实还可以在new函数中执行实例化的动作。如可以在my_agent的new函数中实例化driver和monitor:



代码清单 2-39

function new(string name, uvm_component parent);

super.new(name, parent);

if (is_active == UVM_ACTIVE) begin

drv = my_driver::type_id::create("drv", this);

end

mon = my_monitor::type_id::create("mon", this);

endfunction



这样引起的一个问题是无法通过直接赋值的方式向uvm_agent传递is_active的值。在my_env的build_phase(或者new函数)中,向i_agt和o_agt的is_active赋值,根本不会产生效果。因此i_agt和o_agt都工作在active模式(is_active的默认值是UVM_ACTIVE),这与预想差距甚远。要解决这个问题,可以在my_agent实例化之前使用config_db语句传递is_active的值:

代码清单 2-40

class my_env extends uvm_env;

virtual function void build_phase(uvm_phase phase);

super.build_phase(phase);

uvm_config_db#(uvm_active_passive_enum)::set(this, "i_agt", "is_active", UVM_ACTIVE);

uvm_config_db#(uvm_active_passive_enum)::set(this, "o_agt", "is_active", UVM_PASSIVE);

i_agt = my_agent::type_id::create("i_agt", this);

o_agt = my_agent::type_id::create("o_agt", this);

endfunction

endclass

class my_agent extends uvm_agent ;

function new(string name, uvm_component parent);

super.new(name, parent);

uvm_config_db#(uvm_active_passive_enum)::get(this, "", "is_active", is_active);

if (is_active == UVM_ACTIVE) begin

drv = my_driver::type_id::create("drv", this);

end

mon = my_monitor::type_id::create("mon", this);

endfunction

endclass

只是UVM中约定俗成的还是在build_phase中完成实例化工作。因此,强烈建议仅在build_phase中完成实例化。

时间: 2024-12-17 19:42:41

*2.3.4_封装成agent的相关文章

(原)编写JAVA工具之json自动封装成pojo

代码在最后 我个人是不太喜欢http和json,可能是游戏做的多了的原因的,对通信协议和通信方式特敏感,因此即使是做应用我也会选择rpc而非http,但是有时候因为各种原因,还是不的不处理标准的http+json的东西. 这一次也确实需要处理一大串json,就是将一大堆的json转换成标准的java pojo.也许小json串我们可以直接用JSONObject去提值就行了,但是如果json是这样: 一个拥有近百个不一样的字段的pojo,如果我们需要单独的去取值估计会疯掉,这还不是主要的,更蛋疼的

Asp.net Core中使用NLog,并封装成公共的日志方法

1.安装NLog "NLog.Extensions.Logging": "1.0.0-rtm-alpha4" 2.配置NLog public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging&quo

UDP(socket)接和数据案例封装成C++代码

 配置QT下的pro文件 TEMPLATE = app CONFIG += console CONFIG -= app_bundle CONFIG -= qt   LIBS += -lWs2_32   ##标示使用window下的Ws2_32.lib,-l表示要链接后面的库 #-lWs2_32,link Ws2_32.lib   SOURCES += main.cpp \     udp.cpp   HEADERS += \     udp.h 编写udp.h文件 #ifndef UDP_H

linux下把log4cxx封装成so动态库文件(一)

这是一个经常遇到的问题,在软件开发过程中,需要将某些功能封装成一个独立的模块,这样维护升级也很方便.现在我们就要把开源日志库log4cxx封装成so动态加载库文件. 在上一篇文章<log4cxx日志库RedHat下安装>中,我们已经将log4cxx安装在home/mac/log4cxx/log4cxx下了,那么接下来的操作我们就继续在这个路径下进行. 还是先tree一下/home/mac/log4cxx这个目录吧 log4cxx ---apr ---apr-util ---log4cxx 那再

如何将路由器封装成帧中继

在学习OSPF的时候会使用到帧中继,那如何将路由器当帧中继网络来使用呢?下面帖上一篇配置和介绍给大家看看.模拟环境拓扑如下图: FR: Building configuration... Current configuration : 1632 bytes ! version 12.4 service timestamps debug datetime msec service timestamps log datetime msec no service password-encryption

structs2 jsp页面参数封装成类传递到action

中途切入一个系统的维护,而我又是菜鸟. 系统要实现从前端jsp页面输入查询条件,传入后台action进行处理.根据原来的系统本身的代码大概明白是jsp里ognl表达式传参数过去,但是一直不成功.百度各种办法,找到下面方法都试过,好像都不行.找耳挠腮搞半天才发现,我ognl表达式里的值得大小写和action里的类实例名不一致,真是不能更二咯-.- 对齐了jsp里的ognl表达式和action里的类实例名后,问题解决了.把我搜到的structs2 jsp传参数到后台action的方法记录下来,抄一遍

为什么要用Hibernate框架? 把SessionFactory,Session,Transcational封装成包含crud的工具类并且处理了事务,那不是用不着spring了?

既然用Hibernate框架访问管理持久层,那为何又提到用Spring来管理以及整合Hibernate呢?把SessionFactory,Session,Transcational封装成包含crud的工具类并且处理了事务,那不是用不着spring了? Hibernate操作的步骤如下: 1. 获得Configuration对象 2. 创建SessionFactory 3. 创建Session 4. 打开事务 5. 进行持久化操作.比如上面的添加用户操作 6. 提交事务 7. 发生异常,回滚事务

使用Cordova框架把Webapp封装成Hybrid App实践——Android篇

公司没有IOS和没有安卓开发人员,前端后端都是需要自己玩前几天技术经理说有一个需求要把webapp封装成Hybrid App,现已完成.记录一下从中遇到的问题和需要用到的开发环境的配置 将Webapp封装成Hybrid App有如下步骤 1.下载安装1.8的JDK,并且配置环境变量        (注意:最新版本的cordova,必须要下载1.8的JDK不然会报错) 2.下载安装Ant构建工具并且配置环境变量      (注意:Ant目录不能是中文,不然编译不成功) 3.下载安装android并

将HTML5封装成android应用APK文件的几种方法(转载)

越来越多的开发者热衷于使用html5+JavaScript开发移动Web App.不过,HTML5 Web APP的出现能否在未来取代移动应用,就目前来说,还是个未知数.一方面,用户在使用习惯上,不喜欢在浏览器上输入复杂的网址:另一方面,Html5 Web App 存放在服务器端,在每次使用时需要进行数据传递,会造成流量浪费.有些开发者不想接触复杂的JAVA代码,那么,有什么办法,既可以使用HTMl5开发应 用,又可以将其简单封装成APK文件呢? 一.Android SDK中的WebView1.