I'm trying to write a component (mem_interface) that takes 8 bit input vectors for address and data, writes them into specific positions in larger vector buffers depending on an index, and then outputs these larger vector buffers when asked. The component will sit in between a picoblaze processor (which can only output 8 bit values) and an Artix 7 BRAM, which I have configured with an 18 bit read/write port width (so 11 bit addresses). As an end goal, the mem_interface will accumulate multiple 8 bit outputs from the picoblaze and then read/write the BRAM at the provided address with the provided data.
The issue that I'm having is that writes to the mem_interface's internal data buffer do not take effect.
At 15ns, the testbench first tests writing to the component's address buffer, which works perfectly. At 45ns, it attempts to write to the data buffer which immediately sends the targeted elements to 'X'. I've always understood 'X' to mean a multiple driver issue, but I can't identify one in my code.
Here's the code, mem_interface.vhdl first:
library ieee;
use ieee.std_logic_1164.all;
entity mem_interface is
port (
-- data inputs
clk : in std_logic;
idx : in std_logic_vector(1 downto 0);
split_addr_in : in std_logic_vector(7 downto 0);
split_data_in : in std_logic_vector(7 downto 0);
parity_in : in std_logic;
split_data_out : out std_logic_vector(7 downto 0);
parity_out : out std_logic;
-- signals
addr_buf_en : in std_logic;
data_buf_wr : in std_logic;
data_buf_rd : in std_logic;
reset_bufs : in std_logic;
write_to_mem : in std_logic;
read_from_mem : in std_logic;
-- to bram
addr_out : out std_logic_vector(15 downto 0);
data_out : out std_logic_vector(35 downto 0);
data_in : in std_logic_vector(35 downto 0)
);
end mem_interface;
architecture Behavioral of mem_interface is
signal addr_buf : std_logic_vector(15 downto 0) := (others => '0');
signal data_buf : std_logic_vector(35 downto 0) := (others => '0');
begin
handle_addr_buf : process(clk)
begin
if rising_edge(clk) then
if addr_buf_en = '1' then
case idx(0) is
when '0' => addr_buf(7 downto 0) <= split_addr_in;
when '1' => addr_buf(15 downto 8) <= split_addr_in;
when others => addr_buf <= "1010101010101010";
end case;
elsif reset_bufs = '1' then
addr_buf <= (others => '0');
end if;
end if;
end process handle_addr_buf;
handle_data_buf : process(clk)
begin
if rising_edge(clk) then
if data_buf_wr = '1' then
case idx is
when "00" => data_buf(7 downto 0) <= split_data_in;
data_buf(32) <= parity_in;
when "01" => data_buf(15 downto 8) <= split_data_in;
data_buf(33) <= parity_in;
when "10" => data_buf(23 downto 16) <= split_data_in;
data_buf(34) <= parity_in;
when "11" => data_buf(31 downto 24) <= split_data_in;
data_buf(35) <= parity_in;
when others => data_buf <= "101010101010101010101010101010101010";
end case;
elsif data_buf_rd = '1' then
case idx is
when "00" => parity_out <= data_buf(32);
split_data_out <= data_buf(7 downto 0);
when "01" => parity_out <= data_buf(33);
split_data_out <= data_buf(15 downto 8);
when "10" => parity_out <= data_buf(34);
split_data_out <= data_buf(23 downto 16);
when "11" => parity_out <= data_buf(35);
split_data_out <= data_buf(31 downto 24);
when others => split_data_out <= "10101010";
end case;
elsif reset_bufs = '1' then
data_buf <= (others => '0');
end if;
end if;
end process handle_data_buf;
handle_memory : process(clk)
begin
if rising_edge(clk) then
if write_to_mem = '1' then
addr_out <= addr_buf;
data_out <= data_buf;
elsif read_from_mem = '1' then
addr_out <= addr_buf;
data_buf <= data_in;
else
addr_out <= (others => '0');
data_out <= (others => '0');
end if;
end if;
end process handle_memory;
end Behavioral;
And here's the testbench, mem_interface_tb.vhdl
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity mem_interface_tb is
-- Port ( );
end mem_interface_tb;
architecture Behavioral of mem_interface_tb is
component mem_interface is
port (
-- data inputs
clk : in std_logic;
idx : in std_logic_vector(1 downto 0);
split_addr_in : in std_logic_vector(7 downto 0);
split_data_in : in std_logic_vector(7 downto 0);
parity_in : in std_logic;
split_data_out : out std_logic_vector(7 downto 0);
parity_out : out std_logic;
-- signals
addr_buf_en : in std_logic;
data_buf_wr : in std_logic;
data_buf_rd : in std_logic;
reset_bufs : in std_logic;
write_to_mem : in std_logic;
read_from_mem : in std_logic;
-- to bram
addr_out : out std_logic_vector(15 downto 0);
data_out : out std_logic_vector(35 downto 0);
data_in : in std_logic_vector(35 downto 0)
);
end component;
component sim_clk_wrapper
port (
sim_clk_out : out std_logic;
sim_rst_out : out std_logic
);
end component;
signal sim_clk_sig : std_logic;
signal sim_rst_sig : std_logic;
signal sim_idx : std_logic_vector(1 downto 0) := "00";
signal sim_split_addr_in : std_logic_vector(7 downto 0) := (others => '0');
signal sim_split_data_in : std_logic_vector(7 downto 0) := (others => '0');
signal sim_parity_in : std_logic := '0';
signal sim_split_data_out : std_logic_vector(7 downto 0) := (others => '0');
signal sim_parity_out : std_logic := '0';
signal sim_addr_buf_en : std_logic := '0';
signal sim_data_buf_wr : std_logic := '0';
signal sim_data_buf_rd : std_logic := '0';
signal sim_reset_bufs : std_logic := '0';
signal sim_write_to_mem : std_logic := '0';
signal sim_read_from_mem : std_logic := '0';
signal sim_addr_out : std_logic_vector(15 downto 0) := (others => '0');
signal sim_data_out : std_logic_vector(35 downto 0) := (others => '0');
signal sim_data_in : std_logic_vector(35 downto 0) := (others => '0');
type bram_36k is array (0 to 2048) of std_logic_vector(17 downto 0);
signal sim_bram_36k : bram_36k;
begin
sim_clk_gen : sim_clk_wrapper
port map (
sim_clk_out => sim_clk_sig,
sim_rst_out => sim_rst_sig
);
UUT : mem_interface
port map (
clk => sim_clk_sig,
idx => sim_idx,
split_addr_in => sim_split_addr_in,
split_data_in => sim_split_data_in,
parity_in => sim_parity_in,
split_data_out => sim_split_data_out,
parity_out => sim_parity_out,
addr_buf_en => sim_addr_buf_en,
data_buf_wr => sim_data_buf_wr,
data_buf_rd => sim_data_buf_rd,
reset_bufs => sim_reset_bufs,
write_to_mem => sim_write_to_mem,
read_from_mem => sim_read_from_mem,
addr_out => sim_addr_out,
data_out => sim_data_out,
data_in => sim_data_in
);
-- simulating 18 bit port sizes with 11 bit addresses
manage_sim_bram : process(sim_clk_sig)
begin
if rising_edge(sim_clk_sig) then
if sim_write_to_mem = '1' then
sim_bram_36k(to_integer(unsigned(sim_addr_out(14 downto 4)))) <= sim_data_out(33 downto 32) & sim_data_out(15 downto 0);
elsif sim_read_from_mem = '1' then
sim_data_in(33 downto 32) <= sim_bram_36k(to_integer(unsigned(sim_addr_out(14 downto 4))))(17 downto 16);
sim_data_in(15 downto 0) <= sim_bram_36k(to_integer(unsigned(sim_addr_out(14 downto 4))))(15 downto 0);
end if;
end if;
end process manage_sim_bram;
simulate: process
begin
wait until rising_edge(sim_clk_sig);
sim_reset_bufs <= '1';
wait until rising_edge(sim_clk_sig);
-- first write an address to the buffer
sim_reset_bufs <= '0';
sim_addr_buf_en <= '1';
sim_idx <= "00";
sim_split_addr_in <= "00001111";
wait until rising_edge(sim_clk_sig);
sim_idx <= "01";
sim_split_addr_in <= "10000000";
wait until rising_edge(sim_clk_sig);
-- disable writing to address
sim_addr_buf_en <= '0';
sim_split_addr_in <= "00000000";
sim_idx <= "00";
wait until rising_edge(sim_clk_sig);
-- write to the data
sim_data_buf_wr <= '1';
sim_idx <= "00";
sim_split_data_in <= "11111111";
sim_parity_in <= '1';
wait until rising_edge(sim_clk_sig);
sim_idx <= "01";
sim_split_data_in <= "11111111";
sim_parity_in <= '1';
wait until rising_edge(sim_clk_sig);
-- then write the data to the memory
sim_data_buf_wr <= '0';
sim_split_data_in <= "00000000";
sim_parity_in <= '0';
sim_write_to_mem <= '1';
wait until rising_edge(sim_clk_sig);
wait until rising_edge(sim_clk_sig);
wait until rising_edge(sim_clk_sig);
end process simulate;
end Behavioral;
Any help would be appreciated, I've been staring at this for a few hours and have no idea where the issue is.