---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 21:49:24 05/26/2008 -- Design Name: -- Module Name: top - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; library work; use work.usefuls.ALL; entity SDRAM is generic ( address_width : integer := 24; data_width : integer := 16; sdram_dqm_width : integer := 2; sdram_bank_addr_width : integer := 2; sdram_addr_width : integer := 12; sdram_data_width : integer := 16; clk_period : integer := 25; -- [ns] 40MHz sdram_refresh_cycle : integer := 15625; -- [ns] 64 ms / 4096 sdram_tRCD : integer := 18; -- [ns] sdram_tRFC : integer := 60; -- [ns] sdram_tRP : integer := 18; -- [ns] sdram_tWR : integer := 31; -- [ns] sdram_tMRD_clock : integer := 2; sdram_cas_latency : integer := 3); port ( clk : in std_logic; -- Control side reset : in std_logic; cs : in std_logic; dir : in std_logic; -- W => '1', R=> '0' done : out std_logic; -- complete write / data valid address : in std_logic_vector( address_width-1 downto 0); data_in : in std_logic_vector( data_width-1 downto 0); data_out : out std_logic_vector( data_width-1 downto 0); -- SDRAM side sdram_clk : out std_logic; sdram_cke : out std_logic; sdram_cs_n : out std_logic; sdram_we_n : out std_logic; sdram_cas_n : out std_logic; sdram_ras_n : out std_logic; sdram_dqm : out std_logic_vector( sdram_dqm_width-1 downto 0); sdram_bank_addr : out std_logic_vector( sdram_bank_addr_width-1 downto 0); sdram_addr : out std_logic_vector( sdram_addr_width-1 downto 0); sdram_data : inout std_logic_vector( sdram_data_width-1 downto 0)); end SDRAM; architecture Behavioral of SDRAM is constant sdram_burst_length : integer := data_width / sdram_data_width; constant sdram_burst_length_pow2 : integer := log2_ceil(sdram_burst_length); constant sdram_mode_register : std_logic_vector(sdram_addr_width-1 downto 0) := conv_std_logic_vector(0, sdram_addr_width - 10) & "000" & conv_std_logic_vector(sdram_cas_latency, 3) & "0" & conv_std_logic_vector(sdram_burst_length_pow2, 3); component OverflowTimer is generic ( threshold : integer := 0); port ( clk : in std_logic; reset : in std_logic; overflow : out std_logic); end component; constant refresh_overflow : integer := sdram_refresh_cycle / clk_period; signal reset_refresh_count : std_logic := '0'; signal require_refresh : std_logic := '0'; type state_type is (POR, IDLE, READING, WRITING, REFRESHING); signal current_state : state_type := POR; type command_type is ( C_INHIBIT, C_NOP, C_ACTIVE, C_READ, C_WRITE, C_BURST_TERMINATE, C_PRECHARGE, C_REFRESH, C_LOAD_MODE_REGISTER); signal current_command : command_type := C_INHIBIT; constant sequence_bits : integer := 4; signal sequence_count : std_logic_vector(sequence_bits-1 downto 0) := (others => '0'); constant clk_period_delta : integer := clk_period - 1; constant sdram_tRCD_clock : integer := (sdram_tRCD + clk_period_delta) / clk_period; constant sdram_tRFC_clock : integer := (sdram_tRFC + clk_period_delta) / clk_period; constant sdram_tRP_clock : integer := (sdram_tRP + clk_period_delta) / clk_period; constant sdram_last_write_to_active_clock : integer := (sdram_tRP + sdram_tWR + clk_period_delta) / clk_period; signal cs_buf : std_logic; signal cs_requested : std_logic; signal address_buf : std_logic_vector(address_width-1 downto 0); signal done_buf : std_logic; signal data_buf : std_logic_vector(data_width-1 downto 0); signal sdram_bank_addr_buf : std_logic_vector(sdram_bank_addr_width-1 downto 0); signal sdram_addr_buf : std_logic_vector(sdram_addr_width-1 downto 0); signal sdram_data_buf : std_logic_vector(sdram_data_width-1 downto 0); function transit_next_state( require_refresh : in std_logic; cs_buf : in std_logic; cs : in std_logic; cs_requested : in std_logic; dir : in std_logic) return state_type is begin if require_refresh = '1' then return REFRESHING; elsif ((cs_buf = '0') and (cs = '1')) or cs_requested = '1' then if dir = '1' then return WRITING; else return READING; end if; else return IDLE; end if; end transit_next_state; begin RefreshTimer : OverflowTimer generic map( threshold => refresh_overflow) port map( clk => clk, reset => reset_refresh_count, overflow => require_refresh); sdram_clk <= not clk; sdram_cke <= '0' when reset = '1' else '1'; process(clk, reset) begin if reset = '1' then cs_buf <= '0'; elsif clk'event and clk = '1' then cs_buf <= cs; end if; end process; process(clk, reset) begin if reset = '1' then cs_requested <= '0'; elsif clk'event and clk = '1' then if (current_state = READING or current_state = WRITING) then cs_requested <= '0'; elsif (cs_buf = '0') and (cs = '1') then cs_requested <= '1'; else cs_requested <= cs_requested; end if; end if; end process; process(clk, reset) begin if reset = '1' then current_state <= POR; current_command <= C_INHIBIT; sequence_count <= (others => '0'); elsif clk'event and clk = '1' then case current_state is when POR => if sequence_count = conv_std_logic_vector( 1 + sdram_tRP_clock + (sdram_tRFC_clock * 2) + sdram_tMRD_clock, sequence_bits) then current_state <= transit_next_state(require_refresh, cs_buf, cs, cs_requested, dir); sequence_count <= (others => '0'); current_command <= C_NOP; else current_state <= POR; sequence_count <= sequence_count + 1; if sequence_count = conv_std_logic_vector( 1, sequence_bits) then current_command <= C_PRECHARGE; elsif sequence_count = conv_std_logic_vector( 1 + sdram_tRP_clock, sequence_bits) then current_command <= C_REFRESH; elsif sequence_count = conv_std_logic_vector( 1 + sdram_tRP_clock + sdram_tRFC_clock, sequence_bits) then current_command <= C_REFRESH; elsif sequence_count = conv_std_logic_vector( 1 + sdram_tRP_clock + (sdram_tRFC_clock * 2), sequence_bits) then current_command <= C_LOAD_MODE_REGISTER; else current_command <= C_NOP; end if; end if; when IDLE => current_state <= transit_next_state(require_refresh, cs_buf, cs, cs_requested, dir); current_command <= C_NOP; sequence_count <= (others => '0'); when READING => if sequence_count = conv_std_logic_vector( sdram_tRCD_clock + sdram_cas_latency + (sdram_burst_length - 1), sequence_bits) then current_state <= transit_next_state(require_refresh, cs_buf, cs, cs_requested, dir); sequence_count <= (others => '0'); current_command <= C_NOP; else current_state <= READING; sequence_count <= sequence_count + 1; if sequence_count = conv_std_logic_vector( 0, sequence_bits) then current_command <= C_ACTIVE; elsif sequence_count = conv_std_logic_vector( sdram_tRCD_clock, sequence_bits) then current_command <= C_READ; else current_command <= C_NOP; end if; end if; when WRITING => if sequence_count = conv_std_logic_vector( sdram_tRCD_clock + (sdram_burst_length - 1) + sdram_last_write_to_active_clock, sequence_bits) then current_state <= transit_next_state(require_refresh, cs_buf, cs, cs_requested, dir); sequence_count <= (others => '0'); current_command <= C_NOP; else current_state <= WRITING; sequence_count <= sequence_count + 1; if sequence_count = conv_std_logic_vector( 0, sequence_bits) then current_command <= C_ACTIVE; elsif sequence_count = conv_std_logic_vector( sdram_tRCD_clock, sequence_bits) then current_command <= C_WRITE; else current_command <= C_NOP; end if; end if; when REFRESHING => if sequence_count = conv_std_logic_vector( sdram_tRP_clock + sdram_tRFC_clock, sequence_bits) then current_state <= transit_next_state(require_refresh, cs_buf, cs, cs_requested, dir); sequence_count <= (others => '0'); current_command <= C_NOP; else current_state <= REFRESHING; sequence_count <= sequence_count + 1; if sequence_count = conv_std_logic_vector( 0, sequence_bits) then current_command <= C_PRECHARGE; elsif sequence_count = conv_std_logic_vector( sdram_tRP_clock, sequence_bits) then current_command <= C_REFRESH; else current_command <= C_NOP; end if; end if; when others => null; end case; end if; end process; process(clk,reset) begin if reset = '1' then reset_refresh_count <= '1'; elsif clk'event and clk = '1' then if current_state = POR or (current_state = REFRESHING and sequence_count = conv_std_logic_vector(0, sequence_bits)) then reset_refresh_count <= '1'; else reset_refresh_count <= '0'; end if; end if; end process; process(clk,reset,cs) begin if reset = '1' or cs = '0' then done_buf <= '0'; elsif clk'event and clk = '1' then if ((current_state = READING) and (sequence_count = conv_std_logic_vector( sdram_tRCD_clock + sdram_cas_latency + (sdram_burst_length - 1), sequence_bits))) or ((current_state = WRITING) and (sequence_count = conv_std_logic_vector( sdram_tRCD_clock + (sdram_burst_length - 1), sequence_bits))) then done_buf <= '1'; else done_buf <= done_buf; end if; end if; end process; done <= done_buf when reset = '0' and cs = '1' else 'Z'; process(clk) begin if clk'event and clk = '1' then if (current_state /= READING and current_state /= WRITING) and cs_buf = '0' and cs = '1' and dir = '1' then data_buf <= data_in; elsif current_state = READING then for i in 0 to (sdram_burst_length - 1) loop if sequence_count = conv_std_logic_vector( sdram_tRCD_clock + sdram_cas_latency + i, sequence_bits) then data_buf((((i + 1) * sdram_data_width) - 1) downto (i * sdram_data_width)) <= sdram_data; else data_buf((((i + 1) * sdram_data_width) - 1) downto (i * sdram_data_width)) <= data_buf((((i + 1) * sdram_data_width) - 1) downto (i * sdram_data_width)); end if; end loop; else data_buf <= data_buf; end if; end if; end process; data_out <= data_buf when reset = '0' and cs = '1' else (others => 'Z'); process(clk) begin if clk'event and clk = '1' then if current_state = WRITING then for i in 0 to (sdram_burst_length - 1) loop if sequence_count = conv_std_logic_vector( sdram_tRCD_clock + i, sequence_bits) then sdram_data_buf <= data_buf((((i + 1) * sdram_data_width) - 1) downto (i * sdram_data_width)); end if; end loop; else sdram_data_buf <= sdram_data_buf; end if; end if; end process; sdram_data <= sdram_data_buf when current_state = WRITING else (others => 'Z'); process(clk) begin if clk'event and clk = '1' then if (current_state /= READING and current_state /= WRITING) and cs_buf = '0' and cs = '1' then address_buf <= address; else address_buf <= address_buf; end if; end if; end process; process(clk) begin if clk'event and clk = '1' then case current_state is when POR => if sequence_count = conv_std_logic_vector( 0, sequence_bits) then sdram_addr_buf <= sdram_addr_buf(sdram_addr_width - 1 downto 11) & '1' & sdram_addr_buf(9 downto 0); elsif sequence_count = conv_std_logic_vector( sdram_tRP_clock + sdram_tRFC_clock, sequence_bits) then sdram_addr_buf <= sdram_mode_register; else sdram_addr_buf <= sdram_addr_buf; end if; when REFRESHING => sdram_addr_buf <= sdram_addr_buf(sdram_addr_width - 1 downto 11) & '1' -- All bank refreshing & sdram_addr_buf(9 downto 0); when READING | WRITING => if sequence_count = conv_std_logic_vector( 0, sequence_bits) then sdram_addr_buf <= address_buf( address_width - sdram_bank_addr_width - 1 downto address_width - sdram_bank_addr_width - sdram_addr_width); elsif sequence_count = conv_std_logic_vector( sdram_tRCD_clock, sequence_bits) then sdram_addr_buf <= address_buf(sdram_addr_width - 2 downto 10) & '1' -- Auto Precharge & address_buf(9 downto 0); else sdram_addr_buf <= sdram_addr_buf; end if; when others => null; end case; end if; end process; sdram_addr <= sdram_addr_buf; process(clk) begin if clk'event and clk = '1' then case current_state is when READING | WRITING => if sequence_count = conv_std_logic_vector( 0, sequence_bits) then sdram_bank_addr_buf <= address_buf(address_width - 1 downto address_width - sdram_bank_addr_width); else sdram_bank_addr_buf <= sdram_bank_addr_buf; end if; when others => null; end case; end if; end process; sdram_bank_addr <= sdram_bank_addr_buf; sdram_cs_n <= '1' when current_command = C_INHIBIT else '0'; sdram_ras_n <= '1' when (current_command = C_NOP) or (current_command = C_READ) or (current_command = C_WRITE) or (current_command = C_BURST_TERMINATE) else '0'; sdram_cas_n <= '1' when (current_command = C_NOP) or (current_command = C_ACTIVE) or (current_command = C_BURST_TERMINATE) or (current_command = C_PRECHARGE) else '0'; sdram_we_n <= '1' when (current_command = C_NOP) or (current_command = C_ACTIVE) or (current_command = C_READ) or (current_command = C_REFRESH) else '0'; sdram_dqm <= (others => '0'); end Behavioral;