自定义类型数组聚合问题:带RAM行为的FSM初始化语法错误求助
嘿,我仔细看了你的VHDL代码,能立刻发现几个导致语法错误的核心问题,大多是因为对VHDL的类型系统、赋值语法理解不到位。咱们一步步把这些问题拆解并修正:
1. 最关键的错误:把类型当成了可操作的存储单元
你定义了type ram_block is array (31 downto 0) of ram_word;,但直接在进程里给ram_block(0)赋值——这完全搞错了!ram_block只是一个类型模板,就像“整数”这个概念本身不能存值一样,你必须声明一个该类型的信号(用于进程间共享)或者变量(仅进程内使用)才能实际存储数据:
-- 在architecture的声明区(RTL下)添加这行: signal ram : ram_block; -- 这才是真正的RAM存储信号
之后所有读写操作都要针对ram,而不是ram_block类型。
2. 低级拼写错误:to_unsgined → to_unsigned
在初始化ram_block(0)的行里,你把标准函数to_unsigned拼写成了to_unsgined——少了一个'i',这会直接触发语法错误,编译器根本认不出这个函数。
3. 部分位赋值的语法错误
VHDL的聚合赋值有严格的语法要求,你写的ram_block(4) <= (66 downto 64) => "001";是无效的,因为没有指定剩余位的处理方式。正确的写法有两种:
-- 方式1:显式指定目标位,其余位用0填充(适合初始化) ram(4) <= (66 downto 64 => "001", others => '0'); -- 方式2:直接修改对应位段,保留其他位原有值(适合运行时修改) ram(4)(66 downto 64) <= "001";
另外,你尝试批量初始化地址20-31的写法也不对,因为ram(31 downto 20)是一个由12个67位ram_word组成的数组,正确的批量全0初始化应该是:
ram(31 downto 20) <= (others => (others => '0'));
4. 变量与信号赋值符号混淆
temp_read_ram2是进程内的变量,VHDL中变量赋值必须用:=,而<=是信号的赋值符号。你写的temp_read_ram2 <= ram_block(R_ADDR_S);会触发语法错误,修正后:
temp_read_ram2 := ram(to_integer(unsigned(R_ADDR_S)));
5. 无效的双else语法
在START_FSM进程里,你出现了else else的错误写法,这是完全不符合VHDL语法的,直接去掉多余的那个else就行。
6. 索引类型不匹配
R_ADDR_S是std_logic_vector(4 downto 0)类型,不能直接作为RAM数组的索引——你需要先把它转换成整数类型:
-- 读取RAM时的正确索引方式 temp_read_ram := ram(to_integer(unsigned(R_ADDR_S)));
修正后的完整代码示例
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.numeric_std.all; entity RegisterController is port( r1_p: inout std_logic_vector(31 downto 0); r2_p: inout std_logic_vector(31 downto 0); write_p: in std_logic; enable_p: in std_logic; clk_p: in std_logic; ram_rw: in std_logic; -- 0 => Read from ram | 1 => Write to the ram reset_p: in std_logic ); end RegisterController; architecture RTL of RegisterController is -- Create the ram word subtype ram_word is std_logic_vector(66 downto 0); -- Create the ram block type type ram_block is array (31 downto 0) of ram_word; -- 声明实际的RAM存储信号 signal ram : ram_block; -- Address to read from the ram signal R_ADDR_S: std_logic_vector(4 downto 0) := "00000"; begin RAM_LOAD: process(clk_p) begin if(rising_edge(clk_p)) then if(ram_rw = '1') then -- STATE 0 DESCRIPTION ram(0) <= ("000", std_logic_vector(to_unsigned(0, 32)), std_logic_vector(to_unsigned(0, 32))); ram(1) <= ("000", std_logic_vector(to_unsigned(0, 32)), std_logic_vector(to_unsigned(0, 32))); ram(2) <= ("001", std_logic_vector(to_unsigned(0, 32)), std_logic_vector(to_unsigned(0, 32))); ram(3) <= ("001", std_logic_vector(to_unsigned(0, 32)), std_logic_vector(to_unsigned(0, 32))); -- STATE 1 DESCRIPTION ram(4) <= (66 downto 64 => "001", others => '0'); ram(5) <= (66 downto 64 => "001", others => '0'); ram(6) <= ("001", r2_p, r1_p); ram(7) <= (66 downto 64 => "010", others => '0'); -- STATE 2 DESCRIPTION ram(8) <= (66 downto 64 => "010", others => '0'); ram(9) <= (66 downto 64 => "010", others => '0'); ram(10) <= (66 downto 64 => "011", others => '0'); ram(11) <= (66 downto 64 => "011", others => '0'); -- STATE 3 DESCRIPTION ram(12) <= (66 downto 64 => "011", others => '0'); ram(13) <= (66 downto 64 => "011", others => '0'); ram(14) <= (66 downto 64 => "100", others => '0'); ram(15) <= (66 downto 64 => "100", others => '0'); -- STATE 4 DESCRIPTION ram(16) <= (66 downto 64 => "100", others => '0'); ram(17) <= (66 downto 64 => "100", others => '0'); ram(18) <= (66 downto 64 => "001", others => '0'); ram(19) <= (66 downto 64 => "001", others => '0'); -- 批量初始化地址20-31为全0 ram(31 downto 20) <= (others => (others => '0')); end if; end if; end process; START_FSM: process(clk_p) -- TEMPORARY VARIABLE TO STORE THE READ VALUE FROM THE RAM BLOCK variable temp_read_ram: std_logic_vector(66 downto 0); variable temp_read_ram2: std_logic_vector(66 downto 0); -- R3 Declaration as a variable variable R3_V: std_logic_vector(31 downto 0); begin if(rising_edge(clk_p)) then if(ram_rw = '0') then -- START READING THE RAM FROM ADDRESS 0 temp_read_ram := ram(to_integer(unsigned(R_ADDR_S))); R_ADDR_S(4 downto 2) <= temp_read_ram(66 downto 64); R_ADDR_S(1 downto 0) <= (enable_p, write_p); -- UPDATE THE OUTPUTS if(R_ADDR_S = "00110") then -- READ THE PREVIOUS VALUE IN THAT ADDRESS temp_read_ram2 := ram(to_integer(unsigned(R_ADDR_S))); -- UPDATE THE OUTPUT VALUES INSIDE RAM ram(to_integer(unsigned(R_ADDR_S))) <= (temp_read_ram2(66 downto 64), r2_p, r1_p); -- NO NEED TO UPDATE r2_p and r1_p elsif(R_ADDR_S = "00111") then -- PUT THE CURRENT VALUE OF R1 TO THE R3 temp_read_ram2 := ram(to_integer(unsigned(R_ADDR_S))); -- SAVE R1 TO THE R3_V R3_V := temp_read_ram2(31 downto 0); elsif(R_ADDR_S = "01110" or R_ADDR_S = "01111") then -- READ THE PREVIOUS VALUE IN THOSE ADDRESSES temp_read_ram2 := ram(to_integer(unsigned(R_ADDR_S))); -- UPDATE THE OUTPUT VALUE OF R2 INSIDE RAM ram(to_integer(unsigned(R_ADDR_S))) <= (temp_read_ram2(66 downto 64), R3_V, temp_read_ram2(31 downto 0)); -- UPDATE THE OUTPUT VALUE OF r2_p r2_p <= R3_V; else -- NO CHANGE null; -- 用null表示无操作,避免语法错误 end if; end if; end if; end process; end RTL;
另外提个小建议:RAM初始化如果是上电就固定的值,其实可以直接在信号声明时完成,不需要放在时钟进程里,比如:
signal ram : ram_block := ( 0 => ("000", (others => '0'), (others => '0')), 1 => ("000", (others => '0'), (others => '0')), -- ... 其他地址的初始化 others => (others => '0') );
这样更符合VHDL的初始化规范,也能避免时钟进程里的冗余操作。
内容的提问来源于stack exchange,提问作者hexpheus

