Why use uvm_config_db to pass vif or configuration object is recommended?

In uvm cookbook part:VirtInterfaceFunctionCallChain, it says that one of the disadvantage of assign_vi:
It is not reusable - If the test environment hierarchy changes, these functions must be updated
In the testcase, there is a assign_vi() like function assign_if:


class test_case extends uvm_test;
  test_env env;
  virtual interface test_if vif;
  ...
  function void build_phase (uvm_phase phase);
    this.vif = vif_pkg::vif;
    env = test_env::type_id::create("env", this);
  endfunction : build_phase

  function void connect_phase (uvm_phase phase);
    env.assign_if(vif);
  endfunction : connect_phase
  ...
endclass : test_case

If the hierarchy changed, use agent level instead of env:


class test_case extends uvm_test;
  test_agent agent;
  virtual test_if vif;
  ...
  function void build_phase (uvm_phase phase);
    this.vif = vif_pkg::vif;
    agent = test_agent::type_id::create("agent", this);
  endfunction : build_phase

  function void connect_phase (uvm_phase phase);
    agent.assign_if(vif);
  endfunction : connect_phase
  ...
endclass : test_case

Use config_db may not change the connect_phase() method:


class test_case extends uvm_test;
  test_env env;
  virtual test_if vif;
  ...
  function void build_phase (uvm_phase phase);
    this.vif = vif_pkg::vif;
    env = test_env::type_id::create("env", this);
  endfunction : build_phase

  function void connect_phase (uvm_phase phase);
    uvm_config_db #(virtual test_if)::set(this, "*", "test_if", vif);
  endfunction : connect_phase
  ...
endclass : test_case

and the changed one:


class test_case extends uvm_test;
  test_agent agent;
  virtual test_if vif;
  ...
  function void build_phase (uvm_phase phase);
    this.vif = vif_pkg::vif;
    agent = test_agent::type_id::create("agent", this);
  endfunction : build_phase

  function void connect_phase (uvm_phase phase);
    uvm_config_db #(virtual test_if)::set(this, "*", "test_if", vif);
  endfunction : connect_phase
  ...
endclass : test_case

In uvm cookbook part:UVM/Performance Guidelines, it says “Use specific strings with the uvm_config_db set() and get() calls”, so

uvm_config_db #(virtual test_if)::set(this, "*", "test_if", vif);

is not recommended. The connect_phase() code must be change also if use a specific string when hierarchy changes.

So I wonder why don’t we make directly assignments to set virtual interface handle or configuration object?

Thanks a lot!

In reply to seabeam:

That’s a very good point! It seems to me that different people wrote the two sections and they didn’t align on this. I have been thinking lately that using the config DB might not be necessary. The config DB is a singleton (actually a collection of singletons) and overuse of singletons is a code smell.

In reply to Tudor Timi:

Hi Tudor:
I’v tried to set-get 10,000 integer from parent to child, which uvm_config_db() methord takes 2.1s CPU time & nearly 87M Mem while direct assignment 0.3s CPU time & 3.7M Mem.
However, uvm_config_db() may not take place in specific scenario: sequence get resources from m_sequencer etc.
But is it needed to pass vif or configuration object through UVC hierarchy?

Every agent should have a configuration object that encapsulates all of the parameters that can be modified to control the agent’s behavior. Examples of this include the notion of the agent being ACTIVE or PASSIVE. Included in the configuration object should be the vif handle.

The agent configuration objects should be created and configured at the test level, giving the user the ability to control the agent behavior on a per-test basis. These configuration objects should then be passed to the respective agent using the uvm_config_db().

Using the uvm_config_db() enables a single call to configure the agent instead of using many different calls to set the various agent parameters.

In reply to cgales:

Hi cgales:
Here is an example,
configuration object:


class x_agent_config extends uvm_object;
  virtual x_if  x_port;
  
  uvm_active_passive_enum active = UVM_ACTIVE;
  bit coverage_enable = 1'b1;
  ...
endclass : x_agent_config

agent


class x_agent extends uvm_agent;
  x_agent_config cfg;
  ...
endclass : x_agent

perhaps an env level:


class simple_env extends uvm_env;
  simple_env_config  cfg;

  x_agent x_agt;
  y_agent y_agt;
  ...

  function void build_phase (uvm_phase phase);
    x_agt.cfg = cfg.x_agt_cfg;
    y_agt.cfg = cfg.y_agt_cfg;

    if (cfg.has_scoreboard)
    ...
  endfunction : build_phase
endclass : simple_env

Then make a base class of cases:


class simple_case_base extends uvm_test;
  simple_env env;

  simple_env_config  env_cfg;
  x_agent_config     x_agt_cfg;
  y_agent_config     y_agt_cfg;
  ...

  function void build_phase (uvm_phase phase);
    env_cfg = simple_env_config::type_id::create("env_cfg");
    config_env(env_cfg);
    
    x_agent_cfg = x_agent_config::type_id::create("x_agent_cfg");
    config_x_agent(x_agent_cfg);
    env_cfg.x_agent_cfg = x_agent_cfg;
    ...
    env.cfg = env_cfg;
  endfunction : build_phase
