VHDL generate语句内记录类型数组赋值异常(信号恒为U)
VHDL generate语句中记录数组使用异常排查
问题现象
- 相关代码在Vivado 2021.1中可正常通过综合、实现全流程,但仿真时关联的记录信号始终保持
"U"未定义态,无法被正确赋值 - 公开可查资料中几乎没有generate语句端口映射直接使用记录字段的参考示例
初始实现代码
记录类型与数组信号定义
type record_a_t is record a : std_logic; b : std_logic_vector(7 downto 0); c : std_logic_vector(3 downto 0); d : std_logic; e : std_logic; end record record_a_t; type record_a_array_t is array (0 to 3) of record_a_t; signal record_a_array : record_a_array_t;
generate循环例化映射
GEN_MODULES : for i in 0 to 3 generate modules : entity work.module port map( clk => clk, rst_n => rst_n, a => record_a_array(i).a, b => record_a_array(i).b, c => record_a_array(i).c, d => record_a_array(i).d, e => record_a_array(i).e ); end generate GEN_MODULES;
上述代码可通过Vivado全流程语法检查与构建,但在RivPro 2018仿真、实际实现验证时信号均无法正常赋值跳变:即使模块内部对输出端口做了复位初始化,对应连接的
record_a_array(i).c等信号始终为"U"态,模块输出端口自身也显示为未定义,仿佛内部初始化逻辑被忽略,仅测试台直接驱动的a信号可正常工作。
问题复现用例
被测模块代码
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity module is port( clk : in std_logic; rst_n : in std_logic; a : in std_logic; b : out std_logic_vector(7 downto 0); c : out std_logic_vector(3 downto 0); d : out std_logic; e : out std_logic ); end module; architecture rtl of module is begin process(clk, rst_n) begin if(rst_n = '0') then b <= (others=> '0'); c <= (others=> '0'); d <= '0'; e <= '0'; elsif(rising_edge(clk)) then if(a = '1') then b <= b + '1'; c <= c + '1'; d <= not d; e <= not e; end if; end if; end process; end rtl;
测试台代码
library ieee; use ieee.std_logic_1164.all; entity testbench is end entity testbench; --------------------------------------------------- architecture arch of testbench is --------------------------------------------------- type record_a_t is record a : std_logic; b : std_logic_vector(7 downto 0); c : std_logic_vector(3 downto 0); d : std_logic; e : std_logic; end record record_a_t; type record_a_array_t is array (0 to 3) of record_a_t; signal record_a_array : record_a_array_t; signal clk : std_logic := '1'; signal rst_n : std_logic := '0'; --------------------------------------------------- begin clk <= not clk after 5 ns; rst_n <= '1' after 20 ns; GEN_MODULES : for i in 0 to 3 generate modules : entity work.module port map( clk => clk, rst_n => rst_n, a => record_a_array(i).a, b => record_a_array(i).b, c => record_a_array(i).c, d => record_a_array(i).d, e => record_a_array(i).e ); end generate GEN_MODULES; process(clk, rst_n) begin if(rst_n = '0') then for i in 0 to 3 loop record_a_array(i).a <= '0'; end loop; elsif(rising_edge(clk)) then for i in 0 to 3 loop record_a_array(i).a <= not record_a_array(i).a; end loop; end if; end process; end arch;
仿真异常表现
- 测试台层级连接至模块输出的记录字段信号始终为未定义态
- 循环生成的模块实例输出端无有效驱动,复位阶段置零逻辑未生效
- 仅测试台进程直接驱动的
record_a_array(i).a信号可正常翻转
根因与正确实现方式
问题根因
VHDL是强类型校验语言,该问题和generate语句语法无关,核心诱因是自定义记录类型的定义位置错误:
示例代码中record_a_t、record_a_array_t类型是在测试台的architecture作用域内局部定义的,若后续其他模块也在自身作用域内定义了结构完全相同的同名类型,仿真器会将二者判定为完全独立的两个类型,端口映射时出现隐式连接断开;部分综合工具会做结构优化跳过严格类型校验,因此会出现"综合能过、仿真全U"的反常现象。
正确操作步骤
- 新建独立的VHDL包文件,统一存放所有全局自定义的记录、数组类型定义,禁止在各个模块、测试台的局部作用域重复定义同名同结构的自定义类型。
示例包代码:
library ieee; use ieee.std_logic_1164.all; package common_types_pkg is type record_a_t is record a : std_logic; b : std_logic_vector(7 downto 0); c : std_logic_vector(3 downto 0); d : std_logic; e : std_logic; end record record_a_t; type record_a_array_t is array (0 to 3) of record_a_t; end package common_types_pkg;
- 所有需要使用该类型的模块、测试台,均在代码头部的库声明区域通过
use语句引用全局包,删除原有局部定义的同名类型:
library ieee; use ieee.std_logic_1164.all; -- 引用全局定义的类型包 use work.common_types_pkg.all;
- 若需要进一步简化代码,可将被例化模块的端口直接定义为记录类型,generate例化时直接映射整个记录元素即可,无需逐字段拆分映射,可大幅降低端口接错的概率。
内容的提问来源于stack exchange,提问作者rdensbe
相关产品推荐
相关产品推荐

