Modelsim. Length of arrays do not match - arrays

I have written a program in modelsim that add to numbers and put the result in Ra/Sum. I have used a tristate buffer, but I get this: Fatal: (vsim-3420) Array lengths do not match. Left is 16 (15 downto 0). Right is 8 (7 downto 0). I understand that this is because they have different lengths. But they cant have the same length either, because then I get an error when adding add1 and add2 and putting them in Sum. So what can I do to make this work?
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.numeric_std.all;
entity MAC is
generic (width: integer := 8);
port(
clk, reset : in STD_LOGIC;
MLS_select : in STD_LOGIC;
Rn, Rm, Ra : in STD_LOGIC_VECTOR(width-1 downto 0);
Rd : out STD_LOGIC_VECTOR(width-1 downto 0)
);
end;
architecture behavioral of MAC is
signal mul1, mul2, add1 : UNSIGNED(width-1 downto 0);
signal add2, sum : UNSIGNED(width*2-1 downto 0);
begin
process(clk, reset)
begin
if reset = '1' then Rd <= (others => '0');
elsif rising_edge(clk) then
Rd <= STD_LOGIC_VECTOR(sum(width-1 downto 0));
end if;
end process;
mul1 <= UNSIGNED(Rn);
mul2 <= UNSIGNED(Rm);
add1 <= UNSIGNED(Ra);
add2 <= mul1*mul2;
sum <= add2 when clk = '1' else add2;
sum <= add1+add2;
end architecture;