endclass : simple_case_base

In this situation, there is not many call. Instead, we use uvm_config_db(), we also need to call config_env() then use uvm_config_db’s set() methord. I’m confused that why don’t use direct assignment like above?

Thanks!

In reply to seabeam:

The reason that you can’t use assignments like you showed is because the environment and the agents will use some of the values provided in the configuration object during the build_phase(). With assignments, you can’t assign the configuration object until the component is created, but the component requires the configuration object during the build_phase(), which is called as part of create(). The most effective way to allow the component to retrieve its configuration object is by using the uvm_config_db().

In reply to cgales:

Hi cgales:
It’s correct that before component is created, the assignment can’t be done.
By the way, build_phase() will be called automatically when children use new() to create instance.
I thinks build_phase() is top-down phase, after making assignmet of agent config in env’s build_phase(), even finish involking env’s build_phase(), the children(agent)'s build_phase() is involked. So it has no effect that agents can use these values provided in the configuration object to configurate it’s structure etc.

class x_agent extends uvm_agent;
  x_agent_config cfg;

  x_coverage_collector collector;
  ...

  function void build_phase (uvm_phase phase);
    if (cfg.coverage_enable)
      collector = x_coverage_collector::type_id::create("collector");
    ...
  endfunction : build_phase
endclass : x_agent

The code above can work fine, is there any other reason please?

Thanks a lot!

In reply to seabeam:

Your code won’t work how it is written. When your environment calls create() for your agent, the agent will be new’d() and have the build_phase() called immediately. There is no way for the environment to set the value of the agent’s config object. The agent will need to get the value of its config object via the uvm_config_db.

When the build_phase() is noted as top down, it doesn’t mean that the environment’s build phase will complete and then the sub-component(s) build_phase() will be called. The build_phase() of a component is called as part of the create() call.

In reply to cgales:

Hi cgales,

I have some modifications with the idea of seabeam.

Instead of declare of automatic config object inside agent, I use static config object.

So config object of agent can be easily assign at test class before the agent component actually built.

→ Hence I see that when we used assignment config object directly is more effectively as we use uvm_config_db ( as seabeam pointout

I’v tried to set-get 10,000 integer from parent to child, which uvm_config_db() methord takes 2.1s CPU time & nearly 87M Mem while direct assignment 0.3s CPU time & 3.7M Mem.

Can you explain other reason to use uvm_config_db(), cgales?

Hi cgales:
Here is an example,
configuration object:
class x_agent_config extends uvm_object;
virtual x_if x_port;
uvm_active_passive_enum active = UVM_ACTIVE;
bit coverage_enable = 1’b1;

endclass : x_agent_config
agent
class x_agent extends uvm_agent;
x_agent_config cfg;

endclass : x_agent
perhaps an env level:
class simple_env extends uvm_env;
simple_env_config cfg;
x_agent x_agt;
y_agent y_agt;

function void build_phase (uvm_phase phase);
x_agt.cfg = cfg.x_agt_cfg;
y_agt.cfg = cfg.y_agt_cfg;
if (cfg.has_scoreboard)

endfunction : build_phase
endclass : simple_env
Then make a base class of cases:
class simple_case_base extends uvm_test;
simple_env env;
simple_env_config env_cfg;
x_agent_config x_agt_cfg;
y_agent_config y_agt_cfg;

function void build_phase (uvm_phase phase);
env_cfg = simple_env_config::type_id::create(“env_cfg”);
config_env(env_cfg);
x_agent_cfg = x_agent_config::type_id::create(“x_agent_cfg”);
config_x_agent(x_agent_cfg);
env_cfg.x_agent_cfg = x_agent_cfg;

env.cfg = env_cfg;
endfunction : build_phase
endclass : simple_case_base
In this situation, there is not many call. Instead, we use uvm_config_db(), we also need to call config_env() then use uvm_config_db’s set() methord. I’m confused that why don’t use direct assignment like above?
Thanks!

In reply to pttran:

When you use the ‘static’ property for the config object, all instances of your agent will have the same config object. This prevents you from using unique config objects for each agent.

See paragraph 8.9 of the SystemVerilog LRM for more information.

In reply to cgales:

Hi,
Can you please tell me where to set and get agent config classes? I’ve set in environment and getting in agents, but error is coming. Please help me solve this issue.
Thanks

In reply to sujay_rm:

Could you please explain what is
config_x_agent?

In reply to chr_sue:

I have set the uvm_config_db for agent_config class in environment and i have getting that in wr_agent and rd_agent, this is causing the error.

In reply to sujay_rm:

It would help if you asked this as new question and provided the exact error message along with the lines of code that do the set and get.