Electrical – How to generate positive and negative random numbers in VHDL

random numbervhdl

In my VHDL testbench, I have a configurable parameter DATA_WIDTH which is set to power of 2 such as 16-bits.

I want to generate random signed numbers (2's compliment) of bit width as DATA_WIDTH. For example if DATA_WIDTH is 16 bits, then I want to generate random numbers in range -32,768 to 32,768 (all range inclusive).

As of now I am doing following (snippet of VHDL code, not complete):

variable W : natural                := 16;
variable seed1, seed2 : positive    := 1;
variable x_real: real               := 0.0;
variable x_int : integer            := 0;

variable data_vec std_logic_vector(W-1 downto 0) := ( others =>'0' );

uniform( seed1, seed2, x_real );
x_int := integer(floor(x_real * real(2**W)));

data_vec := std_logic_vector( to_signed( x_int, data_vec'LENGTH ) ) 

However, when I run the testbench simulation, I get following warnings from Modelsim:

Warning: NUMERIC_STD.TO_SIGNED: vector truncated

There is a related question, however the answer in that post doesn't offer solution using standard VHDL libraries but using Open Source VHDL Verification Methodology.

Best Answer

In your code, you have:

x_int := integer(floor(x_real * real(2**W)));

Your generated values for x_int are in the range of 0 to 2**W, so for W=16, you get values from 0 to 65535.

But then next up you convert to a signed vector:

data_vec := std_logic_vector( to_signed( x_int, data_vec'LENGTH ) );

The problem is that a signed value of W bits can only represent -2W-1 to 2W-1-1. So anytime the call to uniform generates a value greater than 2W-1-1, you exceed the range of your vector.

Since uniform returns a value in the range (0.0, 1.0), you need to scale your random value to be (-1.0, 1.0), then apply 2W-1. Though this is equivalent to scaling your random value to (-0.5, 0.5) and then apply 2W.

EDIT: Alternatively, you can use to_unsigned, for which 2W is fine (unsigned vectors have a range of 0 to 2W-1). And since this is just going into an amorphous vector, will work fine.

data_vec := std_logic_vector( to_unsigned( x_int, data_vec'LENGTH ) );
Related Topic