在 VHDL 中实现简单的双端口块 ram 未按预期执行
Implementing simple dual port block ram in VHDL not performing as expected
我一直在尝试在 VHDL 中实现一个简单的双端口块 RAM,但它在仿真中没有产生预期的结果。这是代码:
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;
这是模拟:
clka和clkb都连接到同一个时钟。我给 dib 一些任意值(无符号 300 和 355)。
基本上,doa 总是在读取,所以我希望它是未定义的,直到用 dib 将某些内容写入那些块 ram 地址, 但它总是显示未定义的值。
我期望发生的是 doa 在 addra 再次为 0 时读取 300,在 [=32] 时读取 355 =]addra 是 15。像这样的东西(请原谅我的绘画技巧):
如果有人能指出我做错事的正确方向,我将不胜感激。谢谢
编辑:代码已修改为现在可用(感谢 Paebbels 解决方案):
signal RAM : ram_type;
begin
process (CLKA)
begin
if CLKA'event and CLKA = '1' then
DOA <= RAM(to_integer(unsigned(ADDRA)));
if WEA = '1' then --always 0
RAM(to_integer(unsigned(ADDRA))) <= DIA; --does not happen
end if;
end if;
if CLKA'event and CLKA = '1' then
DOB <= RAM(to_integer(unsigned(ADDRB)));
if WEB = '1' then
RAM(to_integer(unsigned(ADDRB))) <= DIB;
end if;
end if;
end process;
end syn;
双时钟 RAM 的描述是错误的。您需要使用:
- 一个有两个时钟的进程,或者
- 共享变量。
使用一个信号和两个过程是不正确的。它在一个信号上创建多个驱动器。这反过来又造成了多源问题。虽然您的模拟会工作,但由于您的用户定义数组类型中的已解析类型 std_logic_vector
,综合将失败。
此外,为了允许 BlockRAM 的推断,您需要在 VHDL 代码中表示 BlockRAM 的内部结构。这意味着您需要在地址路径上添加流水线寄存器。
您应该阅读 UG901 - Vivado Synthesis Guide 并搜索 "RAM HDL Coding Techniques"。
此外,您应该使用包 numeric_std
而不是 std_logic_unsigned
,这不是官方 IEEE 包。
可在 PoC-Library: PoC.mem.ocram.tdp 中找到有效的真双端口 (TDP) BlockRAM 实现。此实现也适用于 Altera/Intel FPGA 和莱迪思 FPGA。
-- RAM can be inferred correctly only if '-use_new_parser yes' is enabled in XST options
subtype word_t is std_logic_vector(D_BITS - 1 downto 0);
type ram_t is array(0 to DEPTH - 1) of word_t;
signal ram : ram_t;
signal a1_reg : unsigned(A_BITS-1 downto 0);
signal a2_reg : unsigned(A_BITS-1 downto 0);
begin
process (clk1, clk2)
begin -- process
if rising_edge(clk1) then
if ce1 = '1' then
if we1 = '1' then
ram(to_integer(a1)) <= d1;
end if;
a1_reg <= a1;
end if;
end if;
if rising_edge(clk2) then
if ce2 = '1' then
if we2 = '1' then
ram(to_integer(a2)) <= d2;
end if;
a2_reg <= a2;
end if;
end if;
end process;
q1 <= (others => 'X') when SIMULATION and is_x(std_logic_vector(a1_reg)) else
ram(to_integer(a1_reg)); -- returns new data
q2 <= (others => 'X') when SIMULATION and is_x(std_logic_vector(a2_reg)) else
ram(to_integer(a2_reg)); -- returns new data
我一直在尝试在 VHDL 中实现一个简单的双端口块 RAM,但它在仿真中没有产生预期的结果。这是代码:
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;
这是模拟:
clka和clkb都连接到同一个时钟。我给 dib 一些任意值(无符号 300 和 355)。
基本上,doa 总是在读取,所以我希望它是未定义的,直到用 dib 将某些内容写入那些块 ram 地址, 但它总是显示未定义的值。
我期望发生的是 doa 在 addra 再次为 0 时读取 300,在 [=32] 时读取 355 =]addra 是 15。像这样的东西(请原谅我的绘画技巧):
如果有人能指出我做错事的正确方向,我将不胜感激。谢谢
编辑:代码已修改为现在可用(感谢 Paebbels 解决方案):
signal RAM : ram_type;
begin
process (CLKA)
begin
if CLKA'event and CLKA = '1' then
DOA <= RAM(to_integer(unsigned(ADDRA)));
if WEA = '1' then --always 0
RAM(to_integer(unsigned(ADDRA))) <= DIA; --does not happen
end if;
end if;
if CLKA'event and CLKA = '1' then
DOB <= RAM(to_integer(unsigned(ADDRB)));
if WEB = '1' then
RAM(to_integer(unsigned(ADDRB))) <= DIB;
end if;
end if;
end process;
end syn;
双时钟 RAM 的描述是错误的。您需要使用:
- 一个有两个时钟的进程,或者
- 共享变量。
使用一个信号和两个过程是不正确的。它在一个信号上创建多个驱动器。这反过来又造成了多源问题。虽然您的模拟会工作,但由于您的用户定义数组类型中的已解析类型 std_logic_vector
,综合将失败。
此外,为了允许 BlockRAM 的推断,您需要在 VHDL 代码中表示 BlockRAM 的内部结构。这意味着您需要在地址路径上添加流水线寄存器。
您应该阅读 UG901 - Vivado Synthesis Guide 并搜索 "RAM HDL Coding Techniques"。
此外,您应该使用包 numeric_std
而不是 std_logic_unsigned
,这不是官方 IEEE 包。
可在 PoC-Library: PoC.mem.ocram.tdp 中找到有效的真双端口 (TDP) BlockRAM 实现。此实现也适用于 Altera/Intel FPGA 和莱迪思 FPGA。
-- RAM can be inferred correctly only if '-use_new_parser yes' is enabled in XST options
subtype word_t is std_logic_vector(D_BITS - 1 downto 0);
type ram_t is array(0 to DEPTH - 1) of word_t;
signal ram : ram_t;
signal a1_reg : unsigned(A_BITS-1 downto 0);
signal a2_reg : unsigned(A_BITS-1 downto 0);
begin
process (clk1, clk2)
begin -- process
if rising_edge(clk1) then
if ce1 = '1' then
if we1 = '1' then
ram(to_integer(a1)) <= d1;
end if;
a1_reg <= a1;
end if;
end if;
if rising_edge(clk2) then
if ce2 = '1' then
if we2 = '1' then
ram(to_integer(a2)) <= d2;
end if;
a2_reg <= a2;
end if;
end if;
end process;
q1 <= (others => 'X') when SIMULATION and is_x(std_logic_vector(a1_reg)) else
ram(to_integer(a1_reg)); -- returns new data
q2 <= (others => 'X') when SIMULATION and is_x(std_logic_vector(a2_reg)) else
ram(to_integer(a2_reg)); -- returns new data