-------------------------------------------------------------------------------
-- io_registers.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:        io_registers.vhd
-- Version:         v1.10b
-- Description:     This file contains the IO registers for the EMC 
--                  design.
--                  
-- 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:          ALS
-- History:
--   ALS           12/13/02    First Version
--   ALS           01/30/03
-- ^^^^^^
--  Fixed RESET state of control signals
-- ~~~~~~
--  ALS            03/10/03
-- ^^^^^^
--  Inclusion of negative edge IO registers now determined by generic instead
--  of the presence of synchronous memories. C_GLOBAL_SYNC_MEM replaced with
--  C_INCLUDE_NEGEDGE_IOREGS.
-- ~~~~~~
-------------------------------------------------------------------------------
-- 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:                  "*_com" 
--      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 proc_common_v1_00_b;
use proc_common_v1_00_b.proc_common_pkg.all;
use proc_common_v1_00_b.all;

library unisim;
use unisim.all;

-------------------------------------------------------------------------------
-- Definition of Generics:
--      C_GLOBAL_DATAWIDTH_MATCH    -- datawidth matching turned on for at least
--                                      one memory bank
--      C_INCLUDE_NEGEDGE_IOREGS    -- include negative edge IO registers
--      C_IPIF_AWIDTH               -- width of processor address bus
--      C_MAX_MEM_WIDTH             -- maximum data width of memory banks
--      C_NUM_BANKS_MEM             -- number of memory banks
--
-- Definition of Ports:
--  -- internal Memory signals
--     Mem_A_int                     -- Internal Memory address inputs
--     Mem_DQ_I_int                  -- Internal Memory input data bus
--     Mem_DQ_O_int                  -- Internal Memory output data bus
--     Mem_DQ_T_int                  -- Internal Memory data output enable
--     Mem_CEN_int                   -- Internal Memory chip select
--     Mem_OEN_int                   -- Internal Memory output enable
--     Mem_WEN_int                   -- Internal Memory write enable
--     Mem_QWEN_int                  -- Internal Memory qualified write enable
--     Mem_BEN_int                   -- Internal Memory byte enables
--     Mem_RPN_int                   -- Internal Memory reset/power down
--     Mem_CE_int                    -- Internal Memory chip enable
--     Mem_ADV_LDN_int               -- Internal Memory counter advance/load (=0)
--     Mem_LBON_int                  -- Internal Memory linear/interleaved burst order (=0)
--     Mem_CKEN_int                  -- Internal Memory clock enable (=0)
--     Mem_RNW_int                   -- Internal Memory read not write
--                                   
--  -- Memory signals
--     Mem_A                         -- Memory address inputs
--     Mem_DQ_I                      -- Memory input data bus
--     Mem_DQ_O                      -- Memory output data bus
--     Mem_DQ_T                      -- Memory data output enable
--     Mem_CEN                       -- Memory chip select
--     Mem_OEN                       -- Memory output enable
--     Mem_WEN                       -- Memory write enable
--     Mem_QWEN                      -- Memory qualified write enable
--     Mem_BEN                       -- Memory byte enables
--     Mem_RPN                       -- Memory reset/power down
--     Mem_CE                        -- Memory chip enable
--     Mem_ADV_LDN                   -- Memory counter advance/load (=0)
--     Mem_LBON                      -- Memory linear/interleaved burst order (=0)
--     Mem_CKEN                      -- Memory clock enable (=0)
--     Mem_RNW                       -- Memory read not write
--                                  
--    -- Clocks and reset
--      Clk                 
--      Rst
--      Input_datareg_rst
---------------------------------------------------------------------------

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

