--SINGLE_FILE_TAG
-------------------------------------------------------------------------------
-- mem_state_machine.vhd - entity/architecture pair
-------------------------------------------------------------------------------
--
--  ***************************************************************************
--  **  Copyright(C) 2003 by Xilinx, Inc. All rights reserved.               **
--  **                                                                       **
--  **  This text contains proprietary, confidential                         **
--  **  information of Xilinx, Inc. , is distributed by                      **
--  **  under license from Xilinx, Inc., and may be used,                    **
--  **  copied and/or disclosed only pursuant to the terms                   **
--  **  of a valid license agreement with Xilinx, Inc.                       **
--  **                                                                       **
--  **  Unmodified source code is guaranteed to place and route,             **
--  **  function and run at speed according to the datasheet                 **
--  **  specification. Source code is provided "as-is", with no              **
--  **  obligation on the part of Xilinx to provide support.                 **
--  **                                                                       **
--  **  Xilinx Hotline support of source code IP shall only include          **
--  **  standard level Xilinx Hotline support, and will only address         **
--  **  issues and questions related to the standard released Netlist        **
--  **  version of the core (and thus indirectly, the original core source). **
--  **                                                                       **
--  **  The Xilinx Support Hotline does not have access to source            **
--  **  code and therefore cannot answer specific questions related          **
--  **  to source HDL. The Xilinx Support Hotline will only be able          **
--  **  to confirm the problem in the Netlist version of the core.           **
--  **                                                                       **
--  **  This copyright and support notice must be retained as part           **
--  **  of this text at all times.                                           **
--  ***************************************************************************
--
-------------------------------------------------------------------------------
-- Filename:        mem_state_machine.vhd
-- Version:         v1.10b
-- Description:     State machine controller for memory reads and writes
--
-- VHDL-Standard:   VHDL'93
-------------------------------------------------------------------------------
-- Structure:   
--                  emc.vhd
--                      -- addr_counter_mux.vhd
--                      -- data_path.vhd
--                      -- io_registers.vhd
--                      -- mem_state_machine.vhd
--                      -- select_param.vhd
--                      -- wait_states.vhd
-------------------------------------------------------------------------------
-- Author:      DAB
-- History:
--  DAB             11-28-2001      
-- ^^^^^^
--      First version of memory controller.
-- ~~~~~~
--  DAB             11-29-2001      -- Updated for Separate Read and Write Acks
-- 
--  DAB             01-18-2001      -- Updated for Separate Read and Write Reqs
--
--  ALS            11-28-2002
-- ^^^^^^
--  Version 1.10a created to include bus width/mem data width matching.
-- ~~~~~~
--   ALS           03/10/03    
-- ^^^^^^
--  Version 1.10.b created to include a generic to include/exclude negedge 
--  io registers. MEM_OEN is now asserted through states DELAY_ONE and DELAY_TWO
-- ~~~~~~
-------------------------------------------------------------------------------
-- Naming Conventions:
--      active low signals:                     "*_n"
--      clock signals:                          "clk", "clk_div#", "clk_#x" 
--      reset signals:                          "rst", "rst_n" 
--      generics:                               "C_*" 
--      user defined types:                     "*_TYPE" 
--      state machine next state:               "*_ns" 
--      state machine current state:            "*_cs" 
--      combinatorial signals:                  "*_cmb" 
--      pipelined or register delay signals:    "*_d#" 
--      counter signals:                        "*cnt*"
--      clock enable signals:                   "*_ce" 
--      internal version of output port         "*_i"
--      device pins:                            "*_pin" 
--      ports:                                  - Names begin with Uppercase 
--      processes:                              "*_PROCESS" 
--      component instantiations:               "<ENTITY_>I_<#|FUNC>
-------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
--library emc_common_v1_10_a;
--use emc_common_v1_10_a.all;

