Optimized Randomization

Getting started

Using Enhanced Randomization can be somewhat inefficient when trying to randomize several sets of values, especially with large and small ranges. Since the values in the large ranges will be generated more times than the ones in the small ranges in a Uniform distribution, this will cause the simulation to run longer in order to cover all the valid bins.

The idea behind Optimized Randomization is to only generate the required values a specified number of times without replacement and then repeat from the start.

Note

Before using Optimized Randomization, it is recommended to have a look at Functional Coverage to be familiar with the basic concepts, such as bins, minimum coverage and sampling coverage.

By using Optimized Randomization, the internal random generator is automatically constrained to only use the uncovered bins, this reduces simulation time as only the necessary values to achieve coverage are randomly generated.

Once all the bins in the given coverpoint have been covered, the random generator will start again from scratch as if none of the bins have been hit. This behavior will keep on repeating. This is useful when we want to generate constrained sets of random values which repeat over time, similar to Cyclic generation from Enhanced Randomization, but with minimum hits and weighted distribution features.

To use optimized randomization, the function rand() from the protected type t_coverpoint is called with a single parameter which defines whether or not to also sample coverage using the randomly generated value. Since the randomization is based in the bins, no additional constraints need to be given to the function.

In the following examples all the bins have a default min_hits=1, meaning that after being sampled once they stop being selected for randomization until all the bins are covered.

library uvvm_util;
context uvvm_util.uvvm_util_context;
...
signal my_addr : natural;
shared variable my_coverpoint : t_coverpoint;
...
p_main : process
begin

  -- Example 1: The loop will iterate 100 times to generate random values from the 100 different bins
  -- Randomization sequence example: 64,42,35,7,89,92,...
  my_coverpoint.add_bins(bin_range(1,100,0));
  while not(my_coverpoint.coverage_completed(BINS_AND_HITS)) loop
    my_addr := my_coverpoint.rand(NO_SAMPLE_COV);
    configure_addr(my_addr);
    my_coverpoint.sample_coverage(my_addr);
    wait for C_CLK_PERIOD;
  end loop;

  my_coverpoint.delete_coverpoint(VOID);

  -- Example 2: The loop will iterate 4 times to generate random values from the 4 different bins. Only a single random
  -- value from the range bin will be selected, same applies for the bin with multiple values.
  -- Randomization sequence example: 3,7,0,30
  my_coverpoint.add_bins(bin(0));
  my_coverpoint.add_bins(bin(3));
  my_coverpoint.add_bins(bin_range(5,10));
  my_coverpoint.add_bins(bin((20,30,40,50)));
  while not(my_coverpoint.coverage_completed(BINS_AND_HITS)) loop
    my_addr := my_coverpoint.rand(NO_SAMPLE_COV);
    configure_addr(my_addr);
    my_coverpoint.sample_coverage(my_addr);
    wait for C_CLK_PERIOD;
  end loop;

  my_coverpoint.delete_coverpoint(VOID);

  -- Example 3: The loop will iterate 6 times to generate random values from the 3 different bins. When the rand()
  -- function selects a transition bin, the next value selected by rand() will be the next transition value in the bin,
  -- and so on until the all the values in the bin are generated.
  -- Randomization sequence example: 2,4,6,8,0,3
  my_coverpoint.add_bins(bin(0));
  my_coverpoint.add_bins(bin(3));
  my_coverpoint.add_bins(bin_transition((2,4,6,8)));
  while not(my_coverpoint.coverage_completed(BINS_AND_HITS)) loop
    my_addr := my_coverpoint.rand(SAMPLE_COV);
    configure_addr(my_addr);
    wait for C_CLK_PERIOD;
  end loop;

  my_coverpoint.delete_coverpoint(VOID);

  -- Example 4: Every time the 4 bin values are generated by the rand() function and sampled, any bin can be selected
  -- again for generating random values.
  -- Randomization sequence example: 5,1,3,7, 1,7,3,5, 7,5,1,3
  my_coverpoint.add_bins(bin(1));
  my_coverpoint.add_bins(bin(3));
  my_coverpoint.add_bins(bin(5));
  my_coverpoint.add_bins(bin(7));
  for i in 1 to 12 loop
    my_addr := my_coverpoint.rand(SAMPLE_COV);
    configure_addr(my_addr);
    wait for C_CLK_PERIOD;
  end loop;

Caution

Ignore and illegal bins will never be selected for randomization. However, if an illegal or ignore bin contains overlapping values with a valid bin, they might be generated as there is no check to avoid this.

Seeds

The randomization seeds default values are set using the coverpoint’s name at the moment it is initialized (when adding the first configuration or bin). Since each coverpoint has an unique default name, the seeds will be unique for each coverpoint, unless the coverpoint is initialized by configuring the name.

Seeds can also be manually configured by using set_rand_seeds().

-- Example 1
my_coverpoint.set_rand_seeds(10, 100);

-- Example 2
my_coverpoint.set_rand_seeds(seed_vector);

The current seeds can be printed out, for instance when needing to recreate a certain random sequence, by using get_rand_seeds(). This method will return the seeds as two positive integers or a positive integer vector.

-- Example 1
my_coverpoint.get_rand_seeds(seed1, seed2);

-- Example 2
seed_vector := my_coverpoint.get_rand_seeds(VOID);

Randomization weights

Explicit