entity io_registers is
  generic ( C_GLOBAL_DATAWIDTH_MATCH   : integer range 0 to 1;
            C_INCLUDE_NEGEDGE_IOREGS   : integer range 0 to 1;
            C_IPIF_AWIDTH              : integer;
            C_MAX_MEM_WIDTH            : integer;
            C_NUM_BANKS_MEM            : integer
            );
  port (

        -- internal Memory signals
        Mem_A_int              : in   std_logic_vector(0 to C_IPIF_AWIDTH-1);
        Mem_DQ_I_int           : out  std_logic_vector(0 to C_MAX_MEM_WIDTH-1);
        Mem_DQ_O_int           : in   std_logic_vector(0 to C_MAX_MEM_WIDTH-1);
        Mem_DQ_T_int           : in   std_logic_vector(0 to C_MAX_MEM_WIDTH-1);
        Mem_CEN_int            : in   std_logic_vector(0 to C_NUM_BANKS_MEM-1);
        Mem_OEN_int            : in   std_logic_vector(0 to C_NUM_BANKS_MEM-1);
        Mem_WEN_int            : in   std_logic;
        Mem_QWEN_int           : in   std_logic_vector(0 to C_MAX_MEM_WIDTH/8-1); --Qualified WE
        Mem_BEN_int            : in   std_logic_vector(0 to C_MAX_MEM_WIDTH/8-1);
        Mem_RPN_int            : in   std_logic;
        Mem_CE_int             : in   std_logic_vector(0 to C_NUM_BANKS_MEM-1);
        Mem_ADV_LDN_int        : in   std_logic;
        Mem_LBON_int           : in   std_logic;
        Mem_CKEN_int           : in   std_logic;
        Mem_RNW_int            : in   std_logic;

        -- Memory signals
        Mem_A                  : out   std_logic_vector(0 to C_IPIF_AWIDTH-1);
        Mem_DQ_I               : in    std_logic_vector(0 to C_MAX_MEM_WIDTH-1);
        Mem_DQ_O               : out   std_logic_vector(0 to C_MAX_MEM_WIDTH-1);
        Mem_DQ_T               : out   std_logic_vector(0 to C_MAX_MEM_WIDTH-1);
        Mem_CEN                : out   std_logic_vector(0 to C_NUM_BANKS_MEM-1);
        Mem_OEN                : out   std_logic_vector(0 to C_NUM_BANKS_MEM-1);
        Mem_WEN                : out   std_logic;
        Mem_QWEN               : out   std_logic_vector(0 to C_MAX_MEM_WIDTH/8-1); --Qualified WE
        Mem_BEN                : out   std_logic_vector(0 to C_MAX_MEM_WIDTH/8-1);
        Mem_RPN                : out   std_logic;
        Mem_CE                 : out   std_logic_vector(0 to C_NUM_BANKS_MEM-1);
        Mem_ADV_LDN            : out   std_logic;
        Mem_LBON               : out   std_logic;
        Mem_CKEN               : out   std_logic;
        Mem_RNW                : out   std_logic;

        -- Clocks and reset
        Clk                     : in  std_logic;
        Rst                     : in  std_logic;
        Input_datareg_rst       : in  std_logic
    );
end entity io_registers;

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

architecture imp of io_registers is
-----------------------------------------------------------------------------
-- Constant declarations
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
-- Signal declarations
-----------------------------------------------------------------------------
signal mem_a_reg        :  std_logic_vector(0 to C_IPIF_AWIDTH-1);
signal mem_dq_i_reg     :  std_logic_vector(0 to C_MAX_MEM_WIDTH-1);
signal mem_dq_o_reg     :  std_logic_vector(0 to C_MAX_MEM_WIDTH-1);
signal mem_dq_t_reg     :  std_logic_vector(0 to C_MAX_MEM_WIDTH-1);
signal mem_cen_reg      :  std_logic_vector(0 to C_NUM_BANKS_MEM-1);
signal mem_oen_reg      :  std_logic_vector(0 to C_NUM_BANKS_MEM-1);
signal mem_oen_reg_d1   :  std_logic_vector(0 to C_NUM_BANKS_MEM-1);
signal mem_wen_reg      :  std_logic;
signal mem_qwen_reg     :  std_logic_vector(0 to C_MAX_MEM_WIDTH/8-1);
signal mem_ben_reg      :  std_logic_vector(0 to C_MAX_MEM_WIDTH/8-1);
signal mem_rpn_reg      :  std_logic;
signal mem_ce_reg       :  std_logic_vector(0 to C_NUM_BANKS_MEM-1);
signal mem_adv_ldn_reg  :  std_logic;
signal mem_lbon_reg     :  std_logic;
signal mem_cken_reg     :  std_logic;
signal mem_rnw_reg      :  std_logic;