-------------------------------------------------------------------------------
-- Definition of Generics:
--      C_ADDR_CNTR_WIDTH           -- width of address counter used in datawidth 
--                                     matching
--      C_INCLUDE_BURST             -- support burst transactions
--
-- Definition of Ports:
--  -- inputs
--     Valid_Memory_Access          -- current transaction is to memory
--     Valid_Read                   -- current transaction is a read
--     Valid_Write                  -- current transaction is a write
--     Valid_Reg_Write              -- current transaction is a register write
--     Valid_Reg_Read               -- current transaction is a register read
--     Prev_Access_Read             -- previous access was a read
--     Synch_Mem                    -- addressed memory bank is synchronous
--     Two_pipe_delay               -- pipe delay of addressed memory bank
--     Mem_Wait_States              -- wait states for addressed memory bank
--     Rec_Wait_States              -- recovery wait states for addressed memory bank
--     Bus2IP_RNW                   -- bus read not write
--     Bus2IP_Burst                 -- bus burst 
--     Mem_RdAck                    -- memory read acknowledge (from data path logic)
--     Addr_cnt                     -- address count (used in datawidth matching)
--     Access_cnt                   -- number of accesses to datawidth match
--                                   
--  -- outputs
--     Addr_cnt_ce                  -- address counter count enable                 
--     Addr_cnt_rst                 -- address counter reset
--     Reg_RdAck                    -- register read acknowledge
--     Reg_WrAck                    -- register write acknowledge
--     Mem_Wrcycle_Done             -- memory write cycle complete
--     Mem_WrAck                    -- memory write acknowledge
--     Mem_Rdcycle_Done             -- memory read cycle complete
--     Burst_RdAck                  -- burst read acknowledge
--     Burst_WrAck                  -- burst write acknowledge
--     Mem_OEN                      -- memory output enable
--     Mem_WEN                      -- memory write enable
--     Sync_mem_cs                  -- chip select for synchronous memories
--                                  
--    -- Clocks and reset
--      Clk                 
--      Rst
---------------------------------------------------------------------------

-----------------------------------------------------------------------------
-- Entity section
-----------------------------------------------------------------------------

entity Mem_State_Machine is
  generic(C_ADDR_CNTR_WIDTH : integer range 1 to 5;
          C_INCLUDE_BURST   : integer range 0 to 1);
  port (
    Clk                 : in  std_logic;
    Rst                 : in  std_logic;
    Valid_Memory_Access : in  std_logic;
    Valid_Read          : in  std_logic;
    Valid_Write         : in  std_logic;
    Valid_Reg_Write     : in  std_logic;
    Valid_Reg_Read      : in  std_logic;
    Bus2IP_Reg_CS       : in  std_logic;
    Prev_Access_Read    : in  std_logic;
    Synch_Mem           : in  std_logic;
    Two_pipe_delay      : in  std_logic;
    Mem_Wait_States     : in  std_logic_vector(0 to 4);
    Rec_Wait_States     : in  std_logic_vector(0 to 4);
    Bus2IP_RNW          : in  std_logic;
    Bus2IP_Burst        : in  std_logic;
    Mem_RdAck           : in  std_logic;
    Addr_cnt            : in  std_logic_vector(0 to C_ADDR_CNTR_WIDTH-1);
    Access_cnt          : in  std_logic_vector(0 to C_ADDR_CNTR_WIDTH-1);
    Addr_cnt_ce         : out std_logic;
    Addr_cnt_rst        : out std_logic;
    Reg_RdAck           : out std_logic;
    Reg_WrAck           : out std_logic;
    Mem_Wrcycle_Done    : out std_logic;
    Mem_WrAck           : out std_logic;
    Mem_Rdcycle_Done    : out std_logic;
    Burst_RdAck         : out std_logic;
    Burst_WrAck         : out std_logic;
    Mem_OEN             : out std_logic;
    Mem_WEN             : out std_logic;
    Sync_mem_cs         : out std_logic
    );
end entity Mem_State_Machine;

-------------------------------------------------------------------------------
-- Architecture section
-------------------------------------------------------------------------------

