image/svg+xml
  • Contents
      • Back
      • Digital Basics
      • Verilog
      • Verification
      • SystemVerilog
      • UVM
Most Popular
Verification
  Testbench Evolution
  Constraint Random Verification
  Verification Techniques
  Verification Plan
  Code Coverage

Verilog
  Data Types
  Basic Constructs
  Behavioral Modeling
  Gate Modeling
  Simulation Basics
  Design Examples

SystemVerilog
  Data Types
  Class
  Interface
  Constraints and more!
  Testbench Examples

UVM
  Sequences
  Testbench Components
  TLM Tutorial
  Register Model Tutorial
  Testbench Examples

Digital Fundamentals
  Binary Arithmetic
  Boolean Logic
  Karnaugh Maps
  Combinational Logic
  Sequential Logic




uvm_config_db Examples

The UVM configuration database accessed by the class uvm_config_db is a great way to pass different objects between multiple testbench components.

Click here to refresh on config database !

Methods

There are two primary functions used to put and retrieve items from the database which are set() and get() respectively.


static function void set (  uvm_component   cntxt,
                            string          inst_name,
                            string          field_name,
                            T               value);

static function bit get (   uvm_component  cntxt,
                            string         inst_name,
                            string         field_name,
                      inout T              value);

Rules

  • Create or update a config setting for field_name in inst_name from cntxt
  • The setting is made at cntxt with the full scope being {cntxt, ".", inst_name}
  • If cntxt is null, then inst_name provides the complete scope information of the setting
  • field_name is the target field
  • Both inst_name and field_name may be glob style or regular expression style expressions
  • Settings from hierarchically higher levels have higher precedence
  • Settings from the same level of hierarchy have a last setting wins semantic

How to debug uvm_config_db ?

The best way to understand how the combination of cntxt, inst_name and field_name works is by enabling the commandline debug +UVM_CONFIG_DB_TRACE switch for UVM that dumps information on all the set() and get() calls within a simulation.

$> irun <all_other_options> +UVM_CONFIG_DB_TRACE

Example

We'll look at how two testbench environments behave when set and get methods are called from different hierarchies.

1. Test and Env

To understand how config_db evaluates expressions, we'll set up a small testbench structure with an empty environment as shown below. An expression is set from the test class and retrieved in the environment's build_phase

Case #1

We set cntxt to null and inst_name to uvm_test_top to indicate that all components in the test can access the item. To keep things simple, we'll put a string item tagged as Friend.


class base_env extends uvm_env;
	...
	string name;
	
	virtual function void build_phase (uvm_phase phase);
		super.build_name ();
		
		// Retrieve the string that was set in config_db from the test class
		if (uvm_config_db #(string) :: get (null, "uvm_test_top", "Friend", name))
			`uvm_info ("ENV", $sformatf ("Found %s", name), UVM_MEDIUM)
			
	endfunction
endclass

class base_test extends uvm_test;
	...
	base_env 	m_env;
	
	virtual function void build_phase (uvm_phase phase);
		...
		
		// Set this string into config_db
		uvm_config_db #(string) :: set (null, "uvm_test_top", "Friend", "Joey");
	endfunction
endclass

It is quite clear that the first argument cntxt cannot be anything other than a uvm_component object. From the following simulation log, we can see that when +UVM_CONFIG_DB_TRACE is passed as a command-line switch, simulation will dump all function calls to set and get into the log. However, the lines of our interest are higlighted in color, the yellow one representing a set call and the green representing a successful get call. The concatenation of cntxt, inst_name and field_name match for both set and get calls and hence the database successfully finds and returns the string tagged as "Friend".

 Simulation Log
ncsim> run
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_root.svh(392) @ 0: reporter [UVM/RELNOTES] 
----------------------------------------------------------------
UVM-1.2
(C) 2007-2014 Mentor Graphics Corporation
(C) 2007-2014 Cadence Design Systems, Inc.
(C) 2006-2014 Synopsys, Inc.
(C) 2011-2013 Cypress Semiconductor Corp.
(C) 2013-2014 NVIDIA Corporation
----------------------------------------------------------------
UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.base_env.recording_detail' (type logic signed[4095:0]) read by uvm_test_top.base_env = null (failed lookup)
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.base_env.recording_detail' (type int) read by uvm_test_top.base_env = null (failed lookup)
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/SET] Configuration 'uvm_test_top.Friend' (type string) set by  = (string) "Joey"
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.base_env.m_agent0.recording_detail' (type logic signed[4095:0]) read by uvm_test_top.base_env.m_agent0 = null (failed lookup)
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.base_env.m_agent0.recording_detail' (type int) read by uvm_test_top.base_env.m_agent0 = null (failed lookup)
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.base_env.m_agent1.recording_detail' (type logic signed[4095:0]) read by uvm_test_top.base_env.m_agent1 = null (failed lookup)
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.base_env.m_agent1.recording_detail' (type int) read by uvm_test_top.base_env.m_agent1 = null (failed lookup)
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.Friend' (type string) read by  = (string) "Joey"
UVM_INFO testbench.sv(36) @ 0: uvm_test_top.base_env [ENV] Found Joey
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 0: reporter [UVM/REPORT/SERVER] 
--- UVM Report Summary ---

** Report counts by severity
Case #2

Here, we'll make a slight modification to the set method, rest of the code being the same. The first argument cntxt gets this pointer, while inst_name is empty and still we get the same path "uvm_test_top.Friend" after concatenation.


	uvm_config_db #(string) :: set (this, "", "Friend", "Joey");
	
	// Same get method
	if (uvm_config_db #(string) :: get (null, "uvm_test_top", "Friend", name))
			`uvm_info ("ENV", $sformatf ("Found %s", name), UVM_MEDIUM)
 Simulation Log
...
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/SET] Configuration 'uvm_test_top.Friend' (type string) set by uvm_test_top = (string) "Joey"
...
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.Friend' (type string) read by  = (string) "Joey"

