VHDL - Object Class For Formal Parameter of function cant be a variable - vhdl

I am trying to write some VHDL to make a sign magnitude addition (overload +) without using any + in the code. Using Quartus 2 13.0 Cyclonce IV E EP4ce115F29C7
When I try to compile my current project, I get the stack trace:
which points me to this line:
variable sum:std_logic_vector(max downto 0);
I am not sure where I am going wrong, I have looked for material on this but couldn't really find anything.
Here is my code:
Library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
package SIGN_MAGNITUDE_ARITH is
constant word_size: positive := 32;
type SIGN_MAG is array(natural range <>) of std_logic;
function "+"(L:SIGN_MAG; R:SIGN_MAG;) return SIGN_MAG;
--function "-"(L: SIGN_MAG; R: SIGN_MAG;) return SIGN_MAG;
--function "*"(L: SIGN_MAG; R: SIGN_MAG;) return SIGN_MAG;
--procedure "/"(signal Z, D: in SIGN_MAG; signal Q,R: out SIGN_MAG);
end;
package body SIGN_MAGNITUDE_ARITH is
-- Sign Magnitude addition (overload "+")
function "+"(L: SIGN_MAG; R: SIGN_MAG;) return SIGN_MAG is
constant max = (MAX(R'length, L'length));
variable carry:std_logic:='0';
variable sum:std_logic_vector(max downto 0);
begin
if(L(L'length-1)='0') and (R(R'length-1)='0') then
for i in 0 to max - 2 loop
sum(i):= L(i) xor R(i) xor carry;
carry:=( L(i) and R(i) ) or ( L(i) and carry ) or ( R(i) and carry );
end loop;
sum(max-1):=carry;
sum(max):='0';
end if;
return sum;
end;
end;

Related

Generic function in VHDL to extract an arbitrary byte from a std_logic_vector of any length?

How to write a generic function that will extra a byte from a std_logic_vector based on an index value?
library ieee;
use ieee.std_logic_1164.all;
use std.textio.all;
entity tmp is
end entity;
architecture beh of tmp is
function get_byte(
idx: in integer;
dat: in std_logic_vector
) return std_logic_vector is
constant msb :integer := (idx+1)*8 - 1;
constant lsb :integer := idx*8;
variable ret :std_logic_vector(7 downto 0);
begin
ret := dat(msb downto lsb);
return ret;
end function;
begin
process
constant vec :std_logic_vector := X"ABCDEF1234567";
variable b1 :std_logic_vector(7 downto 0);
variable m :line;
begin
b1 := get_byte(1, vec);
report "just kidding! end of testbench" severity failure;
end process;
end architecture;
Here's the error from my attempt:
C:\Xilinx\Vivado\2021.2\bin\xvhdl.bat --incr --relax --work work tmp.vhd
C:\Xilinx\Vivado\2021.2\bin\xelab.bat tmp -snapshot simout
Vivado Simulator v2021.2
Copyright 1986-1999, 2001-2021 Xilinx, Inc. All Rights Reserved.
Running: C:/Xilinx/Vivado/2021.2/bin/unwrapped/win64.o/xelab.exe tmp -snapshot simout
Multi-threading is on. Using 10 slave threads.
Starting static elaboration
ERROR: [VRFC 10-1378] slice direction differs from its index type range [C:/Users/xxx/Desktop/tmp/tmp.vhd:19]
ERROR: [XSIM 43-3321] Static elaboration of top level VHDL design unit tmp in library work failed.
ERROR: [VRFC 10-1378] slice direction differs from its index type
range
Is resolved by specifying the 'to' vs 'downto' ranges on each std_logic_vector declaration. (the default if not shown is to assumed 0 'to' N, not 'downto' - so when not shown/making simulator choose you are sorta mixing types).
As you don't know how your function will be called and what its parameter will be, a very simple approach consists in creating local copies with known ranges:
function get_byte(idx: natural; dat: std_logic_vector) return std_logic_vector is
constant size: natural := dat'length;
constant ldat: std_logic_vector(size-1 downto 0) := dat;
begin
assert 8*idx+7 <= size report "out of range index" severity failure;
return ldat(8*idx+7 downto 8*idx);
end function get_byte;
Not sure why, but it works if I write it this way:
function get_byte(
idx :in integer; -- 0=MS-Byte ... n=LS-BYTE
dat :in std_logic_vector -- uncontrained slv is a "to"
-- not a "Downto" vector?
) return std_logic_vector is
constant msb :integer := (idx+1)*8 - 1;
constant lsb :integer := idx*8;
variable ret :std_logic_vector(7 downto 0);
begin
ret := dat(idx*8 + 0)
& dat(idx*8 + 1)
& dat(idx*8 + 2)
& dat(idx*8 + 3)
& dat(idx*8 + 4)
& dat(idx*8 + 5)
& dat(idx*8 + 6)
& dat(idx*8 + 7);
return ret;
end function;

How can I calculate elements in one vector?

