DRVPR
DRVPR

Reputation: 71

Read, then write RAM VHDL

in VHDL all the code lines are executed in a parallel way, since its a machine. i want to create this RAM that reads a certain register from a ram block to the output and only 'afterwards' writes to the same register the input. my code goes like this:

architecture Behavioral of RAM is

type ram_t is array (0 to numOfRegs-1) of std_logic_vector (rLength-1 downto 0);
signal ram_s: ram_t;
signal loc : integer;

begin

process(clk)
begin
    if(rising_edge(clk)) then
        if(we='1') then
            dataout <= ram_s(loc); -- reads the 'old' data to the output 
            ram_s(loc) <= datain;  --  writes the 'new' data to the RAM
            loc <= conv_integer(addr);
        end if;
    end if;
end process;                
end Behavioral;

there is a similar case presented here.

so I'd like to ask, is my code works fine or is there need for tweaking like putting a delay of half clock cycle, and if so, how to implement it. I'm very new to VHDL thanks for your patience and help.

ive add a testbench simulation below . as can be seen the dataout isnt working at all.

testbench i've simulated

Upvotes: 0

Views: 7670

Answers (1)

user1155120
user1155120

Reputation:

Your question doesn't present a Minimal, Verifiable and Complete example, lacking the ability to replicate your results.

One of the consequences of this is that answers can be ambiguous should there be one or more causes of the problem in portions of your code not shown.

Brian's comment that you aren't reading data when we is invalid is poignant and would be responsible for 'U's in the clock cycle left of your yellow marker in your waveform.

There's also the issue with loc being a signal. Signals are scheduled for update, and no update occurs while any process that is scheduled to resume in the current simulation cycle has not been resumed and suspended.

This means the integer version of your address is delayed and won't be seen in the process until the next rising edge.

Fixing loc by making it a variable as an alternative to pipelining datain and moving the dataout assignment are accomplished in the following changes to your RAM process:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;  -- standard package

entity ram is
    generic (
        ADDRLENGTH: natural := 8;
        RLENGTH:    natural := 16;
        NUMOFREGS:  natural := 256
    );
    port (
        clk:        in  std_logic;
        we:         in  std_logic;
        addr:       in  std_logic_vector (ADDRLENGTH - 1 downto 0);
        datain:     in  std_logic_vector (RLENGTH - 1 downto 0);
        dataout:    out std_logic_vector (RLENGTH - 1 downto 0)
    );

end entity;

architecture behavioral of ram is

    type ram_t is array (0 to NUMOFREGS - 1) of 
            std_logic_vector (RLENGTH - 1 downto 0);
    signal ram_s: ram_t;

    -- signal loc: integer;  -- USE VARIABLE in process instead

begin

    process(clk)
    variable loc: integer;   -- MAKE loc variable so it's immediately available
    begin
        if rising_edge(clk) then
            loc := to_integer(unsigned(addr)); -- MOVED so READ works
            if we = '1' then
                -- dataout <= ram_s(loc); -- reads the 'old' data to the output 
                ram_s(loc) <= datain;  --  writes the 'new' data to the ram
                -- loc <= conv_integer(addr);
            end if;
            dataout <= ram_s(loc); -- MOVED reads the 'old' data to the output 
        end if;
    end process;                
end architecture behavioral;

There's also the liberty of filling in the entity declaration and converting from conv_integer using Synopsys's package std_logic_arith to to_integer in the IEEE's numeric_std package. With a -2008 compliant tool chain you could instead use IEEE's package numeric_std_unsigned and do away with the type conversion to unsigned.

Because the ram_test testbench was also not supplied a testbench was written to replicate your waveform display image:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity ram_tb is
end entity;

architecture foo of ram_tb is
    constant ADDRLENGTH: natural := 8;
    constant RLENGTH:    natural := 16;
    constant NUMOFREGS:  natural := 256;
    signal clk:        std_logic := '0';
    signal we:         std_logic := '1';
    signal addr:       std_logic_vector (ADDRLENGTH - 1 downto 0);
    signal datain:     std_logic_vector (RLENGTH - 1 downto 0);
    signal dataout:    std_logic_vector (RLENGTH - 1 downto 0);

begin
DUT:
    entity work.ram
        generic map (
            ADDRLENGTH => ADDRLENGTH,
            RLENGTH => RLENGTH,
            NUMOFREGS => NUMOFREGS
        )
        port map (
            clk => clk,
            we => we,
            addr => addr,
            datain => datain,
            dataout => dataout
        );

CLOCK:
    process
    begin
        if now = 500 ps then
            wait for 200 ps;
        else 
            wait for 100 ps;
        end if;
        clk <= not clk;
        if now >= 1100 ps then
            wait;
        end if;
    end process;

STIMULI:
    process
    begin
        for i in 0 to 2 loop
            addr   <= std_logic_vector(to_unsigned (i, ADDRLENGTH));
            case i is
                when 0 =>
                    datain <= x"00FF";
                when 1 =>
                    datain <= x"FF00";
                when 2 =>
                    datain <= x"FFFF";
            end case;
            wait until falling_edge(clk);
            if i = 1 then
                we <= '0';
            end if;
        end loop;
        for i in 1 to 2 loop
            addr   <= std_logic_vector(to_unsigned (i, ADDRLENGTH));
            case i is
                when 1 =>
                    datain <= x"FF00";
                when 2 =>
                    datain <= x"FFFF";
            end case;
            wait until falling_edge(clk);
        end loop;        
        wait;
    end process;

end architecture;

And this produced:

ram_tb_match.png

Where the one written address that is subsequently read shows the correct data.

The simulator used does not present non-signals in a waveform dump (bounds in declarations are required to be static) and rst is not found in the portion of your design specification provided.

As noted previously there is no guarantee there isn't another issue with portions of your design specification or testbench not provided in your question.

The testbench shown is by no means comprehensive.

Upvotes: 1

Related Questions