------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------ ---- Project: NULL STAR (Devember 2021) ---- ---- Module: SRAM Interface ---- ---- Drawing: (Not Assigned) ---- ---- ---- ---- Filename: memoroy_interface.vhd ---- ---- File Type: VHDL (93) ---- ---- Modified: 11/05/2021 ---- ---- Target: Universal ---- ---- Toolchain: Universal ---- ---- ---- ---- Dependencies: ---- ---- None. ---- ---- ---- ---- Description: ---- ---- Temporary SRAM memory controller. Interface specified for 1P0 0A development board: ---- ---- Memory size: 2Mb (64k x 32) ---- ---- Cache size: 32kb (1024 x 32) -> 39kb (1024 x 39) with Tag/Valid ---- ---- ---- ---- Revision History: ---- ---- 11/05/2021 - Initial release. ---- ------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.math_real.all; entity memory_interface is generic ( -- Bus Parameters G_BUS_REGION : std_ulogic_vector(1 downto 0) := "00"; -- Interface Parameters G_MCLK_FREQ : integer := 50_000_000; -- System Clock Frequency (Hz) G_SRAM_SPEED : integer := 55 -- SRAM Cycle Time (ns) ); port ( -- System Clock, Reset MCLK : in std_ulogic; MRST : in std_ulogic; -- SRAM Interface SRAM_ADDRESS : out std_ulogic_vector(15 downto 0); SRAM_DATA_IN : in std_ulogic_vector(31 downto 0); SRAM_DATA_OUT : out std_ulogic_vector(31 downto 0); SRAM_DATA_OE : out std_ulogic; SRAM_OE_N : out std_ulogic; SRAM_WE_N : out std_ulogic; -- System Bus Interface BUS_ADDRESS : in std_ulogic_vector(63 downto 0); BUS_REGION : in std_ulogic_vector(1 downto 0); BUS_DATA_IN : in std_ulogic_vector(15 downto 0); BUS_DATA_OUT : out std_ulogic_vector(15 downto 0); BUS_REQUEST_READ : in std_ulogic; BUS_REQUEST_WRITE : in std_ulogic; BUS_READY : out std_ulogic ); end entity memory_interface; architecture Behavioral of memory_interface is -- Cache Memory ----------------------------------------------------------------------------------------------------- -- BUS_ADDRESS ------------------ CACHE LINE --------------------- -- [63:18] - Unused -- [37:32] - Tag -- [16:11] - Tag -- [31:16] - Data[1] -- [10:1] - Index -- [15:0] - Data[0] -- [0] - Offset -- ------------------------------------------------------------------ type cache_array_T is array(0 to 1024) of std_ulogic_vector(37 downto 0); signal cache_array : cache_array_T; signal cache_array_D, cache_array_Q : std_ulogic_vector(37 downto 0); signal cache_hit : std_ulogic; -- Cache Word Decode ------------------------------------------------------------------------------------------------ signal decode_read : std_ulogic_vector(15 downto 0); signal decode_write : std_ulogic_vector(37 downto 0); -- Bus Control FSM -------------------------------------------------------------------------------------------------- type bus_control_state_T is (STATE_READY, STATE_REQUEST_LATCHED, STATE_READ_CHECK_VALID, STATE_READ_WAIT_FOR_READY, STATE_READ_EXECUTE, STATE_READ_UPDATE_CACHE, STATE_READ_CACHE_HIT, STATE_WRITE_UPDATE_CACHE, STATE_WRITE_WAIT_FOR_READY, STATE_WRITE_ENTER_HI_Z, STATE_WRITE_EXECUTE, STATE_WRITE_EXIT_HI_Z); signal bus_control_state : bus_control_state_T; signal bus_request_valid : std_ulogic; signal control_state_ready : std_ulogic; -- SRAM Timing Control ---------------------------------------------------------------------------------------------- constant C_SRAM_FREQ : real := floor(real(real(1000000000)/real(G_SRAM_SPEED))); constant C_CLOCK_DIV : real := ceil(real(real(G_MCLK_FREQ)/C_SRAM_FREQ)); constant C_CLOCK_DIV_RANGE : integer := integer(ceil(log2(C_CLOCK_DIV))); constant C_CLOCK_DIV_ROLL : unsigned(C_CLOCK_DIV_RANGE - 1 downto 0) := to_unsigned(integer(C_CLOCK_DIV) - 1, C_CLOCK_DIV_RANGE); signal register_clock_div_D, register_clock_div_Q : std_ulogic_vector(C_CLOCK_DIV_RANGE - 1 downto 0); signal register_sram_ready_D, register_sram_ready_Q : std_ulogic; signal clock_divider_rollover : std_ulogic; -- I/O Signal Registers --------------------------------------------------------------------------------------------- signal register_bus_data_out_D, register_bus_data_out_Q : std_ulogic_vector(15 downto 0); signal register_bus_data_in_D, register_bus_data_in_Q : std_ulogic_vector(15 downto 0); signal register_bus_address_D, register_bus_address_Q : std_ulogic_vector(16 downto 0); signal register_sram_address_D, register_sram_address_Q : std_ulogic_vector(15 downto 0); signal register_request_type_D, register_request_type_Q : std_ulogic_vector(1 downto 0); alias cache_tag : std_ulogic_vector(5 downto 0) is register_bus_address_Q(16 downto 11); alias cache_index : std_ulogic_vector(9 downto 0) is register_bus_address_Q(10 downto 1); alias cache_offset : std_ulogic is register_bus_address_Q(0); -- Register Controls ------------------------------------------------------------------------------------------------ signal select_cache_source : std_ulogic_vector(1 downto 0); signal select_register_bus_data_out : std_ulogic; signal select_register_bus_data_in : std_ulogic; signal select_register_bus_address : std_ulogic; signal select_register_sram_address : std_ulogic; signal select_register_request_type : std_ulogic; signal select_sram_data_out_enable : std_ulogic; begin -- Concurrent Assignments ------------------------------------------------------------------------------------------- SRAM_ADDRESS <= register_sram_address_Q; SRAM_DATA_OE <= select_sram_data_out_enable; BUS_DATA_OUT <= register_bus_data_out_Q; BUS_READY <= '1' when ((BUS_REGION = G_BUS_REGION) and (control_state_ready = '1')) else '0'; bus_request_valid <= '1' when ((BUS_REGION = G_BUS_REGION) and ((BUS_REQUEST_READ = '1') or (BUS_REQUEST_WRITE = '1'))) else '0'; --------------------------------------------------------------------------------------------------------------------- -- SRAM Clock Divider ----------------------------------------------------------------------------------------------- Clock_Divider_Sync_Process : process (MCLK) begin if rising_edge(MCLK) then register_clock_div_Q <= register_clock_div_D; end if; end process Clock_Divider_Sync_Process; clock_divider_rollover <= '1' when (unsigned(register_clock_div_Q) = C_CLOCK_DIV_ROLL) else '0'; register_clock_div_D <= (others => '0') when ((MRST = '1') or (clock_divider_rollover = '1')) else std_ulogic_vector(unsigned(register_clock_div_Q) + 1); --------------------------------------------------------------------------------------------------------------------- -- Cache Memory ----------------------------------------------------------------------------------------------------- Cache_RAM_Sync_Process : process (MCLK) begin if rising_edge(MCLK) then -- Read Cycle cache_array_Q <= cache_array(to_integer(unsigned(cache_index))); -- Write Cycle cache_array(to_integer(unsigned(cache_index))) <= cache_array_D; end if; end process Cache_RAM_Sync_Process; cache_hit <= '1' when (cache_tag = cache_array_Q(37 downto 32)) else '0'; --------------------------------------------------------------------------------------------------------------------- -- Registers -------------------------------------------------------------------------------------------------------- Register_Sync_Process : process (MCLK) begin if rising_edge(MCLK) then if (MRST = '1') then register_bus_data_out_Q <= (others => '0'); register_bus_data_in_Q <= (others => '0'); register_bus_address_Q <= (others => '0'); register_sram_address_Q <= (others => '0'); register_request_type_Q <= (others => '0'); else register_bus_data_out_Q <= register_bus_data_out_D; register_bus_data_in_Q <= register_bus_data_in_D; register_bus_address_Q <= register_bus_address_D; register_sram_address_Q <= register_sram_address_D; register_request_type_Q <= register_request_type_D; end if; end if; end process Register_Sync_Process; --------------------------------------------------------------------------------------------------------------------- -- Register Controls ------------------------------------------------------------------------------------------------ with select_cache_source select cache_array_D <= cache_array_Q when "00", decode_write when "01", cache_tag & SRAM_DATA_IN when "10", (others => '0') when "11", (others => 'X') when others; with select_register_bus_data_out select register_bus_data_out_D <= register_bus_data_out_Q when '0', decode_read when '1', (others => 'X') when others; with select_register_bus_data_in select register_bus_data_in_D <= register_bus_data_in_Q when '0', BUS_DATA_IN when '1', (others => 'X') when others; with select_register_bus_address select register_bus_address_D <= register_bus_address_Q when '0', BUS_ADDRESS(16 downto 0) when '1', (others => 'X') when others; with select_register_sram_address select register_sram_address_D <= register_sram_address_Q when '0', register_bus_address_Q(16 downto 1) when '1', (others => 'X') when others; with select_register_request_type select register_request_type_D <= register_request_type_Q when '0', BUS_REQUEST_WRITE & BUS_REQUEST_READ when '1', (others => 'X') when others; with select_sram_data_out_enable select SRAM_DATA_OUT <= (others => '0') when '0', cache_array_Q(31 downto 0) when '1', (others => 'X') when others; --------------------------------------------------------------------------------------------------------------------- -- Word Decode ------------------------------------------------------------------------------------------------------ with cache_offset select decode_read <= cache_array_Q(15 downto 0) when '0', cache_array_Q(31 downto 16) when '1', (others => 'X') when others; with cache_offset select decode_write <= cache_tag & cache_array_Q(31 downto 16) & register_bus_data_in_Q when '0', cache_tag & register_bus_data_in_Q & cache_array_Q(15 downto 0 ) when '1', (others => 'X') when others; --------------------------------------------------------------------------------------------------------------------- -- Bus Control FSM -------------------------------------------------------------------------------------------------- Bus_Control_Sync_Process : process (MCLK) begin if rising_edge(MCLK) then if (MRST = '1') then bus_control_state <= STATE_READY; else case bus_control_state is when STATE_READY => if (bus_request_valid = '1') then bus_control_state <= STATE_REQUEST_LATCHED; else bus_control_state <= STATE_READY; end if; when STATE_REQUEST_LATCHED => if (register_request_type_Q = "01") then bus_control_state <= STATE_READ_CHECK_VALID; elsif (register_request_type_Q = "10") then bus_control_state <= STATE_WRITE_UPDATE_CACHE; else bus_control_state <= STATE_READY; end if; when STATE_READ_CHECK_VALID => if (cache_hit = '1') then bus_control_state <= STATE_READ_CACHE_HIT; else bus_control_state <= STATE_READ_WAIT_FOR_READY; end if; when STATE_READ_WAIT_FOR_READY => if (clock_divider_rollover = '1') then bus_control_state <= STATE_READ_EXECUTE; else bus_control_state <= STATE_READ_WAIT_FOR_READY; end if; when STATE_READ_EXECUTE => if (clock_divider_rollover = '1') then bus_control_state <= STATE_READ_UPDATE_CACHE; else bus_control_state <= STATE_READ_EXECUTE; end if; when STATE_READ_UPDATE_CACHE => bus_control_state <= STATE_READ_CACHE_HIT; when STATE_READ_CACHE_HIT => bus_control_state <= STATE_READY; when STATE_WRITE_UPDATE_CACHE => bus_control_state <= STATE_WRITE_WAIT_FOR_READY; when STATE_WRITE_WAIT_FOR_READY => if (clock_divider_rollover = '1') then bus_control_state <= STATE_WRITE_ENTER_HI_Z; else bus_control_state <= STATE_WRITE_WAIT_FOR_READY; end if; when STATE_WRITE_ENTER_HI_Z => if (clock_divider_rollover = '1') then bus_control_state <= STATE_WRITE_EXECUTE; else bus_control_state <= STATE_WRITE_ENTER_HI_Z; end if; when STATE_WRITE_EXECUTE => if (clock_divider_rollover = '1') then bus_control_state <= STATE_WRITE_EXIT_HI_Z; else bus_control_state <= STATE_WRITE_EXECUTE; end if; when STATE_WRITE_EXIT_HI_Z => if (clock_divider_rollover = '1') then bus_control_state <= STATE_READY; else bus_control_state <= STATE_WRITE_EXIT_HI_Z; end if; when others => bus_control_state <= STATE_READY; end case; end if; end if; end process Bus_Control_Sync_Process; Bus_Control_Output_Process : process (bus_control_state) begin case bus_control_state is when STATE_READY => select_cache_source <= "00"; select_register_bus_data_out <= '0'; select_register_bus_data_in <= '1'; select_register_bus_address <= '1'; select_register_sram_address <= '0'; select_register_request_type <= '1'; select_sram_data_out_enable <= '0'; SRAM_OE_N <= '0'; SRAM_WE_N <= '1'; control_state_ready <= '1'; when STATE_REQUEST_LATCHED => select_cache_source <= "00"; select_register_bus_data_out <= '0'; select_register_bus_data_in <= '0'; select_register_bus_address <= '0'; select_register_sram_address <= '1'; select_register_request_type <= '0'; select_sram_data_out_enable <= '0'; SRAM_OE_N <= '0'; SRAM_WE_N <= '1'; control_state_ready <= '0'; when STATE_READ_CHECK_VALID => select_cache_source <= "00"; select_register_bus_data_out <= '0'; select_register_bus_data_in <= '0'; select_register_bus_address <= '0'; select_register_sram_address <= '0'; select_register_request_type <= '0'; select_sram_data_out_enable <= '0'; SRAM_OE_N <= '0'; SRAM_WE_N <= '1'; control_state_ready <= '0'; when STATE_READ_WAIT_FOR_READY => select_cache_source <= "00"; select_register_bus_data_out <= '0'; select_register_bus_data_in <= '0'; select_register_bus_address <= '0'; select_register_sram_address <= '0'; select_register_request_type <= '0'; select_sram_data_out_enable <= '0'; SRAM_OE_N <= '0'; SRAM_WE_N <= '1'; control_state_ready <= '0'; when STATE_READ_EXECUTE => select_cache_source <= "00"; select_register_bus_data_out <= '0'; select_register_bus_data_in <= '0'; select_register_bus_address <= '0'; select_register_sram_address <= '0'; select_register_request_type <= '0'; select_sram_data_out_enable <= '0'; SRAM_OE_N <= '0'; SRAM_WE_N <= '1'; control_state_ready <= '0'; when STATE_READ_UPDATE_CACHE => select_cache_source <= "10"; select_register_bus_data_out <= '0'; select_register_bus_data_in <= '0'; select_register_bus_address <= '0'; select_register_sram_address <= '0'; select_register_request_type <= '0'; select_sram_data_out_enable <= '0'; SRAM_OE_N <= '0'; SRAM_WE_N <= '1'; control_state_ready <= '0'; when STATE_READ_CACHE_HIT => select_cache_source <= "00"; select_register_bus_data_out <= '1'; select_register_bus_data_in <= '0'; select_register_bus_address <= '0'; select_register_sram_address <= '0'; select_register_request_type <= '0'; select_sram_data_out_enable <= '0'; SRAM_OE_N <= '0'; SRAM_WE_N <= '1'; control_state_ready <= '0'; when STATE_WRITE_WAIT_FOR_READY => select_cache_source <= "00"; select_register_bus_data_out <= '0'; select_register_bus_data_in <= '0'; select_register_bus_address <= '0'; select_register_sram_address <= '0'; select_register_request_type <= '0'; select_sram_data_out_enable <= '0'; SRAM_OE_N <= '0'; SRAM_WE_N <= '1'; control_state_ready <= '0'; when STATE_WRITE_ENTER_HI_Z => select_cache_source <= "00"; select_register_bus_data_out <= '0'; select_register_bus_data_in <= '0'; select_register_bus_address <= '0'; select_register_sram_address <= '0'; select_register_request_type <= '0'; select_sram_data_out_enable <= '0'; SRAM_OE_N <= '1'; SRAM_WE_N <= '1'; control_state_ready <= '0'; when STATE_WRITE_EXECUTE => select_cache_source <= "00"; select_register_bus_data_out <= '0'; select_register_bus_data_in <= '0'; select_register_bus_address <= '0'; select_register_sram_address <= '0'; select_register_request_type <= '0'; select_sram_data_out_enable <= '0'; SRAM_OE_N <= '1'; SRAM_WE_N <= '0'; control_state_ready <= '0'; when STATE_WRITE_EXIT_HI_Z => select_cache_source <= "00"; select_register_bus_data_out <= '0'; select_register_bus_data_in <= '0'; select_register_bus_address <= '0'; select_register_sram_address <= '0'; select_register_request_type <= '0'; select_sram_data_out_enable <= '0'; SRAM_OE_N <= '1'; SRAM_WE_N <= '1'; control_state_ready <= '0'; when STATE_WRITE_UPDATE_CACHE => select_cache_source <= "01"; select_register_bus_data_out <= '0'; select_register_bus_data_in <= '0'; select_register_bus_address <= '0'; select_register_sram_address <= '0'; select_register_request_type <= '0'; select_sram_data_out_enable <= '0'; SRAM_OE_N <= '0'; SRAM_WE_N <= '1'; control_state_ready <= '0'; when others => select_cache_source <= "00"; select_register_bus_data_out <= '0'; select_register_bus_data_in <= '0'; select_register_bus_address <= '0'; select_register_sram_address <= '0'; select_register_request_type <= '0'; select_sram_data_out_enable <= '0'; SRAM_OE_N <= '0'; SRAM_WE_N <= '1'; control_state_ready <= '0'; end case; end process Bus_Control_Output_Process; --------------------------------------------------------------------------------------------------------------------- end architecture Behavioral;