VHDL has a built-in pseudo-random generator, but it can only generate floating-point numbers between 0 and 1. Fortunately, you can derive from this any other kind of random data format you should need. Continue reading this article to find out how to produce `real`

or `integer`

values of any range, as well as random `std_logic_vector`

sequences and `time`

values.

The `uniform`

procedure from the IEEE MATH_REAL package is the basis for the algorithms described in this article. Please note that `uniform`

relies on software to generate random numbers. Therefore, none of these algorithms are synthesizable. You can only use them in testbenches.

procedure UNIFORM(variable SEED1, SEED2 : inout POSITIVE; variable X : out REAL);

The listing above shows the prototype of the `uniform`

procedure. It needs two seed variables to work, and it will modify them every time you call the procedure. The output, X, is the random number, which always has a value between 0 and 1.

Just like other pseudo-random number generators, `uniform`

will generate the same sequence of numbers when called with the same initial seed values. Because of this behavior, you can rerun the testbench and get the same result when using the same seed values.

Refer to the Efficient and Portable Combined Random Number Generators paper by Pierre L’Ecuyer for a detailed description of how this algorithm works. You can also view an actual implementation of the algorithm in the GHDL open-source VHDL simulator.

## The test case

All of the examples in this article use the value 999 for both seeds. We declare the seed variables as listed below in the declarative region of a process. Then, we implement our custom randomization algorithms as impure functions within the same process.

variable seed1, seed2 : integer := 999;

You can download a complete testbench containing all the examples in this article by using the form below. The Zip file also contains a ModelSim project with a script that compiles and runs the simulation for you.

## Random real value

The `uniform`

procedure generates a random `real`

value between 0.0 and 1.0. The `real`

type is VHDL’s floating-point format. However, the chances are that you want the random number to be on a different range.

impure function rand_real(min_val, max_val : real) return real is variable r : real; begin uniform(seed1, seed2, r); return r * (max_val - min_val) + min_val; end function;

Fortunately, we can easily translate the output from `uniform`

by multiplying with a scale and adding an offset to it. The code above shows a function that returns a random `real`

value within a min/max range.

## Random integer value

To generate a random `integer`

value within a specified range, you have to multiply by a scale and add an offset to it. But there is a pitfall that you have to avoid. You cannot simply generate a random `real`

value within the range and round it to an `integer`

.

The illustration above shows the problem. In the example, we intend to generate a random `integer`

value in the range -1 to 1. If we base our `integer`

on a random `real`

that goes precisely to the endpoints, the min and max integers only get half the probability of being chosen. Rounding to the 0 `integer`

value happens half of the time, even though there are three number choices.

impure function rand_int(min_val, max_val : integer) return integer is variable r : real; begin uniform(seed1, seed2, r); return integer( round(r * real(max_val - min_val + 1) + real(min_val) - 0.5)); end function;

In the code above, we correct for the endpoint rounding issue by adjusting the random `real`

value to include an additional 0.5 above and below the endpoints.

## Random std_logic_vector

There are many ways to fill a vector with random values, but this method works with vectors of any length. I’m using a for-loop to traverse the vector and select a random value for every bit. In the code below, the `len`

parameter determines the length of the random `std_logic_vector`

to return.

impure function rand_slv(len : integer) return std_logic_vector is variable r : real; variable slv : std_logic_vector(len - 1 downto 0); begin for i in slv'range loop uniform(seed1, seed2, r); slv(i) := '1' when r > 0.5 else '0'; end loop; return slv; end function;

## Random time value

Sometimes you need to generate a random `time`

value in your testbench. Perhaps you want to simulate an external interface which writes bursts of data at random times. Whatever the reason, random `time`

values are easy to produce.

impure function rand_time(min_val, max_val : time; unit : time := ns) return time is variable r, r_scaled, min_real, max_real : real; begin uniform(seed1, seed2, r); min_real := real(min_val / unit); max_real := real(max_val / unit); r_scaled := r * (max_real - min_real) + min_real; return real(r_scaled) * unit; end function;

To generate a random `time`

value in VHDL, you must first convert the desired min and max values to `real`

types. Then, after the randomization formula has done its magic, you convert the result back to a VHDL `time`

type. Note that you must give the simulation time unit that you are using in the simulator as an argument to this function, as shown in the code above.

## The OSVVM Random package

Finally, as an alternative to hand-crafting the randomization algorithm, you can use the Random package from the OSVVM library. It has multiple overloaded functions for generating random values for all kinds of VHDL types.

Open Source VHDL Verification Methodology (OSVVM) is a VHDL library for creating structured testbenches. The Random package is just one out of many useful packages in this library.

library osvvm; use osvvm.RandomPkg.all;

The code above shows how to import the OSVVM package. ModelSim includes the library out-of-the-box, so you don’t have to download it for this simulator. Refer to the RandomPck.vhd file from the OSVVM GitHub repo to find a suitable randomization function for your needs.

Nice use of shared variables,

but VHDL 2008, needs all shared variables ot be of protected type,

so this code will at best raise warnings, at worse fail

can we have a version which uses protected types please

I avoided that problem in this article and downloadable code by using only regular variables. We placed the seed variables and all the new functions in the declarative region of a process.

If you want to share the randomization functions among multiple processes, you will have to define a package and create a shared variable from it. Then you can declare the seed variables and functions in the package.

I recommend studying OSVVM’s RandomPck.vhd to see how you can achieve that. Or simply just use OSVVM for that since it already has this excellent randomization package.