7

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.

3 Answers 3

8

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.

Sign up to request clarification or add additional context in comments.

Comments

5

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)

Comments

2

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.

3 Comments

Indeed VHDL-2008 defines array type (natural range) for boolean, integer, real and time types. However VHDL-2008 support is still very limited, at least in the tools I use (ModelSim, QuartusII).
@wap26: "very limited" is a bit strong. MOdelsim supports most of it now, Aldex supports everything. Altera and Xilinx support quite a large amount. Type/package generics seem to be the worst aspect. integer_vector is supported in 2008 mode for all the tools I'm aware of.
ok, thanks for the fresh news. I'll check the latest version of my tools!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.