UVM中的config_db机制传递interface

(1)定义interface

interface my_if(input clk, input rst_n);

 logic [7:0] data;
 logic valid;

 endinterface

(2)在tb中使用interface

        定义了interface后,在top_tb中实例化DUT时,就可以直接使用。
        先实例化interface

  my_if input_if(clk, rst_n);
  my_if output_if(clk, rst_n);

        将interface与dut绑定

dut my_dut(.clk(clk),
 .rst_n(rst_n),
 .rxd(input_if.data),
 .rx_dv(input_if.valid),
 .txd(output_if.data),
 .tx_en(output_if.valid));

(3)在driver中使用interface

        不能在class中直接例化interface,向下面的代码是错误的:

class my_driver extends uvm_driver;
my_if drv_if;
…
endclass

        在类中使用的是virtual interface。如下面的代码所示:

class my_driver extends uvm_driver;

   virtual my_if vif;
    ...
endclass

        在声明了vif后,就可以在main_phase中使用如下方式驱动其中的信号:

task my_driver::main_phase(uvm_phase phase);
   phase.raise_objection(this);
   `uvm_info("my_driver", "main_phase is called", UVM_LOW);
   vif.data <= 8'b0; 
   vif.valid <= 1'b0;
   while(!vif.rst_n)
      @(posedge vif.clk);
   for(int i = 0; i < 256; i++)begin
      @(posedge vif.clk);
      vif.data <= $urandom_range(0, 255);
      vif.valid <= 1'b1;
      `uvm_info("my_driver", "data is drived", UVM_LOW);
   end
   @(posedge vif.clk);
   vif.valid <= 1'b0;
   phase.drop_objection(this);
endtask

(4)把top_tb中的input_if和my_driver中的vif对应起来

        最简单的方法莫过于直接赋值。此时一 个新的问题又摆在了面前:在top_tb中,通过run_test语句建立了一个my_driver的实例,但是应该如何引用这个实例呢?不可能像 引用my_dut那样直接引用my_driver中的变量:top_tb.my_dut.xxx是可以的,但是top_tb.my_driver.xxx是不可以的。这个问题的终极 原因在于UVM通过run_test语句实例化了一个脱离了top_tb层次结构的实例,建立了一个新的层次结构。
        对于这种脱离了top_tb层次结构,同时又期望在top_tb中对其进行某些操作的实例,UVM引进了config_db机制。在config_db机 制中,分为set和get两步操作。所谓set操作,读者可以简单地理解成是“寄信”,而get则相当于是“收信”。在top_tb中执行set操作

initial begin
   uvm_config_db#(virtual my_if)::set(null, "uvm_test_top", "vif", input_if);
end

        在my_driver中,执行get操作:

   virtual function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      `uvm_info("my_driver", "build_phase is called", UVM_LOW);
      if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
         `uvm_fatal("my_driver", "virtual interface must be set for vif!!!")
   endfunction

        这里引入了build_phase。与main_phase一样,build_phase也是UVM中内建的一个phase当UVM启动后,会自动执行 build_phase。build_phase在new函数之后main_phase之前执行在build_phase中主要通过config_db的set和get操作来传递一些数据, 以及实例化成员变量等。需要注意的是,这里需要加入super.build_phase语句,因为在其父类的build_phase中执行了一些必要的操 作,这里必须显式地调用并执行它。build_phase与main_phase不同的一点在于,build_phase是一个函数phase,而main_phase是一个 任务phase,build_phase是不消耗仿真时间的。build_phase总是在仿真时间($time函数打印出的时间)为0时执行
        在build_phase中出现了uvm_fatal宏,uvm_fatal宏是一个类似于uvm_info的宏,但是它只有两个参数,这两个参数与uvm_info宏 的前两个参数的意义完全一样。与uvm_info宏不同的是,当它打印第二个参数所示的信息后,会直接调用Verilog的finish函数来结 束仿真。uvm_fatal的出现表示验证平台出现了重大问题而无法继续下去,必须停止仿真并做相应的检查。所以对于uvm_fatal来 说,uvm_info中出现的第三个参数的冗余度级别是完全没有意义的,只要是uvm_fatal打印的信息,就一定是非常关键的,所以无 需设置第三个参数。
        config_db的set和get函数都有四个参数,这两个函数的第三个参数必须完全一致。set函数的第四个参数表示要将哪个interface 通过config_db传递给my_driver,get函数的第四个参数表示把得到的interface传递给哪个my_driver的成员变量set函数的第二个参 数表示的是路径索引,即在2.2.1节介绍uvm_info宏时提及的路径索引。在top_tb中通过run_test创建了一个my_driver的实例,那么 这个实例的名字是什么呢?答案是uvm_test_topUVM通过run_test语句创建一个名字为uvm_test_top的实例
        无论传递给run_test的参数是什么,创建的实例的名字都为uvm_test_top。由于set操作的目标是my_driver,所以set函数的第二 个参数就是uvm_test_top。
        set函数与get函数使用双冒号是因为这两个函数都是静态函数,而 uvm_config_db#(virtual my_if)则是一个参数化的类,其参数就是要寄信的类型,这里是virtual my_if。

(5)通过config_db机 制向变量传递值

        假如要向my_driver的var变 量传递一个int类型的数据,那么可以使用如下方式:

initial begin
uvm_config_db#(int)::set(null, "uvm_test_top", "var", 100);
end

        而在my_driver中应该使用如下方式:

class my_driver extends uvm_driver;
    int var;
    virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info("my_driver", "build_phase is called", UVM_LOW);
    if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
    `uvm_fatal("my_driver", "virtual interface must be set for vif!!!")
    if(!uvm_config_db#(int)::get(this, "", "var", var))
    `uvm_fatal("my_driver", "var must be set!!!")
endfunction

        从这里可以看出,可以向my_driver中“寄”许多信。上文列举的两个例子是top_tb向my_driver传递了两个不同类型的数据,其 实也可以传递相同类型的不同数据。假如my_driver中需要两个my_if,那么可以在top_tb中这么做:

initial begin
    uvm_config_db#(virtual my_if)::set(null, "uvm_test_top", "vif", input_if);
    uvm_config_db#(virtual my_if)::set(null, "uvm_test_top", "vif2", output_if);
end

        在my_driver中这么做:

virtual my_if vif;
virtual my_if vif2;
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info("my_driver", "build_phase is called", UVM_LOW);
    if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
    `uvm_fatal("my_driver", "virtual interface must be set for vif!!!")
    if(!uvm_config_db#(virtual my_if)::get(this, "", "vif2", vif2))
    `uvm_fatal("my_driver", "virtual interface must be set for vif2!!!")
endfunction

        ​​​​​​​注意:set和get函数,这两个函数的第三个参数必须完全一致

参考:UVM实战



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值