-- MIPS I system -- Copyright 2011-2012 Stefan Schuermans -- Copyleft GNU public license V2 or later -- http://www.gnu.org/copyleft/gpl.html LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.NUMERIC_STD.ALL; ENTITY e_block_fifo IS GENERIC ( addr_width: natural; data_width: natural ); PORT ( rst: IN std_logic; clk: IN std_logic; o_wr_rdy: OUT std_logic; i_wr_data: IN std_logic_vector(data_width - 1 DOWNTO 0); i_wr_en: IN std_logic; o_rd_rdy: OUT std_logic; o_rd_data: OUT std_logic_vector(data_width - 1 DOWNTO 0); i_rd_en: IN std_logic ); END ENTITY e_block_fifo; ARCHITECTURE a_block_fifo OF e_block_fifo IS COMPONENT e_block_rwram GENERIC ( addr_width: natural; data_width: natural := 8 ); PORT ( clk: IN std_logic; i_rd_addr: IN std_logic_vector(addr_width - 1 DOWNTO 0); o_rd_data: OUT std_logic_vector(data_width - 1 DOWNTO 0); i_wr_addr: IN std_logic_vector(addr_width - 1 DOWNTO 0); i_wr_data: IN std_logic_vector(data_width - 1 DOWNTO 0); i_wr_en: IN std_logic ); END COMPONENT e_block_rwram; SUBTYPE t_pos IS natural RANGE 0 TO 2 ** addr_width - 1; SUBTYPE t_addr IS std_logic_vector(addr_width - 1 DOWNTO 0); SUBTYPE t_data IS std_logic_vector(data_width - 1 DOWNTO 0); SIGNAL r_begin: t_pos := 0; SIGNAL n_begin: t_pos; SIGNAL s_begin_addr: t_addr; SIGNAL s_begin_sn_addr: t_addr; -- _sn_ means sometimes next SIGNAL s_rd_rdy: std_logic; SIGNAL s_rd_en: std_logic; SIGNAL r_end: t_pos := 0; SIGNAL n_end: t_pos; SIGNAL s_end_addr: t_addr; SIGNAL r_end_addr_delay: t_addr := (OTHERS => '0'); SIGNAL s_end_an_addr: t_addr; -- _an_ means always next SIGNAL s_wr_rdy: std_logic; SIGNAL s_wr_en: std_logic; FUNCTION next_pos ( pos: natural RANGE 0 TO 2 ** addr_width - 1 ) RETURN natural IS VARIABLE v_next: natural RANGE 0 TO 2 ** addr_width - 1; BEGIN IF pos = 2 ** addr_width - 1 THEN v_next := 0; ELSE v_next := pos + 1; END IF; RETURN v_next; END FUNCTION next_pos; FUNCTION to_addr ( pos: natural RANGE 0 TO 2 ** addr_width - 1 ) RETURN std_logic_vector IS BEGIN RETURN std_logic_vector(to_unsigned(pos, addr_width)); END FUNCTION to_addr; BEGIN i_rwram: e_block_rwram GENERIC MAP ( addr_width => addr_width, data_width => data_width ) PORT MAP ( clk => clk, i_rd_addr => s_begin_sn_addr, o_rd_data => o_rd_data, i_wr_addr => s_end_addr, i_wr_data => i_wr_data, i_wr_en => s_wr_en ); s_begin_addr <= to_addr(r_begin); s_begin_sn_addr <= to_addr(n_begin); s_rd_rdy <= '1' WHEN s_begin_addr /= r_end_addr_delay ELSE '0'; s_rd_en <= s_rd_rdy AND i_rd_en; s_end_addr <= to_addr(r_end); s_end_an_addr <= to_addr(next_pos(r_end)); s_wr_rdy <= '1' WHEN s_end_an_addr /= s_begin_addr ELSE '0'; s_wr_en <= s_wr_rdy AND i_wr_en; o_wr_rdy <= s_wr_rdy; o_rd_rdy <= s_rd_rdy; p_next: PROCESS(r_begin, r_end, s_rd_en, s_wr_en) BEGIN n_begin <= r_begin; n_end <= r_end; IF s_rd_en = '1' THEN n_begin <= next_pos(r_begin); END IF; IF s_wr_en = '1' THEN n_end <= next_pos(r_end); END IF; END PROCESS p_next; p_sync: PROCESS(rst, clk) BEGIN IF rst = '1' THEN r_begin <= 0; r_end <= 0; r_end_addr_delay <= (OTHERS => '0'); ELSIF rising_edge(clk) THEN r_begin <= n_begin; r_end <= n_end; r_end_addr_delay <= s_end_addr; END IF; END PROCESS p_sync; END ARCHITECTURE a_block_fifo;