-- EE552 PORTA-AMP Project -- file: dram_int.vhd -- Author: Kevin Mlazgar -- -- Max Speed: 49.01 MHz (138 LCs) Normal -- Max Speed: 58.13 MHz (139 LCs) Optimized for speed --Chip/ Input Output Bidir Memory Memory LCs --POF Device Pins Pins Pins Bits % Utilized LCs % Utilized -- --dram_int EPF10K20RC240-4 42 34 16 0 0 % 138 11 % -- Revision 1.0 1999/12/03 -- Modified to be a DRAM controller. -- Designed around the Micron 8MB EDO SIMM: MT16D232M-60 X -- see dm53.pdf at www.micron.com for specifics. -- -- This SIMM has 16 dram devices mounted on it. They are already in groups of -- four as defined by RAS0#, RAS1#, RAS2#, RAS3#. To make a 16 bit datapath -- the RAS signals will be used as bank selects and all the CASN lines will -- be physically connected together. -- There are ten address lines (A0-A9) which are used in conjunction with the -- four RAS (Row Address Strobe) and a common CASN (Column Address Strobe) -- to time multiplex the 20 address lines (in addition to the RAS bank selects) -- required to address 8MB of dram with a 16 bit word size. -- ONLY NORMAL accesses to memory will be utilized. NO EDO or FPM. -- -- NOTE: The RAS and CAS and WE signals ARE ASYNCHRONOUS and not tolerant of -- glitches. The only way found to remove glitches was to have asynchronous -- outputs generated in processes that are sensitive only to the rising edge -- of the clock. Once in the process a decision is made based on the value -- of the state when the rising edge occurred. This has the effect of delaying -- the asynchronous outputs by one clock period. It was feared that hold time -- violations would occur by checking a state that could be about to change -- after a rising edge. However, during timing simulations this never occurred. -- -- -- -- TESTING: -- Annotations: -- NOTE: ALL data from external sources is inserted manually -- 1. verify that cannot read when have not yet written to memory -- 2. verify that mmc_ram_ready goes low upon master issuing a read/write -- VOID 3. verify that wait for sdram client interface to be ready before -- issuing a read/write -- VOID 4. verify that on a write to sdram client interface: -- dpath_r_w = '0' -- dpath_csn = '0' -- dpath_primary_datapath is being driven with the write data -- 5. verify that will wait till write is over -- 6. verify that address incremented for subsequent writes/reads -- 7. verify address starts at zero for first read -- VOID 8. verify only drive read data to master when it is valid: -- during wait_for_end_of_master_read since mmc_ram_ready signal -- returns to high in that state after a read... -- 9. verify address returns to zero on a read when reach end of song... -- 10. verify once start writing the track that keep in write loop till -- mmc_ram_read_write goes high; then go to wait_for_command -- 11. verify once start reading the track that keep in read loop till -- mmc_ram_read_write goes low; then go to wait_for_command -- 12. verify periodic CBR refreshes at least every 15.625us. -- 13. verify that latch a command that occurs on rising edge of -- clock when exiting wait_for_command state to do a refresh. library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use work.sdram_package.all; package dram_int_pkg is component dram_int is generic ( datawidth : positive := 16; addresswidth : positive := 22; bank_addrwidth : positive := 2; -- don't change this... -- dram_addrwidth = (addresswidth - bank_addrwidth)/2 dram_addrwidth : positive := 10; -- delay embedded in commands to DRAM -- increase this to have more delays in accesses... access_delay : positive := 1 ); port ( -- clock dram_int_clk : in std_logic; -- reset dram_int_reset : in std_logic; -- **************************** -- ** DRAM Interface Signals ** -- RAS lines to DRAM -- acts as bank select rasn : out std_logic_vector(3 downto 0); -- CASN line to common CASN line on DRAM DIMM casn : out std_logic; -- write enable line to DRAM -- '1' indicates a READ to DRAM -- '0' indicates a WRITE from DRAM wen : out std_logic; -- data path to DRAM dram_datapath : inout std_logic_vector(datawidth-1 downto 0); -- address path to DRAM (time multiplexed address lines) dram_addresspath : out std_logic_vector(dram_addrwidth-1 downto 0); -- ****************************** -- ** Porta-AMP Direct Signals ** -- This signal should be checked immediately after a command is -- issued to the DRAM interface to ensure that the command -- has not been prempted by the refresh. -- If it has been the command must be resent... mmc_cmd_ack : out std_logic; -- signal to the master indicating that the interface is ready for -- a command. -- The master should NEVER address the sdram interface if this -- signal is low. -- If a read or write had been issued or a refresh is in progress this -- signal will go low during the access. When it goes high again there -- is valid data available on the mc_datapath_out for a read, -- or the write is done. mmc_ram_ready : out std_logic; -- client active-high Chip Select signal is asserted when cpu is addressing -- the memory management controller. -- The data will be loaded into the write_data register of -- the primary data path if a write is also being issued... mmc_ram_enable : in std_logic; -- client read/writen line -- '1' indicates a READ -- '0' indicates a WRITE -- A 1 clock period latency is required to switch between these. -- i.e. wait a period before asserting mmc_ram_enable! -- While doing a read or a write hold this signal at its value and -- assert mmc_ram_enable to do another read or write. Once this signal -- is changed a further read or write will occur at the start of memory. mmc_ram_read_write : in std_logic; -- address path from memory mgmt cont mmc_dram_address_in : in std_logic_vector(addresswidth-1 downto 0); -- data path to memory mgmt cont mmc_datapath_in : in std_logic_vector(datawidth-1 downto 0); mmc_datapath_out : buffer std_logic_vector(datawidth-1 downto 0) ); end component dram_int; end package dram_int_pkg; library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use work.sdram_package.all; entity dram_int is generic ( datawidth : positive := 16; -- addresswidth = framewidth + offsetwidth addresswidth : positive := 22; bank_addrwidth : positive := 2; -- don't change this... -- dram_addrwidth = (addresswidth - bank_addrwidth)/2 dram_addrwidth : positive := 10; -- delay embedded in commands to DRAM -- increase this to have more delays in accesses... access_delay : positive := 1 ); port ( -- clock dram_int_clk : in std_logic; -- reset dram_int_reset : in std_logic; -- **************************** -- ** DRAM Interface Signals ** -- RAS lines to DRAM -- acts as bank select rasn : out std_logic_vector(3 downto 0); -- CASN line to common CASN line on DRAM DIMM casn : out std_logic; -- write enable line to DRAM -- '1' indicates a READ to DRAM -- '0' indicates a WRITE from DRAM wen : out std_logic; -- data path to DRAM dram_datapath : inout std_logic_vector(datawidth-1 downto 0); -- address path to DRAM (time multiplexed address lines) dram_addresspath : out std_logic_vector(dram_addrwidth-1 downto 0); -- ****************************** -- ** Porta-AMP Direct Signals ** -- This signal should be checked immediately after a command is -- issued to the DRAM interface to ensure that the command -- has not been prempted by the refresh. -- If it has been the command must be resent... mmc_cmd_ack : out std_logic; -- signal to the master indicating that the interface is ready for -- a command. -- The master should NEVER address the sdram interface if this -- signal is low. -- If a read or write had been issued or a refresh is in progress this -- signal will go low during the access. When it goes high again there -- is valid data available on the mc_datapath_out for a read, -- or the write is done. mmc_ram_ready : out std_logic; -- client active-high Chip Select signal is asserted when cpu is addressing -- the memory management controller. -- The data will be loaded into the write_data register of -- the primary data path if a write is also being issued... mmc_ram_enable : in std_logic; -- client read/writen line -- '1' indicates a READ -- '0' indicates a WRITE -- A 1 clock period latency is required to switch between these. -- i.e. wait a period before asserting mmc_ram_enable! -- While doing a read or a write hold this signal at its value and -- assert mmc_ram_enable to do another read or write. Once this signal -- is changed a further read or write will occur at the start of memory. mmc_ram_read_write : in std_logic; -- address path from memory mgmt cont mmc_dram_address_in : in std_logic_vector(addresswidth-1 downto 0); -- data path to memory mgmt cont mmc_datapath_in : in std_logic_vector(datawidth-1 downto 0); mmc_datapath_out : buffer std_logic_vector(datawidth-1 downto 0) ); end entity dram_int; architecture mixed of dram_int is -- state enumeration type state_type is (wait_for_command, refresh_delay,cbr_refresh_casn, cbr_refresh_rasn, cbr_refresh_deassert_casn, cbr_refresh_deassert_rasn, cbr_refresh_casn2, cbr_refresh_rasn2, cbr_refresh_deassert_casn2, cbr_refresh_deassert_rasn2, write_delay, write_rasn, write_drive_col_addr, write_casn, write_casn_deassert, read_delay, read_rasn, read_drive_col_addr, read_casn, read_wait_for_data, read_in_data, read_casn_deassert, write_rasn_deassert, read_rasn_deassert ); signal state : state_type; -- the current state constant bank_addr_top : positive := addresswidth - 1; -- 21 constant bank_addr_bottom : positive := addresswidth - bank_addrwidth; -- 20 -- always all '0's signal no_track_detect_addr : std_logic_vector(addresswidth-1 downto 0); -- present address reading/writing from/to in DRAM signal mmc_dram_address : std_logic_vector(addresswidth-1 downto 0); alias bank_addr : std_logic_vector(1 downto 0) is mmc_dram_address(bank_addr_top downto bank_addr_bottom); alias row_addr : std_logic_vector(dram_addrwidth-1 downto 0) is mmc_dram_address(bank_addr_bottom-1 downto dram_addrwidth); alias col_addr : std_logic_vector(dram_addrwidth-1 downto 0) is mmc_dram_address(dram_addrwidth-1 downto 0); signal bank_addr_decode : std_logic_vector(3 downto 0); signal write_data_oe : std_logic; signal write_data_load : std_logic; signal read_data_load : std_logic; signal address_load : std_logic; -- refresh timer counter, designed for 25 MHz clock... -- must at most have a period of 15.625us as per DRAM spec. signal timer_count, timer_end : std_logic_vector(7 downto 0); signal clear_refresh_period_done_latch : std_logic; signal refresh_period_done : std_logic; signal refresh_request : std_logic; -- refresh signal fdelay_count, fdelay_end : std_logic_vector(access_delay-1 downto 0); signal fdelay_done : std_logic; -- write signal wdelay_count, wdelay_end : std_logic_vector(access_delay-1 downto 0); signal wdelay_done : std_logic; -- read signal rdelay_count, rdelay_end : std_logic_vector(access_delay-1 downto 0); signal rdelay_done : std_logic; signal inv_dram_int_reset : std_logic; begin -- mixed inv_dram_int_reset <= not dram_int_reset; -- end of count values for delays in operation of -- refreshs, writes, and reads fdelay_end <= (others => '1'); wdelay_end <= (others => '1'); rdelay_end <= (others => '1'); -- write address from client write_address : generic_register generic map ( generic_register_width => addresswidth ) port map( -- Clear generic_register_clr => inv_dram_int_reset, -- Clock enable generic_register_clk_enable => address_load, -- Clock generic_register_clk => dram_int_clk, -- D inputs generic_register_d => mmc_dram_address_in, -- Q outputs generic_register_q => mmc_dram_address ); -- write data from client to dram write_data : generic_register_with_oe port map( -- Output enable generic_register_oe => write_data_oe, -- Clear generic_register_clr => inv_dram_int_reset, -- Clock enable generic_register_clk_enable => write_data_load, -- Clock generic_register_clk => dram_int_clk, -- D inputs generic_register_d => mmc_datapath_in, -- Q outputs generic_register_q => dram_datapath ); -- read data from dram to client read_data : generic_register port map( -- Clear generic_register_clr => inv_dram_int_reset, -- Clock enable generic_register_clk_enable => read_data_load, -- Clock generic_register_clk => dram_int_clk, -- D inputs generic_register_d => dram_datapath, -- Q outputs generic_register_q => mmc_datapath_out ); -- A refresh timer that counts clock cycles. We design for operation at -- 25MHz therefore a certain minimum delay is guaranteed, however at lower -- frequencies of operation this results in increased latency... -- It calculates a <15us delay and then requests a refresh... timer_end <= (others => '1'); -- 256 * 40ns = 10.24us (8bit counter @ 25 MHz) refresh_timer : process(dram_int_clk, dram_int_reset) begin if dram_int_reset = '0' then timer_count <= (others => '0'); refresh_period_done <= '0'; elsif rising_edge(dram_int_clk) then timer_count <= timer_count + 1; if timer_count = timer_end then refresh_period_done <= '1'; else refresh_period_done <= '0'; end if; end if; end process refresh_timer; refresh_period_done_latch : ff_behave port map ( -- clock ff_behave_clk => dram_int_clk, -- reset ff_behave_reset => inv_dram_int_reset, -- clear the latched value (somewhat redundant w/ the reset) ff_behave_clr => clear_refresh_period_done_latch, -- Active high line which must last at least one rising edge -- of the clock cycle... ff_behave_set => refresh_period_done, -- latched output ff_behave_q => refresh_request ); with state select write_data_load <= '1' when wait_for_command, '0' when others; -- assign in a process to reduce glitches in output... -- only drive read data to dram when it is needed output_write_data_oe : process(dram_int_clk) begin if rising_edge(dram_int_clk) then if inv_dram_int_reset = '1' then write_data_oe <= '0'; elsif state = write_drive_col_addr or state = write_casn then write_data_oe <= '1'; elsif state = write_casn_deassert then write_data_oe <= '1'; else write_data_oe <= '0'; end if; end if; end process output_write_data_oe; -- only load data when DRAM is driving valid data... with state select read_data_load <= '1' when read_in_data, '0' when others; with state select mmc_ram_ready <= '1' when wait_for_command, '0' when others; with state select address_load <= '1' when wait_for_command, '0' when others; with state select clear_refresh_period_done_latch <= '1' when cbr_refresh_deassert_rasn2, '0' when others; with state select mmc_cmd_ack <= '1' when write_delay, '1' when read_delay, '0' when others; -- assign in a process to reduce glitches in output... decode_bank_addr : process(dram_int_clk) begin if rising_edge(dram_int_clk) then if inv_dram_int_reset = '1' then bank_addr_decode <= "1110"; elsif bank_addr = "00" then bank_addr_decode <= "1110"; elsif bank_addr = "01" then bank_addr_decode <= "1101"; elsif bank_addr = "10" then bank_addr_decode <= "1011"; else bank_addr_decode <= "0111"; end if; end if; end process decode_bank_addr; -- assign in a process to reduce glitches in output... output_rasn : process(dram_int_clk) begin if rising_edge(dram_int_clk) then if inv_dram_int_reset = '1' then rasn <= (others => '1'); elsif state = cbr_refresh_rasn or state = cbr_refresh_deassert_casn then rasn <= (others => '0'); elsif state = cbr_refresh_rasn2 or state = cbr_refresh_deassert_casn2 then rasn <= (others => '0'); elsif state = write_rasn or state = write_drive_col_addr then rasn <= bank_addr_decode; elsif state = write_casn or state = write_casn_deassert then rasn <= bank_addr_decode; elsif state = read_rasn or state = read_drive_col_addr then rasn <= bank_addr_decode; elsif state = read_casn or state = read_wait_for_data then rasn <= bank_addr_decode; elsif state = read_in_data or state = read_casn_deassert then rasn <= bank_addr_decode; else rasn <= (others => '1'); end if; end if; end process output_rasn; -- assign in a process to reduce glitches in output... output_casn : process(dram_int_clk) begin if rising_edge(dram_int_clk) then if inv_dram_int_reset = '1' then casn <= '1'; elsif state = cbr_refresh_casn or state = cbr_refresh_rasn then casn <= '0'; elsif state = cbr_refresh_casn2 or state = cbr_refresh_rasn2 then casn <= '0'; elsif state = write_casn or state = read_casn then casn <= '0'; elsif state = read_wait_for_data or state = read_in_data then casn <= '0'; else casn <= '1'; end if; end if; end process output_casn; -- assign in a process to reduce glitches in output... output_wen : process(dram_int_clk) begin if rising_edge(dram_int_clk) then if inv_dram_int_reset = '1' then wen <= '1'; elsif state = write_drive_col_addr or state = write_casn then wen <= '0'; elsif state = write_casn_deassert then wen <= '0'; else wen <= '1'; end if; end if; end process output_wen; -- assign in a process to reduce glitches in output... output_address : process(dram_int_clk) begin if rising_edge(dram_int_clk) then if inv_dram_int_reset = '1' then dram_addresspath <= row_addr; elsif state = write_drive_col_addr or state = write_casn then dram_addresspath <= col_addr; elsif state = read_drive_col_addr or state = read_casn then dram_addresspath <= col_addr; else dram_addresspath <= row_addr; end if; end if; end process output_address; -- delay count to slow down accesses (avoid noise on line) refresh_delay_counter : process(dram_int_clk, dram_int_reset) begin if dram_int_reset = '0' then fdelay_count <= (others => '0'); fdelay_done <= '0'; elsif rising_edge(dram_int_clk) then if state = refresh_delay or state = cbr_refresh_deassert_rasn then fdelay_count <= fdelay_count + 1; if fdelay_count = fdelay_end then fdelay_done <= '1'; else fdelay_done <= '0'; end if; elsif state = cbr_refresh_casn or state = cbr_refresh_rasn then fdelay_count <= fdelay_count + 1; if fdelay_count = fdelay_end then fdelay_done <= '1'; else fdelay_done <= '0'; end if; elsif state = cbr_refresh_casn2 or state = cbr_refresh_rasn2 then fdelay_count <= fdelay_count + 1; if fdelay_count = fdelay_end then fdelay_done <= '1'; else fdelay_done <= '0'; end if; elsif state = cbr_refresh_deassert_casn or state = cbr_refresh_deassert_casn2 or state = cbr_refresh_deassert_rasn2 then fdelay_count <= fdelay_count + 1; if fdelay_count = fdelay_end then fdelay_done <= '1'; else fdelay_done <= '0'; end if; else fdelay_count <= (others => '0'); end if; end if; end process refresh_delay_counter; -- delay count to slow down accesses write_delay_counter : process(dram_int_clk, dram_int_reset) begin if dram_int_reset = '0' then wdelay_count <= (others => '0'); wdelay_done <= '0'; elsif rising_edge(dram_int_clk) then if state = write_delay or state = write_drive_col_addr then wdelay_count <= wdelay_count + 1; if wdelay_count = wdelay_end then wdelay_done <= '1'; else wdelay_done <= '0'; end if; elsif state = write_casn or state = write_casn_deassert then wdelay_count <= wdelay_count + 1; if wdelay_count = wdelay_end then wdelay_done <= '1'; else wdelay_done <= '0'; end if; elsif state = write_rasn or state = write_rasn_deassert then wdelay_count <= wdelay_count + 1; if wdelay_count = wdelay_end then wdelay_done <= '1'; else wdelay_done <= '0'; end if; else wdelay_count <= (others => '0'); end if; end if; end process write_delay_counter; -- delay count to slow down accesses read_delay_counter : process(dram_int_clk, dram_int_reset) begin if dram_int_reset = '0' then rdelay_count <= (others => '0'); rdelay_done <= '0'; elsif rising_edge(dram_int_clk) then if state = read_delay or state = read_drive_col_addr then rdelay_count <= rdelay_count + 1; if rdelay_count = rdelay_end then rdelay_done <= '1'; else rdelay_done <= '0'; end if; elsif state = read_wait_for_data or state = read_casn_deassert then rdelay_count <= rdelay_count + 1; if rdelay_count = rdelay_end then rdelay_done <= '1'; else rdelay_done <= '0'; end if; elsif state = read_rasn or state = read_casn or state = read_rasn_deassert then rdelay_count <= rdelay_count + 1; if rdelay_count = rdelay_end then rdelay_done <= '1'; else rdelay_done <= '0'; end if; else rdelay_count <= (others => '0'); end if; end if; end process read_delay_counter; -- purpose: state machine controlling logic for dram_int_cont -- type: memoryless -- inputs: -- outputs: state state_logic : process (dram_int_clk, inv_dram_int_reset) begin -- process state_logic if inv_dram_int_reset = '1' then state <= wait_for_command; elsif rising_edge(dram_int_clk) then case state is -- wait for command, dram set to standby, -- addressing starts at zero here -- row mmc_dram_address_in will be driven to dram address lines in -- anticipation of a dram access... -- mmc_ram_ready signal IS asserted here. when wait_for_command => if refresh_request = '1' then state <= refresh_delay; elsif mmc_ram_enable = '1' and mmc_ram_read_write = '0' then state <= write_delay; elsif mmc_ram_enable = '1' and mmc_ram_read_write = '1' then state <= read_delay; else state <= wait_for_command; end if; -- -- Refresh Logic -- -- to ensure that do not break timing specifications when refresh_delay => if fdelay_done = '1' then state <= cbr_refresh_casn; else state <= refresh_delay; end if; -- assert CASN low and wen high to initiate a cbr refresh -- INVARIANT: RAS and CASN and wen all high when reach here when cbr_refresh_casn => if fdelay_done = '1' then state <= cbr_refresh_rasn; else state <= cbr_refresh_casn; end if; -- assert RAS vector low while wen still high to complete cbr -- refresh request to all dram devices on SIMM when cbr_refresh_rasn => if fdelay_done = '1' then state <= cbr_refresh_deassert_casn; else state <= cbr_refresh_rasn; end if; -- deassert CASN while RAS still asserted low when cbr_refresh_deassert_casn => if fdelay_done = '1' then state <= cbr_refresh_deassert_rasn; else state <= cbr_refresh_deassert_casn; end if; -- complete cbr refresh by returning dram to standby state -- clear the refresh request... when cbr_refresh_deassert_rasn => if fdelay_done = '1' then state <= cbr_refresh_casn2; else state <= cbr_refresh_deassert_rasn; end if; -- assert CASN low and wen high to initiate a cbr refresh -- INVARIANT: RAS and CASN and wen all high when reach here when cbr_refresh_casn2 => if fdelay_done = '1' then state <= cbr_refresh_rasn2; else state <= cbr_refresh_casn2; end if; -- assert RAS vector low while wen still high to complete cbr -- refresh request to all dram devices on SIMM when cbr_refresh_rasn2 => if fdelay_done = '1' then state <= cbr_refresh_deassert_casn2; else state <= cbr_refresh_rasn2; end if; -- deassert CASN while RAS still asserted low when cbr_refresh_deassert_casn2 => if fdelay_done = '1' then state <= cbr_refresh_deassert_rasn2; else state <= cbr_refresh_deassert_casn2; end if; -- complete cbr refresh by returning dram to standby state -- clear the refresh request... when cbr_refresh_deassert_rasn2 => if fdelay_done = '1' then state <= wait_for_command; else state <= cbr_refresh_deassert_rasn2; end if; -- -- WRITE LOGIC -- when write_delay => if wdelay_done = '1' then state <= write_rasn; else state <= write_delay; end if; -- assert specific bit (bank select) in RASN vector low and wen low -- to initiate a write -- INVARIANT: the row address is already driven to the dram when write_rasn => if wdelay_done = '1' then state <= write_drive_col_addr; else state <= write_rasn; end if; -- drive column address on dram address lines in anticipation -- of asserting CASN low in the next state -- drive valid data for the write on the dram_datapath when write_drive_col_addr => if wdelay_done = '1' then state <= write_casn; else state <= write_drive_col_addr; end if; -- assert CASN low while RAS and wen are still low and column -- address is valid, this will write the data to DRAM -- drive valid data for the write on the dram_datapath when write_casn => if wdelay_done = '1' then state <= write_casn_deassert; else state <= write_casn; end if; -- deassert CASN when write_casn_deassert => if wdelay_done = '1' then state <= write_rasn_deassert; else state <= write_casn_deassert; end if; -- deassert RASN when write_rasn_deassert => if wdelay_done = '1' then state <= wait_for_command; else state <= write_rasn_deassert; end if; -- -- READ LOGIC -- when read_delay => if rdelay_done = '1' then state <= read_rasn; else state <= read_delay; end if; -- assert specific bit (bank select) in RASN vector low and wen high -- to initiate a read -- INVARIANT: the row address is already driven to the dram when read_rasn => if rdelay_done = '1' then state <= read_drive_col_addr; else state <= read_rasn; end if; -- drive column address on dram address lines in anticipation -- of asserting CASN low in the next state when read_drive_col_addr => if rdelay_done = '1' then state <= read_casn; else state <= read_drive_col_addr; end if; -- assert CASN low while RAS is low and wen is high and column -- address is valid, this will cause read data to be driven -- out by dram after a delay and until casn goes high... when read_casn => if rdelay_done = '1' then state <= read_wait_for_data; else state <= read_casn; end if; -- allow data to settle when read_wait_for_data => if rdelay_done = '1' then state <= read_in_data; else state <= read_wait_for_data; end if; -- LOAD the READ DATA from the dram when read_in_data => state <= read_casn_deassert; -- deassert CASN when read_casn_deassert => if rdelay_done = '1' then state <= read_rasn_deassert; else state <= read_casn_deassert; end if; -- deassert RASN when read_rasn_deassert => if rdelay_done = '1' then state <= wait_for_command; else state <= read_rasn_deassert; end if; end case; end if; end process state_logic; end mixed;