-----------------------------------------------------------------------------
-- Component declarations
-----------------------------------------------------------------------------

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

begin 
-------------------------------------------------------------------------------
-- OUTPUTS
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
-- Instantiate the positive clock edge output register 
-- This is always present due to combinational logic on the memory control signals
-------------------------------------------------------------------------------
    POSEDGE_OUTPUTREGS_PROCESS: process(Clk)
    begin
        if Clk'event and Clk = '1' then
--            if Rst = '1' then
--                mem_a_reg       <= (others => '0');
--                mem_dq_o_reg    <= (others => '0');
--                mem_dq_t_reg    <= (others => '1');
--                mem_cen_reg     <= (others => '1');
--                mem_oen_reg     <= (others => '1');
--                mem_oen_reg_d1     <= (others => '1');
--                mem_wen_reg     <= '1';
--                mem_qwen_reg    <= (others => '1');
--                mem_ben_reg     <= (others => '1');
--                mem_rpn_reg     <= '0';
--                mem_ce_reg      <= (others => '0');
--                mem_adv_ldn_reg <= '0';
--                mem_lbon_reg    <= '0';
--                mem_cken_reg    <= '0';
--                mem_rnw_reg     <= '0';
--            else
                mem_a_reg       <= Mem_A_int       ;
                mem_dq_o_reg    <= Mem_DQ_O_int    ;
                mem_dq_t_reg    <= Mem_DQ_T_int    ;
                mem_cen_reg     <= Mem_CEN_int     ;
                mem_oen_reg     <= Mem_OEN_int     ;
                mem_oen_reg_d1  <= mem_oen_reg     ;
                mem_wen_reg     <= Mem_WEN_int     ;
                mem_qwen_reg    <= Mem_QWEN_int    ;
                mem_ben_reg     <= Mem_BEN_int     ;
                mem_rpn_reg     <= Mem_RPN_int     ;
                mem_ce_reg      <= Mem_CE_int      ;
                mem_adv_ldn_reg <= Mem_ADV_LDN_int ;
                mem_lbon_reg    <= Mem_LBON_int    ;
                mem_cken_reg    <= Mem_CKEN_int    ;
                mem_rnw_reg     <= Mem_RNW_int     ;
--            end if;
        end if;
    end process POSEDGE_OUTPUTREGS_PROCESS;


-------------------------------------------------------------------------------
-- Instantiate the negative clock edge output register if design has been
-- configured to do so
-------------------------------------------------------------------------------
NEGEDGE_OUTPUT_REGS_GEN: if C_INCLUDE_NEGEDGE_IOREGS = 1 generate

    NEGEDGE_OUTPUTREGS_PROCESS: process(Clk)
    begin
        if Clk'event and Clk = '0' then
--            if Rst = '1' then
--                Mem_A       <= (others => '0');
--                Mem_DQ_O    <= (others => '0');
--                Mem_DQ_T    <= (others => '1');
--                Mem_CEN     <= (others => '1');
--                Mem_OEN     <= (others => '1');
--                Mem_WEN     <= '1';
--                Mem_QWEN    <= (others => '1');
--                Mem_BEN     <= (others => '1');
--                Mem_RPN     <= '0';
--                Mem_CE      <= (others => '0');
--                Mem_ADV_LDN <= '0';
--                Mem_LBON    <= '0';
--                Mem_CKEN    <= '0';
--                Mem_RNW     <= '0';
--            else
                Mem_A       <= mem_a_reg      ;
                Mem_DQ_O    <= mem_dq_o_reg   ;
                Mem_DQ_T    <= mem_dq_t_reg   ;
                Mem_CEN     <= mem_cen_reg    ;
                Mem_OEN     <= mem_oen_reg ;
                Mem_WEN     <= mem_wen_reg    ;
                Mem_QWEN    <= mem_qwen_reg   ;
                Mem_BEN     <= mem_ben_reg    ;
                Mem_RPN     <= mem_rpn_reg    ;
                Mem_CE      <= mem_ce_reg     ;
                Mem_ADV_LDN <= mem_adv_ldn_reg;
                Mem_LBON    <= mem_lbon_reg   ;
                Mem_CKEN    <= mem_cken_reg   ;
                Mem_RNW     <= mem_rnw_reg    ;
