0
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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 ) );
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ "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 65536." Fencepost error. Max value is 65535. \$\endgroup\$ – WhatRoughBeast Jun 12 '19 at 20:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.