Search code examples
genericsvhdl

Parameterized constants in VHDL


I am designing a generic data path, and as part of that there are constant patterns that different decoders use. For example:

NBITS = 4 -> constant would be "1000"

NBITS = 5 -> constant would be "10000"

NBITS = 16 -> constant would be "1000_0000_0000_0000"

I figured something like the following would do the trick: constant NaR : std_logic_vector(NBITS - 1 downto 0) := (NBITS - 1 => '1', others => '0');

but alas that doesn't compile and generates the error: non-static choice excludes others choice.

How does one specify constant bit patterns that are a function of the generic parameter?


Solution

  • There's a requirement that an aggregate has locally static choices when there's more than one choice. (The code for determining the value of the expression is constructed at analysis time.)

    IEEE Std 1076-2008 9.3.3.3 Array aggregates paragraph 6:

    Apart from a final element association with the single choice others, the rest (if any) of the element associations of an array aggregate shall be either all positional or all named. A named association of an array aggregate is allowed to have a choice that is not locally static, or likewise a choice that is a null range, only if the aggregate includes a single element association and this element association has a single choice. An others choice is locally static if the applicable index constraint is locally static.

    It's possible to provide the value expression of a constant (6.4.2.2 Constant declarations) or initial expression of a variable or signal by a function call (an expression, 9.3.4 Function calls) at elaboration (14.4.2.5 Object declarations). The function can be impure (4. Subprograms and packages, 4.1 General, 9.4.3 Globally static primaries, NOTE 2).

    Constructing a Minimal, Complete, and Verifiable example allows this to be demonstrated:

    library ieee;
    use ieee.std_logic_1164.all;
    
    ravenwater_mcve is
        generic (NBITS: natural := 42);
    end entity;
    
    architecture foo of ravenwater_mcve is
        impure function leftbit return std_logic_vector is
            variable retv:  std_logic_vector (NBITS - 1 downto 0) := 
                              (others => '0');
        begin
            retv(retv'LEFT) := '1';
            return retv;
        end function;
        constant NaR: std_logic_vector(NBITS - 1 downto 0) := leftbit;
        -- (NBITS - 1 => '1', others => '0');
    begin
    end architecture;
    

    The MCVe analyzes, elaborates and simulates.

    You can add a process to determine the value expression is correct:

    RESULT:
        process
        begin
            report "NaR = " & to_string(NaR);
            wait;
        end process;
    

    And if using a VHDL standard revision prior to -2008 provide the to_string function:

        function to_string (inp: std_logic_vector) return string is
                variable image_str: string (1 to inp'length);
                alias input_str:  std_logic_vector (1 to inp'length) is inp;
        begin
            for i in input_str'range loop
                image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
            end loop;
            return image_str;
        end function;
    

    And this produces:

    ghdl -r ravenwater_mcve
    ravenwater_mcve.vhdl:33:9:@0ms:(report note): NaR = 100000000000000000000000000000000000000000

    (Maybe I should have used a smaller default value for the generic constant.)

    You could also pass the value of the generic to a pure function as a parameter.