Maxim Blinov
Maxim Blinov

Reputation: 946

VHDL: Vivado 2016.4: Constant expression required in generic map

As part of my description, within a wrapper component I generate N number of rom components. These roms are initialized from a text file containing the rom image. I pass the name of the file with which I wish to initialize each component as a generic parameter.

A hopefully sufficient excerpt of the description is as follows:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

package lnx1_types is
    type lnx1_cs is array (integer range <>) of std_logic_vector(7 downto 0);
    constant rom_count: integer := 9;
end package lnx1_types;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
use STD.textio.all; -- For reading ucode roms from filesystem
use ieee.std_logic_textio.all;

use work.lnx1_types.all;

entity lnx1_uc_rom is
    generic ( file_name : string := "" );
    port (  uc_addr : in    std_logic_vector(7 downto 0);
        uc_q    : out   std_logic_vector(7 downto 0) );
end entity lnx1_uc_rom;

architecture dataflow of lnx1_uc_rom is
    type lnx1_rom is array (0 to 2 ** 8 - 1) of std_logic_vector(7 downto 0);

    impure function lnx1_load_rom(file_name : in string)
        return lnx1_rom
    is
        file curr_rom_file: text;

        variable curr_il : line;
        variable curr_hx : std_logic_vector(7 downto 0);

        variable rom : lnx1_rom;
        variable good : boolean := TRUE;
    begin
        file_open (curr_rom_file, file_name, READ_MODE);

        for i in rom'range(1) loop
        if not endfile(curr_rom_file) then
            readline(curr_rom_file, curr_il); -- Read line
            read(curr_il, curr_hx, good); -- Read hex code

            rom(i) := curr_hx;
        end if;
        end loop;

        return rom;
    end function lnx1_load_rom;

    signal rom: lnx1_rom := lnx1_load_rom(file_name);
begin
    uc_q <= rom(to_integer(unsigned(uc_addr)));
end architecture dataflow;


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
use work.lnx1_types.all;

entity lnx1_uc is
    port (  uc_addr : in    std_logic_vector(7 downto 0);
        cs_q    : out   lnx1_cs(rom_count - 1 downto 0)
    );
end entity lnx1_uc;

architecture dataflow of lnx1_uc is

    component lnx1_uc_rom is
        generic ( file_name : string := "" );
        port (  uc_addr : in    std_logic_vector(7 downto 0);
                uc_q    : out   std_logic_vector(7 downto 0) );
    end component lnx1_uc_rom;

    type lnx1_rom_names is array (integer range <>) of string;

    constant rom_path: lnx1_rom_names := (
        0 => "r0.hex",
        1 => "r1.hex",
        2 => "r2.hex",
        3 => "r3.hex",
        4 => "r4.hex",
        5 => "r5.hex",
        6 => "r6.hex",
        7 => "r7.hex",
        8 => "r8.hex"
    );
begin
    ucgen: for i in rom_path'range(1) generate
        rom0: lnx1_uc_rom
        generic map ( rom_path(i) )
        port map (
            uc_addr => uc_addr,
            uc_q => cs_q(i)
        );
    end generate ucgen;
end architecture dataflow;


entity intro_main is
end intro_main;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
use work.lnx1_types.all;

architecture testbench_lnx1_uc of intro_main is
    component lnx1_uc is
        port (  uc_addr : in    std_logic_vector(7 downto 0);
            cs_q    : out   lnx1_cs(rom_count - 1 downto 0)
        );
    end component lnx1_uc;

    signal uc_addr: std_logic_vector(7 downto 0);
    signal cs_q: lnx1_cs(rom_count - 1 downto 0);

