The `UVM_config_db` is a global database that stores key-value pairs, similar to Python dictionaries. The values can be of various types, such as integers or objects and so on. Keys consist of a hierarchical instance path and a field name: the path defines the scope where the value is visible, and the field name identifies the specific data entry.
`UVM_config_db` facilitates data exchange between UVM components. Without it, the modularity and reusability of components—fundamental principles of Object-Oriented Programming—would be compromised.
We cannot discuss UVM_config_db without first introducing the UVM_resource_db, as the former is actually built on top of it. The UVM_resource_db is a parameterized container for storing and sharing data between UVM components. This database consists of:
A global resource database exists with both a name table and a type table where each resource is entered. Resources can be retrieved by name or type. The `set()` method is used to add a resource to the database, while `get_by_name()` or `get_by_type()` can be used for retrieval.
This is a very useful error, because the resources are allocated in a queue (First In First Out). The first introduced resources have the highest priority. For instance, consider a queue as shown in Figure 3. If an additional object is added using the `set()` method, it will be placed at the end of the queue. When using `get_by_type()` with a certain datatype, the method will return the first item that has the same datatype. The same happens with `get_by_name()`, if several items have the same name, then the method will return the first item that matches the name.
In the example below, two integer values—23 and 32—are stored in the same scope ("uvm_test_top.env") using the uvm_resource_db. Each value is associated with a different name: "Value_1" and "Value_2". Later, a call to get_by_type() is used to retrieve one of the values from that scope. Since no specific name is provided in the query, the method returns the first matching resource of the specified type found in the given scope. Therefore, the expected result is 23.
`UVM_config_db` is a wrapper for `UVM_resource_db`, simplifying its usage. It provides a more user-friendly and structured interface for interacting with `UVM_resource_db`. Specifically designed for passing configurations between components (e.g., virtual interfaces, control variables), it utilizes safer types and verifies that the set type matches the retrieved type. It is recommended in most cases, especially for configurations between test → environment → agent → driver/monitor.
Examples:
Note that the asterisk indicates that the scope includes the context and all hierarchically higher instances. The full scope is achieved with `context + inst_name`: `{cntxt, ".", inst_name}`. Therefore, the full scope of the second and third examples is the same: "uvm_test_top.m_env.m_apb_agent.*"
When choosing between the second and third examples, using `this` instead of `null` (as in the third example) is preferable. This is because the context helps identify which component set the variable during debugging.
get()
This method returns a bit. If the object sought in a scope is found, it returns 1; otherwise, it returns 0. It is good practice to use the `get()` method within an `if` statement to handle cases where it returns 0 (indicating the object was not found).
In the first example, the code attempts to retrieve the APB virtual interface using uvm_config_db::get(). The first two arguments are "this" and "*"—meaning the search starts from the current component and applies to all components below it in the hierarchy. If the APB interface was previously set in the configuration database, it will be assigned to the apb_if variable.
This retrieval will succeed as long as the interface was set correctly, as shown in Figure 7. In that figure, the apb_if variable is set with the scope "uvm_test_top.", which makes it visible to all components below uvm_test_top. Therefore, any child component within the testbench hierarchy can retrieve it using a wildcard "" in its get call.
In the second example, the uvm_config_db::get() function is called with null as the context. This means the search will begin from the absolute instance path provided as the second argument—"uvm_test_top" in this case. The method is attempting to retrieve the cov_enable variable from that exact component.
However, as shown in Figure 7, the cov_enable variable was actually set in the scope "uvm_test_top.m_env.apb_agent.*", making it available only to components located under apb_agent. Since "uvm_test_top" does not match this path, the search will not find the variable, and the get() method will return 0.
This method returns a 1 if the field_name exists within the specified scope.
Figure 29 illustrates how to check if “apb_vif” exists. As the variable was configured in Figure 7 to be visible to any component in the test, the `exist()` method will return 1.
Note that this is a blocking task. This means that it will halt the execution of the current thread until the field_name within the scope {cntxt.inst_name} is modified. The following example demonstrates its application:
In this scenario, we have an environment and an agent component. Inside the agent’s run_phase, the wait_modified() task is invoked, which suspends the agent’s execution until a specific configuration value—loop_count—is modified.
Since the loop_count variable is set from within the environment (i.e., higher in the hierarchy), the agent can perform the uvm_resource_db::wait_modified() call using an empty string ("") as the inst_name. This instructs the method to search upward through the hierarchy until it finds a matching resource. Once the environment updates the value of loop_count, the agent’s execution resumes.
Error debugging can be facilitated by appending the “plusarg” “+uvm_config_db” to the command line instruction that starts the simulation. This provides the following diagnostic information:
Generally, as observed in the first line of Figure 15, a variable is set within a specific scope, on a particular line of a designated file. Subsequently, that variable is successfully retrieved from a separate line in another file.
The UVM Config database is a good alternative to semaphores and mailboxes for sending data from one part of the UVM environment to another part.
Written by Roberto Millon Tello, Patricio Gallo & Marcelo Pouso
Edited by Adrian Evaraldo
For further inquiries, contact us: info@emtech.com.ar