UVM验证方法学_config_db机制

config_db机制是uvm中很重要的机制之一。由于验证平台的结构往往会比较复杂,其中的组件如果要进行互相通信和参数传递,则需要一种高效且稳妥的办法,这就是config_db机制的意义。 

目录

一、config_db机制概述

(1)路径

(2)set和get

(3)省略get函数

二、跨层次多重设置

三、非直线获取

四、对通配符的支持

五、保证传递的正确

六、调试

总结


一、config_db机制概述

uvm树形结构的节点,往往需要高层次的组件来下发环境参数,或者通过配置来进行环境模式的变更。例如interface,环境中的driver和monitor都需要用到interface和DUT连接,interface往往在top中例化,输入不同的时钟和复位信号。interface例化好了之后就需要进行传递,传递的方法就是config_db机制。

传递的过程有两个信息很重要:路径和名称。

(1)路径

先说component。使用get_full_name()可以获得component的路径,也就是在整个树形结构中的层次关系。最顶层的module top例化之后的名字为__top__,而testcase的名称为uvm_test_top,所显示的绝对路径会从uvm_test_top开始。

例如driver,在这张图中的绝对路径为: uvm_test_top.env.i_agt.drv。

当然,使用绝对路径太过冗余,更多的时候会使用相对路径。例如driver相对于testcase的路径为:this.env.i_agt.drv;相对于env的路径为:this.i_agt.drv。路径的正确,是进行传递的前提。

(2)set和get

假如有人给你寄了一封信,那么这封信寄到需要满足三个条件:有人寄信(寄信地址正确),有人收信(收信地址正确),信上有双方达成一致的收信人名字。这几个条件就是config_db机制的参数。set函数就是寄信,get函数就是收信。

config_db机制共有四个参数。

在set函数中:

① 前两个参数合起来组成目标路径,必须保证正确。第一个参数是component实例的指针,第二个参数则是相对于该实例的路径。

② 第三个参数表示传递过程的名称,该参数必须和get函数中一致。

③ 最后一个参数表示需要set的变量。

在get函数中:

① 前两个参数合起来组成目标路径,必须保证正确。第一个参数是component实例的指针,第二个参数则是相对于该实例的路径。如果第一个参数为this,则第二个参数为空。

② 第三个参数表示传递过程的名称,该参数必须和set函数中一致。

③ 最后一个参数表示需要get的变量。

例如,在top中例化了一个信号wr_stop_sig,需要传递给driver。根据实例化的名称,set和get函数分别为:

uvm_config_db#(int)::set(null,"uvm_test_top.fifo_env.wr_agt.drv","wr_stop_sig",wr_stop_sig)
uvm_config_db#(int)::get(this,"","wr_stop_sig",wr_stop_sig);

因为是在top中set,第一个参数为null,会自动替换为uvm_root::get(),即uvm_top。

set和get的第三个参数必须保证一致。第四个参数则根据当前的定义,为了方便可以和第三个参数保持一致。

(3)省略get函数

首先不推荐这种用法。set和get一般都是成对出现,但是get可以省略。需要满足几个条件:

① 组件必须使用uvm_component_utils宏注册。

② 变量必须使用uvm_field_int宏注册。

③ set函数的第三个参数必须与所要get的变量名字一致。

例如,在driver中使用transaction中的filed_automation机制定义变量