I'm new at VHDL code, and I'm trying to figure out, how is the easiest way to calculate elements in STD_LOGIC_VECTOR.
so how my ports look like:
Port ( D : in STD_LOGIC_VECTOR (width-1 downto 0); -- data input
parity : out STD_LOGIC -- parity bit
);
so I want to do something like this (code in c)
int helper = 0;
for (int i = 0; i < width; i++) {
if (D[i] == 1) {
helper++;
}
}
if (helper % 2 == 0) {
parity = 1;
}
if im not enought clear sorry for that, i can probably answer your question, if there will be.
Probably the best way to do this in VHDL is with xor_reduce from ieee.std_logic_misc. Addition modulo 2 is exactly the same as XOR, and xor_reduce XORs all of the inputs together, giving you the addition modulo 2 of your input bits. This would look like:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_misc.xor_reduce;
entity PARITY_GEN is
generic (width : integer := 8);
port( D: in std_logic_vector(width-1 downto 0);
parity: out std_logic
);
end PARITY_GEN;
architecture bhv of PARITY_GEN is
begin
process(D)
begin
parity <= xor_reduce(D);
end process;
end bhv;
If you don't want to include xor_reduce, you could do the same just using xor:
library ieee;
use ieee.std_logic_1164.all;
entity PARITY_GEN is
generic (width : integer := 8);
port( D: in std_logic_vector(width-1 downto 0);
parity: out std_logic
);
end PARITY_GEN;
architecture bhv of PARITY_GEN is
begin
process(D)
variable temp:std_logic_vector(width-1 downto 0);
begin
temp(0) := D(0);
loop:for i in 1 to width-1 generate
temp(i) := temp(i-1) xor D(i);
end generate;
parity <= temp(width-1);
end process;
end bhv;

Constant initialisation from a user-made function synthesis takes forever but easily created in simulation

I have created a function "my_func" in a package which when inputted with x produced a matrix of integers of shape [log2(x), x]. I wish to place this slice into ROM memory for synthesis.
For the sake of synthesis I attatch a counter to the ROM and read out one register per clk cycle. I have been able to simulate this and get the expected answers. The synthesis of the code never finishes, even when the generic controling the function is very small as shown in the code.
I am confused as to why Vivado can very quickly simulate the desired design but takes forever to synthesise. I get no errors from vivado saying that the design is unsynthesisable.
Has anyone else experienced this problem, and what are the steps I can take to avoid the problem in the future?
Please see my synthesis code below and a snippet of the function code below
For the record for this question Synthesis = Elaborate Design (RTL)
library IEEE;
library WORK;
use WORK.mylib.all;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use IEEE.math_real.all;
entity try is
generic(
x : integer := 8
);
port(
clk : in std_logic;
ouput: out integer;
);
end entity try;
architecture v1 of try is
constant sig : my_matrix_of_integers(0 to integer(log2(real(x)))-1, 0 to x-1) := my_func(x);
signal counter : unsigned(integer(log2(real(x)))-1 downto 0);
begin
process(clk)
begin
if rising_edge(clk) then
output <= sig(0, to_integer(counter));
counter <= counter + 1;
end if;
end process;
end architecture v1;
Here is a snippet of my function code
function my_func (x: integer) return mat_t is
variable y: integer := integer(log2(real(x)));
variable cluster : integer;
variable index : integer;
variable mat : my_matrix_of_integers(0 to y-1, 0 to x-1);
begin
for s in 0 to y-1 loop
index := x/(2**(s+1));
cluster := x/index;
for c in 0 to cluster - 1 loop
for i in 0 to index -1 loop
if c mod 2 = 0 then
mat(s, (c*index) + i) := 0;
else
mat(s, (c*index) + i) := i*(2**(s));
end if;
end loop;
end loop;
end loop;
return mat;
end function my_func;
and type ...
type my_matrix_of_integers is array(integer range <>, integer range <>) of integer;

VHDL adder, same word length?

