VHDL: Multiple for loop serial execution - arrays

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;

Related

Assigning to record type arrays in generate statements

How do you use record arrays in generate statements in VHDL? Below is what I have done, which passes synthesis and implementation in Vivado (2021.1). However, when I simulate it, it shows none of the record signals getting assigned and are always "U". I can also not find any examples of record fields used in port maps in generate statements.
type record_a_t is record
a : std_logic;
b : std_logic_vector(7 downto 0);
c : std_logic_vector(3 downto 0);
d : std_logic;
e : std_logic;
end record record_a_t;
type record_a_array_t is array (0 to 3) of record_a_t;
signal record_a_array : record_a_array_t;
Then, I generate the modules with signal mapping like:
GEN_MODULES : for i in 0 to 3 generate
modules : entity work.module
port map(
clk => clk,
rst_n => rst_n,
a => record_a_array(i).a,
b => record_a_array(i).b,
c => record_a_array(i).c,
d => record_a_array(i).d,
e => record_a_array(i).e
);
end generate GEN_MODULES;
Again, the above seems to pass all the tools syntax checking and builds in Vivado, but simulation (RivPro 2018) and implementation show signals not getting assigned or changing. They are always "U", even if driven from the module. For example, if port a is an output that is initialized in the module, record_a_array(i).c is always "U". Even the module output port is "U", as if the internal initialization is ignored, which makes no sense to me.
Below is an example.
Test Module:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity module is
port(
clk : in std_logic;
rst_n : in std_logic;
a : in std_logic;
b : out std_logic_vector(7 downto 0);
c : out std_logic_vector(3 downto 0);
d : out std_logic;
e : out std_logic
);
end module;
architecture rtl of module is
begin
process(clk, rst_n)
begin
if(rst_n = '0') then
b <= (others=> '0');
c <= (others=> '0');
d <= '0';
e <= '0';
elsif(rising_edge(clk)) then
if(a = '1') then
b <= b + '1';
c <= c + '1';
d <= not d;
e <= not e;
end if;
end if;
end process;
end rtl;
Test Bench:
library ieee;
use ieee.std_logic_1164.all;
entity testbench is
end entity testbench;
---------------------------------------------------
architecture arch of testbench is
---------------------------------------------------
type record_a_t is record
a : std_logic;
b : std_logic_vector(7 downto 0);
c : std_logic_vector(3 downto 0);
d : std_logic;
e : std_logic;
end record record_a_t;
type record_a_array_t is array (0 to 3) of record_a_t;
signal record_a_array : record_a_array_t;
signal clk : std_logic := '1';
signal rst_n : std_logic := '0';
---------------------------------------------------
begin
clk <= not clk after 5 ns;
rst_n <= '1' after 20 ns;
GEN_MODULES : for i in 0 to 3 generate
modules : entity work.module
port map(
clk => clk,
rst_n => rst_n,
a => record_a_array(i).a,
b => record_a_array(i).b,
c => record_a_array(i).c,
d => record_a_array(i).d,
e => record_a_array(i).e
);
end generate GEN_MODULES;
process(clk, rst_n)
begin
if(rst_n = '0') then
for i in 0 to 3 loop
record_a_array(i).a <= '0';
end loop;
elsif(rising_edge(clk)) then
for i in 0 to 3 loop
record_a_array(i).a <= not record_a_array(i).a;
end loop;
end if;
end process;
end arch;
Simulation:
Simulation of module example
Notice how the record signals wired to the module outputs in at the TestBench level are never defined and how the outputs of the generated module instances themselves are not driven, even though they all get asserted in the reset condition. The only signal that gets driven is the 'a' signal from the test bench level.
Since the record is not crossing into the RTL space, unwanted drivers can be turned off using std_logic using 'Z':
constant REC_INIT : record_a_t := (
a => 'Z',
b => "ZZZZZZZZ",
c => "ZZZZ",
d => 'Z',
e => 'Z'
) ;
. . .
signal record_a_array : record_a_array_t := (0 to 3 => REC_INIT) ;
As you start to look at the issue in the LRM, you might also note you can find the issues the IEEE VHDL working group has recorded at: : https://gitlab.com/IEEE-P1076/VHDL-Issues/-/issues. There is a remotely related issue in https://gitlab.com/IEEE-P1076/VHDL-Issues/-/issues/275 that may be able to address both its issue and this one - though time will tell on that.
For verification, I use Open Source VHDL Verification Methodology (OSVVM). We use records on ports and as a result, use special resolution functions with them so they do not require initialization.

Modelsim. Length of arrays do not match

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).

Instantiating VHDL components using generate statement with std_logic_vector