The parameter rand_weight in the add_bins() procedure specifies the relative number of times a bin will be selected during randomization until it is covered. This parameter is not applicable for ignore or illegal bins since they are never selected for randomization.

Once all the bins in the given coverpoint have been covered, the random generator will start again from scratch as if none of the bins have been hit. This behavior will keep on repeating. This is useful when we want to generate constrained sets of random values which repeat over time, similar to Cyclic generation from Enhanced Randomization, but with minimum hits and weighted distribution features.

add_bins(bin, min_hits, rand_weight, [bin_name])

my_coverpoint.add_bins(bin(0), 100, 1); -- Selected 10% of the time
my_coverpoint.add_bins(bin(2), 100, 3); -- Selected 30% of the time
my_coverpoint.add_bins(bin(4), 100, 6); -- Selected 60% of the time

Adaptive

If a randomization weight is not specified, the bin will have a default weight equal to the minimum coverage (min_hits). Moreover, this weight will be reduced by 1 every time the bin is sampled, thus balancing the randomization of the bins in an “adaptive” way.

Once all the bins in the given coverpoint have been covered, the random generator will start again from scratch as if none of the bins have been hit. This behavior will keep on repeating. This is useful when we want to generate constrained sets of random values which repeat over time, similar to Cyclic generation from Enhanced Randomization, but with minimum hits and weighted distribution features.

add_bins(bin, min_hits, [bin_name])

my_coverpoint.add_bins(bin(0), 10);         -- rand_weight = min_hits = 10
my_coverpoint.add_bins(bin(2), 5);          -- rand_weight = min_hits = 5
my_coverpoint.add_bins(bin_range(4,8), 5);  -- rand_weight = min_hits = 5
while not(my_coverpoint.coverage_completed(BINS_AND_HITS)) loop
  my_addr := my_coverpoint.rand(SAMPLE_COV);
  configure_addr(my_addr);
  wait for C_CLK_PERIOD;
end loop;

-- Example of how the sampling of the generated random values affect the randomization weights:
-- ======= ========================= ========================= =========================
--  Value            bin(0)                    bin(2)                bin_range(4,8)
-- ======= ========================= ========================= =========================
--    -     50.0% (rand_weight = 10)  25.0% (rand_weight = 5)   25.0% (rand_weight = 5)
--    0     47.3% (rand_weight = 9)   26.3% (rand_weight = 5)   26.3% (rand_weight = 5)
--    0     44.4% (rand_weight = 8)   27.8% (rand_weight = 5)   27.8% (rand_weight = 5)
--    0     41.2% (rand_weight = 7)   29.4% (rand_weight = 5)   29.4% (rand_weight = 5)
--    4     43.8% (rand_weight = 7)   31.2% (rand_weight = 5)   25.0% (rand_weight = 4)
--    0     40.0% (rand_weight = 6)   33.3% (rand_weight = 5)   26.7% (rand_weight = 4)
--    2     42.8% (rand_weight = 6)   28.6% (rand_weight = 4)   28.6% (rand_weight = 4)
--    5     46.1% (rand_weight = 6)   30.8% (rand_weight = 4)   23.1% (rand_weight = 3)
-- ======= ========================= ========================= =========================

Randomization using transitions

The Optimized Randomization mechanism will always select random values among the bins. In the case of a transition bin, when it is selected for randomization, it will return each value of the bin in sequence until the complete transition is generated, this ensures that the complete sequence can be randomly generated. However, if we also want to generate random transitions which are not included in the transition bins, we can use a range bin:

-- The range bin will generate random values in the range [1:20]. Note that it has a min_hits value of 9 since the bin
-- values overlap with those of the transition bins, therefore if a transition bin is sampled, the range bin will also
-- be sampled.
my_coverpoint.add_bins(bin_transition((1,5,10)), 1);
my_coverpoint.add_bins(bin_transition((1,6,20)), 1);
my_coverpoint.add_bins(bin_range(1,20), 9);

while not(my_coverpoint.coverage_completed(BINS_AND_HITS)) loop
  my_addr := my_coverpoint.rand(SAMPLE_COV);
  configure_addr(my_addr);
  wait for C_CLK_PERIOD;
end loop;

Randomization using crosses

When running the rand() procedure on a coverpoint containing a cross, the procedure will return a vector containing a set of values from the uncovered crosses. The length of the vector will be the same as the number of crossed elements.

coverpoint_a.add_bins(bin(0));
coverpoint_a.add_bins(bin(1));
coverpoint_b.add_bins(bin(0));
coverpoint_b.add_bins(bin(1));

-- Create cross of above coverpoints. The cross coverpoint will contain the following bins:
-- 0x0, 0x1, 1x0, 1x1
coverpoint_cross.add_cross(coverpoint_a, coverpoint_b);

-- Generate vectors containing the data pairs above until all four pairs have been generated.
while not(coverpoint_cross.coverage_completed(BINS_AND_HITS)) loop
    my_data_vector := coverpoint_cross.rand(SAMPLE_COV);
end loop;

Additional info

Note

Enhanced Randomization, Optimized Randomization and Functional Coverage were inspired by general statistics and similar functionality in SystemVerilog and OSVVM.

Note

Disclaimer: This IP and any part thereof are provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and non-infringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with this IP.

Footnotes

Note

A bin is considered covered when the value or values have been drawn at least the number of specified times, while for optimized randomization this means the exact number of specified times. If the hits_coverage_goal is configured, this will affect the number of times the value or values must be drawn in order for the bin to be covered.