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