Assigning configuration objects using database vs direct assignment

Currently, I generate the environment, and it’s config obj from the test. I configure the cfg object, and then I place it in the config DB, in the environment’s scope.

Then, in the environment, I perform the same process to extract the agent’s config objects from the environment object, and place those in the DB, scoped towards the agents.

Why not simply perform direct assignment of the environment’s configuration object handle, from the test? (and likewise with the agents?) This would avoid unnecessary use of the (horribly inefficient, so I’m told) configuration database.

In reply to bmorris:

I’ll say from the start that I’m not a fan of the config DB.

The marketing pitch is that you can override config stuff form higher levels. You could also do this, I guess, if you write your code in a certain way, but using the config DB is an easy recipe. Back in the day, when OVM came out, I guess the focus was on providing people with easy recipes that make all cakes look and taste the same. It’s also easier (and lazier) to pass stuff around. Need something inside some sequence? Put it in the config DB and get it afterwards.

You could probably implement the exact same thing (configurability) using randomization and constraints, like we used to do in e (IEEE 1647).

It’s also a ‘workaround’ for not being able to call constructors with more arguments that the classical ‘string name, uvm_component parent’ (to allow factory overrides). If you can’t pass some argument to a constructor (to initialize some covergroup or constant field) you’re going to put some get from the config DB inside the constructor body.

I avoid it as much as possible. I can’t use nice IDE features (like hyperlinks inside the code window) with the config DB and that’s really annoying. This is because dependencies between different parts of the TB aren’t documented inside the code declaratively, but implicitly via lookup strings. It’s also fragile. If you change your hierarchy (e.g. component names), everything gets messed up. Refactoring tools can’t help you there either. I prefer to implement stuff either as constraints or as private/protected fields + get/set methods (which one is better is a totally different discussion). The only config DB calls I use are to pass stuff from the top level module to the TB (virtual interfaces and such).

In reply to Tudor Timi:

I am confused how the configurability relates to the resource sharing aspect; these sound like separate topics.

configurability (in the test!):
In my test, I’ve got the environment configuration, and I’ve also got one more more configuration “items” that need to find their way to certain components in the env, so they can do their job correctly. For example, a coverage component needs to know the upper limit on an address range. I can manually set these items, or randomize them (with constraints), etc. Is this the “configurability” you mean? This, in itself, doesn’t have any relation to the database usage.

resource-sharing:
Now that I’ve got all these randomized (or not) configuration items/objects/whatevers, I need to get those values to their recipients in the env. Currently, I just punted one large configuration object into the DB, and any components that need it, pull it (like my coverage monitor). Could you give me an example of how you pass a value/object from the test to a component in the env (without using the database)?

In reply to bmorris:

My philosophy is that every layer of your UVM environment should have a configuration object, similar to your approach. The configuration object will contain the configuration object(s) for every sub-component, as well as the specific configuration details required for that component.

For example, an agent’s configuration object will contain the following:

  • Virtual interface handle
  • is_active setting to control creation of sequencer/driver
  • has_coverage to control any embedded cover groups
  • Behavioral configuration information that isn’t sequence item specific

The environment configuration object will contain:

  • The configuration object for every agent
  • Register map
  • Other behavior information

Since the configuration object contains information required to build the environment properly (i.e. sequencer/driver, number of agents and types, etc.), it is required to be present in the build_phase, which will require the use of the uvm_config_db. Each component is required to get() it’s own configuration object, then set() the configuration object for each sub-component.

Encapsulating all of the configuration information within configuration objects provides several distinct advantages:

  • The test can control every aspect of the environment’s architecture and behavior by adjusting the configuration objects. These objects are always randomizable to allow maximum flexibility.
  • Only configuration objects are put into the uvm_config_db, minimizing the overhead requirements and the need to pass individual configuration items such as is_active, virtual interface, etc.
  • When a component needs to get a configuration setting, it only needs to reference its own configuration object. There is no need to copy it to a separate variable. A scoreboard or coverage at the environment will have access to all of the agent’s address ranges (if applicable) since the environment’s configuration object has every slave’s configuration.

In reply to cgales:

Yes; I agree about your philosophy of each level having it’s own configuration object (the environment, and all children).

Since the configuration object contains information required to build the environment properly (i.e. sequencer/driver, number of agents and types, etc.), it is required to be present in the build_phase, which will require the use of the uvm_config_db. Each component is required to get() it’s own configuration object, then set() the configuration object for each sub-component.

What I am really getting at, though, is the following…

function void build_phase(uvm_phase phase); // test build phase
// configure the environment config object
// and any children config objects
// agent1_cfg.randomize();
// e_cfg.set_up(,);

uvm_config_db #( LNP_env_config )::set( this , “env” , “CONFIG” , e_cfg ) ; // place into dB
// Or…
env.cfg=e_cfg; // done! no config_db required

And repeat for env->children components too. I understand it’s a single call to the dB so the overhead is not an issue; just curious.

// -------------------------------------------------

In either option, it’s very clear-cut; perhaps some reuseability issues, etc. However, what about transient objects like sequences and sequence_items? (I also mentioned this in another post just now)