VHDL:Vivado 2016.4:通用映射中需要的常量表达式

时间:2017-07-02 19:50:01

标签: vhdl

作为我的描述的一部分,在包装器组件中,我生成了N个rom组件。这些rom是从包含rom图像的文本文件初始化的。我传递了我希望将每个组件初始化为通用参数的文件的名称。

希望有足够的描述摘录如下:

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;

尽管描述合成没有错误,但尝试模拟失败时出现以下消息:

[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.

第1080行指的是

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

我因此做了以下改变:

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

现在,根据定义,lnx_rom_names不再具有无约束的元素类型。但是,这种改变不仅不会消除先前的模拟错误,还会在合成过程中引入一些非常奇怪的错误:

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

这意味着在generate循环的第一次迭代期间,rom_path(i)确实指向第一个项目,但根本没有元素的定界 - 简单地说,整个线性数据段开始在那一点上,在string(0 to 32);

中传递

在我写这篇文章的时候,我意识到我有两个问题,后者则试图回答第一个问题:

  • 为什么无约束元素类型错误仍然存​​在?
  • 为什么存在上述数组行为,即传递数组的线性数据块,而不是实际的数组成员?

我怀疑后者的答案可能是由于VHDL根本没有初始化string(0 to 32)中剩余的备用插槽,因此下一个元素会在之后立即分配;但是,我不相信VHDL包含这样的破坏功能。

1 个答案:

答案 0 :(得分:2)

正如user1155120在评论中指出的那样,问题是由于数组元素类型的长度不正确,并且我实际上是先尝试过模拟,我会受到一些非常有用的错误消息的欢迎:

enter image description here

因此,改变行

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

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

删除所有错误并模拟产生预期结果。

此外,字符串必须具有自然索引范围,因此string(0 to n)无效,应为string(1 to n);以下所有代码都已相应修改。

由于我投入(或者可能浪费了)这么多时间来解决这个问题,我认为至少记录我关于字符串连接的发现是不浪费的。

在合成期间,当尝试将数组元素作为参数传递给generic map成员时,Vivado决定连接尽可能多的顺序数组元素以适应错误大小的数组元素:

    ...
    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;
...

我更多地讨论了描述,并发现要复制连接行为,字符串数组中存在的字符总数必须大于字符串长度单个数组元素,即:

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"
);

将失败并显示[Synth 8-3302] unable to open file 'r0.hexr1.hexr2.hexr3.hexr4.hexr5.' in 'r' mode ["D:/...":48]

然而

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

不会导致出现该错误。

合成/模拟期间的对数比较(图像):

With concatenation error

Without concatenation error

供参考,以下是我使用的说明。它与OP略有不同,因为我已经有时间处理它并且没有使用版本控制,但仍然表明了问题。

顶级实体和架构位于底部,如果合适,应重命名。

示例r0.hex文件:Click here

内容并不重要,只需复制并重命名为r1,r2 ......等。

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;