begin
    uc0: lnx1_uc
    port map (
        uc_addr => uc_addr,
        cs_q => cs_q
    );

    main: process
        variable index: integer range 0 to 255 := 0;
    begin
        uc_addr <= std_logic_vector(to_unsigned(index, uc_addr'length(1)));
        wait for 5 ns;

        index := index + 1;
    end process main;

end architecture testbench_lnx1_uc;

Although the description synthesis is without errors, attempt at simulation fails with the following message:

[VRFC 10-322] array element type cannot be unconstrained ["...":1080]
[XSIM 43-3321] Static elaboration of top level VHDL design unit intro_main in library work failed.

line 1080 is referring to

type lnx1_rom_names is array (integer range <>) of string;


I accordingly made the following change:

- type lnx1_rom_names is array (integer range <>) of string;
+ type lnx1_rom_names is array (integer range <>) of string(0 to 32);

Now, by definition, lnx_rom_names no longer has an unconstrained element type. However, not only does this change not remove the previous simulation error, it also introduces some very curious errors during synthesis:

[Synth 8-3302] unable to open file 'r0.hexr1.hexr2.hexr3.hexr4.hexr5.' in 'r' mode ["...":1026]

This implies that during the first iteration of the generate loop, rom_path(i) indeed points to the first item, however there is no delimitation of elements at all - simply, the entire linear segment of data beginning at that point is passed, in a string(0 to 32);.

As I write this, I realize that I have two questions, the latter borne out of trying to answer the first:

I suspect the answer in the latter may be due to VHDL simply not initializing the spare slots left in the string(0 to 32), and thus the next element being allocated immediately afterwards; However, I would not believe VHDL to contain such broken functionality.

Upvotes: 2

Views: 1654

Answers (1)

Maxim Blinov
Maxim Blinov

Reputation: 946

As user1155120 pointed out in the comments, the issue was due to incorrect length of the array element type, and had I actually tried to simulate first, I would've been greeted by some very helpful error messages:

enter image description here

Thus, changing the line

type lnx1_rom_names is array (integer range <>) of string(1 to 32);

to

type lnx1_rom_names is array (integer range <>) of string(1 to 6);

Removed all errors and simulation produced the expected result.

Also, strings must have a natural index range, so string(0 to n) is invalid, and should be string(1 to n); all following code has been amended accordingly.


Since I invested (or perhaps wasted) so much time into this problem, I thought it would be a waste not to at-least document my findings regarding string concatenation.

During synthesis Vivado decides to concatenate as many sequential array elements as would fit in the mis-sized array element when trying to pass an array element as an argument to, in this case, a generic map member:

    ...
    type lnx1_rom_names is array (integer range <>) of string(1 to 32);

    constant rom_path: lnx1_rom_names := (
        0 => "r0.hex",
        1 => "r1.hex",
        2 => "r2.hex",
        3 => "r3.hex",
        4 => "r4.hex",
        5 => "r5.hex",
        6 => "r6.hex",
        7 => "r7.hex",
        8 => "r8.hex",
    );
begin

ucgen: for i in rom_path'range generate
    rom0: lnx1_romblk
    generic map (
        file_name => rom_path(i) -- << rom_path(i) evalues to "r0.hexr1.hexr2.hex ... "
    ) port map (
        addr => uc_addr,
        data => cs_q(i)
    );
end generate ucgen;
...

I fiddled around with the description some more, and discovered that to replicate the concatenation behavior, the total number of characters present in the array of strings must be greater than the string length of a single array element, i.e.:

type lnx1_rom_names is array (integer range <>) of string(1 to 32);

constant rom_path: lnx1_rom_names := (
    0 => "r0.hex",
    1 => "r1.hex",
    2 => "r2.hex",
    3 => "r3.hex",
    4 => "r4.hex",
    5 => "r5.hex"
);

will fail with [Synth 8-3302] unable to open file 'r0.hexr1.hexr2.hexr3.hexr4.hexr5.' in 'r' mode ["D:/...":48]

however

constant rom_path: lnx1_rom_names := (
    0 => "r0.hex",
    1 => "r1.hex",
    2 => "r2.hex",
    3 => "r3.hex",
    4 => "r4.hex"
);

will not cause that error to appear.

Comparison of log during synthesis/simulation (images):

With concatenation error

Without concatenation error


For reference, below is the description I used. It is slightly different from the OP as I've already had time to work on it and didn't use version control, but still demonstrates the problem.

The top level entity and architecture are at the bottom and should be renamed if appropriate.

Sample r0.hex file: Click here

The contents are not important, simply duplicate and rename to r1, r2... etc.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

package lnx1_types is
    type lnx1_cs is array (integer range <>) of std_logic_vector(7 downto 0);
    constant rom_count: integer := 2;
end package lnx1_types;


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
use STD.textio.all; -- For reading ucode roms from filesystem
use ieee.std_logic_textio.all;
use work.lnx1_types.all;

entity lnx1_romblk is
    generic ( file_name : string := "";
          awidth : integer := 8;
          dwidth : integer := 8 );
    port (  addr    : in    std_logic_vector(AWIDTH-1 downto 0);
        data    : out   std_logic_vector(DWIDTH-1 downto 0) );
end entity lnx1_romblk;

architecture dataflow of lnx1_romblk is
    type lnx1_rom is array (0 to 2 ** AWIDTH - 1) of std_logic_vector(DWIDTH-1 downto 0);

    impure function lnx1_load_rom(file_name : in string)
        return lnx1_rom
    is
        file curr_rom_file: text;

        variable curr_il : line;
        variable curr_hx : std_logic_vector(DWIDTH-1 downto 0);

        variable rom : lnx1_rom;
        variable good : boolean := TRUE;
    begin
        -- If no filename passed, initailize with 0
        if file_name = "" then
            for i in rom'range loop
                rom(i) := (others => '0');
            end loop;
            return rom;
        end if;

        file_open (curr_rom_file, file_name, READ_MODE);

        for i in rom'range loop
        if not endfile(curr_rom_file) then
            readline(curr_rom_file, curr_il); -- Read line
            read(curr_il, curr_hx, good); -- Read binary value

            rom(i) := curr_hx;
        end if;
        end loop;

        return rom;
    end function lnx1_load_rom;

    signal rom: lnx1_rom := lnx1_load_rom(file_name);
begin
    data <= rom(to_integer(unsigned(addr)));
end architecture dataflow;


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
use work.lnx1_types.all;

entity lnx1_uc is
    port (  uc_addr : in    std_logic_vector(7 downto 0);
        cs_q    : out   lnx1_cs(rom_count - 1 downto 0)
    );
end entity lnx1_uc;

architecture dataflow of lnx1_uc is

    component lnx1_romblk is -- Needs testbench
        generic ( file_name : string := "";
              awidth : integer := 8;
              dwidth : integer := 8 );
        port (  addr    : in    std_logic_vector(awidth-1 downto 0);
            data    : out   std_logic_vector(dwidth-1 downto 0) );
    end component lnx1_romblk;

    type lnx1_rom_names is array (integer range <>) of string(1 to 32);

    constant rom_path: lnx1_rom_names := (
        0 => "r0.hex",
        1 => "r1.hex",
        2 => "r2.hex",
        3 => "r3.hex",
        4 => "r4.hex"
--      5 => "r5.hex" -- Uncomment this line to generate the error.
--      6 => "r6.hex",
--      7 => "r7.hex",
--      8 => "r8.hex",
    );
begin
    ucgen: for i in rom_path'range generate
        rom0: lnx1_romblk
        generic map (
            file_name => rom_path(i)
        ) port map (
            addr => uc_addr,
            data => cs_q(i)
        );
    end generate ucgen;
end architecture dataflow;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
use work.lnx1_types.all;

-- Here should go the top level entity declaration; I initially created
-- the project with the name "intro_main", so change to whatever is your case.

entity intro_main is
end entity intro_main;

architecture top_level of intro_main is
    component lnx1_uc is
        port (  uc_addr : in    std_logic_vector(7 downto 0);
            cs_q    : out   lnx1_cs(rom_count - 1 downto 0)
        );
    end component lnx1_uc;

    signal uc_addr  : std_logic_vector(7 downto 0);
    signal cs_q : lnx1_cs(rom_count - 1 downto 0);
begin
    uc0: lnx1_uc port map ( uc_addr, cs_q );
end architecture;

Upvotes: 1

Related Questions