Tuesday, 6 November 2018

Automatic configuration through uvm_config_db

UVM has an internal database table in which we can store values (of any data type including user defined data type) with unique name and can be retrieved later by some other testbench component.
There are two interface through which we can access configuration database.
1) uvm_resource_db, 2) uvm_config_db

Uvm_config_db is a great way to pass different resources (variable/object/virtual interface) within UVM testbench component hierarchy.

The uvm_config_db class provides a convenience interface on top of the uvm_resource_db to simplify the basic interface that is used for configuring uvm_component instances.

Let’s go through basic example:
-------------------------------------------------------------------------
-------------------------------------------------------------------------

UVM provides automatic configuration of resources (variable/object etc…) which are registered in the respective component (which is extended from uvm_component) by calling apply_config_settings method.
Any component which is extended from uvm_component should call super.build_phase(phase) to execute apply_config_settings method.
Let's go through basic example of automatic configuration.
-------------------------------------------------------------------------
-------------------------------------------------------------------------

But,
This is not recommended approach as it introduces extremely poor simulation performance and big confusion on what kind of field/resource it supports and does not supports.

Some of the types get automatically configured and while some are not.

Let’s go through one more example of automatic configuration,
-------------------------------------------------------------------------
-------------------------------------------------------------------------

Observation:
1)      If you set any object which is extended from uvm_object and set it into config_db using extended type it won't get automatically configured (obj2).
2)      If you set extended object into config_db using uvm_object as type then it will get automatically configured (obj1).
3)      Unpack array will not get automatically configured (ary_int).
4)      If resource (variable/object etc) is not registered in respective class using `uvm_field_* macro then it won't get automatically configured (idx1).
5)      Virtual interface won't get automatically configured as we can't register it using `uvm_field_* macro.
6)      If you set any vector (let’s say bit [47:0]) in config_db using uvm_config_db#(int)::set then it will get automatically configured. Even though width of int is 32 bit but still 48 bits will get automatically configured (idx2).
7)      But if you set same vector (bit [47:0]) in config_db using uvm_config_db#(bit[47:0])::set then it won't get automatically configured (idx22).


If you want to pass Unpack array using uvm_config_db then you can set it directly using for loop as done in above example. But this is not efficient approach, instead of that create a class (extended from uvm_object) that includes unpack arrays and then do set/get of that class using uvm_config_db.

Reference:
1) https://verificationacademy.com/forums/uvm/uvmconfigdb-usage-big-confusion

Sunday, 28 January 2018

Automatic/Static Variables and Function/Task with Automatic Lifetime in SystemVerilog

Before going into static and automatic variable let’s first go through 2 important terminology and then will go through automatic and static.

Scope:
Scope is the region or section of code where a variable can be accessed.
Variables declared inside a module, interface, program, or checker, but outside a task, process, or function, are local in scope.

Lifetime:
Lifetime is the time duration where an object/variable is in a valid state.
Variables declared outside a module, program, interface, checker, task, or function are local to the
compilation unit and have a static lifetime (exist for the whole simulation).
Variables declared inside a static task, function, or block are local in scope and default to a static lifetime.

Specific variables within a static task, function, or block can be explicitly declared as automatic. Such
variables have the lifetime of the call or block and are initialized on each entry to the call or block.
---------------------------------------------------------------------
---------------------------------------------------------------------
Result:
---------------------------------------------------------------------
---------------------------------------------------------------------


Automatic Function/Task (Function/Task with Automatic Lifetime):
In Verilog default lifetime of all the task/function is static.
Tasks and functions may be declared as automatic. Variables declared in an automatic task, function, or block are local in scope, default to the lifetime of the call or block, and are initialized on each entry to the call or block.

In other word, Automatic task/function variables cannot be accessed by hierarchical references. Automatic variables are automatically destroyed once the scope (task, function, block) in which they are created ends and regenerated when again enters into scope (task, function, block).
---------------------------------------------------------------------
---------------------------------------------------------------------


Class methods has Automatic lifetime by default:
Because of backward compatibility reason, SystemVerilog could not change the default lifetime qualifier to ‘automatic’ but since class methods were new, it changed the lifetime of all methods to be automatic.
---------------------------------------------------------------------
---------------------------------------------------------------------


The keyword ‘static’ is overloaded. There is a semantic difference between the meaning of ‘static’ used to the left of a function/task keyword and ‘static’ used to the right of the function/task keyword.

When used to the left of the function or task, ‘static’ is a class qualifier and has the same as on any static method in C++/Java. It is a method of the class type, not of an instance of a class object. Other class qualifiers are ‘local’ and ‘protected’ and along with ‘static’ are only allowed in front of methods of a class. There is no corresponding ‘automatic’ class qualifier.

