------------------------------------------------------------------------- -- Project: SDRAM controller -- This file: SDRAM command controller -- -- Copyright (C) 2007 J. Ahrensfeld -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- -- For questions and ideas, please contact the author at jens@jayfield.org -- -------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.numeric_std.ALL; use work.sdram_config.all; use work.sdram_types.all; entity sdram_cmd is Generic (BL : natural := 2); Port ( rst : in STD_LOGIC; clk : in STD_LOGIC; enable : in STD_LOGIC; u_tag_in : in user_tag_t; u_tag_out : out user_tag_t; phy_ctrl : out phy_ctrl_t; cmd : in sdr_cmd_t; cmd_we : in STD_LOGIC; cmd_ack : out STD_LOGIC; col_addr : in col_addr_t; mode_word : in mode_word_t; sdr_cmd_ctrl : out sdr_cmd_lines_t; sdr_addr : out sdr_addr_t; sdr_ba : out sdr_ba_t ); end sdram_cmd; architecture behaviour of sdram_cmd is signal st_sdr, st_sdr_next : sdr_state_t; signal cc_preset : natural range 0 to 10; signal cc_load_en : std_logic; signal cycle_finished : std_logic; signal burst_preset : natural range 0 to 3; signal burst_load_en : std_logic; signal burst_finished : std_logic; begin u_tag_out <= u_tag_in; ------------------------------------------------------------------------------------------ fsm_sdr_state: process (st_sdr, cmd, cmd_we, cycle_finished, burst_finished, mode_word, enable, col_addr) begin st_sdr_next <= st_sdr; sdr_cmd_ctrl <= COMMAND(SD_NOP); cc_load_en <= '0'; cc_preset <= TIMING(cmd); burst_load_en <= '0'; cmd_ack <= '0'; burst_preset <= BL/2-1; phy_ctrl.re <= '0'; phy_ctrl.drive_en <= '0'; phy_ctrl.we <= '0'; phy_ctrl.utag_we <= '0'; sdr_addr <= mode_word(sdr_addr_t'left downto sdr_addr_t'right); sdr_ba <= mode_word(mode_word_t'left downto mode_word_t'left-1); case st_sdr is when PWR_DOWN => sdr_cmd_ctrl <= COMMAND(SD_DESELECT); if enable = '1' then st_sdr_next <= IDLE; end if; when PRECHARGE => if cycle_finished = '1' then st_sdr_next <= IDLE; end if; when MODE => if cycle_finished = '1' then st_sdr_next <= IDLE; end if; when IDLE => if cmd_we = '1' then cmd_ack <= '1'; cc_load_en <= '1'; cc_preset <= TIMING(cmd); sdr_cmd_ctrl <= COMMAND(cmd); case cmd is when SD_PRE => st_sdr_next <= PRECHARGE; sdr_addr(BIT_PRE_ALL) <= mode_word(BIT_PRE_ALL); when SD_LMR => st_sdr_next <= MODE; when SD_ACT => st_sdr_next <= ROW_ACT; when SD_AR => st_sdr_next <= AUTO_REF; when others => null; end case; end if; when ROW_ACT => if cycle_finished = '1' then if cmd_we = '1' then cmd_ack <= '1'; burst_load_en <= '1'; cc_load_en <= '1'; cc_preset <= TIMING(cmd); sdr_cmd_ctrl <= COMMAND(cmd); case cmd is when SD_PRE => st_sdr_next <= PRECHARGE; when SD_READ => phy_ctrl.utag_we <= '1'; st_sdr_next <= READ; sdr_addr(col_addr_t'range) <= col_addr; when SD_WRITE => phy_ctrl.utag_we <= '1'; phy_ctrl.drive_en <= '1'; st_sdr_next <= WRITE; sdr_addr(col_addr_t'range) <= col_addr; when others => null; end case; end if; end if; when WRITE => phy_ctrl.drive_en <= '1'; phy_ctrl.we <= '1'; if burst_finished = '1' then if cmd_we = '1' and cmd = SD_WRITE then sdr_addr(col_addr_t'range) <= col_addr; cmd_ack <= '1'; burst_load_en <= '1'; sdr_cmd_ctrl <= COMMAND(cmd); phy_ctrl.utag_we <= '1'; else phy_ctrl.drive_en <= '0'; cc_load_en <= '1'; cc_preset <= TIMING(SD_WRITE)+1; st_sdr_next <= ROW_ACT; end if; end if; when READ => phy_ctrl.re <= '1'; if burst_finished = '1' then if cmd_we = '1' and cmd = SD_READ then sdr_addr(col_addr_t'range) <= col_addr; cmd_ack <= '1'; burst_load_en <= '1'; sdr_cmd_ctrl <= COMMAND(cmd); phy_ctrl.utag_we <= '1'; else cc_load_en <= '1'; cc_preset <= TIMING(SD_READ); st_sdr_next <= ROW_ACT; end if; end if; when WRITE_A => -- not implemented yet cmd_ack <= '1'; st_sdr_next <= IDLE; when READ_A => -- not implemented yet cmd_ack <= '1'; st_sdr_next <= IDLE; when BURST_STOP => -- not implemented yet cmd_ack <= '1'; st_sdr_next <= IDLE; when SELF_REF => -- not implemented yet cmd_ack <= '1'; st_sdr_next <= IDLE; when PRE_PWR_DOWN => -- not implemented yet cmd_ack <= '1'; st_sdr_next <= IDLE; when ACT_PWR_DOWN => -- not implemented yet cmd_ack <= '1'; st_sdr_next <= IDLE; when AUTO_REF => if cycle_finished = '1' then st_sdr_next <= IDLE; end if; when others => st_sdr_next <= IDLE; end case; end process; fsm_sdr_state_next: process (rst, clk) begin if rst = '1' then st_sdr <= PWR_DOWN; elsif rising_edge(clk) then st_sdr <= st_sdr_next; end if; end process; ------------------------------------------------------------------------------------------ cycle_counter: process (rst, clk) variable cycle_cnt : natural range 0 to 10; begin if rst = '1' then cycle_cnt := 0; cycle_finished <= '0'; elsif rising_edge(clk) then cycle_finished <= '0'; if cc_load_en = '1' then cycle_cnt := cc_preset; elsif cycle_cnt /= 0 then cycle_cnt := cycle_cnt - 1; else cycle_finished <= '1'; end if; end if; end process; ------------------------------------------------------------------------------------------ burst_counter: process (rst, clk) variable burst_cnt : natural range 0 to 3; begin if rst = '1' then burst_cnt := 0; elsif rising_edge(clk) then burst_finished <= '0'; if burst_load_en = '1' then burst_cnt := burst_preset; elsif burst_cnt /= 0 then burst_cnt := burst_cnt - 1; end if; if burst_cnt = 0 then burst_finished <= '1'; end if; end if; end process; ------------------------------------------------------------------------------------------ end behaviour;