UVM Tutorial for Candy Lovers – 18. Configuration Database Revisited

Last updated: December 20, 2015

In the post, Configurations, we looked at the configuration flow of the jelly bean verification. We also looked at the behind the scenes of the configuration flow in the post, Configuration Database. This post will focus on the syntax and semantics of accessing the configuration database. In Configurations, we stored and retrieved the jelly_bean_if, jelly_bean_env_config, and jelly_bean_agent_config using the configuration database. The following figure depicts the component hierarchy used in Configurations on the left, and the configuration database (shown as clouds) on the right. The code snippets to access the database are shown in the middle.

Accessing Configuration Database
Accessing Configuration Database

Storing the jelly_bean_env_config

Let’s look at how to store and retrieve the jb_env_cfg (shown in gray in the figure) first as this might be the easiest to understand. The jelly_bean_base_test called set() function to store the jb_env_cfg in the database as follows.

uvm_config_db#( jelly_bean_env_config )::set( .cntxt( this ), .inst_name( "*" ), 
                                              .field_name( "jb_env_cfg" ), .value( jb_env_cfg ) )

The uvm_config_db is a parameterized class. In the above code, the uvm_config_db is specialized with the jelly_bean_env_config type. The cntxt (context) and inst_name (instance name) are used to create a scope in the database. The scope is created by concatenating the full name of the context and the instance name ({ cntxt.get_full_name(), ".", inst_name }). In the above example, the scope is { this.get_full_name(), ".", "*" }, which is evaluated to "uvm_test_top.*". Note that the full name of the jelly_bean_base_test is assigned to be "uvm_test_top" when the run_test() task is called in the top-level module (top). Note also that the "*" is a wildcard character that matches any components. The object handle of jb_env_cfg is stored under the name of "jb_env_cfg". The picture below conceptually shows how the jb_env_cfg is tagged in the database.

jb_env_cfg
The jb_env_cfg Stored in the Configuration Database

Retrieving the jelly_bean_env_config

The jb_env called get() function to retrieve the jb_env_cfg from the database as follows.

uvm_config_db#( jelly_bean_env_config )::get( .cntxt( this ), .inst_name( "" ), 
                                              .field_name( "jb_env_cfg" ), .value( jb_env_cfg ) )

The meanings of the arguments of the get() function are the same as those of the set() function. Similar to the set() function, the scope is defined as { cntxt.get_full_name(), ".", inst_name }. In the above code, the scope is evaluated to "uvm_test_top.jb_env". It is typical to use this as the cntxt and "" as the inst_name. Note that if the inst_name is empty (""), the dot (".") is also omitted. The get() function searches the database and tries to find the object that matches the type, scope, and field_name. Since the scope of the jb_env_cfg was defined as "uvm_test_top.*" in the database, the scope, "uvm_test_top.jb_env", successfully matches it.

Storing the jelly_bean_agent_config

Now let’s look at another example. This time, the jb_env stores the jb_agent_cfg, then the jb_agent1 retrieves it (shown in orange in the figure on the top). The jb_env called set() function to store the jb_agent_cfg in the database as follows.

uvm_config_db#( jelly_bean_agent_config )::set( .cntxt( this ), .inst_name( "jb_agent1*" ), 
                       .field_name( "jb_agent_cfg" ), .value( jb_env_cfg.jb_agent_cfg1 ) )

The uvm_config_db is specialized with the jelly_bean_agent_config type. The scope of the object is { this.get_full_name(), ".", "jb_agent1*" }, which is evaluated to "uvm_test_top.jb_env.jb_agent1*". Note that this scope matches jb_agent1 and any components under it. The jb_env_cfg.jb_agent_cfg1 is stored under the name of "jb_agent_cfg". The picture below conceptually shows how the jb_agent_cfg1 is tagged in the database.

The jb_agent_cfg1 Stored in the Configuration Database
The jb_agent_cfg1 Stored in the Configuration Database

Retrieving the jelly_bean_agent_config

The jb_agent1 called get() function to retrieve the jb_agent_cfg1 as follows.

uvm_config_db#( jelly_bean_agent_config )::get( .cntxt( this ), .inst_name( "" ), 
                                                .field_name( "jb_agent_cfg" ), .value( jb_agent_cfg ) )

The scope is { this.get_full_name(), ".", "" }, which is evaluated to "uvm_test_top.jb_env.jb_agent1". Since the scope of the jb_agent_cfg1 in the database is "uvm_test_top.jb_env.jb_agent1*", it successfully matches the scope defined by this get() function.

Storing the jelly_bean_if