--            end if;
        end if;
    end process NEGEDGE_OUTPUTREGS_PROCESS;
end generate NEGEDGE_OUTPUT_REGS_GEN;

-------------------------------------------------------------------------------
-- Pass the values through if there are no negative io registers
-------------------------------------------------------------------------------
NO_NEGEDGE_OUTPUT_REGS_GEN: if C_INCLUDE_NEGEDGE_IOREGS = 0 generate

    Mem_A       <= mem_a_reg      ;
    Mem_DQ_O    <= mem_dq_o_reg   ;
    Mem_DQ_T    <= mem_dq_t_reg   ;
    Mem_CEN     <= mem_cen_reg    ;
    Mem_OEN     <= mem_oen_reg_d1 ;   -- delay OEN
    Mem_WEN     <= mem_wen_reg    ;
    Mem_QWEN    <= mem_qwen_reg   ;
    Mem_BEN     <= mem_ben_reg    ;
    Mem_RPN     <= mem_rpn_reg    ;
    Mem_CE      <= mem_ce_reg     ;
    Mem_ADV_LDN <= mem_adv_ldn_reg;
    Mem_LBON    <= mem_lbon_reg   ;
    Mem_CKEN    <= mem_cken_reg   ;
    Mem_RNW     <= mem_rnw_reg    ;

end generate NO_NEGEDGE_OUTPUT_REGS_GEN;

-------------------------------------------------------------------------------
-- INPUTS
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
-- Instantiate the negative clock edge input register if there are any 
-- negative IO registers in the design
-------------------------------------------------------------------------------
NEGEDGE_INPUT_REGS_GEN: if C_INCLUDE_NEGEDGE_IOREGS = 1 generate

    NEGEDGE_INPUTREGS_PROCESS: process(Clk)
    begin
        if Clk'event and Clk = '0' then
            if Input_datareg_rst = '1' then
                mem_dq_i_reg    <= (others => '0');
            else
                mem_dq_i_reg    <= Mem_DQ_I;
            end if;
        end if;
    end process NEGEDGE_INPUTREGS_PROCESS;
end generate NEGEDGE_INPUT_REGS_GEN;

-------------------------------------------------------------------------------
-- Pass the input values through if there are no negative io registers in the design
-------------------------------------------------------------------------------
NO_NEGEDGE_INPUT_REGS_GEN: if C_INCLUDE_NEGEDGE_IOREGS = 0 generate

    mem_dq_i_reg    <= Mem_DQ_I;

end generate NO_NEGEDGE_INPUT_REGS_GEN;

-------------------------------------------------------------------------------
-- Instantiate the positive clock edge register if data width matching has 
-- been implemented
-------------------------------------------------------------------------------
POSEDGE_INPUT_REGS_GEN: if C_GLOBAL_DATAWIDTH_MATCH = 1 generate

    POSEDGE_INPUTREGS_PROCESS: process(Clk)
    begin
        if Clk'event and Clk = '1' then
            if Input_datareg_rst = '1' then
                Mem_DQ_I_int    <= (others => '0');
            else
                Mem_DQ_I_int    <= mem_dq_i_reg;
            end if;
        end if;
    end process POSEDGE_INPUTREGS_PROCESS;
    
end generate POSEDGE_INPUT_REGS_GEN;

-------------------------------------------------------------------------------
-- Pass the values through if there is no data matching in the design
-------------------------------------------------------------------------------
NO_POSEDGE_INPUT_REGS_GEN: if C_GLOBAL_DATAWIDTH_MATCH = 0 generate

    Mem_DQ_I_int    <= mem_dq_i_reg;

end generate NO_POSEDGE_INPUT_REGS_GEN;

            
end imp;
