第三段:uvm_config_db与uvm_resource_db分析(二次更新)

 

初版内容:

    1)基础用法:我们在工程中主要是对virtual的interface用到了config_db,大概流程如下:

    首先我们在顶层中例化了interface,然后就用config_db::set把interface这样一个virtual interface放入resource_pool中,resource_pool也就是两张表,之后在所需要的时候调用config_db::get获取即可,config_db::set有4个参数,前两个组成一个范围,这个范围内的单位才可以通过get获取我放入资源池的数据,第三个参数是标签参数,在get时放入对应标签才能找到对应数据,第四个参数是我们需要放入资源池的数据。

    2)项目用法升级:

    上面是基础用法,实际中我们在virtual sequencer中放入,在子agent中get后,再次set到子agent的各个子component中,完成数据在各个agent之间的随机调用。

    3)底层原理分析:

    Virtual_interface解释:

    interface 和 module是一样的, 都是静态的变量, 也就是在程序开始时, 内存中就有了其实例.但是在class里使用virtual interface时之前有两部必须提前完成:

    定义:将接口作为一个类进行定义。

    实例化:在RTL级的顶层中对接口进行实例化。

    总结:定义一个interface,且实例化多个后,如果没有定义virtual,则在任何一个实例中修改了某个信号值,在其他实例中都会受到影响。如果定义了virtual,则每个实例独立。如果该interface只有一个实例,可用可不用virtual,有多个实例,需要virtual。更好的办法是,都加上virtual。virtual interface只是申明一个handle, 就好像一个指针一样, 可以再程序进行中进行construct, 所以class里必须是virtual interface

    Config解释:

       

    首先在官网的介绍中,uvm_config_db提供的是对uvm_resource_base和uvm_resource#(T)这两个类里(由uvm_object分出来)的内容的一些整体操作,如下图:

       

    图中的type和name就是刚才所说的放入数据的类型和标签。

       

       

    最下一层就是uvm_resource_pool了,它里面就是两个放资源的联合数组。一个按名字排的,一个按类型排的。

       

    最后梳理一下整个配置流程:

    首先在顶层调用config_db::set,该源码中主要是对rsrc_t(uvm_config_db类)的初始化,然后调用uvm_resource里面的write和set函数。write的作用主要是把传递进来的数据赋值给uvm_resource类的val,这个值是给下其它一些功能使用的(这个我们不关心)。然后是set函数,这就是真正把数据放入资源池的操作了。

    相应的config_db::get就是相应的逆向操作。获取配置的类型和标签,去资源池搜索目标数据,最后通过uvm_resource#(T)中的read函数读出数据。

二次更新内容:

    我的工程中主要是对virtual interface用到了config_db,流程是这样的:

    1.在TB(testbench)中例化了interface,然后通过config_db::set来把interface这个样的一个virtual interface放进resource_pool里面,resource_pool也就是两张表。放起来的目的是为了让需要使用virtual interface的component可以获取这个virtual interface。

module tb;
  reg clk;
  
  always #10 clk =~ clk;
  DUT_if 	_if (clk);

float64_add_DUT_RTL float64_add_DUT_RTL_1(
	.clk(clk),
	.rstN(_if.rstN),
	.start(_if.start),
	.fin(_if.fin),
	.a(_if.a),
	.b(_if.b),
	.return_value(_if.return_value));

  test t0;
  
  initial begin
    clk <= 0;
    uvm_config_db#(virtual DUT_if)::set(null, "uvm_test_top", "DUT_vif", _if);//注册interface
    run_test("test");
  end
  
  initial begin
    $dumpfile ("dump.vcd");
    $dumpvars;
  end
endmodule

    config_db::set一共有4个参数。

    a. 头两个参数的作用是合起来形成一个范围,只有在这个范围内的单位才可以通过config_db::get来获得我们set的东西。

    b. 第三个参数是我们自己瞎起的一个名字,就是个string型的标签,到时候系统在执行config_db::get的时候,就依据我们起的这个名字以及我们规定的类型(在这里类型就是virtual DUT_if)来在资源池里找我们要的东西。

    c. 第四个参数就是我们正儿八经要放进资源池的东西,我想应该就是放了个地址进type表和name表里面。

    2.那么谁要用到virtual interface呢,是agent中的monitor,driver。于是我们这么做,在test中通过config_db::get拿到已经写入资源池的virtual interface,然后通过config_db::set来重新设置一个virtual interface,并且设置它的范围是例化出来的ageent a0下面的所有单元都有权利调用它。

class test extends uvm_test;
  `uvm_component_utils(test)
  function new(string name = "test", uvm_component parent=null);
    super.new(name, parent);
  endfunction
  
  env e0;
  virtual DUT_if vif;
  
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    e0 = env::type_id::create("e0", this);
    if (!uvm_config_db#(virtual DUT_if)::get(this, "", "DUT_vif", vif))
      `uvm_fatal("TEST", "Did not get vif")
      
      uvm_config_db#(virtual DUT_if)::set(this, "e0.a0.*", "DUT_vif", vif);//
  endfunction

    这里我们注意,get函数的头两个参数就很简单了,因为跟set一样,头两个参数的作用只是指定范围,正常情况下都是在哪用在哪get,应该不会有故意要在A类里给B类get一个资源的这种操作,所以无脑this和""就可以了。

    后两个参数就是怎么set的怎么get。

    这样config_db做资源的传递就完成了。

    3.最后是具体到真正的使用者怎么用这个virtual interface。

    monitor的run_phase里面:

class monitor extends uvm_monitor;//monitor属于agent(a0),所以它是有权限来取vif的
  `uvm_component_utils(monitor)
  function new(string name="monitor", uvm_component parent=null);
    super.new(name, parent);
  endfunction
  
  uvm_analysis_port  #(transaction_item) mon_analysis_port;
  virtual DUT_if vif;
  uvm_event ev;
  
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if (!uvm_config_db#(virtual DUT_if)::get(this, "", "DUT_vif", vif))
      `uvm_fatal("MON", "Could not get vif")
    mon_analysis_port = new ("mon_analysis_port", this);
  endfunction

    driver的run_phase里面:

class driver extends uvm_driver #(transaction_item);              
  `uvm_component_utils(driver)
  function new(string name = "driver", uvm_component parent=null);
    super.new(name, parent);
  endfunction
  //声明interface
  virtual DUT_if vif;
  uvm_event ev;
  
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if (!uvm_config_db#(virtual DUT_if)::get(this, "", "DUT_vif", vif))
      `uvm_fatal("DRV", "Could not get vif")
    ev = uvm_event_pool::get_global("ev_ab");
  endfunction

    以上都是初级使用,在项目中不可能只有一个agent,下面升级下难度:(实用干货,高能注意)

    当我们使用virtual_sequencer将多个agent包括起来时,你考虑过如何让config_db正确下发到对应的agent的组件没有?

    这里我们可以采用分层法,如下所示:        

    可以将结构拆成三层,顶层下发到各个agent,agent收到后再次下发,最后使driver等拿到数据。

                          virtual_sequencer中的db进行set ---> 各个agent中的db先get再set ---> 各个组件的db进行get

    暂时写到这,之后有空再补充。

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃辣椒的年糕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值