VHDL:Vivado 2016.4:通用映射中需要常量表达式
作为我描述的一部分,在包装器组件中,我生成了N个rom组件。这些rom是从包含rom映像的文本文件初始化的。我传递了文件名,希望使用该文件将每个组件初始化为通用参数 下面是描述的充分摘录:VHDL:Vivado 2016.4:通用映射中需要常量表达式,vhdl,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
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;
第1080行是指
type lnx1\u rom\u names是字符串的数组(整数范围)代码>
因此,我做了以下更改:
- type lnx1_rom_names is array (integer range <>) of string;
+ type lnx1_rom_names is array (integer range <>) of string(0 to 32);
这意味着在generate
循环的第一次迭代期间,rom_路径(i)
确实指向第一个项目,但是根本没有元素的定界-简单地说,以字符串(0到32)传递从该点开始的整个线性数据段代码>
当我写这篇文章时,我意识到我有两个问题,后一个问题来自于试图回答第一个问题:
- 为什么无约束图元类型错误持续存在
- 为什么会出现上述数组行为,即传递数组的线性数据块,而不是实际的数组成员
我怀疑后者的答案可能是因为VHDL没有初始化字符串(0到32)
中剩余的备用插槽,因此随后立即分配下一个元素;但是,我不相信VHDL包含这样的破坏性功能。正如user1155120在评论中指出的,问题是由于数组元素类型的长度不正确,如果我确实尝试先进行模拟,我会收到一些非常有用的错误消息:
因此,改变路线
type lnx1_rom_name是字符串(1到32)的数组(整数范围)代码>
到
type lnx1_rom_name是字符串(1到6)的数组(整数范围)代码>
消除了所有错误,模拟产生了预期的结果
此外,字符串必须具有自然索引范围,因此string(0到n)
无效,应该是string(1到n)
;以下所有代码均已相应修订
由于我在这个问题上投入了(或者可能浪费了)太多时间,我认为至少不记录我关于字符串连接的发现是一种浪费
在合成过程中,当试图将数组元素作为参数传递给通用映射
成员时,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;
...
不会导致出现该错误
合成/模拟期间的日志比较(图像):
以下是我使用的说明,仅供参考。它与OP略有不同,因为我已经有时间来处理它,并且没有使用版本控制,但仍然演示了这个问题
顶层实体和体系结构位于底部,如果合适,应重命名
r0.hex文件示例:
内容并不重要,只需复制并重命名为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;
IEEE库;
使用IEEE.STD_LOGIC_1164.ALL;
使用IEEE.NUMERIC_STD.ALL;
包lnx1_类型为
lnx1_cs型是标准逻辑向量(7到0)的数组(整数范围);
常量rom_计数:整数:=2;
端封装lnx1_类型;
图书馆IEEE;
使用IEEE.STD_LOGIC_1164.ALL;
使用IEEE.NUMERIC_STD.all;
使用STD.textio.all;——用于从文件系统读取ucode ROM
使用ieee.std_logic_textio.all;
使用work.lnx1_types.all;
实体lnx1_romblk为
通用(文件名:字符串=“”);
awidth:整数:=8;
dwidth:整数:=8);
端口(地址:标准逻辑向量中(AWIDTH-1向下至0);
数据:输出标准逻辑向量(DWIDTH-1向下至0);
终端实体lnx1_romblk;
lnx1_romblk的架构数据流为
lnx1_rom型是标准逻辑_矢量(DWIDTH-1向下至0)的阵列(0至2**AWIDTH-1);
不纯函数lnx1_加载_rom(文件名:字符串形式)
返回lnx1_rom
是
文件当前rom文件:文本;
可变货币:行;
变量curr_hx:std_逻辑_向量(DWIDTH-1向下至0);
变量rom:lnx1_-rom;
变量good:boolean:=TRUE;
开始
--如果未传递文件名,则使用0初始化
如果文件名为“”,则
在rom'range循环中的i
rom(i):=(其他=>“0”);
端环;
返回rom;
如果结束;
文件打开(当前rom文件、文件名、读取模式);
在rom'range循环中的i
如果不是endfile(curr\u rom\u文件),则
读线(当前rom文件,当前il);--读线
读(curr_il,curr_hx,good);-读取二进制值
rom(i):=电流hx;
如果结束;
端环;
返回rom;
端功能lnx1_加载_rom;
信号rom:lnx1_rom:=lnx1_加载_rom(文件名);
开始
数据“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”,
);
开始
ucgen:为rom_路径范围内的i生成
rom0:lnx1u romblk
通用地图(
文件名=>rom路径(i)
)港口地图(
地址=>uc\U地址,
数据=>cs_q(i)
);
末端生成ucgen;
终端架构数据流;
图书馆IEEE;
使用IEEE.STD_LOGIC_1164.ALL;
使用IEEE.NUMERIC_STD.all;
使用work.lnx1_types.all;
--这里应该是顶级实体声明;我最初创建
--该项目名为“intro_main”,因此请根据您的情况进行更改。
实体简介主要是
结束实体介绍;
体系结构介绍的顶层是
组件lnx1_uc为
端口(uc地址:标准逻辑向量中(7到0);
cs_q:out lnx1_cs(rom_计数-1下降到0)
);
端部元件lnx1_uc;
...
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"
);
constant rom_path: lnx1_rom_names := (
0 => "r0.hex",
1 => "r1.hex",
2 => "r2.hex",
3 => "r3.hex",
4 => "r4.hex"
);
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;