VHDL 错误的 RAM 读取行为
VHDL wrong RAM beahviour on reading
在处理同一问题 1 天后,也许是时候在 Whosebug 上提问了:(
在我的项目中,我有一个具有以下代码的实体 RAM:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity RAM is
--generic ( N : positive := 4 );
port ( clk, w_on : in STD_LOGIC;
data_in : in STD_LOGIC_VECTOR (3 downto 0);
data_out : out STD_LOGIC_VECTOR (3 downto 0);
address : in STD_LOGIC_VECTOR (2 downto 0));
end RAM;
architecture ram8x4 of RAM is
type RAM_type is array (7 downto 0) of STD_LOGIC_VECTOR (3 downto 0);
signal MEMORY : RAM_type;
begin
data_out <= MEMORY(conv_integer(address));
process(clk, w_on)
begin
data_out <= MEMORY(conv_integer(address));
if (clk = '0' and w_on = '1') then
MEMORY(conv_integer(address)) <= data_in;
end if;
end process;
end ram8x4;
一个主要实体使用这个 RAM 实体。它在 RAM 中的数据设置方面工作正常。
不起作用的是保留以前从 RAM 存储的数据。
主体架构如下代码:
architecture rtl of MainEntity is
.......
signal INSERTED : STD_LOGIC := '0';
signal AREA : STD_LOGIC_VECTOR (9 downto 0) := (others => '0');
signal CHECKER : STD_LOGIC_VECTOR (9 downto 0) := (others => '0');
signal CLK : STD_LOGIC := '0';
signal KEY_NUM : STD_LOGIC_VECTOR (3 downto 0) := (others => '-');
signal STATE : STD_LOGIC_VECTOR (1 downto 0) := (others => '-');
signal RAM_OUTPUT : STD_LOGIC_VECTOR (3 downto 0) := (others => '0');
signal RAM_ADDR : STD_LOGIC_VECTOR (2 downto 0) := (others => '0');
signal RAM_RW : STD_LOGIC := '0'; -- = 1 for write
signal ALARM_OFF : STD_LOGIC := '1';
signal TEL_NUM : STD_LOGIC_VECTOR (3 downto 0) := (others=> '-');
begin
clock : entity work.ClockGeneric(clock_1ns) port map(CLK);
......
ram : entity work.RAM(ram8x4) port map(CLK,RAM_RW,KEY_NUM,RAM_OUTPUT,RAM_ADDR);
CHECKER <= AREA OR areas_pin;
alarm <= ALARM_OFF;
tel_pin <= TEL_NUM;
process(CLK)
.......
variable counter : integer := 0;
begin
.....
if STATE = "11" then
RAM_RW <= '0';
if counter = 8 then
TEL_NUM <= (others => '-');
RAM_ADDR <= "000";
end if;
if(CLK = '0' and ALARM_OFF = '0' and counter < 8) then
--RAM_ADDR <= STD_LOGIC_VECTOR(TO_UNSIGNED(counter,3));
case counter is
when 0 => RAM_ADDR <= "000";
when 1 => RAM_ADDR <= "001";
when 2 => RAM_ADDR <= "010";
when 3 => RAM_ADDR <= "011";
when 4 => RAM_ADDR <= "100";
when 5 => RAM_ADDR <= "101";
when 6 => RAM_ADDR <= "110";
when 7 => RAM_ADDR <= "111";
when others => RAM_ADDR <= "000";
end case;
TEL_NUM <= RAM_OUTPUT;
counter := counter + 1;
end if;
.......
end if;
end process;
end rtl;
我的目标是,在特定条件下,获取从地址“000”到“111”开始的所有 RAM 内存,在输出中逐一设置(在 tel_pin 输出上),改变每个时钟循环.
通过编译我的代码,没有错误,但是通过模拟它,我遇到了一个非常奇怪的行为,我无法理解原因和解决方案。
模拟给了我这个:
为什么 tel_pin 和 RAM_ADDR 之间存在这样的转换,不允许我输出所有 RAM 数据?地址似乎正确增加,但我不知道为什么 MEMORY(0) 重复 2 个时钟周期。
最后我找到了解决方案:这个问题与处理 VHDL 编程的不同方式有关。在细节中,如果我有这样的代码:
architecture …
signal x : bit := ‘0’;
…
process(clk)
begin
…
if a = b then
x <= ‘1’;
end if;
if x = ‘1’ then
y <= ‘1’;
end if;
end process;
当进程启动并 a=b
时,第一个 if 将设置 x=1
但这对第二个 if 不可见,第二个 if 仍然考虑 x=0
。所以 y <= '1'
只会在下一次执行过程中完成。而对于像 C 这样的软件语言,第二个 if 将在同一个进程执行中执行。
一般来说,VHDL 中的信号是在进程终止时设置的,所以比较的是上次进程执行时得到的值。
所以,回到问题,解决方案可以将条件边界设置为 8(而不是 7):counter < 9
在处理同一问题 1 天后,也许是时候在 Whosebug 上提问了:(
在我的项目中,我有一个具有以下代码的实体 RAM:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity RAM is
--generic ( N : positive := 4 );
port ( clk, w_on : in STD_LOGIC;
data_in : in STD_LOGIC_VECTOR (3 downto 0);
data_out : out STD_LOGIC_VECTOR (3 downto 0);
address : in STD_LOGIC_VECTOR (2 downto 0));
end RAM;
architecture ram8x4 of RAM is
type RAM_type is array (7 downto 0) of STD_LOGIC_VECTOR (3 downto 0);
signal MEMORY : RAM_type;
begin
data_out <= MEMORY(conv_integer(address));
process(clk, w_on)
begin
data_out <= MEMORY(conv_integer(address));
if (clk = '0' and w_on = '1') then
MEMORY(conv_integer(address)) <= data_in;
end if;
end process;
end ram8x4;
一个主要实体使用这个 RAM 实体。它在 RAM 中的数据设置方面工作正常。 不起作用的是保留以前从 RAM 存储的数据。
主体架构如下代码:
architecture rtl of MainEntity is
.......
signal INSERTED : STD_LOGIC := '0';
signal AREA : STD_LOGIC_VECTOR (9 downto 0) := (others => '0');
signal CHECKER : STD_LOGIC_VECTOR (9 downto 0) := (others => '0');
signal CLK : STD_LOGIC := '0';
signal KEY_NUM : STD_LOGIC_VECTOR (3 downto 0) := (others => '-');
signal STATE : STD_LOGIC_VECTOR (1 downto 0) := (others => '-');
signal RAM_OUTPUT : STD_LOGIC_VECTOR (3 downto 0) := (others => '0');
signal RAM_ADDR : STD_LOGIC_VECTOR (2 downto 0) := (others => '0');
signal RAM_RW : STD_LOGIC := '0'; -- = 1 for write
signal ALARM_OFF : STD_LOGIC := '1';
signal TEL_NUM : STD_LOGIC_VECTOR (3 downto 0) := (others=> '-');
begin
clock : entity work.ClockGeneric(clock_1ns) port map(CLK);
......
ram : entity work.RAM(ram8x4) port map(CLK,RAM_RW,KEY_NUM,RAM_OUTPUT,RAM_ADDR);
CHECKER <= AREA OR areas_pin;
alarm <= ALARM_OFF;
tel_pin <= TEL_NUM;
process(CLK)
.......
variable counter : integer := 0;
begin
.....
if STATE = "11" then
RAM_RW <= '0';
if counter = 8 then
TEL_NUM <= (others => '-');
RAM_ADDR <= "000";
end if;
if(CLK = '0' and ALARM_OFF = '0' and counter < 8) then
--RAM_ADDR <= STD_LOGIC_VECTOR(TO_UNSIGNED(counter,3));
case counter is
when 0 => RAM_ADDR <= "000";
when 1 => RAM_ADDR <= "001";
when 2 => RAM_ADDR <= "010";
when 3 => RAM_ADDR <= "011";
when 4 => RAM_ADDR <= "100";
when 5 => RAM_ADDR <= "101";
when 6 => RAM_ADDR <= "110";
when 7 => RAM_ADDR <= "111";
when others => RAM_ADDR <= "000";
end case;
TEL_NUM <= RAM_OUTPUT;
counter := counter + 1;
end if;
.......
end if;
end process;
end rtl;
我的目标是,在特定条件下,获取从地址“000”到“111”开始的所有 RAM 内存,在输出中逐一设置(在 tel_pin 输出上),改变每个时钟循环.
通过编译我的代码,没有错误,但是通过模拟它,我遇到了一个非常奇怪的行为,我无法理解原因和解决方案。
模拟给了我这个:
为什么 tel_pin 和 RAM_ADDR 之间存在这样的转换,不允许我输出所有 RAM 数据?地址似乎正确增加,但我不知道为什么 MEMORY(0) 重复 2 个时钟周期。
最后我找到了解决方案:这个问题与处理 VHDL 编程的不同方式有关。在细节中,如果我有这样的代码:
architecture …
signal x : bit := ‘0’;
…
process(clk)
begin
…
if a = b then
x <= ‘1’;
end if;
if x = ‘1’ then
y <= ‘1’;
end if;
end process;
当进程启动并 a=b
时,第一个 if 将设置 x=1
但这对第二个 if 不可见,第二个 if 仍然考虑 x=0
。所以 y <= '1'
只会在下一次执行过程中完成。而对于像 C 这样的软件语言,第二个 if 将在同一个进程执行中执行。
一般来说,VHDL 中的信号是在进程终止时设置的,所以比较的是上次进程执行时得到的值。
所以,回到问题,解决方案可以将条件边界设置为 8(而不是 7):counter < 9