VHDL: Vivado 2016.4: Constant Expression Required in Shared Map

As part of my description, in a shell component, I generate N number of rom components. These ROMs are initialized from a text file containing the ROM image. I am passing in the name of the file with which I want to initialize each component as a shared parameter.

Hopefully a sufficient excerpt from 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 synthesis of the description has no errors, a simulation attempt 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 refers to

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


I 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 unbounded element type. However, not only does this change not fix the previous modeling error, it also causes some very curious errors during synthesis:

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

      

This means that during the first iteration of the loop it generate

rom_path(i)

does point to the first element, however, there is no delineation of elements at all - just the entire line segment of data starting at that point, at string(0 to 32);

.

As I write this, I realize that I have two questions, the last one is trying to answer the first:

  • Why is the non-confidential item type error persisting?
  • Why is there the aforementioned array behavior, namely passing a linear block of array data and not an actual member of the array?

I suspect the answer in the latter case may be due to the fact that VHDL simply does not initialize the spare slots left in string(0 to 32)

, and hence the next item is allocated immediately after that; However, I would not believe VHDL to contain such broken functionality.

+3


source to share


1 answer


As noted in the comments by user 1155120, the problem is with the wrong length of the array element type, and if I had actually tried to simulate first, I would have been greeted with 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 the simulation gave the expected result.

In addition, rows must have a natural index range, so it string(0 to n)

is invalid and should be string(1 to n)

; the following code has been changed.


Since I wasted (or perhaps wasted) so much time on this issue, I thought it would be a waste of time not to document my conclusions about string concatenation.

During synthesis, Vivado decides to concatenate as many consecutive array elements as would fit into an incorrectly sized array element when trying to pass an array element as an argument, in this case a member generic map

:

    ...
    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 twisted the description a bit and found that to replicate the concatenation behavior, the total number of characters present in the array of strings must be greater than the length of the string one element of the array , 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 end 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 this error to appear.

Comparison of the log during synthesis / simulation (images):

With concatenation error

No concatenation error


For reference, below is the description I used. It is a little different from the OP as I already had time to process it and did not use version control, but still demonstrates the problem.

The top-level entity and architecture is at the bottom and should be renamed if necessary.

Example r0.hex file: Click here

The content is not important, just 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;

      

+2


source







All Articles