class wr_driver extends uvm_driver#(wr_transaction);
    int test_sig;

    `uvm_component_utils_begin(wr_driver)
        `uvm_field_int(test_sig,UVM_ALL_ON)
    `uvm_component_utils_end

    virtual wr_interface wr_drv_if;
    string name;
    function new(string name = "",
                 uvm_component parent = null);
        super.new(name,parent);
        this.name = name;
        test_sig = 5;
    endfunction

    extern virtual function void build_phase(uvm_phase phase);
    extern virtual function void connect_phase(uvm_phase phase);
    extern virtual task reset_phase(uvm_phase phase);
    extern virtual task main_phase(uvm_phase phase);
    extern virtual task drive_tr(input wr_transaction req);

endclass:wr_driver

在top中传递变量:

int test_sig = 8;

initial begin
    uvm_config_db#(int)::set(null,"uvm_test_top.fifo_env.wr_agt.drv","test_sig",test_sig);
end

driver的build_phase中执行super之后,就会自行完成get。

    function void wr_driver::build_phase(uvm_phase phase);
        `uvm_info(this.name,$sformatf("test_sig=%0d",test_sig),UVM_LOW)
        super.build_phase(phase);
        `uvm_info(this.name,$sformatf("test_sig=%0d",test_sig),UVM_LOW)

        `uvm_info(this.name,"build_phase active.",UVM_LOW)
        if(!uvm_config_db#(virtual wr_interface)::get(this,"","wr_drv_if",wr_drv_if))begin
            `uvm_fatal(this.name,"wr_driver interface fatal!")
        end
    endfunction

 查看log

UVM_INFO ../tc/tc_sanity.sv(30) @ 0.00ns: uvm_test_top [uvm_test_top] build_phase active.
UVM_INFO ../ver/env.sv(33) @ 0.00ns: uvm_test_top.fifo_env [fifo_env] build_phase active.
UVM_INFO ../ver/scoreboard.sv(36) @ 0.00ns: uvm_test_top.fifo_env.scb [scb] build_phase active.
UVM_INFO ../ver/wr_agent/wr_agent.sv(32) @ 0.00ns: uvm_test_top.fifo_env.wr_agt [wr_agt] build_phase active.
UVM_INFO ../ver/wr_agent/wr_driver.sv(35) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.drv [drv] test_sig=5
UVM_INFO ../ver/wr_agent/wr_driver.sv(37) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.drv [drv] test_sig=8
UVM_INFO ../ver/wr_agent/wr_driver.sv(39) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.drv [drv] build_phase active.
UVM_INFO ../ver/wr_agent/wr_monitor.sv(29) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.mon [mon] build_phase active.
UVM_INFO ../ver/wr_agent/wr_sequencer.sv(28) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr [sqr] build_phase active.

test_sig最开始赋值为5,通过get之后值更改为8。

对于set语句则无法省略。这种省略get语句的用法有局限性,而且会影响代码可读性,并不推荐使用。

二、跨层次多重设置

考虑一种多次设置,只获取依次的情况。uvm中对于多次的设置,采用层次越高优先级越高的原则。对于树形结构,层次越高意味着越靠近用户,也就意味着越符合用户的真实意图,适合于重用。如果需要对参数进行修改,在高层次中修改更加便捷高效,设想如果要跨过层层结构去修改某个参数,则很容易出现问题。

例如在testcase和env中同时进行set,则最终获取到的值以testcase中为准。但是有前提,必须在set函数的第一个参数为this时,这种情况才会成立。

如果两次的set所使用的路径均为绝对路径,即set函数的第一个参数是uvm_root::get(),所有的路径起点都是uvm_top,这种情况只能比较时间,以时间更靠后的为准。uvm的phase机制中build_phase是自顶向下运行,也就意味着testcase会先于env进行创建。此时,最终获取到的值就会以env中的为准。

如果set函数的第一个参数有this,也有uvm_root::get(),则统一以后者为准。uvm_top在UVM树中具有最高的优先级。

可以总结为:

(1)set函数的第一个参数都是this,以层次更高的为准。

(2)set函数的第一个参数都是uvm_root::get(),以层次更低的为准(时间更靠后)。

(3)set函数的第一个参数有this也有uvm_root::get(),以使用uvm_root::get()的为准。

多次设置的场景构建要更加小心,避免因为传递参数错误所带来的问题。

除此之外,还有同层次的多重设置,这种场景有时候会用到,可能会有少量的测试值与其他的大部分不同,以构建一些corner case。对于同层次的多重设置,以时间更靠后为准。其实这种情况实现的方法就是在继承后子类中重新传参,即可完成多重设置,最终结果以子类新赋的值为准。

三、非直线获取

再次观察uvm树形结构,如果从uvm_test_top向env或者agent中的组件进行设置,即为直线传递。

现在考虑兄弟关系的组件(例如agent和scoreboard),或者叔侄关系的组件(例如driver和scoreboard),它们之间要进行设置就是非直线获取。

在phase机制中,兄弟级别的组件执行按照字典序,需要看例化后的具体名称。所以非直线的设置会有一定的风险,因为执行的情况并不确定,应该尽量避免这种情况的出现。非直线的获取也只需要设置其第一和第二个参数,可以在某些情况下避免config_db::set() 的冗余,例如在验证平台中多个组件需要使用同一个参数的时候。

四、对通配符的支持

假设如果需要向非树形结构节点的类传递参数,该如何实现呢?既然不是结构节点,就不是组件,自然就没法写出地址。尤其是sequence,sequence是环境中非常重要的一部分,但sequence是object而不是component。这个时候如果要用config_db机制对sequence进行set,就需要使用通配符。注意:除了对必要的object进行设置之外,对组件的设置不推荐使用通配符。

通配符其实就是不给出完整的路径。例如现在要对sequence进行set,sequence都需要交由sequencer处理,而sequencer的路径是可以给出的,所以要找到sequence只需要在启动这个sequence的sequencer后面,加上通配符。

在异步FIFO环境,由top向wr_sequence传递一个参数:

int wr_sig = 66;
initial begin
    uvm_config_db#(int)::set(null,"uvm_test_top.fifo_env.wr_agt.sqr.*","wr_sig",wr_sig);
end

在sequence中进行get

        int wr_sig;

        uvm_config_db#(int)::get(null,get_full_name(),"wr_sig",wr_sig);
        `uvm_info(this.name,$sformatf("wr_sig=%0d.",wr_sig),UVM_LOW)

get_full_name()获得了sequencer的路径加上例化sequence时传递的名字,用来找到sequence。

除此之外,如果对组件使用通配符,例如:

initial begin
    uvm_config_db#(int)::set(null,"uvm_test_top.fifo_env.wr_agt.*","wr_sig",wr_sig);
end

这时候wr_agt下的所有组件都可以接收到。这种虽然能简化代码,但是会使得set的路径和意图非常不清晰,不利于日后环境的重用。除非是对整个验证平台的结构有非常明确的了解,否则根本不清楚最终是设置给哪个目标的。所以对于组件来说,不建议使用通配符。

五、保证传递的正确

一个复杂的环境中可能要进行很多次传递,难免会出现错误。config_db机制有一个致命缺点,其set函数的第二个参数是字符串,如果字符串写错,那么就不能正确地设置参数值。针对这种情况uvm中提供了一个函数check_config_usage(),它可以显示出截止到此函数调用时有哪些参数是被设置过,但是却没有被获取过。该函数一般在connect_phase被调用:

function void tc_sanity::connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        `uvm_info(this.name,"connect_phase active.",UVM_LOW)

        ...

        check_config_usage();
endfunction

这样当出现传递错误时,uvm就会上报。


六、调试

config_db机制也可以进行调试。uvm提供了print_config函数来进行调试:

function void tc_sanity::connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        `uvm_info(this.name,"connect_phase active.",UVM_LOW)

        ...

        check_config_usage();
        print_config(1);
endfunction

参数1表示递归的查询;若为0则只显示当前component的信息。它会遍历整个环境的所有结点,找出哪些被设置过的信息对于它们是可见的。

UVM_INFO @ 0.00ns: uvm_test_top [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.drv [CFGPRT] visible resources:
rd_drv_if [/^uvm_test_top\.fifo_env\.rd_agt\.drv$/] : (virtual interface rd_interface#(8)) ?
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.drv.rsp_port [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.drv.seq_item_port [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.mon [CFGPRT] visible resources:
rd_mon_if [/^uvm_test_top\.fifo_env\.rd_agt\.mon$/] : (virtual interface rd_interface#(8)) ?
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.mon.ap [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.sqr [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.sqr.req_fifo [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.sqr.req_fifo.get_ap [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.sqr.req_fifo.get_peek_export [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.sqr.req_fifo.put_ap [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.sqr.req_fifo.put_export [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.sqr.rsp_export [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.sqr.seq_item_export [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.sqr.sqr_rsp_analysis_fifo [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.sqr.sqr_rsp_analysis_fifo.analysis_export [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.sqr.sqr_rsp_analysis_fifo.get_ap [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.sqr.sqr_rsp_analysis_fifo.get_peek_export [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.sqr.sqr_rsp_analysis_fifo.put_ap [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rd_agt.sqr.sqr_rsp_analysis_fifo.put_export [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rdmon_scb_fifo [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rdmon_scb_fifo.analysis_export [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rdmon_scb_fifo.get_ap [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rdmon_scb_fifo.get_peek_export [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rdmon_scb_fifo.put_ap [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.rdmon_scb_fifo.put_export [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.scb [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.scb.rd_port [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.scb.wr_port [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.drv [CFGPRT] visible resources:
wr_drv_if [/^uvm_test_top\.fifo_env\.wr_agt\.drv$/] : (virtual interface wr_interface#(8)) ?
-  
test_sig [/^uvm_test_top\.fifo_env\.wr_agt\.drv$/] : (int) 8
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.drv.rsp_port [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.drv.seq_item_port [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.mon [CFGPRT] visible resources:
wr_mon_if [/^uvm_test_top\.fifo_env\.wr_agt\.mon$/] : (virtual interface wr_interface#(8)) ?
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.mon.ap [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr.req_fifo [CFGPRT] visible resources:
wr_sig [/^uvm_test_top\.fifo_env\.wr_agt\.sqr\..*$/] : (int) 66
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr.req_fifo.get_ap [CFGPRT] visible resources:
wr_sig [/^uvm_test_top\.fifo_env\.wr_agt\.sqr\..*$/] : (int) 66
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr.req_fifo.get_peek_export [CFGPRT] visible resources:
wr_sig [/^uvm_test_top\.fifo_env\.wr_agt\.sqr\..*$/] : (int) 66
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr.req_fifo.put_ap [CFGPRT] visible resources:
wr_sig [/^uvm_test_top\.fifo_env\.wr_agt\.sqr\..*$/] : (int) 66
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr.req_fifo.put_export [CFGPRT] visible resources:
wr_sig [/^uvm_test_top\.fifo_env\.wr_agt\.sqr\..*$/] : (int) 66
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr.rsp_export [CFGPRT] visible resources:
wr_sig [/^uvm_test_top\.fifo_env\.wr_agt\.sqr\..*$/] : (int) 66
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr.seq_item_export [CFGPRT] visible resources:
wr_sig [/^uvm_test_top\.fifo_env\.wr_agt\.sqr\..*$/] : (int) 66
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr.sqr_rsp_analysis_fifo [CFGPRT] visible resources:
wr_sig [/^uvm_test_top\.fifo_env\.wr_agt\.sqr\..*$/] : (int) 66
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr.sqr_rsp_analysis_fifo.analysis_export [CFGPRT] visible resources:
wr_sig [/^uvm_test_top\.fifo_env\.wr_agt\.sqr\..*$/] : (int) 66
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr.sqr_rsp_analysis_fifo.get_ap [CFGPRT] visible resources:
wr_sig [/^uvm_test_top\.fifo_env\.wr_agt\.sqr\..*$/] : (int) 66
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr.sqr_rsp_analysis_fifo.get_peek_export [CFGPRT] visible resources:
wr_sig [/^uvm_test_top\.fifo_env\.wr_agt\.sqr\..*$/] : (int) 66
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr.sqr_rsp_analysis_fifo.put_ap [CFGPRT] visible resources:
wr_sig [/^uvm_test_top\.fifo_env\.wr_agt\.sqr\..*$/] : (int) 66
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr.sqr_rsp_analysis_fifo.put_export [CFGPRT] visible resources:
wr_sig [/^uvm_test_top\.fifo_env\.wr_agt\.sqr\..*$/] : (int) 66
-  
UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wrmon_scb_fifo [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wrmon_scb_fifo.analysis_export [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wrmon_scb_fifo.get_ap [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wrmon_scb_fifo.get_peek_export [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wrmon_scb_fifo.put_ap [CFGPRT] visible resources:

UVM_INFO @ 0.00ns: uvm_test_top.fifo_env.wrmon_scb_fifo.put_export [CFGPRT] visible resources:

还可以使用一个命令行参数UVM_CONFIG_DB_TRACE来对config_db进行调试,同样也可以加入到Makefile当中使用。

这里说一下default_sequence。对于sequence的启动,一般会选择default_sequence的方法。这种方法和config_db非常类似,同样具有四个参数,前两个参数同样用来组成路径。这个时候如果同样出现了字符串错误,uvm是无法上报的,而整个环境会因为无法启动sequence而根本不会运行。所以对于这种启动方法,也有一些小技巧,后面会详细讨论关于sequence的内容。


总结

config_db机制是uvm中很重要的机制之一。由于验证平台的结构往往会比较复杂,其中的组件如果要进行互相通信和参数传递,则需要一种高效且稳妥的办法,这就是config_db机制的意义。正确地运用config_db机制,能够帮助我们灵活地对环境进行控制,实现不同的场景。

你可能感兴趣的:(UVM验证方法学,fpga开发,linux,模块测试,硬件工程,测试用例)