zoukankan      html  css  js  c++  java
  • *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中完成实例化。

  • 相关阅读:
    Redis配置文件详解
    Redis基本操作-20150608
    Redis操作命令
    JedisPoolConfig配置
    jedis提供的功能
    配置Redis主从复制
    python数组查找算法---bisect二分查找插入
    python赋值和拷贝----一切皆对象,参数皆引用
    xml 解析 python
    进阶中级程序员需要做的事
  • 原文地址:https://www.cnblogs.com/YINBin/p/6843367.html
Copyright © 2011-2022 走看看