At first, ... when clk = '1' else ... will create a latch, but no flip-flop.
You need to use ... when rising_edge(clk);.
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity MAC is
generic (width: integer := 8);
port(
clk, reset : in STD_LOGIC;
MLS_select : in std_logic;
Rn, Rm, Ra : in std_logic_vector(width - 1 downto 0);
Rd : out std_logic_vector(width - 1 downto 0) := (others => '0')
);
end entity;
architecture rtl of MAC is
signal mul1, mul2, add1 : unsigned(width - 1 downto 0);
signal add2, sum : unsigned(width * 2 - 1 downto 0);
begin
process(clk, reset)
begin
if (reset = '1') then
Rd <= (others => '0');
elsif rising_edge(clk) then
Rd <= std_logic_vector(sum(Rd'range));
end if;
end process;
mul1 <= unsigned(Rn);
mul2 <= unsigned(Rm);
add1 <= unsigned(Ra);
add2 <= (mul1 * mul2) when rising_edge(clk);
sum <= resize(add1, add'length) + add2;
end architecture;
Signal MLS_select is unused. There is no need to calculate the sum with so many bits. I suggest to truncate add2 before the addition, to reduce the number of unused bits (and warnings generated by them).

Related

VHDL: Multiple for loop serial execution

I might be new to synthesizing loops. I am trying to create a counting sort in VHDL which takes arbitary length(say N) of integer array as input for sorting.
The code for design heavily relies on for loop. The looping logic seems to be parallel within a process or may be across processes. So I put all of the for loop in one process. But with that, the loops seem to execute in parallel independently. Which defeats the purpose as one loop should follow the other.
I have used counting sort algorithm from https://www.geeksforgeeks.org/counting-sort/
I am unable to get the logic working as mentioned in the algorithm.
Q1: How does the for loop execute within a process. Does all the for loop execute in parallel.
Q2:Is there an alternate way of implementing this for loop logic in VHDL, so that it executes serially?
Q3:Are there limitations for synthesizing for loops?
Design code:
library ieee;
use ieee.std_logic_1164.all;
package sorting_pkg is
type intarray is array(natural range <>) of std_logic_vector(7 downto 0);
end package;
library ieee;
use ieee.std_logic_1164.all;
use work.sorting_pkg.all;
use IEEE.NUMERIC_STD.all;
use ieee.std_logic_unsigned.all;
entity Sorting is
generic (
N : integer );
port(
--clk : in STD_LOGIC;
rst : in STD_LOGIC;
inStream : in intarray(0 to N-1);
outStream : out intarray(0 to N-1);
BoutArray: out intarray(0 to 16);
CoutArray: out intarray(0 to 16)
);
end entity;
architecture behavior of Sorting is
signal BArray: intarray(0 to 16) := (others => "00000000");
signal CArray: intarray(0 to 16) := (others => "00000000");
signal DArray: intarray(0 to 16) := (others => "00000000");
--signal Aindex1,Aindex2,Cindex,k: std_logic_vector(7 downto 0);
--signal Aindex1,Aindex2,Cindex,k : natural range 0 to 16;
begin
process
begin
if(rst = '1') then
outStream <=(others => "00000000");
else
Bloop: for i in 0 to N-1 loop
BArray(to_integer(unsigned(inStream(i)))) <=BArray(to_integer(unsigned(inStream(i)))) + 1;
end loop;
CArray(0) <= BArray(0);
Cloop: for j in 1 to 16 loop
CArray(j) <= BArray(j) + CArray(j - 1);
end loop;
Coutloop:for l in 0 to N-1 loop
DArray(to_integer(unsigned(inStream(l)))) <= CArray(to_integer(unsigned(inStream(l)))) - 1;
end loop;
outloop:for m in 0 to N-1 loop
outStream(to_integer(unsigned(DArray(to_integer(unsigned(inStream(m))))))) <= inStream(m);
end loop;
BoutArray <= BArray;
CoutArray <= DArray;
end if;
wait;
end process;--end proc
end architecture;
Testbench code:
library ieee;
use ieee.std_logic_1164.all;
library work;
use work.sorting_pkg.all;
use IEEE.NUMERIC_STD.all;
use ieee.std_logic_unsigned.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity tb_camera is
-- Port ( );
end tb_camera;
architecture Behavioral of tb_camera is
component Sorting
generic (
N : integer := 10);
PORT
(--clk: in std_logic;
rst : in std_logic;
inStream : in intarray(0 to 9);
outStream : out intarray(0 to 9);
BoutArray: out intarray(0 to 16);
CoutArray: out intarray(0 to 16)
);
end component;
signal A : intarray(0 to 9);
signal D : intarray(0 to 9);
signal rst_tb : std_logic;
-- signal clk_tb : std_logic;
signal BoutArray : intarray(0 to 16);
signal CoutArray : intarray(0 to 16);
--constant clk_period : time :=500ns;
begin
uut:Sorting port map (inStream => A, outStream => D, rst => rst_tb,
BoutArray => BoutArray, CoutArray=> CoutArray );
sim_tb:process
begin
wait for 100ns;
rst_tb<='1';
wait for 100ns;
rst_tb<='0';
--wait for 50ns;
A(0 to 9) <= (0 => x"07",
1 => x"09",
2 => x"06",
3 => x"02",
4 => x"05",
5 => x"00",
6 => x"08",
7 => x"01",
8 => x"03",
9 => x"04");
wait;
end process;
end Behavioral;

How to get a slice of a VHDL unconstrained array?

I'm trying to model a RAM chip in VHDL with generic parameters for the address and data bus widths and for the base address where the RAM is placed in the address space. My problem is that I cannot figure out how to get a slice of an generic unconstrained array parameter to compare it against a std_logic_vector signal.
This the reduced code that is intended to compute the "chip select" signal:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity e is
generic (
BASE_ADDR :std_logic_vector := x"C000";
CELL_ADDR_WIDTH :integer := 4
);
port (
address :in std_logic_vector (BASE_ADDR'length-1 downto 0)
);
end;
architecture behavioral of e is
constant ADDR_WIDTH :integer := BASE_ADDR'length;
signal cs :std_logic;
begin
cs <= '1' when address(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) = BASE_ADDR(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) else '0';
end behavioral;
The Lattice ispLEVER VHDL compiler reports the following error:
23:64:23:110|Slice range direction does not match argument range
The message is caused by the expression BASE_ADDR(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH).
How is a slice of the generic unconstrained array BASE_ADDR accessed correctly in VHDL?
Both solutions suggested by #Paebbels and #user1155120 resolve the VHDL compilation error. I quote the suggestions here with the code updated accordingly.
#Paebbels: Use to in slice
Your unconstrained array defaults to a "to" range because the index type of std_logic_vector is integer and integer in turn is defined with a to range :). So use the to keyword in your slice.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity e is
generic (
BASE_ADDR :std_logic_vector := x"C000";
CELL_ADDR_WIDTH :integer := 4
);
port (
address :in std_logic_vector (BASE_ADDR'length-1 downto 0)
);
end;
architecture behavioral of e is
constant ADDR_WIDTH :integer := BASE_ADDR'length;
signal cs :std_logic;
begin
cs <= '1' when address(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) = BASE_ADDR(ADDR_WIDTH-1 to CELL_ADDR_WIDTH) else '0';
end behavioral;
#user1155120: Declare an alias to define a direction
You'll could also add an alias to your architecture declarative region - alias BASEADDR: std_logic_vector(BASE_ADDR'LENGTH - 1 downto 0) is BASE_ADDR; to define a direction and use that - cs <= '1' when address(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) = BASEADDR(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) else '0';
I used a more prominent name for the alias:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity e is
generic (
BASE_ADDR :std_logic_vector := x"C000";
CELL_ADDR_WIDTH :integer := 4
);
port (
address :in std_logic_vector (BASE_ADDR'length-1 downto 0)
);
end;
architecture behavioral of e is
constant ADDR_WIDTH :integer := BASE_ADDR'length;
signal cs :std_logic;
alias BASE_ADDR_ALIAS: std_logic_vector(BASE_ADDR'LENGTH - 1 downto 0) is BASE_ADDR;
begin
cs <= '1' when address(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) = BASE_ADDR_ALIAS(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) else '0';
end behavioral;

Synthesizable multidimensional arrays in VHDL

I need to use multidimensional arrays to represent matrices in my design. I have tried the two available options:
Declaring array of arrays
type t11 is array (0 to c1_r2) of std_logic_vector(31 downto 0);
type t1 is array (0 to r1) of t11; --r1*c1_r2 matrix
Multidimensional arrays.
type matrix is array (natural range <>, natural range <>)
of std_logic_vector(31 downto 0);
However, in both the cases my post synthesis simulation in xilinx gives me the error "Sliced name is allowed only on single-dimensional arrays".
What is the correct way of using multidimensional arrays in synthesizable vhdl design? Any inputs would be welcome.
I am using the XST Synthesizer that comes with Xilinx ISE.
I am indexing both i and j, as my matrix dimension is m * n * 32.
My net a_in in the entity
a_in: in matrix (0 to size - 1, 0 to size - 1);
got modified to
a_in : in STD_LOGIC_VECTOR3 ( 1 downto 0 , 1 downto 0 , 31 downto 0 );
In my program, I access values from the matrix inside two generate statements for k and m as:
add_instx: add
port map (
a => a_in(k,m),
b => b_in(k,m),
clk => clk,
sclr => clr,
ce => start,
result => temp_out(k,m),
rdy => add_over(k,m)
);
My test bench input for a_in is given as
a_in <= (("00111111100000000000000000000000", "00000000000000000000000000000000"),("00000000000000000000000000000000", "00111111100000000000000000000000"));
My synthesis generated warnings of the type: Xst:387 - The KEEP property attached to the net may hinder timing optimization. You may achieve better results by removing this property. However, I have not set any keep property and I am not sure where to look for this property. Please help! Thanks a lot.
I apologize for not adding the complete code. Please find below the code and package.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use work.mat_pak.all;
entity newproj is
generic ( size: natural := 2 );
port (
clk: in std_logic;
clr: in std_logic;
start: in std_logic;
a_in: in matrix (0 to size - 1, 0 to size - 1);
b_in: in matrix (0 to size - 1, 0 to size - 1);
aplusb: out matrix (0 to size - 1, 0 to size - 1);
parallel_add_done: out std_logic);
end newproj;
architecture Behavioral of newproj is
COMPONENT add --This is a 32 bit floating point add IP core
PORT (
a : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
b : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
clk : IN STD_LOGIC;
sclr : IN STD_LOGIC;
ce : IN STD_LOGIC;
result : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
rdy: OUT STD_LOGIC
);
END COMPONENT;
signal temp_out: matrix (0 to size - 1, 0 to size - 1) := (others => (others => (others => '0')));
signal add_over: bmatrix (0 to size - 1, 0 to size - 1) := (others => (others => '0'));
begin
g0:
for k in 0 to mat_dim generate
g0x:
for m in 0 to mat_dim generate
add_instx: add
port map (
a => a_in(k,m),
b => b_in(k,m),
clk => clk,
sclr => clr,
ce => start,
result => temp_out(k,m),
rdy => add_over(k,m)
);
end generate;
end generate;
aplusb <= temp_out;
p1_add:
process (add_over)
variable check_all_done: std_logic;
begin
check_all_done := '1';
for k in 0 to mat_dim loop
for m in 0 to mat_dim loop
check_all_done := check_all_done and add_over(k)(m);
end loop;
end loop;
parallel_add_done <= check_all_done;
end process;
end Behavioral;
The package used here is:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.ALL;
package mat_pak is
CONSTANT mat_dim : natural := 2;
type matrix is array (natural range <>, natural range <>)
of std_logic_vector(31 downto 0);
type bmatrix is array (natural range <>, natural range <>)
of std_logic;
end mat_pak;
The post synthesis simulation model file modified the entity in terms of ordering and data type, on its own. The entity looks as below:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library UNISIM;
use UNISIM.VCOMPONENTS.ALL;
use UNISIM.VPKG.ALL;
entity newproj is
port (
clk : in STD_LOGIC := 'X';
clr : in STD_LOGIC := 'X';
start : in STD_LOGIC := 'X';
parallel_add_done : out STD_LOGIC;
a_in : in STD_LOGIC_VECTOR3 ( 1 downto 0 , 1 downto 0 , 31 downto 0 );
b_in : in STD_LOGIC_VECTOR3 ( 1 downto 0 , 1 downto 0 , 31 downto 0 );
aplusb : out STD_LOGIC_VECTOR3 ( 1 downto 0 , 1 downto 0 , 31 downto 0 )
);
end newproj;
Your first array is not a multi dimensional array, it's a 2-times nested 1 dimensional array.
Your example:
type t11 is array (0 to c1_r2) of std_logic_vector(31 downto 0);
type t1 is array (0 to r1) of t11;
This definition is more clear:
subtype t_dim1 is std_logic_vector(31 downto 0);
type t_dim1_vector is array(natural range <>) of t_dim1;
subtype t_dim2 is t_dim1_vector(0 to c1_r2);
type t_dim3_vector is array(natural range <>) of t_dim2;
subtype t_dim3 is t_dim3_vector(0 to r1);
You can access this structure by indexing each dimension:
signal matrix3 : t_dim3;
signal matrix2 : t_dim2;
signal matrix1 : t_dim1;
signal slv : std_logic_vector(31 downto 0);
signal sl : std_logic;
matrix2 <= matrix3(i);
matrix1 <= matrix2(j);
matrix1 <= matrix3(i)(j);
slv <= matrix3(i)(j);
sl <= matrix3(i)(j)(k);
You can also slice each dimension:
signal matrix3 : t_dim3;
signal slice3 : t_dim3_vector(0 to 3);
signal slice2 : t_dim2_vector(0 to 3);
signal slv : std_logic_vector(7 downto 0);
slice3 <= matrix3(4 to 7);
slice2 <= matrix3(i)(2 to 5);
slice2 <= slice3(i)(2 to 5);
slv <= matrix3(i)(j)(15 downto 8);
Your second example:
type matrix is array (natural range <>, natural range <>) of std_logic_vector(31 downto 0);
This is a 2-dimensional array with a nested 1-dimensional array. This structure can be accessed as follows:
signal mat : matrix(0 to r1, p to c1_r2);
signal slv : std_logic_vector(31 downto 0);
signal sl : std_logic;
slv <= mat(i, j);
sl <= mat(i, j)(k);
Since VHDL-2008 slicing is also allowed in multi dimensional array. Before VHDL-2008 you have to employ functions for this job.
Have a look into my PoC.vectors package to see ways on how you can handle 1- and multi dimensional arrays.
In the mean time Xilinx has added some information in it's [Vivado synthesis user guide (UG901)](xilinx website offline at time of writing)
For example:
-- 3-D Ram Inference Example (Single port)
-- Compile this file in VHDL2008 mode
-- File:rams_sp_3d.vhd
library ieee;
use ieee.std_logic_1164.all;
package mypack is
type myarray_t is array(integer range<>) of std_logic_vector;
type mem_t is array(integer range<>) of myarray_t;
end package;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.mypack.all;
entity rams_sp_3d is
generic (
NUM_RAMS : integer := 2;
A_WID : integer := 10;
D_WID : integer := 32
);
port (
clk : in std_logic;
we : in std_logic_vector(NUM_RAMS-1 downto 0);
ena : in std_logic_vector(NUM_RAMS-1 downto 0);
addr : in myarray_t(NUM_RAMS-1 downto 0)(A_WID-1 downto 0);
din : in myarray_t(NUM_RAMS-1 downto 0)(D_WID-1 downto 0);
dout : out myarray_t(NUM_RAMS-1 downto 0)(D_WID-1 downto 0)
);
end rams_sp_3d;
architecture arch of rams_sp_3d is
signal mem : mem_t(NUM_RAMS-1 downto 0)(2**A_WID-1 downto 0)(D_WID-1 downto 0);
begin
process(clk)
begin
if(clk’event and clk=’1’) then
for i in 0 to NUM_RAMS-1 loop
if(ena(i) = ‘1’) then
if(we(i) = ‘1’) then
mem(i)(to_integer(unsigned(addr(i)))) <= din(i);
end if;
dout(i) <= mem(i)(to_integer(unsigned(addr(i))));
end if;
end loop;
end if;
end process;
end arch;

VHDL error related to concatenation of variable

I am writing VHDL code in which I have used tempx and tempz as variables and tried to concatenate them, but I am having some errors on the line annotated below. Suggestions on what to do please?
The errors are:
Error (10500): VHDL syntax error at ArrayDivider.vhd(53) near text ":="; expecting "(", or "'", or ".",
Error (10500): VHDL syntax error at ArrayDivider.vhd(53) near text "&"; expecting "(", or "'", or "."
Code:
------- Array Divider --------
library ieee;
use ieee.std_logic_1164.all;
----- Entity -----
entity ArrayDivider is
generic
(
---- For x/y
Nx : integer := 8; --- Number of bits in x
Ny : integer := 4 --- Number of bits in y
);
port
(
ipx : in std_logic_vector(Nx-1 downto 0); -- Input x --- (Nx-1 downto 0)
ipy : in std_logic_vector(Ny-1 downto 0); -- Input y --- (Ny-1 downto 0)
opd : out std_logic_vector(Nx-Ny downto 0); -- Quotient --- (Nx-Ny downto 0)
opr : out std_logic_vector(Ny-1 downto 0) -- Remainder --- (Ny-1 downto 0)
);
end ArrayDivider;
----- Architecture -----
Architecture Div of ArrayDivider is
--- This component will compare ipy with parts of ipx of given bits and ---
--- generate bits of divident as well as partial subtraction results ---
--- x = parts of ipx (tempx), y = ipy, op = opd(x) and final z = opr ---
component Cmp is
generic
(
N : integer := 4
);
port
(
x : in std_logic_vector(N-1 downto 0); --- N-1 downto 0
y : in std_logic_vector(N-1 downto 0); --- N-1 downto 0
z : out std_logic_vector(N-1 downto 0); --- N-1 downto 0
op : out std_logic
);
end Component;
variable tempx : std_logic_vector(Ny-1 downto 0) := ipx(Nx-1 downto Nx-Ny); --- (Ny-1 downto 0) (Nx-1 downto Nx-Ny)
variable tempz : std_logic_vector(Ny-1 downto 0); --- (Ny-1 downto 0)
begin
lup:
for a in Nx-Ny downto 0 generate --- Nx-Ny downto 0
begin
Cmpa: Cmp generic map(Ny) port map(tempx, ipy, tempz, opd(a)); --- (Ny)
grea:
if(a > 0) generate
tempx := tempz(Ny-2 downto 0) & ipx(a-1); --- (Ny-2 downto 0)
end generate grea;
zero:
if(a = 0) generate
opr <= tempz;
end generate zero;
end generate lup;
end Div;
as you are not using a process, you should use signals instead of variables for tempx and tempz. your line 53 must then look as follows:
tempx <= tempz(Ny-2 downto 0) & ipx(a-1);
however, probably the use of a process makes more sense. then you have to implement your cmp component as a procedure (not done in example below). the process could look as follows:
...
end Component;
begin
div_proc: process(ipy, ipx)
variable tempx : std_logic_vector(Ny-1 downto 0) ;
variable tempz : std_logic_vector(Ny-1 downto 0);
begin
lup:
for a in 1 downto 0 loop
-- Cmpa: Cmp generic map(Ny) port map(tempx, ipy, tempz, opd(a));
grea:
if(a > 0) then
tempx := tempz(Ny-2 downto 0) & ipx(a-1);
end if;
zero:
if(a = 0) then
opr <= tempz;
end if;
end loop;
end process div_proc;
...

Sum of Array elements VHDL

I am new to VHDL and I searched all of the internet and i didnt find anything that would help me !
I am trying to add the elements of an array (32 Elements !), so i cant just write
for example s <= s(0) + s(1) + s(3) ... s(5) + ....s(32)
how can i generalise such a calculation ??
or what am i doing wrong ?
My Code (that didnt work in the simulation) is ..
(just for 5 elemets ....)
library IEEE;
library work;
library std;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use ieee.std_logic_arith.all;
entity main is Port (
EIN : in std_logic;
AUS_1 : out std_logic_vector(3 downto 0));
end main;
architecture Behaviour of main is
type Cosinus is array (0 to 4) of std_logic_vector(3 downto 0);
type Sinus is array (0 to 4) of std_logic_vector(3 downto 0);
Signal SumSin :std_logic_vector(3 downto 0);
begin
main : process(Ein)
variable Cos : Cosinus;
variable Sin : Sinus;
begin
if( Ein='1' ) then
sin(0) := "0011";
sin(1) := "0001";
sin(2) := "1010";
sin(3) := "1111";
sin(4) := "1110";
for n in 0 to 4 loop
SumSin <= SumSin + Sin(n);
end loop;
else
sin(0) := "1011";
sin(1) := "0101";
sin(2) := "1000";
sin(3) := "1001";
sin(4) := "1100";
for n in 0 to 4 loop
SumSin <= SumSin + Sin(n);
end loop;
end if;
end process;
Aus_1 <= SumSin;
end Behaviour;
I would be thanksfull
First... Don't use std_logic_arith.
Then, Use a variable for the running sum and assign is to a signal afterwards:
...
main : process(Ein)
variable Cos : Cosinus;
variable Sin : Sinus;
variable SumSin : signed(3 downto 0);
begin
sumsin := (others => '0');
....
for n in Sin'range loop
SumSin := SumSin + Sin(n);
end loop;
end if;
Aus_1 <= SumSin;
end process;

Resources