7
votes

I need to use multidimensional arrays to represent matrices in my design. I have tried the two available options:

  1. 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
    
  2. 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;
2
What synthesis tool are you using?Jonathan Drolet
Show us how you are trying to use the said multi-dimensional array. Are you trying to index both i,j indicies? mysignal(i)(j)? Or something else?Josh
I'd amplify Josh's comment. show us where and how i and j are used and declared. The above isn't a Minimal, Complete, and Verifiable example. Show us the nested generate statements, too. Your problem likely stems from never assigning parts of your matrix, it sounds like something is begin eaten because it's got a fixed value. See the Constraints Guide (cgd.pdf). See Keep and Keep Hierarchy (in particular). Slices are only of one dimensional arrays (See IEEE Std 1076-2008, 8.5 Slice names).user1155120
Reading Paebbels plug for his PoC library (and he made no claim that was incorrect in his answer), it brings attention to the lack of a declaration for STD_LOGIC_VECTOR3 the type mark in the (signal declaration for a_in. Your question is not a Minimal, Complete, and Verifiable example. The problem can't be reproduced nor fully understood.user1155120
Apologies Mr. David Koontz for incomplete information in my question. I have added the program and the package data. The std_logic_vector3 was auto-generated after synthesis by the Xilinx synthesis tool. As suggested by you I will check the constraints guide as well. Any more inputs would be great! Thank you very much.Soumya

2 Answers

8
votes

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.

0
votes

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;