如何正确解决VHDL数组长度不匹配的vsim-3714致命错误?
问题背景
问题 - 目标信号的约束范围与被条件赋值的常量范围不匹配。
作为VHDL新手,在第一个大型项目中编写代码,根据输入ID字节的值,将自定义unconstrained array(非约束数组)类型的常量之一赋值给同类型信号。每个常量有独立范围且不一定相同,代码编译无错,但仿真时出现错误:
Fatal: (vsim-3714) At array depth 1, array lengths do not match. Left is 5 (0 to 4). Right is 4 (0 to 3).
Time: 100 us Iteration: 0 Process: /active_set/line__41 File: C:/...ProjectPath.../Active_Set.vhd
Fatal error in Architecture Behavioral at C:/...Project.../Active_Set.vhd line 41
最小可复现代码
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity Active_Set is Port( ID : in std_logic_vector(7 downto 0) ); end entity; Architecture Behavioral of Active_Set is type t_CMD_SET is array (natural range <>) of std_logic_vector(7 downto 0); constant SET_10h : t_CMD_SET := (x"11", x"12", x"13", x"14"); constant SET_20h : t_CMD_SET := (x"21", x"22", x"23", x"24", x"25"); constant SET_DUMMY : t_CMD_SET := (x"00", x"00", x"00", x"00", x"00"); function f_ACT_SET (ID : std_logic_vector; SET1 : t_CMD_SET; SET2 : t_CMD_SET; SET3 : t_CMD_SET ) return t_CMD_SET is begin if ID = x"10" then return SET1; elsif ID = x"20" then return SET2; else return SET3; end if; end function; signal ACT_SET : t_CMD_SET(0 to 4); begin -- NEXT LINE IS PROBLEMATIC, LINE 41 ACT_SET <= f_ACT_SET(ID, SET_10h, SET_20h, SET_DUMMY); end Behavioral;
仿真.do文件
onerror {resume} quietly WaveActivateNextPane {} 0 add wave -noupdate -radix hexadecimal /active_set/ID add wave -noupdate -radix hexadecimal /active_set/ACT_SET TreeUpdate [SetDefaultTree] WaveRestoreCursors {{Cursor 1} {0000000 ps} 0} quietly wave cursor active 1 configure wave -namecolwidth 270 configure wave -valuecolwidth 70 configure wave -justifyvalue left configure wave -signalnamewidth 0 configure wave -snapdistance 10 configure wave -datasetprefix 0 configure wave -rowmargin 4 configure wave -childrowmargin 2 configure wave -gridoffset 0 configure wave -gridperiod 1 configure wave -griddelta 40 configure wave -timeline 0 configure wave -timelineunits us update WaveRestoreZoom {0 ps} {210 us} view wave wave clipboard store wave create -driver freeze -pattern repeater -initialvalue 00000000 -period 100us -sequence { 00000000 00010000 00100000 00000000 } -repeat 1 -range 7 0 -starttime 0us -endtime 400us sim:/active_set/ID WaveExpandAll -1 WaveCollapseAll -1 wave clipboard restore
拒绝通过补全常量至相同大小的解决方法(违背非约束数组初衷、维护困难),提出两个问题:
- 是否有其他无需补全常量的解决方法?需兼容VHDL 1076-2002,不切换至2008版本。
- 是否可以完全避免使用else分支的SET3?
解决方案
问题1:无需补全常量的兼容方案(VHDL 2002)
VHDL 2002中数组赋值要求左右范围完全匹配,可通过以下两种方式解决:
方案1:进程内条件赋值(推荐)
去掉原有函数,直接在进程中针对不同ID处理数组赋值,仅对常量的有效范围赋值,超出部分设为默认值:
signal ACT_SET : t_CMD_SET(0 to 4); begin process(ID) begin -- 默认初始化所有位置为0(可自定义默认值) ACT_SET <= (others => x"00"); if ID = x"10" then -- 遍历SET_10h的有效索引,仅赋值对应位置 for i in SET_10h'range loop ACT_SET(i) <= SET_10h(i); end loop; elsif ID = x"20" then -- SET_20h长度与目标信号匹配,直接赋值 ACT_SET <= SET_20h; end if; end process;
该方案保留非约束数组灵活性,无需修改原有常量定义,完全兼容VHDL 2002。
方案2:修改函数返回固定长度数组
若需保留函数形式,让函数返回与目标信号同范围的数组,内部处理长度差异:
function f_ACT_SET (ID : std_logic_vector; SET1 : t_CMD_SET; SET2 : t_CMD_SET ) return t_CMD_SET is -- 定义与目标信号同范围的返回变量,默认初始化 variable ret_val : t_CMD_SET(0 to 4) := (others => x"00"); begin if ID = x"10" then for i in SET1'range loop ret_val(i) := SET1(i); end loop; elsif ID = x"20" then ret_val := SET2; end if; return ret_val; end function; signal ACT_SET : t_CMD_SET(0 to 4); begin ACT_SET <= f_ACT_SET(ID, SET_10h, SET_20h);
问题2:避免使用dummy数组处理无效ID
完全可以去掉SET_DUMMY,直接在逻辑中处理无效ID:
- 在上述进程赋值方案中,默认将
ACT_SET设为全0(或自定义默认值),ID无效时保持该状态即可 - 若需明确标记有效性,可添加额外信号:
signal ACT_SET : t_CMD_SET(0 to 4); signal ACT_SET_VALID : std_logic := '0'; -- 标记命令集是否有效 begin process(ID) begin ACT_SET_VALID <= '0'; ACT_SET <= (others => x"00"); if ID = x"10" then for i in SET_10h'range loop ACT_SET(i) <= SET_10h(i); end loop; ACT_SET_VALID <= '1'; elsif ID = x"20" then ACT_SET <= SET_20h; ACT_SET_VALID <= '1'; end if; end process;
通过ACT_SET_VALID信号可直接判断当前ACT_SET是否为有效命令集,无需额外定义dummy常量。
内容的提问来源于stack exchange,提问作者HardwareEE

