--############################################################################# -- -- LOGIC CORE: Command module -- MODULE NAME: command() -- COMPANY: Altera Corporation -- www.altera.com -- -- REVISION HISTORY: -- -- Revision 1.1 06/06/2000 Description: Initial Release. -- -- FUNCTIONAL DESCRIPTION: -- -- This module is the command processor module for the SDR SDRAM controller. -- -- -- Copyright (C) 1991-2000 Altera Corporation --############################################################################# library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; entity command is generic ( ASIZE : integer := 23; DSIZE : integer := 32; ROWSIZE : integer := 12; COLSIZE : integer := 9; BANKSIZE : integer := 2; ROWSTART : integer := 9; -- Starting position of the row address within ADDR COLSTART : integer := 0; -- Starting position of the column address within ADDR BANKSTART : integer := 20 -- Starting position of the bank address within ADDR ); port ( CLK : in std_logic; -- System Clock RESET_N : in std_logic; -- System Reset SADDR : in std_logic_vector(ASIZE-1 downto 0); -- Address NOP : in std_logic; -- Decoded NOP command READA : in std_logic; -- Decoded READA command WRITEA : in std_logic; -- Decoded WRITEA command REFRESH : in std_logic; -- Decoded REFRESH command PRECHARGE : in std_logic; -- Decoded PRECHARGE command LOAD_MODE : in std_logic; -- Decoded LOAD_MODE command SC_CL : in std_logic_vector(1 downto 0); -- Programmed CAS latency SC_RC : in std_logic_vector(1 downto 0); -- Programmed RC delay SC_RRD : in std_logic_vector(3 downto 0); -- Programmed RRD delay SC_PM : in std_logic; -- programmed Page Mode SC_BL : in std_logic_vector(3 downto 0); -- Programmed burst length REF_REQ : in std_logic; -- Hidden refresh request REF_ACK : out std_logic; -- Refresh request acknowledge CM_ACK : out std_logic; -- Command acknowledge OE : out std_logic; -- OE signal for data path module SA : out std_logic_vector(11 downto 0); -- SDRAM address BA : out std_logic_vector(1 downto 0); -- SDRAM bank address CS_N : out std_logic_vector(1 downto 0); -- SDRAM chip selects CKE : out std_logic; -- SDRAM clock enable RAS_N : out std_logic; -- SDRAM RAS CAS_N : out std_logic; -- SDRAM CAS WE_N : out std_logic -- SDRAM WE_N ); end command; architecture RTL of command is -- signal declarations signal do_nop : std_logic; signal do_reada : std_logic; signal do_writea : std_logic; signal do_writea1 : std_logic; signal do_refresh : std_logic; signal do_precharge : std_logic; signal do_load_mode : std_logic; signal command_done : std_logic; signal command_delay : std_logic_vector(7 downto 0); signal rw_shift : std_logic_vector(3 downto 0); signal do_act : std_logic; signal rw_flag : std_logic; signal do_rw : std_logic; signal oe_shift : std_logic_vector(7 downto 0); signal oe1 : std_logic; signal oe2 : std_logic; signal oe3 : std_logic; signal oe4 : std_logic; signal rp_shift : std_logic_vector(3 downto 0); signal rp_done : std_logic; signal rowaddr : std_logic_vector(ROWSIZE-1 downto 0); signal coladdr : std_logic_vector(COLSIZE-1 downto 0); signal bankaddr : std_logic_vector(BANKSIZE-1 downto 0); signal REF_REQ_int : std_logic; begin rowaddr <= SADDR(ROWSTART + ROWSIZE - 1 downto ROWSTART); -- assignment of the row address bits from SADDR coladdr <= SADDR(COLSTART + COLSIZE - 1 downto COLSTART); -- assignment of the column address bits bankaddr <= SADDR(BANKSTART + BANKSIZE - 1 downto BANKSTART); -- assignment of the bank address bits -- This process monitors the individual command lines and issues a command -- to the next stage if there currently another command already running. -- process(CLK, RESET_N) begin if (RESET_N = '0') then do_nop <= '0'; do_reada <= '0'; do_writea <= '0'; do_refresh <= '0'; do_precharge <= '0'; do_load_mode <= '0'; command_done <= '0'; command_delay <= (others => '0'); rw_flag <= '0'; rp_shift <= (others => '0'); rp_done <= '0'; do_writea1 <= '0'; elsif rising_edge(CLK) then -- Issue the appropriate command if the sdram is not currently busy if ((REF_REQ = '1' or REFRESH = '1') and command_done = '0' and do_refresh = '0' and rp_done = '0' -- Refresh and do_reada = '0' and do_writea = '0') then do_refresh <= '1'; else do_refresh <= '0'; end if; if ((READA = '1') and (command_done = '0') and (do_reada = '0') and (rp_done = '0') and (REF_REQ = '0')) then -- READA do_reada <= '1'; else do_reada <= '0'; end if; if ((WRITEA = '1') and (command_done = '0') and (do_writea = '0') and (rp_done = '0') and (REF_REQ = '0')) then -- WRITEA do_writea <= '1'; do_writea1 <= '1'; else do_writea <= '0'; do_writea1 <= '0'; end if; if ((PRECHARGE = '1') and (command_done = '0') and (do_precharge = '0')) then -- PRECHARGE do_precharge <= '1'; else do_precharge <= '0'; end if; if ((LOAD_MODE = '1') and (command_done = '0') and (do_load_mode = '0')) then -- LOADMODE do_load_mode <= '1'; else do_load_mode <= '0'; end if; -- set command_delay shift register and command_done flag -- The command delay shift register is a timer that is used to ensure that -- the SDRAM devices have had sufficient time to finish the last command. if ((do_refresh = '1') or (do_reada = '1') or (do_writea = '1') or (do_precharge = '1') or (do_load_mode = '1')) then command_delay <= "11111111"; command_done <= '1'; rw_flag <= do_reada; else command_done <= command_delay(0); -- the command_delay shift operation command_delay(6 downto 0) <= command_delay(7 downto 1); command_delay(7) <= '0'; end if; -- start additional timer that is used for the refresh, writea, reada commands if (command_delay(0) = '0' and command_done = '1') then rp_shift <= "1111"; rp_done <= '1'; else rp_done <= rp_shift(0); rp_shift(2 downto 0) <= rp_shift(3 downto 1); rp_shift(3) <= '0'; end if; end if; end process; -- logic that generates the OE signal for the data path module -- For normal burst write he duration of OE is dependent on the configured burst length. -- For page mode accesses(SC_PM=1) the OE signal is turned on at the start of the write command -- and is left on until a PRECHARGE(page burst terminate) is detected. -- process(CLK, RESET_N) begin if (RESET_N = '0') then oe_shift <= (others => '0'); oe1 <= '0'; oe2 <= '0'; oe3 <= '0'; oe4 <= '0'; OE <= '0'; elsif rising_edge(CLK) then if (SC_PM = '0') then if (do_writea1 = '1') then if (SC_BL = "0001") then -- Set the shift register to the appropriate oe_shift <= (others => '0'); -- value based on burst length. elsif (SC_BL = "0010") then oe_shift <= "00000001"; elsif (SC_BL = "0100") then oe_shift <= "00000111"; elsif (SC_BL = "1000") then oe_shift <= "01111111"; end if; oe1 <= '1'; else oe_shift(6 downto 0) <= oe_shift(7 downto 1); -- Do the shift operation oe_shift(7) <= '0'; oe1 <= oe_shift(0); oe2 <= oe1; oe3 <= oe2; oe4 <= oe3; if (SC_RC = "10") then OE <= oe3; else OE <= oe4; end if; end if; else if (do_writea1 = '1') then -- OE generation for page mode accesses oe4 <= '1'; elsif (do_precharge = '1' or do_reada = '1' or do_refresh = '1') then oe4 <= '0'; end if; OE <= oe4; end if; end if; end process; -- This process tracks the time between the activate command and the -- subsequent WRITEA or READA command, RC. The shift register is set using -- the configuration register setting SC_RC. The shift register is loaded with -- a single '1' with the position within the register dependent on SC_RC. -- When the '1' is shifted out of the register it sets so_rw which triggers -- a writea or reada command -- process(CLK, RESET_N) begin if (RESET_N = '0') then rw_shift <= (others => '0'); do_rw <= '0'; elsif rising_edge(CLK) then if ((do_reada = '1') or (do_writea = '1')) then if (SC_RC = "01") then -- Set the shift register do_rw <= '1'; elsif (SC_RC = "10") then rw_shift <= "0001"; elsif (SC_RC = "11") then rw_shift <= "0010"; end if; else rw_shift(2 downto 0) <= rw_shift(3 downto 1); -- perform the shift operation rw_shift(3) <= '0'; do_rw <= rw_shift(0); end if; end if; end process; -- This process generates the command acknowledge, CM_ACK, signal. -- It also generates the acknowledge signal, REF_ACK, that acknowledges -- a refresh request that was generated by the internal refresh timer circuit. process(CLK, RESET_N) begin if (RESET_N = '0') then CM_ACK <= '0'; REF_ACK <= '0'; elsif rising_edge(CLK) then if (do_refresh = '1' and REF_REQ = '1') then -- Internal refresh timer refresh request REF_ACK <= '1'; elsif ((do_refresh = '1') or (do_reada = '1') or (do_writea = '1') or (do_precharge = '1') -- externa commands or (do_load_mode = '1')) then CM_ACK <= '1'; else REF_ACK <= '0'; CM_ACK <= '0'; end if; end if; end process; -- This process generates the address, cs, cke, and command signals(ras,cas,wen) -- process(CLK, RESET_N) begin if (RESET_N = '0') then SA <= (others => '0'); BA <= (others => '0'); CS_N <= "01"; RAS_N <= '1'; CAS_N <= '1'; WE_N <= '1'; CKE <= '0'; elsif rising_edge(CLK) then CKE <= '1'; -- Generate SA if (do_writea = '1' or do_reada = '1') then -- ACTIVATE command is being issued, so present the row address SA(ROWSIZE-1 downto 0) <= rowaddr; else SA(COLSIZE-1 downto 0) <= coladdr; -- else alway present column address end if; if ((do_rw='1') or (do_precharge='1')) then SA(10) <= not(SC_PM); -- set SA(10) for autoprecharge read/write or for a precharge all command end if; -- don't set it if the controller is in page mode. if (do_precharge='1' or do_load_mode='1') then BA <= "00"; -- Set BA=0 if performing a precharge or load_mode command else BA <= bankaddr(1 downto 0); -- else set it with the appropriate address bits end if; if (do_refresh='1' or do_precharge='1' or do_load_mode='1') then CS_N <= "00"; -- Select both chip selects if performing else -- refresh, precharge(all) or load_mode CS_N(0) <= SADDR(ASIZE-1); -- else set the chip selects based off of the CS_N(1) <= not(SADDR(ASIZE-1)); -- msb address bit end if; --Generate the appropriate logic levels on RAS_N, CAS_N, and WE_N --depending on the issued command. -- if (do_refresh='1') then -- Refresh: S=00, RAS=0, CAS=0, WE=1 RAS_N <= '0'; CAS_N <= '0'; WE_N <= '1'; elsif ((do_precharge='1') and ((oe4 = '1') or (rw_flag = '1'))) then -- burst terminate if write is active RAS_N <= '1'; CAS_N <= '1'; WE_N <= '0'; elsif ((do_precharge='1')) then -- precharge RAS_N <= '0'; CAS_N <= '1'; WE_N <= '0'; elsif (do_load_mode='1') then -- Mode Write: S=00, RAS=0, CAS=0, WE=0 RAS_N <= '0'; CAS_N <= '0'; WE_N <= '0'; elsif (do_reada = '1' or do_writea = '1') then -- Activate: S=01 or 10, RAS=0, CAS=1, WE=1 RAS_N <= '0'; CAS_N <= '1'; WE_N <= '1'; elsif (do_rw = '1') then -- Read/Write: S=01 or 10, RAS=1, CAS=0, WE=0 or 1 RAS_N <= '1'; CAS_N <= '0'; WE_N <= rw_flag; else RAS_N <= '1'; CAS_N <= '1'; WE_N <= '1'; end if; end if; end process; end RTL;