You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;

问题根源

  1. 多进程驱动冲突:你用两个独立进程分别处理端口A和端口B,而两个进程都对RAM信号进行读写操作。在VHDL中,多个进程同时驱动同一个信号会产生不确定行为——仿真器无法判断哪个进程的操作优先,导致RAM的写入和读取状态混乱,自然读不到正确的值。
  2. 类型转换的规范性问题:你使用的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:46:48