VHDL实现简单双端口Block RAM仿真不符合预期问题排查
双端口Block RAM仿真异常的问题分析与解决
先梳理你的问题:你尝试用VHDL实现一个简单的双端口Block RAM,但仿真结果不符合预期——doa始终显示未定义值,无法读取到通过dib写入的300、355等数据,即使addra指向已写入的地址也不行。
初始代码
library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_unsigned.all; entity rams is generic ( g_adress_width: integer:= 18; g_ram_size: integer:= 1000 ); port( clka : in std_logic; clkb : in std_logic; wea : in std_logic; web : in std_logic; addra : in std_logic_vector(g_adress_width-1 downto 0); addrb : in std_logic_vector(g_adress_width-1 downto 0); dia : in std_logic_vector(15 downto 0); dib : in std_logic_vector(15 downto 0); doa : out std_logic_vector(15 downto 0); dob : out std_logic_vector(15 downto 0) ); end rams; architecture syn of rams is type ram_type is array (g_ram_size-1 downto 0) of std_logic_vector(15 downto 0); signal RAM : ram_type; begin process (CLKA) begin if CLKA'event and CLKA = '1' then DOA <= RAM(conv_integer(ADDRA)); if WEA = '1' then --always 0 RAM(conv_integer(ADDRA)) <= DIA; --does not execute end if; end if; end process; process (CLKB) begin if CLKB'event and CLKB = '1' then DOB <= RAM(conv_integer(ADDRB)); if WEB = '1' then RAM(conv_integer(ADDRB)) <= DIB; end if; end if; end process; end syn;
问题根源
- 多进程驱动冲突:你用两个独立进程分别处理端口A和端口B,而两个进程都对
RAM信号进行读写操作。在VHDL中,多个进程同时驱动同一个信号会产生不确定行为——仿真器无法判断哪个进程的操作优先,导致RAM的写入和读取状态混乱,自然读不到正确的值。 - 类型转换的规范性问题:你使用的
conv_integer来自std_logic_unsigned包,虽然能临时工作,但更推荐使用IEEE标准的numeric_std包中的to_integer(unsigned(...)),兼容性和可读性更好。
修复后的代码
你后来修改的版本已经解决了核心问题,这里再优化一下规范性:
library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; -- 改用标准的numeric_std包 entity rams is generic ( g_adress_width: integer:= 18; g_ram_size: integer:= 1000 ); port( clka : in std_logic; clkb : in std_logic; wea : in std_logic; web : in std_logic; addra : in std_logic_vector(g_adress_width-1 downto 0); addrb : in std_logic_vector(g_adress_width-1 downto 0); dia : in std_logic_vector(15 downto 0); dib : in std_logic_vector(15 downto 0); doa : out std_logic_vector(15 downto 0); dob : out std_logic_vector(15 downto 0) ); end rams; architecture syn of rams is type ram_type is array (g_ram_size-1 downto 0) of std_logic_vector(15 downto 0); signal RAM : ram_type; begin process (CLKA) begin if CLKA'event and CLKA = '1' then -- 处理端口A的读操作 DOA <= RAM(to_integer(unsigned(ADDRA))); -- 端口A写操作(你的场景里wea始终为0,不影响) if WEA = '1' then RAM(to_integer(unsigned(ADDRA))) <= DIA; end if; -- 处理端口B的读写(因为clka和clkb接同一时钟,合并到同一进程) DOB <= RAM(to_integer(unsigned(ADDRB))); if WEB = '1' then RAM(to_integer(unsigned(ADDRB))) <= DIB; end if; end if; end process; end syn;
修复说明
- 合并进程:因为你把
clka和clkb接了同一个时钟,所以把两个端口的逻辑合并到同一个时钟触发的进程里,彻底避免了多进程驱动RAM的冲突,确保读写操作的顺序是确定的。 - 标准类型转换:用
to_integer(unsigned(ADDRA))替代conv_integer,依赖numeric_std包,这是VHDL的标准做法,减少不同工具之间的兼容性问题。 - 如果后续需要使用独立的两个时钟,建议直接调用FPGA厂商提供的BRAM原语(比如Xilinx的
RAMB16_SDP或者Intel的altsyncram),这些原语原生支持独立时钟的双端口RAM,比自己写的代码更可靠。
内容的提问来源于stack exchange,提问作者metaplexer
相关产品推荐
相关产品推荐