Let’s look at the last example. The top-level module stores a virtual interface (shown in yellow in the figure on the top). The top module called set() function as follows.

uvm_config_db#( virtual jelly_bean_if )::set( .cntxt( null ), .inst_name( "uvm_test_top" ), 
                                              .field_name( "jb_if1" ), .value( jb_if1 ) )

Two things to note here. The first is that we used null as the cntxt. This was because the top-level module is not a uvm_component and cannot obtain its full name by calling the get_full_name(). The second is that we used "uvm_test_top" as the inst_name. As we have seen, the "uvm_test_top" is the full name of the top-level test component. Thus, it is important to use this name as a part of the scope.
If the cntxt is null, the scope consists of the inst_name only, which is "uvm_test_top". The picture below conceptually shows how the jb_if1 is tagged in the database.

jb_if1
The jb_if1 Stored in the Configuration Database

Retrieving the jelly_bean_if

The jelly_bean_base_test called get() function to retrieve the jb_if1 as follows.

uvm_config_db#( virtual jelly_bean_if )::get( .cntxt( this ), .inst_name( "" ), 
                                              .field_name( "jb_if1" ), .value( jb_agent_cfg1.jb_if ) )

The scope is { this.get_full_name(), ".", "" }, which is evaluated to "uvm_test_top" ("." is not included if the inst_name is ""). Since the scope of the jb_if1 in the database is "uvm_test_top", it successfully matches the scope defined by this get() function.

Summary of the scopes

The table below summarizes which component matches the scopes defined in our example assuming get() function uses this as the cntxt and "" as the inst_name. Note that the scope "uvm_test_top.*" matches any components under the uvm_test_top, but it does not match the scope "uvm_test_top" (1). On the other hand, the scope "uvm_test_top" matches "uvm_test_top" only. It does not match any components under the uvm_test_top (2).

Component/Scope uvm_test_top.* uvm_test_top.jb_env.jb_agent1* uvm_test_top
jelly_bean_base_test (uvm_test_top) cross (1) cross tick (2)
uvm_test_top.jb_env tick cross cross
uvm_test_top.jb_env.jb_agent1 tick tick cross
uvm_test_top.jb_env.jb_agent2 tick cross cross

I hope this post helped to understand how to access the configuration database.

8 thoughts on “UVM Tutorial for Candy Lovers – 18. Configuration Database Revisited”

  1. The picture below conceptually shows how the jb_agent_cfg1 is tagged in the database
    Shouldn’t the scope be w wrong the scope should be “uvm_test_top.jb_env.jb_agent1*”, because the picture shows “uvm_test_top.jb_agent1*”

    I commented on the earlier post of configuration and asked for more details, Please avoid that comment Isee you added it in this post.
    Thanks a lot, the posts are a great learning help, I advised my friends to look at it too.

    Moses

  2. You did write that “the scope “uvm_test_top.*” matches any components under the uvm_test_top, but it does not match the scope “uvm_test_top””. But for agent_config you written that “”uvm_test_top.jb_env.jb_agent1*” will matches jb_agent1 and any components under it.

    Why for uvm_test_top wildcard will not match uvm_test_top as explained for jb_agent1.

    1. This is because "uvm_test_top.*" has a dot (.) before the wildcard (*). If the scope is "uvm_test_top*" (no dot), it would match any components under the uvm_test_top as well as the uvm_test_top itself.

  3. uvm_config_db#( virtual jelly_bean_if )::set( .cntxt( null ), .inst_name( “uvm_test_top” ),
    .field_name( “jb_if1” ), .value( jb_if1 ) )
    If we use * as inst_name, we can get interface anywhere in the hierarchy.
    Am I correct?

  4. Hi Keisuke,

    I have a question here, would you please take look,

    I want to pass the config to clk_seq which is start in a virtual sequence.

    If I set config in env , it will show v_seq.clk_clk_seq.m_config could not be gotten.

    uvm_config_db#(clk_base_config)::set(this, "*", "m_clk_cfg", m_clk_cfg);

    If I set config in test level, it will show v_seq.clk_clk_seq.m_config could not be gotten.

    uvm_config_db#(clk_base_config)::set(this, "*", "m_clk_cfg", m_clk_cfg);

    But if I use uvm_root::get(), in the test level, the config could be gotten.

    uvm_config_db#(clk_base_config)::set(uvm_root::get(), "*", "m_clk_cfg", m_clk_cfg);

    I just wonder if all the sequence (including virtual sequence) is instantiated in the level of uvm_root. and those objects are paralleled to uvm_test_top?

    Or Is there any better way to pass the config to sequence ?

    Best,

Leave a Reply