When used to the right of a function or task, ‘static’ is a lifetime qualifier, with ‘automatic’ being the corresponding qualifier.

For more details refer this link.

Friday, 26 January 2018

`define macro usage in SystemVerilog

It's not possible to use a `define macro within a string literal. According to the SystemVerilog LRM: Macro substitution and argument substitution shall not occur within string literals
Let’s go through below example to understand it in detail,
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------

However a string literal can be constructed by using a macro that takes an argument and including the quotes in the macro by using `".
According to SystemVerilog LRM: An `" overrides the usual lexical meaning of " and indicates that the expansion shall include the quotation mark, substitution of actual arguments, and expansions of embedded macros. This allows string literals to be constructed from macro arguments.
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------

Now what if you want to add double quotes in string which is constructed using macro. SystemVerilog provides support for that.
A `\`" indicates that the expansion should include the escape sequence \".
Let’s go through example to see how it works,
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------

 SystemVerilog LRM also provides support to construct identifier from arguments using ``.
There are three places where we can substitute argument to construct identifier
1) Substitute argument in between something (neither at the end nor at the beginning of the identifier)
2) Prepend argument (at the beginning of the identifier)
2) Append argument (at the end of the identifier)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------

Reference:
1) SystemVerilog 2012 LRM

Weighted Distributions in SystemVerilog

In constrain random verification, it may take a long time for a particular corner case to be generated. Sometime even after running test-case for N number of time corner case may not be generated and you may see holes in functional coverage. To resolve this you can use a weighted distribution to drive stimulus in particular direction.

The dist keyword in systemverilog allows you to create weighted distributions so that some values are chosen more often than others. There are 2 different kind of distribution operators available in systemverilog.
The := operator assigns the specified weight to the item or, if the item is a range, to every value in the range. 
The :/ operator assigns the specified weight to the item or, if the item is a range, to the range as a whole. If there are n values in the range, the weight of each value is range_weight / n.

Limitation:
dist expressions cannot appear in other expressions.
dist operation shall not be applied to randc variables.

Let's go through below example to understand how it works,
----------------------------------------------------------------------------
----------------------------------------------------------------------------

Reference:
1) SystemVerilog LRM 2012
2) SystemVerilog for Verification 3rd edition by Chris Spear

Wednesday, 8 November 2017

Timeunit and Timeprecision in SystemVerilog

Within a design element, such as a module, program or interface, the time precision specifies how delay values are rounded before being used in simulation.

The time precision is relative to the time units. If the precision is the same as the time units, then delay values are rounded off to whole numbers (integers). If the precision is one order of magnitude smaller than the time units, then delay values are rounded off to one decimal place.

For example, if the time unit specified is 1ns and the precision is 100ps, then delay values are rounded off to one decimal place (100ps is equivalent to 0.1ns). Thus, a delay of 2.75ns would be rounded off to 2.8ns.

The time unit and time precision can be specified in the following two ways:
— Using the compiler directive `timescale
— Using the keywords timeunit and timeprecision

Here in this post, we will go in details of second way (timeunit and timeprecision).

The time precision may also be declared using an optional second argument to the timeunit keyword using the slash separator. For example:

------------------------------------------------------------------------------
------------------------------------------------------------------------------

Defining the timeunit and timeprecision constructs within the design element removes the file order dependency problems with compiler directives.

There shall be at most one time-unit and one time-precision for any module, program, package, or interface definition or in any compilation-unit scope. This shall define a time scope.

The timeunit and timeprecision declarations shall precede any other items in the current time scope. i.e. timeunit and timeprecision shall be declared either inside module, program, package, interface or after any item in any compilation-unit scope.

The timeunit and timeprecision declarations can be repeated as later items, but must match the previous declaration within the current time scope.

If a timeunit is not specified within a module, program, package, or interface definition, then the time unit shall be determined using the following rules of precedence:
  1. If the module or interface definition is nested, then the time unit shall be inherited from the enclosing module or interface (programs and packages cannot be nested).
  2. Else, if a `timescale directive has been previously specified (within the compilation unit), then the time unit shall be set to the units of the last `timescale directive.
  3. Else, if the compilation-unit scope specifies a time unit (outside all other declarations), then the time unit shall be set to the time units of the compilation unit.
  4. Else, the default time unit shall be used.


The global time precision, also called the simulation time unit, is the minimum of,
  • All the timeprecision statements,
  • All the time precision arguments to timeunit declarations, and
  • The smallest time precision argument of all the `timescale compiler directives in the design.

Let's go through one example,
------------------------------------------------------------------------------
------------------------------------------------------------------------------

Reference:
1) SystemVerilog LRM (1800-2012)