So im trying to simulate a simple write and read memory program in Vivado design suite.

Before implementing a clock in the sensitivity list on the process to write and read, the reading part used to work correctly in the simulation, but i changed it because the RAM block was created using fpga resources, and then i introduced the clock and now it works as intended (not using the fpga resources but the internal RAM instead), but in the simulation, something is not right, because the reading bits are not the same are the written ones.

When W_R is '0', the memory is writing, and reading in '1'. This is the testbench

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity RAM_SP_tb is
generic(
constant memory_depth : integer := 256; -- numero de palabras de la memoria
constant memory_lenght : integer := 8   -- numero de bits por palabra
);
end RAM_SP_tb;

architecture Behavioral of RAM_SP_tb is

component RAM_SP
Port (
data_in : in std_logic_vector(memory_lenght - 1 downto 0); -- datos de entrada
address : in std_logic_vector(memory_lenght - 1 downto 0); -- direccion de memoria
W_R : IN STD_LOGIC;  --Escribe con '0' y Lee con '1'
data_out : out std_logic_vector(memory_lenght - 1 downto 0);-- datos de salida
clk : in std_logic
);
end component;

signal data_in : std_logic_vector(memory_lenght - 1 downto 0):= "00000000";
signal address : std_logic_vector(memory_lenght - 1 downto 0):= "00000000";
signal W_R : STD_LOGIC := '0';
signal data_out : std_logic_vector(memory_lenght - 1 downto 0):= "00000000";
signal clk : std_logic := '0';

constant clock : time := 100ns;
begin

uut: RAM_SP port map (
data_in => data_in,
W_R => W_R,
data_out => data_out,
clk => clk
);

clock_p :process
begin
clk<='0';
wait for clock/2;
clk<='1';
wait for clock/2;
end process;

stim_proc: process
begin
-- Write data into RAM
WAIT FOR 100 ns;
DATA_IN<="00000001";
WAIT FOR 100 ns;
DATA_IN<="00000010";
WAIT FOR 100 ns;
DATA_IN<="00000011";
WAIT FOR 100 ns;
DATA_IN<="00000100";
WAIT FOR 100 ns;

W_R<='1';
WAIT FOR 100 ns;
WAIT FOR 100 ns;
WAIT FOR 100 ns;
WAIT FOR 100 ns;
WAIT FOR 100 ns;

end  process;

end Behavioral;


and this is the principle module

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

entity RAM_SP is
generic(
constant memory_depth : integer := 256; -- numero de palabras de la memoria
constant memory_lenght : integer := 8   -- numero de bits por palabra
);

Port (
data_in : in std_logic_vector(memory_lenght - 1 downto 0); -- datos de entrada
address : in std_logic_vector(memory_lenght - 1 downto 0); -- direccion de memoria
W_R : in std_logic;  --Escribe con '0' y Lee con '1'
data_out : out std_logic_vector(memory_lenght - 1 downto 0);-- datos de salida
clk : in std_logic
);
end RAM_SP;

architecture Behavioral of RAM_SP is
type mem is array (0 to memory_depth - 1) of std_logic_vector(memory_lenght - 1 downto 0); --Una memoria de 256 palabras de 8 bits
signal memory : mem; --Asocio la memoria creada a la señal/palabra/constante memory
signal addr : integer range 0 to memory_depth - 1; --Creo una señal que puede tomar valores enteros de 0 a 255
begin

process(clk)
begin
if(rising_edge(clk)) then
if(W_R = '0')then
elsif(W_R = '1')then
else
data_out<="ZZZZZZZZ";
end if;
end if;
end process;
end Behavioral;


i would really be grateful if anyone cold guide with the problem, and other issue that i noted is the UU data that is read when W_R is '1', when the address is '00', the data_out is supposed to be '00', but it read UU instead, and the remains readings are not on phase. What could be happening?

Delta cycle delay on addr ... you are writing to the PREVIOUS address so you write 0 to addr UUUU.... ditto reading from the previous address.

Either think through the pipeline more carefully, or compute addr before the clock edge (i.e. outside the clocked process in a concurrent assignment), or make addr a variable instead of a signal.

The phase delay on read is obvious : you read and write on the rising clock edge.

For preference, lose the obsolete std_logic_unsigned library and use numeric__std instead (I would then prefer to make Address unsigned) but that is not material to the current problem.

You can also lose

    else
data_out<="ZZZZZZZZ";


because there are no tristates internal to the FPGA!

• OR memory(conv_integer(address)) <= data_in; and data_out <= memory (conv_integer(address)); without a variable or signal addr. It's not possible to have a memoy index out of range when the address length is 2log memory depth, e.g. address : in std_logic_vector{positive(ceil(log2(real(memory_depth)))) - 1 downto 0); with a use clause use ieee.math_real.all;. (Can use the -2008 equivalent of std_logic_unsigned.conv_integer, numeric_std_unsigned.to_integer). – user8352 Oct 6 at 23:04
• And what does user8352 meant with "its not possible to have a memory index out of range when....", is there something wrong to the way i did it or is just an option. – esencia Oct 7 at 0:27
• @esencia I'm not clear on that. It's not even true since a 6k memory needs an address length capable of addressing 8k. What you have done works ... but it is fragile. It relies on memory_depth being 2**memory_lenght (sic). I would add an ASSERT with severity FAILURE to catch errors in the generics, or a check that address is in range if you wanted to allow a mismatch. Either of these can catch bugs faster and eliminate a bunch of time wasted during verification. – Brian Drummond Oct 7 at 14:07