首页 文章

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

提问于
浏览
3

作为我的描述的一部分,在包装器组件中,我生成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) 确实指向第一个项目,但是根本没有元素的定界 - 简单地说,在该点开始的整个线性数据段在_2586186中传递 .

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

  • 为什么无约束元素类型错误仍然存在?

  • 为什么存在上述数组行为,即传递数组的线性数据块,而不是实际的数组成员?

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

1 回答

  • 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) ;以下所有代码均已相应修改 .


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

    在合成期间,Vivado决定连接尽可能多的顺序数组元素,以便在尝试将数组元素作为参数传递给错误大小的数组元素时,在本例中为 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;
    ...
    

    我更多地摆弄了描述,并发现要复制串联行为, total number of characters present in the array of strings 必须大于 string length of a single array element ,即:

    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;
    

相关问题