Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to specify an integer array as generic in VHDL?

I am trying to create a generic driver for an SPI based IO expander. The idea is to pass initialization values in the instantiation, that matches the requested IO setup.

My current attempt look like this :

entity max7301_simple is
   generic ( 
        IO_cfg : array (1 to 7) OF integer range 0 to 255 := (16#55#, 16#55#, 16#55#, 16#55#, 16#55#, 16#55#, 16#55#)
           );
     port  (
        -- Application interface :
        clk_i       :   in std_logic;        -- input clock, xx MHz.
        rst_i       :   in std_logic;        -- sync reset.
        en_i        :   in std_logic;        -- enable, forces re-init of pins on MAX7301.
        output_i    :   in std_logic_vector(27 downto 0);   --data to write to output pins on MAX7301
        irq_o       :   out std_logic;       -- IRQ, TODO: what triggers, change on inputs ?
        input_o     :   out std_logic_vector(27 downto 0);  --data read from input pins on MAX7301
        -- MAX7301 SPI interface
        sclk        :   out std_logic;        -- SPI clock
        din         :   in std_logic;        -- SPI data input
        dout        :   out std_logic;       -- SPI read data
        cs          :   out std_logic        -- SPI chip select
    );
end max7301_simple;

The problem is with the IO_cfg array, i have tried various attempts w/wo init values etc. And cannot seem to figure how to specify the array.

I belive to have read that you can pass an array as generic, but still haven't got much luck with it. Xilinx ISE just tells med "syntax error near 'array' " wich is not informative enough to get me forward.

Any help would be appreciated

I always need 7 values, when instantiating this module.

like image 667
opprud Avatar asked Aug 03 '12 07:08

opprud


3 Answers

You are allowed to use an array as a generic parameter however you are not allowed to declare it there, on-the-fly as an anonymous type.

You have to first declare your integer array type in a separate package (which can be in the same file or in a separate one) and then use the package in your entity and when you instantiate it.

Here is an example of how you can do it:

-- package declaration
package mytypes_pkg is

     type my_array_t is array (1 to 7) of integer range 0 to 255;

end package mytypes_pkg;

-- entity "uses" the package   
use work.mytypes_pkg.all;

entity max7301_simple is
   generic ( 
        IO_cfg : my_array_t := (16#55#, 16#55#, 16#55#, 16#55#, 16#55#, 16#55#, 16#55#)
           );
   -- ports [...]
end max7301_simple;

Be careful to also usethe package in the architecture that instantiates your entity.


(Optional reading)

Why is it really a syntax error to write it like you did?

Looking at the VHDL grammar in the VHDL (2002) standard, each generic parameter's declaration is a interface_constant_declaration and you have the following grammar rules:

[§ 4.3.2]
interface_constant_declaration ::=  
            [ constant ] identifier_list : [ in ] subtype_indication [ := static_expression ]

[§ 4.2]
subtype_indication ::= 
            [ resolution_function_name ] type_mark [ constraint ]

The type reference can only be the name of an existing type (type_mark) or the restriction of an existing type.

like image 198
wap26 Avatar answered Oct 18 '22 20:10

wap26


I propose a bit more generic approach by using 2008 VHDL standard and predefined attributes - this allows passing an array of any length. Define your type in your package like this:

package data_types is
    type array_of_integers is array(natural range <>) of integer;
end package;

Now in your code pass generic array as follows:

generic(
    COEFFICIENTS : array_of_integers := (-1, 0, 1)
);

Now software will be using a default indexing scheme. It can be taken into account with predetermined 'left attribute (reference can be found at: http://www.csee.umbc.edu/portal/help/VHDL/attribute.html):

-- First coefficient
    ... <= COEFFICIENTS(COEFFICIENTS'left);
-- Second coefficient
    ... <= COEFFICIENTS(COEFFICIENTS'left + 1);

Generally you should use this array in some kind of loop or generate statement:

GENERATE_STATEMENT: for entry in 0 to COEFFICIENTS'length-1 generate
    out(entry) <= std_logic_vector(to_signed(COEFFICIENTS(COEFFICIENTS'left + entry), out(entry)'length));
end generate;

As a little side note for Quartus II users - it is also possible to use generic arrays in .bdf schematic files. Set parameter type to Auto and rewrite parameter value in this format - A(D"-1", D"0", D"1"), where D stands for decimal data type (Useful link: http://quartushelp.altera.com/14.0/mergedProjects/assign/asd/asd_tab_param.htm)

like image 21
teaholic Avatar answered Oct 18 '22 20:10

teaholic


If you don't mind a less-constrained generic, you can do:

generic (IO_cfg : integer_vector);

As long as you have a VHDL-2008 compiler.

like image 43
Martin Thompson Avatar answered Oct 18 '22 20:10

Martin Thompson