I am working on creating processing element in VHDL that have variable bit inputs. I try to use a generate statement to instantiate more components of the processing element and need the inputs to be std_logic_vectors so it can be parameterized but I get errors when trying to synthesize. Please can you help show why I am getting the synthesis error and what can be done to solve the error.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
package logic_array_type is
constant number_of_PE: integer := 16; -- number of processing elements
constant data_width: integer := 8; -- size of datapath, can be changed.
type vector_array is array (natural range <>) of std_logic_vector(data_width-1 downto 0);--to allow use of signal as CurBlk(i) to connect to the ith generated instanciation of entity/component.
type vector_array2 is array (natural range <>) of std_logic_vector(data_width downto 0);
end package logic_array_type;
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use work.logic_array_type.all;
entity MEengine is
Generic(
number_of_PE: integer := 16; -- number of processing elements
data_width: integer := 8; -- size of data_width, can be changed.
w: integer := 8); -- w value(size of datapath) can be changed.
Port ( reset : in STD_LOGIC;------ To be indexed in future instantiations
clk : in STD_LOGIC;
sel : in STD_LOGIC;
mv : out STD_LOGIC_VECTOR (w-1 downto 0));
end MEengine;
architecture Behavioral of MEengine is
component ProEle is
Generic(w: integer := 8); -- w value can be changed
Port ( CurBlk : in STD_LOGIC_VECTOR (w-1 downto 0);
RefBlk1 : in STD_LOGIC_VECTOR (w-1 downto 0);
RefBlk2 : in STD_LOGIC_VECTOR (w-1 downto 0);
Sad : out STD_LOGIC_VECTOR (w downto 0);
SEL : in STD_LOGIC;
clk : in STD_LOGIC;
reset : in STD_LOGIC;
lat_en : in STD_LOGIC; -------------- future control for delay latches
Dlat : out STD_LOGIC_VECTOR (w-1 downto 0));
end component ProEle;
---component specification--
for all : ProEle use entity work.ProEle(behavioral);
----internal signals-------
signal CurBlk : vector_array(data_width-1 downto 0);
signal RefBlk1 :vector_array (data_width-1 downto 0);
signal RefBlk2 : vector_array (data_width-1 downto 0);
signal Sad : vector_array2 (data_width downto 0);
signal lat_en : STD_LOGIC; -------------- future control for delay latches
signal Dlat : vector_array (data_width-1 downto 0);
begin
-----------create the processing elements---------
gen_pro_ele: for i in 0 to number_of_PE-1 generate
Processing_Element : ProEle port map( CurBlk => CurBlk(i), ------- pins to wires or sinals
RefBlk1 => RefBlk1(i),
RefBlk2 => RefBlk2(i),
Sad => Sad(i),
SEL => SEL,
clk => clk,
reset => reset,
lat_en => lat_en,
Dlat => Dlat(i));
end generate gen_pro_ele;
end Behavioral;
The Error after synthesis is
Line 100: Index value <8> is out of range [7:0] of array < curblk >
ERROR:HDLCompiler:1316 - Line 101: Index value <8> is out of range [7:0] of array< refblk1 >
ERROR:HDLCompiler:1316 - Line 102: Index value <8> is out of range [7:0] of array< refblk2 >
ERROR:HDLCompiler:1316 - Line 108: Index value <8> is out of range [7:0] of array < dlat >
For which Line100 is - Processing_Element : ProEle port map( CurBlk => CurBlk(i), ------- pins to wires or sinals
Line101 - RefBlk1 => RefBlk1(i),
Line102 - RefBlk2 => RefBlk2(i),
Line108 - Dlat => Dlat(i));
I expect the component ProEle to be generated 16 times having inputs(CurBlk, RefBlk1, RefBlk2) as 8bits wide.
The rtl schematic for ProEle component can be found in this link
What I really do not understand is why synthesis tool produces error
Index value <8> is out of range [7:0] of array < curblk > etc. rather than generate 16 instances of ProEle component, as the type vector_array has a range natural of 8bits(current data_width)and should be able to cope with index 8-16, producing the 16 instances of the component.
package logic_array_type is
constant number_of_PE: integer := 16; -- number of processing elements
constant data_width: integer := 8; -- size of datapath, can be changed.
type vector_array is array (natural range <>) of std_logic_vector(data_width-1 downto 0);--to allow use of signal as CurBlk(i) to connect to the ith generated instanciation of entity/component.
type vector_array2 is array (natural range <>) of std_logic_vector(data_width downto 0);
end package logic_array_type;
The error is in the package. Array range declaration suggests that I am using the maximum length of the vector as the number of times I want to loop.
(natural range <>).
whereas I am requesting the loop for more than these number of times in the generate statement .......
gen_pro_ele: for i in 0 to number_of_PE-1 generate.
hence it was necessary to change (natural range <>) to (0 to number_of_PE) in the package.

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;

Resources