Question

I'm having a lot of trouble getting some simple math done in VHDL. I'm terrible at this language so if my syntax is stupid or something, I have an excuse :P. I'm trying to implement a very simple random number generator that calculates a pseudo-random number by this formula:

seed = (seed*1103515245) + 12345

How I'm trying to do it:

Signalss here

signal seed: std_logic_vector(31 downto 0) := x"2B4C96B9";
signal multiply: std_logic_vector(31 downto 0) := x"41C64E6D";
signal add: std_logic_vector(31 downto 0) := x"00003039";
signal temp1: std_logic_vector(63 downto 0);
signal temp2: std_logic_vector(31 downto 0);

Computation here (done in a state in a state machine)

temp2 <= seed;
temp1 <= std_logic_vector((unsigned(temp2)*unsigned(multiply)));
seed <= std_logic_vector(unsigned(temp1(31 downto 0)) + unsigned(add));

temp2 always ends up being undefined. Additionally, seed ends up being undefined as well. I've tried it several different ways but all of them were wrong mostly because of the vector sizes and order or operations. I feel like I'm doing it right at the moment based on what I've found through semi-extensive Googling but I just can't figure it out.

The best thing I can think of right now is to do each step of the calculation in its own state in a state machine. Can anyone see what I'm doing wrong here?

Was it helpful?

Solution

VHDL is different from other languages in that signal assign by <= does not take effect for read until after a delta delay, thus if you do:

temp2 <= seed;
temp1 <= std_logic_vector((unsigned(temp2)*unsigned(multiply)));
seed <= std_logic_vector(unsigned(temp1(31 downto 0)) + unsigned(add));

then the temp2 not actually updated for read in the expression used to assign temp1 until a delta delay has passed.

Depending on the details about your design, you can consider declaring the intermediate variables as variables:

variable temp1: std_logic_vector(63 downto 0);
variable temp2: std_logic_vector(31 downto 0);

and then assign like:

temp2 := seed;
temp1 := std_logic_vector((unsigned(temp2)*unsigned(multiply)));
seed <= std_logic_vector(unsigned(temp1(31 downto 0)) + unsigned(add));

In this case the intermediate variables temp1 and temp2 will have the result ready for read right after the assign, and the seed will have the value after a delta delay, assuming that you will not do the next iteration until next cycle.

It will clarify the intention in the code if constants are declared as such, doing:

constant MULTIPLY : std_logic_vector(31 downto 0) := x"41C64E6D";
constant ADD      : std_logic_vector(31 downto 0) := x"00003039";

A comment on you calculation, then the VHDL design truncates the result of the multiplication, thus doing:

seed = (seed*1103515245) mod (2**32) + 12345

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top