VHDL Bit Vector Operators - math

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?

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

Related

assign data(i) into std_logic_vector(0 downto 0) in vhdl

I have the following problem:
My code has this constant value
constant source_vector : std_logic_vector(7 downto 0) := "1011000";
This value needs to be fed into a signal of type std_logic_vector, bit by bit. The problem is that the destination vector has a size defined in a constant. For the test, I am using size 1.
constant k : integer := 1;
dest_vector : in std_logic_vector(k-1 downto 0);
When I try to assign the first bit:
dest_vector <= std_logic_vector(to_unsigned(source_vector(0), k));
I got this error:
ERROR: [VRFC 10-925] indexed name is not a natural
I have tried several things, but no luck. Perhaps I am missing something... Any advice here?
Answer from user1155120 Jul 16 '17 at 19:47
Use dest_vector <= source_vector(0 downto 0); which uses a slice name or dest_vector(0) <= source_vector(0); which uses indexed names for both target and right hand side. There's also dest_vector <= "" & source_vector(0); which derives the type of the concatenation result from context while concatenating a null array to a value of the element type. See IEEE Std 1076-2008 8.4 Indexed names, 8.5 Slice names, 9.2.5 Adding operators ("&") and 12.5 The context of overload resolution (which "&").

recursion using for do loop (pascal)

I'm trying to use the concept of recursion but using for do loop. However my program cannot do it. For example if I want the output for 4! the answer should be 24 but my output is 12. Can somebody please help me?
program pastYear;
var
n,i:integer;
function calculateFactorial ( A:integer):real;
begin
if A=0 then
calculateFactorial := 1.0
else
for i:= A downto 1 do
begin
j:= A-1;
calculateFactorial:= A*j;
end;
end;
begin
writeln( ' Please enter a number ');
readln ( n);
writeln ( calculateFactorial(n):2:2);
readln;
end.
There are several problems in your code.
First of all it doesn't compile because you are accessing the undefined variable j.
Calculating the factorial using a loop is the iterative way of doing it. You are looking for the recursive way.
What is a recursion? A recursive function calls itself. So in your case calculateFactorial needs a call to itself.
How is the factorial function declared?
In words:
The factorial of n is declared as
1 when n equals 0
the factorial of n-1 multiplied with n when n is greater than 0
So you see the definition of the factorial function is already recursive since it's referring to itself when n is greater than 0.
This can be adopted to Pascal code:
function Factorial(n: integer): integer;
begin
if n = 0 then
Result := 1
else if n > 0 then
Result := Factorial(n - 1) * n;
end;
No we can do a few optimizations:
The factorial function doesn't work with negative numbers. So we change the datatype from integer (which can represent negative numbers) to longword (which can represent only positive numbers).
The largest value that a longword can store is 4294967295 which is twice as big as a longint can store.
Now as we don't need to care about negative numbers we can reduce one if statement.
The result looks like this:
function Factorial(n: longword): longword;
begin
if n = 0 then
Result := 1
else
Result := Factorial(n - 1) * n;
end;

VHDL directly comparing vectors

I was wondering if its possible to directly compare 2 vectors with eachother instead of just looking at them bit by bit.
For example:
entity Comparator is
port(a,b in: std_logic_vector (2 downto 0);
out1, out2 out: std_logic);
end Comparator;
architecture behavioural of Comparator1 is
begin
if a = b then
out1 <= '1'
else if /= then
out2 <= '1'
end if;
end behaviour;
Is this possible?
The answer is yes, you can compare two array types of the same type and subtype indication directly.
However your example code isn't valid.
The result of the expression a=b is boolean. You convert that to std_logic by assigning out1 and out2. An if statement in this context has to be in a process statement. Also you don't need two outputs:
architecture foo of Comparator1 is
begin
UNLABELED:
process (a,b)
begin
if a = b then
out1 <= '1';
else
out1 <= '0';
end if;
end process;
end architecture;
Alternative a concurrent signal assignment statement, a conditional signal assignment that has an equivalent process to that above:
architecture fum of Comparator1 is
begin
UNLABELED:
out1 <= '1' when a = b else '0';
end architecture;
You can also use to_integer(unsigned(a)) and threat them as integers.
For example:
IF(to_integer(unsigned(a)) < to_integer(unsigned(b))) THEN

VHDL Synthesis Error

