How to generate an array of unique random values

In short: To generate an array of unique random values in SystemVerilog, mark the array rand and add one unique constraint: constraint c { unique {arr}; }. The solver then fills every element with a different value. You can also list extra values inside the braces to keep those out of the set, which is handy for excluding reserved addresses. The unique constraint arrived in IEEE 1800-2012 and replaced the older, slower approaches.

Test scenarios often need a set of addresses, IDs, or instructions with no repeats, usually held in an array. Before 2012 this took nested loops or one element at a time solving. The unique constraint does it in a single line, so this is now the clean way to get a no repeat array.

A simple way to picture it

Think of dealing cards from a shuffled deck. Each card you deal is different from the ones already on the table, because a deck has no duplicates. You do not check each card by hand; the deck itself guarantees no repeats. The unique constraint is that guarantee: you ask for a set of values and the solver deals them so none match.

The unique constraint

Mark the array as rand and wrap the array name in a unique {...} constraint. Every element gets a value different from the others, chosen from the element type range. Here ten 4 bit elements each get a different value from 0 to 15.

class uniq_set;
  rand bit [3:0] data[10];        // 10 elements, each 0..15
  constraint c_uniq { unique {data}; }
endclass

module tb;
  initial begin
    uniq_set u = new();
    if (u.randomize())
      $display("data = %p", u.data);   // 10 different values
    else
      $display("randomize failed");
  end
endmodule

Because a 4 bit value has 16 possible states and you ask for 10, there is always room for a valid set. Ask for more elements than the range allows and the solve fails.

Excluding values from the set

You can add fixed values inside the same unique braces. Those values join the uniqueness check, so the random elements avoid them. This is a neat way to keep reserved values, such as 0 or a broadcast address, out of the generated set.

class uniq_excl;
  rand bit [3:0] data[8];
  const bit [3:0] reserved[] = {0, 15};
  // data must be unique among themselves AND differ from 0, 5, 15
  constraint c_uniq { unique {data, reserved, 5}; }
endclass

module tb;
  initial begin
    uniq_excl u = new();
    if (u.randomize())
      $display("data = %p", u.data);   // none are 0, 5, or 15
  end
endmodule

The older ways (before the unique constraint)

It helps to see what the unique constraint replaced, because you may still meet these in older code. The first old way used nested foreach loops to say every pair of elements must differ. The second solved one element at a time and excluded the values seen so far.

// Old way 1: nested foreach, every pair must differ
class uniq_old1;
  rand bit [3:0] data[10];
  constraint c_pairs {
    foreach (data[i])
      foreach (data[j])
        if (i != j) data[i] != data[j];
  }
endclass
// Old way 2: one element at a time, exclude earlier values
class uniq_old2;
  rand bit [3:0] data[10];
  constraint c_step {
    foreach (data[i])
      foreach (data[j])
        if (j < i) data[i] != data[j];
  }
endclass

Both work, but the nested loops grow quickly with array size and are harder to read. The single unique line does the same job and lets the solver handle it efficiently.

Comparison of approaches

ApproachLinesReadabilityNotes
unique {data}OneClearPreferred since IEEE 1800-2012
Nested foreach (all pairs)SeveralHarderCost grows with array size
One at a time excludeSeveralHarderVerbose, easy to get index math wrong

Expected output, in plain words

The first example prints ten different 4 bit values in a mixed order, covering ten of the sixteen possible values with no repeats. The exclude example prints eight different values, none of which are 0, 5, or 15. Exact numbers vary by seed.

Note: these outputs describe what the code is written to produce from a read of the IEEE 1800 LRM. Compile and run on your own simulator or EDA Playground to confirm.

When to use the unique constraint

  • You need a set of addresses, IDs, or instructions with no repeats.
  • You want to keep certain reserved values out of the set by listing them in the braces.
  • You want short, readable stimulus code instead of nested loops.
  • You are on a tool that supports IEEE 1800-2012, which covers all current simulators.

Common mistakes to avoid

  • Asking for more elements than the range holds: ten unique values need at least ten possible states, or the solve fails.
  • Forgetting the array is rand: the unique constraint only acts on random variables.
  • Expecting order: the values are unique but not sorted; add a sort after randomize if you need order.
  • Confusing unique with a fully random draw: excluding values shrinks the pool, so a tight range plus many excludes can make the solve fail.

If you do not need true randomness

When you just need distinct values in a mixed order and full randomness is not required, you can skip constraints entirely and shuffle a filled array. We show that lighter method in our guide on unique values without random and constraints.

For no repeat cycling of a single variable, see randc behavior from a rand variable. To turn rules on and off, read rand_mode and constraint_mode. More is in our SystemVerilog tutorials.

Frequently asked questions

How do I generate an array of unique random values in SystemVerilog?

Mark the array as rand and add one unique constraint: constraint c { unique {arr}; }. The solver fills every element with a different value from the element type range.

How do I exclude certain values from a unique array?

List the fixed values inside the same unique braces, for example unique {data, reserved, 5}. Those values join the uniqueness check, so the random elements avoid them.

When was the unique constraint added?

The unique constraint was added in IEEE 1800-2012. Before that you used nested foreach loops or solved one element at a time excluding earlier values.

Why does my unique randomize fail?

Usually you asked for more unique elements than the range allows, or a tight range plus many excluded values left no legal set. Widen the range or reduce the element count.

Does the unique constraint sort the values?

No. The values are all different but not in order. If you need them sorted, sort the array after randomize returns.

What is the difference between unique and shuffle for this?

unique with a constraint gives a fully random set with no repeats. Filling an array then calling shuffle gives distinct values in a mixed order but is not fully random. Use unique when true randomness matters.

Similar Posts

One Comment

  1. One more way to generate unique values in array
    class set_unique_val;
    rand bit [3:0] data[10];
    constraint uniq {
    foreach(data[i])
    foreach(data[j])
    if(i!=j)
    data[i] != data[j];
    }
    endclass : set_unique_val

Comments are closed.