RandomPkg Usage Basics: Protected Types, Seeds, and Randomization

The Basics

RandomPkg implements its randomization capability using a protected type, named RandomPType. Using a protected type allows the seed to be stored internal to the protected type, which in turn allows randomization to be done using functions.

To use RandomPkg, first you must reference the OSVVM library and RandomPkg as shown below.

library osvvm ; 
    use osvvm.RandomPkg.all ; 
entity tb is 

To do randomization, a process must declare its own local randomization variable as shown below.

UartTxProc : process
  variable RV : RandomPType ;   -- randomization variable

Each process doing randomization needs its own randomization variable with a unique seed value. One easy way to do this is to name the process and use RV’instance_name (or RV’path_name) as a parameter to InitSeed. Using the instance_name or path_name gives each seeds a unique name – even when there are multiple instances of a stimulus generation component.

RV.InitSeed (RV'instance_name)  ; 

Randomization is done with one of the overloaded functions, such as RandInt.

RandInt := RV.RandInt(0, 255) ;

Putting all of the pieces together results in the following process.

UartTxProc : process
  variable RV : RandomPType ;                   -- protected type from RandomPkg
  RV.InitSeed (RV'instance_name)  ;              -- Generate initial seeds
  for i in 0 to 255*6 loop 
    do_transaction(…, RV.RandInt(0, 255), …) ;  -- random value between 0 and 255

Note the calls to protected type methods (subprograms) include the protected type variable (RV) within the call (such as RV.RandInt(0, 255)).

Seeds and Repeatability

RandomPkg uses ieee.math_real.uniform as its basis for randomization. With uniform (or any other pseudo random sequence generator), when the same seed value is used, the same sequence, and hence, the same test is produced. This is an important fact for testing since when we fix a bug, we need to repeat the same sequence to verify the bug has been fixed.

On the other hand, we do not want two processes to repeat the same values and/or sequences when testing. Hence, we need to ensure that each process has its own randomization variable and is initialized with a unique seed value.

Stability and Random Variables

Stability is about being able rerun a test and get the exact same results. Stability is essential.

When each process has its own local variable for randomization, then each process will always produce the same sequence and the test will be stable.

On the other hand, if the randomization object is a shared variable and it is shared by many separate processes, the test will not be stable. In this case, two or more processes can randomize a value during the same delta cycle. Hence if process execution order were to change, the order of randomization would change, the randomized values would change, and the test would change. Process execution order within a given delta cycle is not defined by the language and can change due to compilation or optimization. Hence, in this situation, fixing a bug can result in the test producing different stimulus.