I'm trying to write some simple math functions in VHDL but I keep getting the error
found '0' definitions of operator "+", cannot determine exact overload matching definition for "+" and I also get the same error about the division.
Here is the relevant code:
signal delay_1 : integer range 0 to 127;
-- signal delay_2 : integer range 0 to 127;
-- signal delay_3 : integer range 0 to 127;
-- signal delay_4 : integer range 0 to 127;
signal us_clock : std_logic;
signal ds_squareroot : integer range 0 to 100;
signal ds_squared : integer range 0 to 5000;
if(i_reset = '1') then
delay_1 <= 0;
delay_2 <= 0;
delay_3 <= 0;
delay_4 <= 0;
ds_squared <= 0;
ds_squareroot <= 0;
elsif(rising_edge(i_clock)) then
-- Delay 1 calculations
ds_squared <= (i_distance*i_distance + (speaker_distance)*(speaker_distance));
for n in 0 to 20 loop
ds_squareroot <= ((50 + ds_squared/ds_squareroot)/2);
end loop;
delay_1 <= (ds_squareroot - i_distance)/ speed_sound;
And here are the libraries that I'm calling.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
library UNISIM;
use UNISIM.VComponents.all;
Any advice as to why this is not compiling would be very helpful.
The error was that i_distance was a std_logic_vector and speaker_distance was an integer. Obviously this did not synthesize because of the difference in types here. I solved it with this simple expression
distance <= conv_integer(i_distance);
This made both integers, which allowed the design to synthesize. Thanks for the help.

Is overflow defined for VHDL numeric_std signed/unsigned

If I have an unsigned(MAX downto 0) containing the value 2**MAX - 1, do the VHDL (87|93|200X) standards define what happens when I increment it by one? (Or, similarly, when I decrement it by one from zero?)
Short answer:
There is no overflow handling, the overflow carry is simply lost. Thus the result is simply the integer result of your operation modulo 2^MAX.
Longer answer:
The numeric_std package is a standard package but it is not is the Core the VHDL standards (87,93,200X).
For reference : numeric_std.vhd
The + operator in the end calls the ADD_UNSIGNED (L, R : unsigned; C : std_logic) function (with C = '0'). Note that any integer/natural operand is first converted into an unsigned.
The function's definition is:
function ADD_UNSIGNED (L, R : unsigned; C : std_logic) return unsigned is
constant L_left : integer := L'length-1;
alias XL : unsigned(L_left downto 0) is L;
alias XR : unsigned(L_left downto 0) is R;
variable RESULT : unsigned(L_left downto 0);
variable CBIT : std_logic := C;
begin
for i in 0 to L_left loop
RESULT(i) := CBIT xor XL(i) xor XR(i);
CBIT := (CBIT and XL(i)) or (CBIT and XR(i)) or (XL(i) and XR(i));
end loop;
return RESULT;
end ADD_UNSIGNED;
As you can see an "overflow" occurs if CBIT='1' (carry bit) for i = L_left. The result bit RESULT(i) is calculated normally and the last carry bot value is ignored.
I've had the problem with wanting an unsigned to overflow/underflow as in C or in Verilog and here is what I came up with (result and delta are unsigned):
result <= unsigned(std_logic_vector(resize(('1' & result) - delta, result'length))); -- proper underflow
result <= unsigned(std_logic_vector(resize(('0' & result) + delta, result'length))); -- proper overflow
For overflow '0' & result makes an unsigned which is 1 bit larger to be able to correctly accommodate the value of the addition. The MSB is then removed by the resize command which yields the correct overflow value. Same for underflow.
For a value of MAX equal to 7 adding 1 to 2**7 - 1 (127) will result in the value 2**7 (128).
The maximum unsigned value is determined by the length of an unsigned array type:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity foo is
end entity;
architecture faa of foo is
constant MAX: natural := 7;
signal somename: unsigned (MAX downto 0) := (others => '1');
begin
UNLABELED:
process
begin
report "somename'length = " & integer'image(somename'length);
report "somename maximum value = " &integer'image(to_integer(somename));
wait;
end process;
end architecture;
The aggregate (others => '1') represents a '1' in each element of somename which is an unsigned array type and represents the maximum binary value possible.
This gives:
foo.vhdl:15:9:#0ms:(report note): somename'length = 8
foo.vhdl:16:9:#0ms:(report note): somename maximum value = 255
The length is 8 and the numerical value range representable by the unsigned array type is from 0 to 2**8 - 1 (255), the maximum possible value is greater than 2**7 (128) and there is no overflow.
This was noticed in a newer question VHDL modulo 2^32 addition. In the context of your accepted answer it assumes you meant length instead of the leftmost value.
The decrement from zero case does result in a value of 2**8 - 1 (255) (MAX = 7). An underflow or an overflow depending on your math religion.
Hat tip to Jonathan Drolet for pointing this out in the linked newer question.

Resources