2. Test, Env, and two Agents

Now we'll expand the environment to have a couple of agents to make things more interesting.


class base_agent extends uvm_agent;
	...
	
	virtual function void build_phase (uvm_phase phase);
		if (uvm_config_db #(string) :: get (null, "uvm_test_top", "Friend1", name))
			`uvm_info ("AGENT", $sformatf ("[%s] found %s", this.get_name(), name), UVM_MEDIUM)
	endfunction
endclass

class base_env extends uvm_env;
	...
	base_agent 	m_agent0;
	base_agent 	m_agent1;
	...
endclass

If we run the code again with the new agents in place, you'll find that both agents also found the string tagged as "Friend1".

 Simulation Log
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/SET] Configuration 'uvm_test_top.Friend1' (type string) set by uvm_test_top = (string) "Joey"
...
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.Friend1' (type string) read by  = (string) "Joey"
UVM_INFO testbench.sv(44) @ 0: uvm_test_top.base_env [ENV] Found Joey
...
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.Friend1' (type string) read by  = (string) "Joey"
UVM_INFO testbench.sv(22) @ 0: uvm_test_top.base_env.m_agent0 [AGENT] [m_agent0] Found Joey
...
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'uvm_test_top.Friend1' (type string) read by  = (string) "Joey"
UVM_INFO testbench.sv(22) @ 0: uvm_test_top.base_env.m_agent1 [AGENT] [m_agent1] Found Joey

Recommended Practice

The setting in config_db is visible by only those elements that can evaluate to the same expression as the set call. If we keep a global scope such as uvm_test_name, then all components will be able to retrieve that setting. However, this poses a potential problem of collision of field_name within the same scope, as well as retrieval of settings via unintended get calls. Hence, the recommended practice is to make the setting available to only those components that really require the setting to function. In a similar way, during get calls, components should look for settings that are available to them.

The expression that is set in config_db is "uvm_test_top.Friend" based on the set function call. config_db results show the expression evaluated by the get method call. If both of these expressions match or satisfies the glob properties, it is considered to be a match. In the case below, all the three get method calls failed simply because the expression each of the component tried to get is different from the expression that is set.

uvm_config_db #(string) :: set (this, "m_env.m_agent*", "Friend", "Joey");    // Set in test, available to agents
uvm_config_db #(string) :: get (this, "", "Friend", name);                   // Get in env
uvm_config_db #(string) :: get (this, "", "Friend", name);                   // Get in agent

cntxt = uvm_test_top, inst_name = m_env.m_agent*, tag = Friend
Expression set : "uvm_test_top.m_env.m_agent1*.Friend"

CONFIG_DB_TRACE results:
[CFGDB/SET] Configuration 'uvm_test_top.m_env.m_agent*.Friend' (type string) set by uvm_test_top = (string) "Joey"
[CFGDB/GET] Configuration 'uvm_test_top.m_env.Friend' (type string) read by uvm_test_top.m_env = null (failed lookup)
[CFGDB/GET] Configuration 'uvm_test_top.m_env.m_agent0.Friend' (type string) read by uvm_test_top.m_env.m_agent0 = (string) "Joey"
[CFGDB/GET] Configuration 'uvm_test_top.m_env.m_agent1.Friend' (type string) read by uvm_test_top.m_env.m_agent1 = (string) "Joey"

In the above case, the setting was made available only to the agents and hence environment was not able to retrieve it at its level. To make the setting available to the environment, we'll make another set call just for the environment. If you put a * like m_env*, then the setting will be made available to all the components in the environment.

uvm_config_db #(string) :: set (this, "m_env.m_agent*", "Friend", "Joey");    // Set in test, available to agents
uvm_config_db #(string) :: set (this, "m_env",          "Friend", "Joey");    // Set in test, available to env
uvm_config_db #(string) :: get (this, "", "Friend", name);                    // Get in env
uvm_config_db #(string) :: get (this, "", "Friend", name);                    // Get in agent

cntxt = uvm_test_top, inst_name = m_env.m_agent*, tag = Friend
Expression set : "uvm_test_top.m_env.m_agent1*.Friend"
cntxt = uvm_test_top, inst_name = m_env, tag = "Friend"
Expression set : "uvm_test_top.m_env.Friend"

CONFIG_DB_TRACE results:
[CFGDB/SET] Configuration 'uvm_test_top.m_env.Friend' (type string) set by uvm_test_top = (string) "Joey"
[CFGDB/SET] Configuration 'uvm_test_top.m_env.m_agent*.Friend' (type string) set by uvm_test_top = (string) "Joey"
[CFGDB/GET] Configuration 'uvm_test_top.m_env.Friend' (type string) read by uvm_test_top.m_env = (string) "Joey"
[CFGDB/GET] Configuration 'uvm_test_top.m_env.m_agent0.Friend' (type string) read by uvm_test_top.m_env.m_agent0 = (string) "Joey"
[CFGDB/GET] Configuration 'uvm_test_top.m_env.m_agent1.Friend' (type string) read by uvm_test_top.m_env.m_agent1 = (string) "Joey"

A few examples on set and get methods were illustrated in the previous article. Now we'll see more combinations of expressions used to set and get settings from config_db and see the result of such operations on the same testbench structure with two agents in an environment.

set vs get results

To recap, a setting with field_name "Friend" is set with different cntxt and inst_name in the config_db. This is obtained by both agents and the environment using the get method with different cntxt and inst_name combinations. If the get call is successful, the cell is highlighted in pale green, else it is highlighted in pale red.


// Set the given field_name "Friend" in test
uvm_config_db #(string) :: set (cntxt, inst_name, "Friend", "Ross");

// Get "Friend" in env and agents
uvm_config_db #(string) :: get (cntxt, inst_name, "Friend", "Ross");

Hierarchy of each component:
  Environment : uvm_test_top.m_env
  Agent1      : uvm_test_top.m_env.m_agent1
  Agent2      : uvm_test_top.m_env.m_agent2

The first column in the table shown below is for the test class that sets the field Friend with the given cntxt and inst_name. All subsequent columns represent different components that try to get the setting from config_db which in our example is the environment and two agents.

Test :: setEnv :: getAgent1 :: getAgent2 :: get
(null, "uvm_test_top") uvm_test_top.Friend(this, "") uvm_test_top.m_env.Friend(this, "") uvm_test_top.m_env.m_agent0.Friend(this, "") uvm_test_top.m_env.m_agent1.Friend
(this, "") uvm_test_top.Friend(this, "") uvm_test_top.m_env.Friend(this, "") uvm_test_top.m_env.m_agent0.Friend(this, "") uvm_test_top.m_env.m_agent1.Friend
(this, "*") uvm_test_top.*.Friend(this, "") uvm_test_top.m_env.Friend(this, "") uvm_test_top.m_env.m_agent0.Friend(this, "") uvm_test_top.m_env.m_agent1.Friend
(this, "m_env") uvm_test_top.m_env.Friend(this, "") uvm_test_top.m_env.Friend(this, "") uvm_test_top.m_env.m_agent0.Friend(this, "") uvm_test_top.m_env.m_agent1.Friend
(this, "m_env.*") uvm_test_top.m_env.*.Friend(this, "") uvm_test_top.m_env.Friend(this, "") uvm_test_top.m_env.m_agent0.Friend(this, "") uvm_test_top.m_env.m_agent1.Friend
(this, "m_env.m_agent*") uvm_test_top.m_env.m_agent*.Friend(this, "") uvm_test_top.m_env.Friend(this, "") uvm_test_top.m_env.m_agent0.Friend(this, "") uvm_test_top.m_env.m_agent1.Friend
(null, "uvm_test_top.m_env.m_agent1") uvm_test_top.m_env.m_agent1.Friend(this, "") uvm_test_top.m_env.Friend(this, "") uvm_test_top.m_env.m_agent0.Friend(this, "") uvm_test_top.m_env.m_agent1.Friend
(this, "*.m_agent1") uvm_test_top.*.m_agent1.Friend(this, "") uvm_test_top.m_env.Friend(this, "") uvm_test_top.m_env.m_agent0.Friend(this, "") uvm_test_top.m_env.m_agent1.Friend
(this, "m_env.m_ag*") uvm_test_top.m_env.m_ag*.Friend(this, "") uvm_test_top.m_env.Friend(this, "") uvm_test_top.m_env.m_agent0.Friend(this, "") uvm_test_top.m_env.m_agent1.Friend

SystemVerilog file operations

System Verilog allows us to read and write into files in the disk.

How to open and close a file ?

A file can be opened for either read or write using the $fopen() system task. This task will return a 32-bit integer handle called a file descriptor. This handle should be used to read and write into that file until it is closed. The file descriptor can be closed with the $fclose() system task. No further reads or writes to the file descriptor is allowed once it is closed.

Example

In the code shown below, we will declare a int variable called fd to hold the file descriptor. fd is initially zero, and gets a valid value from $fopen() and can be checked to see if the file opened successfully. The file is finally closed when $fclose() is executed.


module tb;
  initial begin
  	// 1. Declare an integer variable to hold the file descriptor
  	int fd; 		
  	
  	// 2. Open a file called "note.txt" in the current folder with a "read" permission
  	// If the file does not exist, then fd will be zero
    fd = $fopen ("./note.txt", "r"); 	
    if (fd)  $display("File was opened successfully : %0d", fd);
    else     $display("File was NOT opened successfully : %0d", fd);
    
    // 2. Open a file called "note.txt" in the current folder with a "write" permission
    //    "fd" now points to the same file, but in write mode
    fd = $fopen ("./note.txt", "w"); 	
    if (fd)  $display("File was opened successfully : %0d", fd);
    else     $display("File was NOT opened successfully : %0d", fd);
    
    // 3. Close the file descriptor
    $fclose(fd);
  end
endmodule

It is important to close all open files before end of simulation to completely write contents into the file

 Simulation Log
ncsim> run
Open failed on file "./note.txt". No such file or directory
File was NOT opened successfully : 0
File was opened successfully : -2147483645
ncsim: *W,RNQUIE: Simulation is complete.

Read more: SystemVerilog file operations

SystemVerilog Command Line Arguments

Every now and then you come across the need to avoid testbench recompilation, and instead be able to accept values from the command line just like any scripting language like bash or perl would do. In SystemVerilog, this information is provided to the simulation as an optional argument always starting with the + character. These arguments passed in from the command line are accessible in SV code via the following system functions called as plusargs.

Syntax


	$test$plusargs (user_string)
	
	$value$plusargs (user_string, variable)

$test$plusargs

The function $test$plusargs is typically used when a value for the argument is not required. It searches the list of plusargs for a user specified string. A variable can also be used to specify the string, and any null character will be ignored. If the prefix of one of the supplied plusargs matches all characters in the provided string, the function will return a non-zero integer, and otherwise zero.

Read more: SystemVerilog Command Line Arguments

SystemVerilog Mailbox

A SystemVerilog mailbox is a way to allow different processes to exchange data between each other. It is similar to a real postbox where letters can be put into the box and a person can retrieve those letters later on.

SystemVerilog mailboxes are created as having either a bounded or unbounded queue size. A bounded mailbox can only store a limited amount of data, and if a process attempts to store more messages into a full mailbox, it will be suspended until there's enough room in the mailbox. However, an unbounded mailbox has unlimited size.

There are two types:

  • Generic Mailbox that can accept items of any data type
  • Parameterized Mailbox that can accept items of only a specific data type

SystemVerilog Mailbox vs Queue

Although a SystemVerilog mailbox essentially behaves like a queue, it is quite different from the queue data type. A simple queue can only push and pop items from either the front or the back. However, a mailbox is a built-in class that uses semaphores to have atomic control the push and pop from the queue. Moreover, you cannot access a given index within the mailbox queue, but only retrieve items in FIFO order.

Where is a mailbox used ?

A SystemVerilog mailbox is typically used when there are multiple threads running in parallel and want to share data for which a certain level of determinism is required.

Generic Mailbox Example

Two processes are concurrently active in the example shown below, where one initial block puts data into the mailbox and another initial block gets data from the mailbox.


module tb;
	// Create a new mailbox that can hold utmost 2 items
  	mailbox 	mbx = new(2);
  
  	// Block1: This block keeps putting items into the mailbox
  	// The rate of items being put into the mailbox is 1 every ns
  	initial begin
		for (int i=0; i < 5; i++) begin
        	#1 mbx.put (i);
        	$display ("[%0t] Thread0: Put item #%0d, size=%0d", $time, i, mbx.num());
      	end
    end
  
  	// Block2: This block keeps getting items from the mailbox
  	// The rate of items received from the mailbox is 2 every ns
	initial begin
		forever begin
			int idx;
			#2 mbx.get (idx);
          	$display ("[%0t] Thread1: Got item #%0d, size=%0d", $time, idx, mbx.num());
		end
	end
endmodule

Read more: SystemVerilog Mailbox

SystemVerilog Semaphore

Semaphore is just like a bucket with a fixed number of keys. Processes that use a semaphore must first get a key from the bucket before they can continue to execute. Other proceses must wait until keys are available in the bucket for them to use. In a sense, they are best used for mutual exclusion, access control to shared resources and basic synchronization.

Syntax


	semaphore 	[identifier_name];

Note that semaphore is a built-in class and hence it should be used just like any other class object. It has a few methods with which we can allocate the number of keys for that semaphore object, get and put keys into the bucket.

Methods

Read more: SystemVerilog Semaphore

  1. SystemVerilog randcase
  2. SystemVerilog Package
  3. SystemVerilog Disable Randomization
  4. SystemVerilog Disable Constraints
  5. SystemVerilog Inline Constraints

Page 27 of 63

  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
Interview Questions
  Verilog Interview Set 1
  Verilog Interview Set 2
  Verilog Interview Set 3
  Verilog Interview Set 4
  Verilog Interview Set 5

  SystemVerilog Interview Set 1
  SystemVerilog Interview Set 2
  SystemVerilog Interview Set 3
  SystemVerilog Interview Set 4
  SystemVerilog Interview Set 5

  UVM Interview Set 1
  UVM Interview Set 2
  UVM Interview Set 3
  UVM Interview Set 4
Related Topics
  Digital Fundamentals
  Verilog Tutorial

  Verification
  SystemVerilog Tutorial
  UVM Tutorial
  • Verilog Testbench
  • Verilog Coding Style Effect
  • Verilog Conditional Statements
  • Verilog Interview Set 10
  • Synchronous FIFO
  • SystemVerilog Interview Set 10
  • SystemVerilog Interview Set 9
  • SystemVerilog Interview Set 8
  • SystemVerilog Interview Set 7
  • SystemVerilog Interview Set 6
  • UVM Singleton Object
  • UVM Component [uvm_component]
  • UVM Object [uvm_object]
  • UVM Root [uvm_root]
  • UVM Interview Set 4
© 2015 - 2023 ChipVerify
Terms and Conditions | DMCA.com Protection Status