Search code examples
vhdlvivado

Can you make an array of types in VHDL?


Vivado Simulation cannot support unconstrained types which have a signed component to them.

i.e.

type A is array (natural range <>) of signed;

I have been using this in a design where type A is used in port declarations as I wish to have a parallel design which I control through a generic as well as the current stage word length e.g.

port (
inputdata : A(0 to number_of_parallel_generic-1)(stage_wordlength_generic-1 downto 0)
);

As I use the type A with many variations of the generics controling them e.g. 4 wide arrays with 16 wordlengths and other variations (often controled by a for generate loop)

for i in 0 to length_of_generate_statement-1 generate
    signal example_signal : A(0 to 3)(stage_wordlength_generic + i - 1 downto 0);
begin
    <functional code>
end generate;

This sort of code would allow me to gain bit growth from sequential sections of my archetecture - e.g. from an addition.

Now... getting to the question at hand.

One way I could get round this rather than initiating a signal with a forever changing generate statement could actually be in the creation of an "array of types".

Lend me your eyes this is written in a not quite vhdl way but hopefully you can see what Im trying to do.

type my_arr_of_types is array(0 to length_of_array-1) of type;

for i in 0 to length_of_array-1 generate
    my_arr_of_types(i) <= <type declaration with some dependance on i>;
end generate;

Hopefully you can see what I am trying to do.

This would allow you to then call an element of the my_arr_of_types which itself is a type to then assign to a signal/variable.

i.e. signal my_sig : my_arr_of_types(n);

*Where n is any valid index of the array.

Obviously this is not allowed in VHDL or any simulation tool. But can anyone see a potential solution to my problem?

Remember I use most of these types on port statements so any solution has to fit within the limitations of the port declarations.


Solution

  • Using two dimensional arrays as a solution:

    Package

    library ieee;
    use     ieee.numeric_std.all;
    
    package utilities is
      type T_SLM is array(natural range <>, natural range <>) of std_logic;
    end package;
    

    Entity

    Now you can use this type in a port declaration together with two generic parameters. As sizes are now known in the architecture, you can create your used defined type of signed values and you can use either generate statements or a function to convert from the T_SLM to myArray type.

    library ieee;
    use     ieee.numeric_std.all;
    
    library myLib;
    use     myLib.utilities.all;
    
    entity foo is
      generic (
        number_of_parallel : natural;
        stage_wordlength   : natural
      );
      port (
        Input : T_SLM(0 to number_of_parallel - 1, stage_wordlength - 1 downto 0)
      );
    end entity;
    
    architecture a of foo is
      type myArray is array (natural range <>) of signed(Input'range(2));
    
      function convert(matrix : T_SLM) return myArray is
        variable result : myArray(matrix'range(1));
      begin
        for i in matrix'range(1) loop
          for k in matrix'range(2) loop
            result(i)(j) := matrix(i, j);
          end loop;
        end loop;
        return result;
      end function;
    
      signal InputData1 : myArray(Input'range(1));
      signal InputData2 : myArray(Input'range(1));
    begin
      genInput: for i in Input'range(1) generate
        genInput: for j in Input'range(2) generate
          InputData1(i)(j) <= Input(i, j);
        end generate;
      end generate;
    
      InputData2 <= convert(Input);
    end architecture;
    

    Many helper functions like this have been implemented in the PoC Library in package PoC.vectors.