Search code examples
vhdlmodelsim

VHDL wrong RAM beahviour on reading


After 1 day of working on the same issue, maybe it is time to ask on stackoverflow :(

In my project I have an entity RAM which has the following code:

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;

A main entity use this RAM entity. It works fine regarding the setting of the data in the RAM. What doesn't work is keeping the data previously stored from the RAM.

The architecture of the main entity is the following code:

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;

My goal is to take, under certain conditions, all the RAM memory starting from the address "000" to "111", one by one setting in output (on tel_pin output), changing each clock cycle.

By compiling my code there are no errors but by simulating it I face a very strange behaviour and I can't understand the reason and so the solution.

The simulation gives me this: enter image description here

Why there is such a shift between tel_pin and RAM_ADDR that doesn't allow me to have in output all the RAM data? The address seems to increase correctly but I dont' know why the MEMORY(0) is repeated for 2 clock cycle.


Solution

  • Fianlly I found the solution: the issue is related to a different way of approaching the VHDL programming. In the details if I have a code like this:

    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;
    

    When the process starts and a=b, the first if will set the x=1 but this is not visible to the second if, which consider still x=0. So y <= '1' will be done only in the next execution of process. While with a software language like C the second if will be performed in the same process execution.

    In general in VHDL signals are set when the process terminates, so the comparison is with the value got the last time the process was exectured.

    So, coming back to the question, the solution can be just setting the condition boundary to 8 (not 7): counter < 9