Search code examples
genericstypessizevhdl

vhdl :: creating a type with a size parameter


I was wondering is there was a way to defined a type with a size parameter in VHDL. e.g.

type count_vector(size: Natural) is unsigned (size-1 downto 0);

and then later on do something like

variable int : count_vector(32) := (others => '0');
variable nibble : count_vector(4) := (others => '0');

Essentially, is there a way to defined an "array-like" type, or is that not allowed by syntax?

I am currently trying to use generics for re-usability, but I would like to be able to take maximal advantage of generic typing (ie: Is it possible to write type-generic entities in VHDL? ).

Thanks in advance!


Solution

  • library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity foo is
         generic (
            constant INT_LEFT:    natural := 32;
            constant NIB_LEFT:    natural := 4
         );
         -- note entity declarative items are forward looking only
         -- a port declaration requires a type or subtype declared in a package
         -- you can also use a package for any constants
    
         -- a type or subtype can be declared as an entity declarative item here:
    --     subtype int_size is unsigned(INT_LEFT downto 0);
    --     subtype nib_size is unsigned(NIB_LEFT downto 0);
    end entity;
    
    architecture fum of foo is
        -- or as an architecture declarative item here:
        subtype int_size is unsigned(INT_LEFT downto 0);
        subtype nib_size is unsigned(NIB_LEFT downto 0);   
    
    begin
    USAGE:
        process 
            variable int:  int_size := (others => '0');
            variable nibble: nib_size := (others =>'0');
        begin
            int := int + 3;
            -- the function "+" is L: UNSIGNED, R: NATURAL
            --  int_size and nibble_size are subtypes of UNSIGNED
            Report integer'IMAGE(TO_INTEGER(int));
            -- ditto for TO_INTEGER
            nibble := nibble + 2;
            -- if int_size or nibble_size were types it would require
            -- operator functions for those types.
            Report integer'IMAGE(TO_INTEGER(nibble));
            wait;
        end process;
    
    end architecture fum;
    

    Added:

    This is in response to BennyBarns assertion in a comment on the question: "I would like to add that while you can use n-dimensional arrays in VHDL, only the first one may be unconstrained".

    Contrary to the assertion:

    entity t1 is
    end entity;
    
    architecture foo of t1 is
    
        type typeI is array ( natural range <>, natural range <>) of integer;
    
    begin
        process is
            variable sigI : typeI(0 to 1, 0 to 1);  -- 2D integer array
        begin
            sigI(0,0) := 1;
            sigI(0,1) := 2;
            sigI(1,0) := 3;
            sigI(1,1) := 4; 
            report "Initialized indiviually";
            report "sigI(0,0) = " & integer'IMAGE(sigI(0,0));
            report "sigI(0,1) = " & integer'IMAGE(sigI(0,1));
            report "sigI(1,0) = " & integer'IMAGE(sigI(1,0));
            report "sigI(1,1) = " & integer'IMAGE(sigI(1,1));
            sigI := ((11,12),(13,14));
            report "Initialized as an aggregate";
            report "sigI(0,0) = " & integer'IMAGE(sigI(0,0));
            report "sigI(0,1) = " & integer'IMAGE(sigI(0,1));
            report "sigI(1,0) = " & integer'IMAGE(sigI(1,0));
            report "sigI(1,1) = " & integer'IMAGE(sigI(1,1));
            wait;
        end process;
    end architecture;
    

    The statement is imprecise and relates in the example subtype declaration to the deferred range constraint in the type declaration of UNSIGNED in package numeric_std. The subtype indication requires a constraint either supplied by the type mark or explicitly. It's only valid for a subtype indication type mark that is an unconstrained type.

    A subtype declaration of an unconstrained type must provide a constraint just as if you had added

    signal A: unsigned;
    

    as an architecture declarative item to fum of entity foo:

    ghdl -a foo.vhdl
    foo.vhdl:24:12: declaration of signal "a" with unconstrained array type "unsigned" is not allowed
    

    And just to make things interesting things interface lists can be special:

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity fie is
        port (
            a:  in  unsigned
        );
    end entity;
    
    architecture fee of fie is
    
    begin
    
    EVAL:
        process (a)
        begin
            report "Fie:a range is " & integer'IMAGE(a'LEFT) & " to " & 
                                      integer'IMAGE(a'RIGHT) ;
        end process;
    
    end architecture fee;
    
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity fie_tb is
    end entity;
    
    architecture fum of fie_tb is
        component fie is
            port (a: in unsigned);
        end component;
    
        signal aa:  unsigned (3 to 7);
    begin
    
    EUT: fie port map (a => aa);
    
    end architecture;
    

    The 'rules' can be found in the LRM section on Index constraints and discrete ranges, IEEE Std 1076-2008 5.3.2.2, -2002/-1993 3.2.1.1.