Need help with random # generator function

Guest
Hi, I'm still wading my way through VHDL, after years in Verilog.

I got to generate random numbers using 'uniform', but I got stuck
trying to turn the verbose code into a function. Since I'm using it a
lot, having a one line function call makes the code much more readable.
This is for a testbench, so needs not be synthesizable.

I've included the code below (simplified from the actual code, just
contains the random # generator). It works as included, but when I try
to comment out the verbose section and use the function, I get
compilation error - "Actual for formal 'seed1' is not a variable". Can
anyone help?

I have a feeling that it has to something with seed1/2 being shared
variables. I figured out that the function needs to be impure. Do I
need the function defined with no arguments? I tried using the
function with no argument (is it legal?), declaring seed1/2 as shared
variables, even trying prodecures.

Thank you in advance.

(The problematic function is commented out, from FUNCTION_START to
FUNCTION_END), along with the function call.)
===============================================================
LIBRARY ieee;
LIBRARY modelsim_lib;

USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.ALL;
use ieee.numeric_std.all;
use ieee.math_real.all;
use std.textio.all;
use work.image_pkg.all;

entity tb_rand is

end tb_rand;

architecture behavior of tb_rand is

signal sim_done : boolean := FALSE;
signal result : std_logic_vector(15 downto 0);
signal stim32 : std_logic_vector(31 downto 0);

begin

stimulus : process

variable L : line;
variable seed1 : positive; -- Seed values for random gen
variable seed2 : positive; -- Seed values for random gen
variable rand_hi : real; -- Random real-num value, 0 to 1.0
variable rand_lo : real; -- Random real-num value, 0 to 1.0
variable int_rand_hi: integer; -- Random int value, 0..65536
variable int_rand_lo: integer; -- Random int value, 0..65536
variable stim_hi : std_logic_vector(15 downto 0); -- random 16b
variable stim_lo : std_logic_vector(15 downto 0); -- random 16b
variable i : integer;