architecture IMP of Mem_State_Machine is

-------------------------------------------------------------------------------
-- Signal Declarations
-------------------------------------------------------------------------------
type MEM_SM_TYPE is (START_STATE,
                ASSERT_WE,
                NEGATE_WE,
                SET_ADDR,
                DELAY_ONE,
                DELAY_TWO,
                ASSERT_OE,
                READ_RECOVERY,
                WRITE_RECOVERY,
                WAIT_XFERACK,
                AFTER_XFERACK);
                
signal current_State         : MEM_SM_TYPE := START_STATE;
signal next_State            : MEM_SM_TYPE;
signal count_wait_TC         : std_logic;
signal count_wait_1          : std_logic;
signal count_wait_2          : std_logic;
signal count_wait_next       : integer;
signal count_wait_current    : integer;
signal counter_wait_s        : std_logic_vector(0 to 4);
signal count_recover_TC      : std_logic;
signal count_recover_2       : std_logic;
signal count_recover_next    : integer;
signal count_recover_current : integer;
signal counter_recover       : integer;
signal counter_recover_s     : std_logic_vector(0 to 4);
signal recover               : std_logic;
signal reg_rdack_next        : std_logic;
signal reg_wrack_next        : std_logic;
signal mem_wrcycle_done_next : std_logic;
signal mem_wrack_next        : std_logic;
signal mem_rdcycle_done_next : std_logic;
signal read_xfer_next        : std_logic;
signal write_xfer_next       : std_logic;
signal read_xfer             : std_logic;
signal write_xfer            : std_logic;

-------------------------------------------------------------------------------
-- Begin architecture
-------------------------------------------------------------------------------

begin

SM_COMB_PROCESS: process (current_State,Prev_Access_Read,Valid_Read,
                          Valid_Write,count_wait_current,count_recover_current,
                          count_wait_TC,count_recover_TC,count_wait_2,recover,
                          Valid_Reg_Write,Mem_Wait_States,Rec_Wait_States,
                          Synch_Mem,Bus2IP_RNW,Valid_Reg_Read, Addr_cnt,
                          Access_cnt, Bus2IP_Burst, Mem_RdAck, read_xfer,
                          write_xfer
                          ) is
