上一节在验证平台中加入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中完成实例化。

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

  1. .NET 同步与异步之封装成Task(五)

    本随笔续接:.NET 实现并行的几种方式(四) 前篇随笔已经介绍了几种可以实现并发的方式,其中异步方法.是最简便的方式.而 异步方式是基于 Task 和 async修饰符和await运算符实现的. 换 ...

  2. 将HTML5封装成android应用APK文件的几种方法

    越来越多的开发者热衷于使用html5+JavaScript开发移动Web App.不过,HTML5 Web APP的出现能否在未来取代移动应用,就目前来说,还是个未知数.一方面,用户在使用习惯上,不喜 ...

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

    越来越多的开发者热衷于使用html5+JavaScript开发移动Web App.不过,HTML5 Web APP的出现能否在未来取代移动应用,就目前来说,还是个未知数.一方面,用户在使用习惯上,不喜 ...

  4. 如何将Js代码封装成Jquery插件

    很多相同的Jquery代码会在很多页面使用,每次都复制粘贴太麻烦了,不如封装成一个Jquery插件就方便了,至于影响网页的速度不,我就没有测试了哈. 代码如下 这是一个自定闪烁打印文字的Jquery特 ...

  5. 将Python脚本封装成exe可执行文件 转

    将Python脚本封装成exe可执行文件 http://www.cnblogs.com/renzo/archive/2012/01/01/2309260.html  cx_freeze是用来将 Pyt ...

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

    1.安装NLog "NLog.Extensions.Logging": "1.0.0-rtm-alpha4" 2.配置NLog public void Conf ...

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

    作为下一代的网页语言,HTML5拥有很多让人期待已久的新特性.HTML5的优势之一在于能够实现跨平台游戏编码移植,现在已经有很多公司在移动 设备上使用HTML5技术.随着HTML5跨平台支持的不断增强 ...

  8. hibernate将本地SQL查询结果封装成对象

    hibernate将本地SQL查询结果封装成对象 不知道大家有没有碰过这种情况,迫于很多情况只能用native SQL来查询(如:复杂统计等),然而使用native查询后,结果会被放到object里, ...

  9. jquery自动将form表单封装成json的具体实现

    前端页面:<span style="font-size:14px;"> <form action="" method="post&q ...

随机推荐

  1. 【转】如何避免OOM总结

    原文地址:http://www.csdn.net/article/2015-09-18/2825737/3 减小对象的内存占用 避免OOM的第一步就是要尽量减少新分配出来的对象占用内存的大小,尽量使用 ...

  2. Firefox mobile (android) and orientationchange

    Firefox for Android does not support the orientationchange event but you can achieve the same result ...

  3. 深入理解js立即执行函数

    看过jQuery源码的人应该知道,jQuery开篇用的就是立即执行函数.立即执行函数常用于第三方库,好处在于隔离作用域,任何一个第三方库都会存在大量的变量和函数,为了避免变量污染(命名冲突),开发者们 ...

  4. Unity&C# SingerMonoManager泛型单例

    管理各种管理器 ///为什么需要单例 ///单例模式核心在于对于某个单例类,在系统中同时只存在唯一一个实例,并且该实例容易被外界所访问: ///避免创建过多的对象,意味着在内存中,只存在一个实例,减少 ...

  5. 1-初步了解C#-语言基础

    本篇博客对应视频讲解 前言 终于开始讲语言了,我选择讲C#.为什么呢?因为C#是很好的入门语言,简洁.全面,面向对象类型安全,开发体验好,上手容易.而其他的语言也已经有人讲了很多了,C#相对来说要少一 ...

  6. Mounting VMDK files in Linux

    1.用 loop 方式挂载 vmdk 文件 losetup /dev/loop0 docker_pull-flat.vmdk 2.查看分区 [root@localhost]# parted /dev/ ...

  7. linux shell中"2>&1"含义

    在计划任务中经常可以看到.例如我们公司的计划任务举例: */ * * * * root cd /opt/xxxx/test_S1/html/xxxx/admin; php index.php task ...

  8. python中多线程,多进程,多协程概念及编程上的应用

    1, 多线程 线程是进程的一个实体,是CPU进行调度的最小单位,他是比进程更小能独立运行的基本单位. 线程基本不拥有系统资源,只占用一点运行中的资源(如程序计数器,一组寄存器和栈),但是它可以与同属于 ...

  9. 面向对象之ajax

    1.Ajax发送请求的几个步骤 1. 创建 XMLHttpRequest 对象 var xhr = new XMLHttpRequest();//IE6 使用var xhr= new ActiveXO ...

  10. [转] Cisco路由器DNS配置

    禁用Web服务 Cisco路由器还在缺省情况下启用了Web服务,它是一个安全风险.如果你不打算使用它,最好将它关闭.举例如下: Router(config)# no ip http server 配置 ...