In VHDL i want to add a number of 5 bits and a number of 8 bits.(Unsigned) And how many bits does the output have?
I want my code to answer the questions i just asked. My code currently look like this...
My code is:
library ieee;
use ieee-std_logic_1164.all;
entity adder is
port( a : in unsigned (7 downto 0);
b : in unsigned (4 downto 0); - - Need to convert this to 8 bit right? But how?
z : out unsigned(7 downto 0)); - - This one must be 8 bits right? Cuz a & b & z must have the same WL. Or am i wrong?
end adder;
archictecture add of adder is
begin
z <= a + b;
end archictecture;
In package numeric_std for function "+" (L, R: UNSIGNED) return UNSIGNED the length of the longest argument defines the return value length:
function "+" (L, R: UNSIGNED) return UNSIGNED is
constant SIZE: NATURAL := MAX(L'LENGTH, R'LENGTH);
variable L01 : UNSIGNED(SIZE-1 downto 0);
variable R01 : UNSIGNED(SIZE-1 downto 0);
begin
if ((L'LENGTH < 1) or (R'LENGTH < 1)) then return NAU;
end if;
L01 := TO_01(RESIZE(L, SIZE), 'X');
if (L01(L01'LEFT)='X') then return L01;
end if;
R01 := TO_01(RESIZE(R, SIZE), 'X');
if (R01(R01'LEFT)='X') then return R01;
end if;
return ADD_UNSIGNED(L01, R01, '0');
end "+";
The maximum of the left and right arguments length is SIZE, the range of the two arguments is is resized to SIZE -1 downto 0 as arguments to ADD_UNSIGNED.
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;
The RESULT's length is that of the L argument which is the same of both arguments to UNSIGNED_ADD. There is no carry out implied in the result.
As in your case the result, assigned to z can be 8 bits.
Fix the comment delimiters in the port declarations, add a use clause to access package numeric_std, fix a '-' that should be a '.', spelling of architecture and add a test bench adding values for a and b set to all '1's and you can analyze, elaborate and run your design without error, telling you there isn't an array length error executing.
To get that ninth 'bit' as an output of the adder you can RESIZE one of your arguments to + to 9 bits or concatenate one argument with leading zeros to make a 9 bit value:
z <= "0" & a + b;
It'll demonstrate that the 9th bit is needed for an accurate result:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity adder is
port(
a: in unsigned (7 downto 0);
b: in unsigned (4 downto 0);
z: out unsigned (8 downto 0)
);
end adder;
architecture add of adder is
begin
z <= "0" & a + b;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb_adder is
end entity;
architecture foo of tb_adder is
signal a: unsigned (7 downto 0) := (others => '1');
signal b: unsigned (4 downto 0) := (others => '1');
signal z: unsigned (8 downto 0);
function unsigned_image(inp: unsigned) return string is
variable image_str: string (1 to inp'length);
alias input_str: unsigned (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end;
begin
DUT:
entity work.adder
port map (
a => a,
b => b,
z => z
);
MONITOR:
process
begin
wait for 1 ns;
report "z = " & unsigned_image(z);
wait;
end process;
end architecture;
david_koontz#Macbook: ghdl -a adder.vhdl
david_koontz#Macbook: ghdl -e tb_adder
david_koontz#Macbook: ghdl -r tb_adder
adder.vhdl:54:9:#1ns:(report note): z = 100011110
Other than this correction:
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
Your code is fine.
Additionally, adding an 8 bit number and a 5 bit number produces a 9 bit number, because you can overflow. For example, "11111111" + "11111" overflows a 8 bit output, but doesn't overflow a 9 bit output.

Conversion from numeric_std unsigned to std_logic_vector in vhdl

I have a question related to conversion from numeric_std to std_logic_vector. I am using moving average filter code that I saw online and filtering my ADC values to stable the values.
The filter package code is:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package filterpack is
subtype number is unsigned(27 downto 0);
type numbers is array(natural range <>) of number;
function slv_to_num(signal slv: in std_logic_vector) return number;
procedure MAF_filter(
signal x: in number;
signal h: inout numbers;
signal y: out number
);
end filterpack;
package body filterpack is
function slv_to_num(signal slv: in std_logic_vector) return number is
variable x: number := (others => '0');
begin
for i in slv'range loop
if slv(i) = '1' then
x(i+4) := '1';
end if;
end loop;
return x;
end function slv_to_num;
procedure MAF_filter(
signal x: in number;
signal h: inout numbers;
signal y: out number
) is
begin
h(0) <= x + h(1); -- h[n] = x[n] + h[n-1]
y <= h(0) - h(h'high); -- y[n] = h[n] - h[n-M]
end MAF_filter;
end package body filterpack;
In my top level file, I call the MAF_filter procedure.
Asign_x: x <= slv_to_num(adc_dat);
Filter: MAF_filter(x,h,y);
The adc_dat is defined as:
adc_dat : out std_logic_vector (23 downto 0);
I want to convert the output of the MAF_Filter to std_logic_vector (23 downto 0). Can anyone tell how can I convert filter output 'y' to 'std_logic_vector'?
Many Thanks!
What do you want to do with the 4 extra bits? Your type number has 28 bits, but your signal adc_dat has only 24.
If it's ok to discard them, you could use:
adc_dat <= std_logic_vector(y(adc_dat'range));
Also, is there a reason not to write your function slv_to_num as shown below?
function slv_to_num(signal slv: in std_logic_vector) return number is
begin
return number(slv & "0000");
end function slv_to_num;
The conversion has to solve 2 problems : the type difference you noted, and the fact that the two words are different sizes.
The type difference is easy : std_logic_vector (y) will give you the correct type. Because the two types are related types, this is just a cast.
The size difference ... only you have the knowledge to do that.
adc_dat <= std_logic_vector(y(23 downto 0)) will give you the LSBs of Y - i.e. the value of Y itself, but can overflow. Or as Rick says, adc_dat <= std_logic_vector(y(adc_dat'range)); which is usually better, but I wanted to expose the details.
adc_dat <= std_logic_vector(y(27 downto 4)) cannot overflow, but actually gives you y/16.

Resources