begin
  -- Default outputs
  next_State            <= current_State;
  count_wait_next       <= count_wait_current;
  count_recover_next    <= count_recover_current;
  Mem_OEN               <= '1';
  Mem_WEN               <= '1';
  reg_rdack_next        <= '0';
  reg_wrack_next        <= '0';
  mem_wrcycle_done_next <= '0';
  mem_wrack_next        <= '0';
  mem_rdcycle_done_next <= '0';
  Addr_cnt_ce           <= '0';
  Addr_cnt_rst          <= '0';
  Sync_mem_cs           <= '0';
  Burst_RdAck           <= '0';
  Burst_WrAck           <= '0';
  
  -- Next States
  case current_State is
    ----------------------- Start State -----------------------
    when START_STATE        =>
      Addr_cnt_rst <= '1';
      count_wait_next    <= Conv_integer(Mem_Wait_States);
      count_recover_next <= Conv_integer(Rec_Wait_States);
                  
      if (Valid_Write ='1' and Prev_Access_Read ='1' and recover ='1') then
        next_State <= READ_RECOVERY;
      elsif (Valid_Write ='1' and Prev_Access_Read ='0' and recover ='1') or
            (Valid_Write ='1' and recover ='0') then
        next_State <= ASSERT_WE;
        if Synch_Mem = '1' then
            Addr_cnt_rst <= '0';
        end if;
      end if;

      if Valid_Read='1' and Prev_Access_Read='0' and recover='1' then
        next_State <= WRITE_RECOVERY;
      elsif (Valid_Read='1' and Prev_Access_Read='1' and recover='1') or
            (Valid_Read='1' and recover='0') then
        next_State <= ASSERT_OE;
        if Synch_Mem = '1' then
            Addr_cnt_rst <= '0';
            Burst_RdAck <= '1';
        end if;
      end if;
      
      if Valid_Reg_Write='1' then
        next_State <= AFTER_XFERACK;
        reg_wrack_next <= '1';
      end if;

      if Valid_Reg_Read='1' then
        next_State <= AFTER_XFERACK;
        reg_rdack_next <= '1';
      end if;

    ----------------------- ASSERT_WE -----------------------    
    when ASSERT_WE =>
      Mem_WEN    <= '0';
      Sync_mem_cs<= '1';

      if Synch_Mem = '1' then
        -- synchronous memory access
        if Addr_cnt = Access_cnt then
            -- data width matching is complete
            Addr_cnt_rst <= '1';
            if Bus2IP_Burst = '1' then
                -- keep going
                Burst_WrAck <= '1';
            else
                -- wait for PIPELINE delay before ending cycle
                next_state <= DELAY_ONE;
            end if;
        else
            Addr_cnt_ce <= '1';
        end if;
      else
        -- asynchronous memory access
        count_wait_next <= count_wait_current-1;
        
        if count_wait_TC = '1' then
            next_State <= NEGATE_WE;
            if Addr_cnt = Access_cnt then
                -- data width matching is complete
                mem_wrack_next <= '1';
            end if;
        end if;
      end if;

    ----------------------- NEGATE_WE -----------------------    
    when NEGATE_WE =>
        if Addr_cnt = Access_cnt then
            Addr_cnt_rst <= '1';
            -- check to see if bursting
            if Bus2IP_Burst = '1' then
                next_state <= SET_ADDR;
            else
                next_state <= START_STATE;
            end if;
        else
            next_state <= SET_ADDR;
            Addr_cnt_ce <= '1';             
        end if;

    ----------------------- SET_ADDR -----------------------    
    when SET_ADDR =>
            next_state <= ASSERT_WE;
            count_wait_next <= Conv_integer(Mem_Wait_States);

    ----------------------- ASSERT_OE -----------------------      
    when ASSERT_OE =>
      Mem_OEN  <= '0';
      Sync_mem_cs<= '1';
      read_xfer_next <= '1';
      
      if Synch_Mem = '1' then
        -- synchronous memory access
        if Addr_cnt = Access_cnt then
            -- data width matching is complete
            Addr_cnt_rst <= '1';
            if Bus2IP_Burst = '0' then
                --finished bursting or never burst
                -- wait for PIPELINE delay before ending cycle
                next_state <= DELAY_ONE;
                if Two_pipe_delay='0' and Bus2IP_RNW='1' then
                    mem_rdcycle_done_next <= '1';
                end if;  
            end if;
        else
            Addr_cnt_ce <= '1';     
        end if;
      else
        -- asynchronous memory access
        if count_wait_TC = '1' then
            if Addr_cnt = Access_cnt then
                -- data width matching is complete
                    next_State <= WAIT_XFERACK;
            else
                -- data width matching is not complete
              count_wait_next    <= Conv_integer(Mem_Wait_States);
              Addr_cnt_ce <= '1';
          end if;
        else
            count_wait_next <= count_wait_current-1;      
        end if;

        if count_wait_2 = '1' then
            mem_rdcycle_done_next <= '1';
        end if;
      end if;
    ----------------------- READ_RECOVERY -----------------------      
    when READ_RECOVERY =>
      count_recover_next <= count_recover_current-1;
      if count_recover_TC='1' then
        next_State <= ASSERT_WE;
      end if;

    ----------------------- WRITE_RECOVERY -----------------------      
    when WRITE_RECOVERY =>
      count_recover_next <= count_recover_current-1;
      if count_recover_TC='1' then
        next_State <= ASSERT_OE;
      end if;
      
    ----------------------- DELAY_ONE -----------------------          
      when DELAY_ONE =>
        Sync_mem_cs<= '1';

        if Bus2IP_RNW = '1' then
            Mem_OEN  <= '0';
        end if;    
        
        if Valid_Memory_Access = '1' then
            -- bus transaction has not completed
            if Two_pipe_delay = '0' then  
                -- synchronous memory only has single pipe stage
                if Bus2IP_RNW = '0' then
                    mem_wrack_next <= '1';
                    next_state <= AFTER_XFERACK;
                elsif Bus2IP_RNW = '1' then
                    if Mem_RdAck = '1' then
                        next_state <= START_STATE;
                    else
                        next_state <= WAIT_XFERACK;
                    end if;
                end if;
            else
                if Bus2IP_RNW ='1' then
                    mem_rdcycle_done_next <= '1';
                end if;
                next_State <= DELAY_TWO;
            end if;
        else
            -- bus has all the data it needs, go back to START
            next_state <= START_STATE;
        end if;

    ----------------------- DELAY_TWO -----------------------          
      when DELAY_TWO =>
            Sync_mem_cs<= '1';
            if Bus2IP_RNW = '1' then 
                Mem_OEN  <= '0';
                if Mem_RdAck = '1' then
                    next_state <= START_STATE;
                else
                    next_State <= WAIT_XFERACK;
                end if;
            elsif Bus2IP_RNW = '0' then
                mem_wrack_next <= '1';
                next_State <= AFTER_XFERACK;
            end if;
    ----------------------- WAIT_XFERACK -----------------------          
    when WAIT_XFERACK =>
        Addr_cnt_rst <= '1';
        -- wait in this state for the memory read to complete
        if Mem_RdAck = '1' then
            -- data has been captured and next address is available
            -- check if burst (this will only be set if asynch mem)
            if Bus2IP_Burst = '1' then
                -- keep getting data
                next_State <= ASSERT_OE;
                count_wait_next <= conv_integer(mem_wait_states);
            else   
                -- done with transaction
                next_State <= START_STATE;
            end if;
        end if;
    ----------------------- AFTER_XFERACK -----------------------          
    when AFTER_XFERACK =>
        next_State <= START_STATE;                  
      
  end case;      
