Search code examples
vhdlxilinxghdl

Why is GHDL and/or VHDL-2002 so restrictive on ranges in loops?


I have here some valid VHDL code, which can be compiled with

  • GHDL 0.31 (--std is not set)
  • ISE 14.7 (XST and iSim; std = 200x)
  • Vivado (Synth and xSim)
  • Altera Quatus II 13.1 and last but not least
  • QuestaSim 10.0d

GHDL understands this code if option '--std' is not set. When I set '--std' to VHDL-2002 I get errors complaining on the ranges in for-loops. Hmmm in pre 2002 mode this lines throw already a warning :(

So here is my function:

-- create vector-vector from vector (4 bit)
FUNCTION to_slvv_4(slv : STD_LOGIC_VECTOR) RETURN T_SLVV_4 IS
    VARIABLE Result     : T_SLVV_4((slv'length / 4) - 1 DOWNTO 0);
BEGIN
    IF ((slv'length MOD 4) /= 0) THEN
        REPORT "to_slvv_4: width mismatch - slv'length is no multiple of 4"
        SEVERITY FAILURE;
    END IF;

    FOR I IN 0 TO (slv'length / 4) - 1 LOOP
        Result(I)   := slv((I * 4) + 3 DOWNTO (I * 4));
    END LOOP;
    RETURN Result;
END FUNCTION;

GHDL error message:

D:\VHDL\git\PoC\src\common\vectors.vhdl:249:25:
->  universal integer bound must be numeric literal or attribute

The faulty line 249 is FOR I IN 0 TO (slv'length / 4) - 1 LOOP. The user defined type T_SLVV_4 is defined as:

type T_SLVV_4 is array(natural range <>) of std_logic_vector(3 downto 0);

My code has 8 errors like that. I could rewrite two of them from 'length to 'range so, 6 are left. But some these can not be rewritten...

So why are loop boundary calculations with 'length not allowed in GHDL and/or VHDL >=2002?


Solution

  • See vhdl - Address of array provided as std_logic_vector - Stack Overflow. This is the same issue.

     1  library ieee;
     2  use ieee.std_logic_1164.all;
     3  
     4  entity paebbels is
     5  end entity;
     6  
     7  architecture foo of paebbels is
     8          
     9      type T_SLVV_4 is array(natural range <>) of std_logic_vector(3 downto 0);
    10      -- create vector-vector from vector (4 bit)
    11      FUNCTION to_slvv_4(slv : STD_LOGIC_VECTOR) RETURN T_SLVV_4 IS
    12          VARIABLE Result     : T_SLVV_4((slv'length / 4) - 1 DOWNTO 0);
    13      BEGIN
    14          IF ((slv'length MOD 4) /= 0) THEN
    15              REPORT "to_slvv_4: width mismatch - slv'length is no multiple of 4"
    16              SEVERITY FAILURE;
    17          END IF;
    18  
    19          FOR I IN 0 TO (slv'length / 4) - 1 LOOP
    20              Result(I)   := slv((I * 4) + 3 DOWNTO (I * 4));
    21          END LOOP;
    22          RETURN Result;
    23      END FUNCTION;
    24  
    25  begin
    26  end architecture;
    

    This is the same issue, but for the range of a loop instead of an a subtype indication:

    hdl -a --std=02 paebbels.vhdl
    paebbels.vhdl:19:18: universal integer bound must be numeric literal or attribute
    ghdl: compilation error

    ghdl -a --std=93 paebbels.vhdl
    paebbels.vhdl:19:18: universal integer bound must be numeric literal or attribute
    ghdl: compilation error

    ghdl -a --std=93c paebbels.vhdl
    paebbels.vhdl:19:18:warning: universal integer bound must be numeric literal or attribute

    (No error but a warning, which VHDL doesn't actually have. std=93c is what you get when you don't pass a std, it's a relaxed rule.)

    See Issue Report IR2073.txt, with the issue raised most recently by Tristan Gingold (the author of ghdl, incidentally).

    This resulted in a Language Change Specification (LCS) for P1076-200X (-2008, LCS-2006-32) that also gave permission to interpret the text in the -2002 standard as specified in the Issue Report.

    It would seem Tristan never saw that LCS or otherwise implemented it. He added the 93c standard after the the IR was accepted. You could submit a bug report on ghdl-updates on SourceForge or otherwise contact Tristan. There's also nothing that gives authority to interpret the change for the -1993 standard (despite the 93c).

    There's also an easy way to evade the issue:

        -- FOR I IN 0 TO (slv'length / 4) - 1 LOOP
        for i in Result'range loop
    

    Which gives us:

    ghdl -a paebbels.vhdl

    (No errors, no warnings).

    There's also using type conversion to avoid the issue:

        -- FOR I IN 0 TO (slv'length / 4) - 1 LOOP
        --for i in Result'range loop
        for i in 0 to natural(slv'length/4-1) loop
    

    I'd claim the 93c behavior is incorrect, but there's actually a historical dispute whether the LCS changed the meaning of the standard or simply clarified it's interpretation, the intent all along being to allow conversion to universal integer.