-------------------------------------------------------------------------
-- FUNCTION_START
-- Function get_rand
-- impure function get_rand (seed1, seed2 : positive)
-- return std_logic_vector is
--
-- variable rand : real;
-- variable int_rand_hi : integer;
-- variable int_rand_lo : integer;
-- variable result : std_logic_vector(31 downto 0);
-- begin
-- -- Get 16-bit random slv
-- UNIFORM(seed1, seed2, rand);
-- int_rand_hi := integer(trunc(rand*65536.0));
-- stim_hi := std_logic_vector(to_unsigned(int_rand_hi,
-- stim_hi'LENGTH));
--
-- -- Get 16-bit random slv
-- UNIFORM(seed1, seed2, rand);
-- int_rand_lo := integer(trunc(rand*65536.0));
-- stim_lo := std_logic_vector(to_unsigned(int_rand_lo,
-- stim_lo'LENGTH));
--
-- result := stim_hi & stim_lo;
--
-- return result;
-- end get_rand;
-- FUNCTION_END
----------------------------------------------------------------

------------------------------------------------------------------
-- Test Vector stimuli
------------------------------------------------------------------

begin

seed1 := 1;
seed2 := 2;

for i in 1 to 10 loop
wait for 1 ns;

--------------------------------------------------------------
-- VERBOSE_START
-- Get 16-bit random slv
uniform(seed1, seed2, rand_hi);
int_rand_hi := INTEGER(TRUNC(rand_hi*65536.0));
stim_hi := std_logic_vector(to_unsigned(int_rand_hi,
stim_hi'LENGTH));

-- Get 16-bit random slv
uniform(seed1, seed2, rand_lo);
int_rand_lo := INTEGER(TRUNC(rand_lo*65536.0));
stim_lo := std_logic_vector(to_unsigned(int_rand_hi,
stim_hi'LENGTH));

-- Concatenate the two to form 32-bit random slv
stim32 <= stim_hi & stim_lo;
-- VERBOSE_END
--------------------------------------------------------------

-- I'd Like to replace above code
-- from 'VERBOSE_START' to 'VERBOSE_END'
-- with the following line, or something like it.
-- 'FUNCTION_START' to 'FUNCTION_END' needs to be uncommented.
-- stim32 <= get_rand(seed1, seed2) & get_rand(seed1, seed2);

wait for 1 ns;
write(L, string'("stim32 = " & HexImage(stim32)));
writeline(output, L);


end loop;

wait for 100 ns;
sim_done <= TRUE;

wait;

end process;

end behavior;
 
Hi,
In ieee.math_real, uniform is defined as:
procedure uniform(variable seed1,seed2:inout positive; variable x:eek:ut real);

If you want to call uniform with a function, for seed1 and seed2,
you need a variable class object that is both read and write.
Unfortunately function parameters are only permitted to be inputs
(hence read only) so seed1 and seed2 cannot be input parameters.

However, you are on the right track with an impure function.
Impure functions that are defined in a process can read and
write objects that are visible to them. So, as long as seed1 and
seed2 are declared before your function (which they are), your
function can see them. So strike the parameter list of get_rand:

impure function get_rand
return std_logic_vector is


Also you need to remove the parameters from the call to get_rand
and only call it once since your current version returns 32 bits.
Hence your call to it resolves to:

stim32 <= get_rand ;


Also note that there is a bug in your verbose code. The
following should use int_rand_lo:
-- stim_lo := std_logic_vector(to_unsigned(int_rand_hi,
-- stim_hi'LENGTH));

Going further, you might want to reconsider your encapsulation
point. Generally I like to set up my subprograms so they
encapsulate an entire interface sequence. As a result, I use
procedures since only procedures allow wait. In this case,
I might do either:

for i in 1 to 10 loop
IF1_rand_seq (seed1, seed2, stim32) ;
end loop ;
...

or:

IF1_rand_seq(seed1, seed2, stim32) ;
IF1_rand_seq(seed1, seed2, stim32) ;
IF1_direct(X"AABBCCDD", stim32) ;
...

Using the procedures in this fashion also allows them to be
put in a package. Alternately you can also remove all objects
from the call if you define the procedure in the process.
You can mix the two if you put the procedure with full parameters
in a package and call it from a procedure defined in the process
that references the objects by side-effects.

You probably don't want to print everytime you apply
stimulus. Printing is slow.

Cheers,
Jim
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jim Lewis
Director of Training mailto:Jim@SynthWorks.com
SynthWorks Design Inc. http://www.SynthWorks.com
1-503-590-4787

Expert VHDL Training for Hardware Design and Verification
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Hi, I'm still wading my way through VHDL, after years in Verilog.

I got to generate random numbers using 'uniform', but I got stuck
trying to turn the verbose code into a function. Since I'm using it a
lot, having a one line function call makes the code much more readable.
This is for a testbench, so needs not be synthesizable.

I've included the code below (simplified from the actual code, just
contains the random # generator). It works as included, but when I try
to comment out the verbose section and use the function, I get
compilation error - "Actual for formal 'seed1' is not a variable". Can
anyone help?

I have a feeling that it has to something with seed1/2 being shared
variables. I figured out that the function needs to be impure. Do I
need the function defined with no arguments? I tried using the
function with no argument (is it legal?), declaring seed1/2 as shared
variables, even trying prodecures.

Thank you in advance.

(The problematic function is commented out, from FUNCTION_START to
FUNCTION_END), along with the function call.)
===============================================================
LIBRARY ieee;
LIBRARY modelsim_lib;

USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.ALL;
use ieee.numeric_std.all;
use ieee.math_real.all;
use std.textio.all;
use work.image_pkg.all;

entity tb_rand is

end tb_rand;

architecture behavior of tb_rand is

signal sim_done : boolean := FALSE;
signal result : std_logic_vector(15 downto 0);
signal stim32 : std_logic_vector(31 downto 0);

begin

stimulus : process

variable L : line;
variable seed1 : positive; -- Seed values for random gen
variable seed2 : positive; -- Seed values for random gen
variable rand_hi : real; -- Random real-num value, 0 to 1.0
variable rand_lo : real; -- Random real-num value, 0 to 1.0
variable int_rand_hi: integer; -- Random int value, 0..65536
variable int_rand_lo: integer; -- Random int value, 0..65536
variable stim_hi : std_logic_vector(15 downto 0); -- random 16b
variable stim_lo : std_logic_vector(15 downto 0); -- random 16b
variable i : integer;


-------------------------------------------------------------------------
-- FUNCTION_START
-- Function get_rand
-- impure function get_rand (seed1, seed2 : positive)
-- return std_logic_vector is
--
-- variable rand : real;
-- variable int_rand_hi : integer;
-- variable int_rand_lo : integer;
-- variable result : std_logic_vector(31 downto 0);
-- begin
-- -- Get 16-bit random slv
-- UNIFORM(seed1, seed2, rand);
-- int_rand_hi := integer(trunc(rand*65536.0));
-- stim_hi := std_logic_vector(to_unsigned(int_rand_hi,
-- stim_hi'LENGTH));
--
-- -- Get 16-bit random slv
-- UNIFORM(seed1, seed2, rand);
-- int_rand_lo := integer(trunc(rand*65536.0));
-- stim_lo := std_logic_vector(to_unsigned(int_rand_lo,
-- stim_lo'LENGTH));
--
-- result := stim_hi & stim_lo;
--
-- return result;
-- end get_rand;
-- FUNCTION_END
----------------------------------------------------------------

------------------------------------------------------------------
-- Test Vector stimuli
------------------------------------------------------------------

begin

seed1 := 1;
seed2 := 2;

for i in 1 to 10 loop
wait for 1 ns;

--------------------------------------------------------------
-- VERBOSE_START
-- Get 16-bit random slv
uniform(seed1, seed2, rand_hi);
int_rand_hi := INTEGER(TRUNC(rand_hi*65536.0));
stim_hi := std_logic_vector(to_unsigned(int_rand_hi,
stim_hi'LENGTH));

-- Get 16-bit random slv
uniform(seed1, seed2, rand_lo);
int_rand_lo := INTEGER(TRUNC(rand_lo*65536.0));
stim_lo := std_logic_vector(to_unsigned(int_rand_hi,
stim_hi'LENGTH));

-- Concatenate the two to form 32-bit random slv
stim32 <= stim_hi & stim_lo;
-- VERBOSE_END
--------------------------------------------------------------

-- I'd Like to replace above code
-- from 'VERBOSE_START' to 'VERBOSE_END'
-- with the following line, or something like it.
-- 'FUNCTION_START' to 'FUNCTION_END' needs to be uncommented.
-- stim32 <= get_rand(seed1, seed2) & get_rand(seed1, seed2);

wait for 1 ns;
write(L, string'("stim32 = " & HexImage(stim32)));
writeline(output, L);


end loop;

wait for 100 ns;
sim_done <= TRUE;

wait;

end process;

end behavior;
 
fastgreen2000@yahoo.com wrote:
Hi, I'm still wading my way through VHDL, after years in Verilog.

LIBRARY ieee;
LIBRARY modelsim_lib;

USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.ALL;
use ieee.numeric_std.all;
Don't include std_logic_unsigned and numeric_std at the same time.
Don't use std_logic_unsigned (or std_logic_arith) at all.

-a
 
Thanks Jim,

I got it to work as an impure function. I had tried getting rid of
argument list for the function, but didn't go far enough to get rid of
the parentheses. Thanks for pointing out the silly bug (oh, printing
was just for debug).

Your point about the encapsulation point makes sense. It'll make the
code read more efficiently.

I still have to modify the seeds in a file so I don't use same numbers
over and over, but that shouldn't be hard. Changing over to procedures
is in order, too. Thanks again.
 
Andy Peters wrote:
.. . .
USE ieee.std_logic_unsigned.ALL;
use ieee.numeric_std.all;
....

Don't include std_logic_unsigned and numeric_std at the same time.
Don't use std_logic_unsigned (or std_logic_arith) at all.
Ironically std_logic_unsigned works better with
numeric_std than it does with std_logic_arith.
So the only reason to not use it is methodology (religion).
Note that although std_logic_unsigned is not an IEEE
standard, it is well supported by industry.


The methodology I use is:
1) Never use std_logic_vector for anything is math.
2) Type numeric_std.unsigned is recommended for incrementers
and decrementers, however, I am not going to stress if you
use std_logic_vector and std_logic_unsigned."+" or
std_logic_unsigned."-"
3) For a testbench, it is permitted to do unsigned math on
a std_logic_vector IO (such as address or data fields)
using std_logic_unsigned.
4) Never use the package std_logic_signed.


A less-restrictive methodology:
1) All types unless otherwise denoted are unsigned.
2) Freely use std_logic_unsigned.


The more-restrictive methodology:
1) std_logic_vector never has a numeric value.
2) Always use types signed and unsigned to any numeric operation.
3) Never use std_logic_unsigned.

Pick something that makes sense to you and stick to it.

Beware if you do not use std_logic_unsigned, you may be surprised
at the result of a comparison of two std_logic_vectors that have
different lengths.


Cheers,
Jim

--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jim Lewis
Director of Training mailto:Jim@SynthWorks.com
SynthWorks Design Inc. http://www.SynthWorks.com
1-503-590-4787

Expert VHDL Training for Hardware Design and Verification
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

Welcome to EDABoard.com

Sponsor

Back
Top