end process SM_COMB_PROCESS;

SM_SEQ_PROCESS: process (Clk) is
begin
  if Clk'event and Clk='1' then
    if Rst='1' or (valid_Memory_Access = '0' and Bus2IP_Reg_CS = '0') then
      current_State         <= START_STATE;
      count_wait_current    <= 0;
      count_recover_current <= 0;      
      Reg_RdAck             <= '0';
      Reg_WrAck             <= '0';
      Mem_Wrcycle_Done      <= '0';
      Mem_WrAck             <= '0';
      Mem_Rdcycle_Done      <= '0';
    else
      current_State         <= next_State;
      count_wait_current    <= count_wait_next;
      count_recover_current <= count_recover_next;
      Reg_RdAck             <= reg_rdack_next;
      Reg_WrAck             <= reg_wrack_next;
      Mem_Wrcycle_Done      <= mem_wrcycle_done_next;
      Mem_WrAck             <= mem_wrack_next;
      Mem_Rdcycle_Done      <= mem_rdcycle_done_next;
    end if;
  end if;
end process SM_SEQ_PROCESS;


counter_wait_s    <= Conv_std_logic_vector(count_wait_current,5);
counter_recover_s <= Conv_std_logic_vector(count_recover_current,5);
count_wait_1     <= '1' when counter_wait_s    = "00001" else '0'; --count = 1
count_wait_2     <= '1' when counter_wait_s    = "00010" else '0'; --count = 2
count_recover_2  <= '1' when counter_recover_s = "00010" else '0'; --count = 2
count_wait_TC    <= '1' when counter_wait_s    = "00001" else '0'; --count = 1
count_recover_TC <= '1' when counter_recover_s = "00001" else '0'; --count = 1
recover          <= '0' when Rec_Wait_States   = "00000" else '1'; --count = 0

end architecture IMP;
