---------------------------------------------------------------------------
-- NDT Solutions Ltd. Proprietary Information
-- Company Confidential
-- Copyright 2008
--
-- Filename: SDRAMIf.vhd
-- Language: VHDL '93
-- Project:  NDTS2100 DSP FPGA
--
-- Design Description:
-- Top Level for NDTS2100 DDR2 SDRAM interface
---------------------------------------------------------------------------

library IEEE;
use IEEE.Std_Logic_1164.all;

library UNISIM;
use UNISIM.vcomponents.all;
use work.DspFpgaPkg.all;

entity SDRAMIf is
  port (ClkIn     : in    std_ulogic;
        nReset    : in    std_ulogic;
        MemClkOut : out   std_ulogic;
        -- User i/o
        uDIn      : in    std_logic_vector(127 downto 0);
        uDMask    : in    std_logic_vector(15 downto 0);
        uDOut     : out   std_logic_vector(127 downto 0);
        uAddr     : in    std_logic_vector(30 downto 5);
        uWr       : in    std_ulogic;
        uWrPop    : out   std_ulogic;
        uRd       : in    std_ulogic;
        uRdPush   : out   std_ulogic;
        uAck      : out   std_ulogic;
        -- SDRAM
        SR_Ck     : out   std_logic_vector(1 downto 0);
        nSR_Ck    : out   std_logic_vector(1 downto 0);
        SR_Cke    : out   std_logic_vector(1 downto 0);
        SR_Dq     : inout std_logic_vector(63 downto 0);
        SR_Dqs    : inout std_logic_vector(7 downto 0);
        nSR_Dqs   : inout std_logic_vector(7 downto 0);
        SR_DM     : out   std_logic_vector(7 downto 0);
        SR_A      : out   std_logic_vector(13 downto 0);
        SR_Ba     : out   std_logic_vector(2 downto 0);
        nSR_We    : out   std_ulogic;
        nSR_Ras   : out   std_ulogic;
        nSR_Cas   : out   std_ulogic;
        SR_ODT    : out   std_logic_vector(1 downto 0);
        nSR_S     : out   std_logic_vector(1 downto 0);
        SR_SCL    : out   std_ulogic;
        SR_SDA    : inout std_ulogic;
        SR_SA     : out   std_logic_vector(1 downto 0);
        RstDqsDiv : inout std_ulogic;
        RfrshReq  : out   std_ulogic;
        RfrshDone : out   std_ulogic;
        SoDimmSize: out   std_logic_vector(3 downto 0); -- x 256M
        SoDimmVal : out   std_ulogic);
end entity SDRAMIf;


architecture Str of SDRAMIf is
  component ClkRst
    generic(gClkFreq: integer := 100); -- in MHz
    port (Clk       : in  std_ulogic;
          nReset    : in  std_ulogic;
          Clk0      : out std_ulogic;
          Clk90     : out std_ulogic;
          MemClk    : out std_ulogic;
          SyncRst   : out std_ulogic;
          SyncRst90 : out std_ulogic;
          SyncRst180: out std_ulogic;
          Wait200us : out std_ulogic;
          ResetCal  : in  std_ulogic;
          DelaySel  : out std_logic_vector(4 downto 0));
  end component;

  component Ddr2IO
    generic(gClkWidth : integer := 2;
            gDataWidth: integer := 64;
            gRowAddress: integer := 14;
            gBankAddress: integer := 3;
            gChipSelect: integer := 2);
    port (nReset    : in    std_ulogic;
          Clk       : in    std_ulogic;
          nClk      : in    std_ulogic;
          Clk90     : in    std_ulogic;
          nClk90    : in    std_ulogic;
          DOutEn    : in    std_ulogic;
          DOutTri   : in    std_ulogic;
          DOutR     : in    std_logic_vector(gDataWidth-1 downto 0);
          DOutF     : in    std_logic_vector(gDataWidth-1 downto 0);
          MemClk    : in    std_ulogic;
          nMemClk   : in    std_ulogic;
          DInR      : out   std_logic_vector(gDataWidth-1 downto 0);
          DInF      : out   std_logic_vector(gDataWidth-1 downto 0);
          DQSReset  : in    std_ulogic;
          DQSOutTri : in    std_ulogic;
          DQSIn     : out   std_logic_vector((gDataWidth/8-1) downto 0);
          DmR       : in    std_logic_vector((gDataWidth/8-1) downto 0);
          DmF       : in    std_logic_vector((gDataWidth/8-1) downto 0);
          CKEOut    : in    std_ulogic;
          ODTOut    : in    std_logic_vector(gChipSelect-1 downto 0);
          nCSOut    : in    std_logic_vector(gChipSelect-1 downto 0);
          CSDisable : in    std_ulogic;
          --
          RstDqsDivOutP: in  std_ulogic;
          RstDqsDivOutN: in  std_ulogic;
          RstDqsDivIn  : out std_ulogic;
          --
          CK        : out   std_logic_vector(gClkWidth-1 downto 0);
          nCK       : out   std_logic_vector(gClkWidth-1 downto 0);
          CKE       : out   std_logic_vector(gClkWidth-1 downto 0);
          DQ        : inout std_logic_vector(gDataWidth-1 downto 0);
          DQS       : inout std_logic_vector((gDataWidth/8-1) downto 0);
          nDQS      : out   std_logic_vector((gDataWidth/8-1) downto 0);
          DM        : out   std_logic_vector((gDataWidth/8-1) downto 0);
          ODT       : out   std_logic_vector(gChipSelect-1 downto 0);
          nCS       : out   std_logic_vector(gChipSelect-1 downto 0);
          --
          RstDqsDiv : inout std_ulogic);
  end component;

  component Ddr2DataPath
    generic(gDataWidth: integer := 64);
    port (Clk         : in    std_ulogic;
          Clk90       : in    std_ulogic;
          SyncRst     : in    std_ulogic;
          SyncRst90   : in    std_ulogic;
          UserWrData  : in    std_logic_vector((gDataWidth*2)-1 downto 0);
          UserWrMask  : in    std_logic_vector((gDataWidth/8*2)-1 downto 0);
          UserWrEn    : in    std_ulogic;
          UserRdData  : out   std_logic_vector((gDataWidth*2)-1 downto 0);
          UserRdVal   : out   std_ulogic;
          UserRdAck   : out   std_ulogic;
          --
          MemClk      : in    std_ulogic;
          nMemClk     : in    std_ulogic;
          DInR        : in    std_logic_vector(gDataWidth-1 downto 0);
          DInF        : in    std_logic_vector(gDataWidth-1 downto 0);
          DQSIn       : in    std_logic_vector((gDataWidth/8-1) downto 0);
          DOutR       : out   std_logic_vector(gDataWidth-1 downto 0);
          DOutF       : out   std_logic_vector(gDataWidth-1 downto 0);
          DmR         : out   std_logic_vector((gDataWidth/8-1) downto 0);
          DmF         : out   std_logic_vector((gDataWidth/8-1) downto 0);
          WriteEn     : out   std_ulogic;
          FifoWe0     : in    std_ulogic;
          FifoWe1     : in    std_ulogic;
          RstDqsDivIn : in    std_ulogic;
          DelaySel    : in    std_logic_vector(4 downto 0);
          Test        : out   std_logic_vector(7 downto 0));
  end component;

  component Ddr2State
    generic(gDevices  : integer := 1;
            gClkFreq  : integer := 100); -- in MHz
    port(nReset       : in  std_ulogic;
         SyncRst      : in  std_ulogic;
         Clk          : in  std_ulogic;
         InitWait     : in  std_ulogic;
         RfshReq      : in  std_ulogic;
         WriteReq     : in  std_ulogic;
         ReadReq      : in  std_ulogic;
         DeviceSelect : in  std_logic_vector(SizeToBits(gDevices)-1 downto 0);
         WrPop        : out std_ulogic;
         DInEnable    : out std_ulogic;
         DOutTri      : out std_ulogic;
         nCeEn        : out std_logic_vector(gDevices-1 downto 0);
         CeDisable    : out std_ulogic;
         nRas         : out std_ulogic;
         nCas         : out std_ulogic;
         nWe          : out std_ulogic;
         RstDqsDivP   : out std_ulogic;
         RstDqsDivN   : out std_ulogic;
         FifoWe0      : out std_ulogic;
         FifoWe1      : out std_ulogic;
         Row          : out std_ulogic;
         WriteAck     : out std_ulogic;
         ReadAck      : in  std_ulogic;
         AddrLatEn    : out std_ulogic;
         ModeSetFlag  : out std_ulogic;
         ModeReg      : out std_logic_vector(15 downto 0);
         RfshDone     : out std_ulogic);
  end component;

  component SDRAMRefresh
    generic(ClocksPerCycle: integer := 100;
            RefreshCount  : integer := 1024);
	  port(Reset          : in  std_ulogic;
	       SyncRst        : in  std_ulogic;
         InitWait       : in  std_ulogic;
	       RefreshHoldOff : in  std_ulogic;
	       SDClk          : in  std_ulogic;
		     RfshDone       : in  std_ulogic;
		     RfshReq        : out std_ulogic);
  end component;

  component SPDRead
    port (Clk   : in    std_ulogic;
          Reset : in    std_ulogic;
          --
          SCL   : out   std_ulogic;
          SDA   : inout std_ulogic;
          SA    : out   std_logic_vector(1 downto 0);
          --
          Delay : in    std_ulogic;
          Size  : out   std_logic_vector(3 downto 0);
          Valid : out   std_ulogic);
  end component;

  signal Clk        : std_ulogic;
  signal nClk       : std_ulogic;
  signal Clk0       : std_ulogic;
  signal Clk01      : std_ulogic;
  signal Clk90      : std_ulogic;
  signal nClk90     : std_ulogic;
  signal MemClk     : std_ulogic;
  signal nMemClk    : std_ulogic;
  signal Reset      : std_ulogic;
  signal SyncRst    : std_ulogic;
  signal SyncRst90  : std_ulogic;
  signal SyncRst180 : std_ulogic;
  signal Wait200us  : std_ulogic;
  signal DelaySel   : std_logic_vector(4 downto 0);

  signal DInEnable  : std_ulogic;
  signal DOutTri    : std_ulogic;
  signal DOutR      : std_logic_vector(63 downto 0);
  signal DOutF      : std_logic_vector(63 downto 0);
  signal DInR       : std_logic_vector(63 downto 0);
  signal DInF       : std_logic_vector(63 downto 0);
  signal DQSReset   : std_ulogic;
  signal DQSIn      : std_logic_vector(7 downto 0);

  signal RstDqsDivIn  : std_ulogic;
  signal RstDqsDivOutP: std_ulogic;
  signal RstDqsDivOutN: std_ulogic;
  signal FifoWe0      : std_ulogic;
  signal FifoWe1      : std_ulogic;

  signal DmR        : std_logic_vector(7 downto 0);
  signal DmF        : std_logic_vector(7 downto 0);
  signal CKEOut     : std_ulogic;
  signal ODTOut     : std_logic_vector(1 downto 0);

  signal RfshReq    : std_ulogic;
  signal RfshDone   : std_ulogic;
  signal ModeSet    : std_ulogic;
  signal ModeReg    : std_logic_vector(15 downto 0);
  signal nCeEn      : std_logic_vector(1 downto 0);
  signal CeDisable  : std_ulogic;
  signal Row        : std_ulogic;
  signal AddrLatEn  : std_ulogic;
  signal Addr       : std_logic_vector(13 downto 0);
  signal WrAck      : std_ulogic;
  signal RdAck      : std_ulogic;

begin

  -- Clock DCM, Reset generation and DQS Delay Tap generation
  CkRst: ClkRst
    generic map(gClkFreq => 66) -- in MHz
    port map (Clk        => ClkIn,
              nReset     => nReset,
              Clk0       => Clk0,
              Clk90      => Clk90,
              MemClk     => MemClk,
              SyncRst    => SyncRst,
              SyncRst90  => SyncRst90,
              SyncRst180 => SyncRst180,
              Wait200us  => Wait200us,
              ResetCal   => DInEnable,
              DelaySel   => DelaySel);

  MemClkOut <= Clk0;
  Clk01 <= Clk0;  -- compensate for Simulation Delta delays
  Clk <= Clk01;
  nClk <= not Clk01;
  nClk90 <= not Clk90;
  nMemClk <= not MemClk;

  CKEOut <= not wait200us;
  ODTOut <= (others => '0');
  DQSReset <= '0';

  -- IO FFs
  Io: Ddr2IO
    generic map(gClkWidth     => 2,
                gDataWidth    => 64,
                gRowAddress   => 14,
                gBankAddress  => 3,
                gChipSelect   => 2)
    port map (nReset    => nReset,
              Clk       => Clk,
              nClk      => nClk,
              Clk90     => Clk90,
              nClk90    => nClk90,
              DOutEn    => '1',
              DOutTri   => DOutTri,
              DOutR     => DOutR,
              DOutF     => DOutF,
              MemClk    => MemClk,
              nMemClk   => nMemClk,
              DInR      => DInR,
              DInF      => DInF,
              DQSOutTri => DOutTri,
              DQSReset  => DQSReset,
              DQSIn     => DQSIn,
              DmR       => DmR,
              DmF       => DmF,
              CKEOut    => CKEOut,
              ODTOut    => ODTOut,
              nCSOut    => nCeEn,
              CSDisable => CeDisable,
              --
              RstDqsDivOutP => RstDqsDivOutP,
              RstDqsDivOutN => RstDqsDivOutN,
              RstDqsDivIn   => RstDqsDivIn,
              --
              CK        => SR_Ck,
              nCK       => nSR_Ck,
              CKE       => SR_Cke,
              DQ        => SR_Dq,
              DQS       => SR_Dqs,
              nDQS      => nSR_Dqs,
              DM        => SR_DM,
              ODT       => SR_ODT,
              nCS       => nSR_S,
              --
              RstDqsDiv => RstDqsDiv);

  -- Data path
  DataPath: Ddr2DataPath
    generic map(gDataWidth => 64)
    port map (Clk         => Clk,
              Clk90       => Clk90,
              SyncRst     => SyncRst,
              SyncRst90   => SyncRst90,
              UserWrData  => uDIn,
              UserWrMask  => uDMask,
              UserWrEn    => uWr,
              UserRdData  => uDOut,
              UserRdVal   => uRdPush,
              UserRdAck   => RdAck,
              --
              MemClk      => MemClk,
              nMemClk     => nMemClk,
              DInR        => DInR,
              DInF        => DInF,
              DQSIn       => DQSIn,
              DOutR       => DOutR,
              DOutF       => DOutF,
              DmR         => DmR,
              DmF         => DmF,
              WriteEn     => open,
              FifoWe0     => FifoWe0,
              FifoWe1     => FifoWe1,
              RstDqsDivIn => RstDqsDivIn,
              DelaySel    => DelaySel,
              Test        => open);

  -- Memory controller state machine
  StateM: Ddr2State
    generic map (gDevices  => 2,
                 gClkFreq  => 66*2)
    port map (nReset       => nReset,
              SyncRst      => SyncRst,
              Clk          => Clk,
              InitWait     => Wait200us,
              RfshReq      => RfshReq,
              WriteReq     => uWr,
              ReadReq      => uRd,
              DeviceSelect => uAddr(27 downto 27),
              WrPop        => uWrPop,
              DInEnable    => DInEnable,
              DOutTri      => DOutTri,
              nCeEn        => nCeEn,
              CeDisable    => CeDisable,
              nRas         => nSR_Ras,
              nCas         => nSR_Cas,
              nWe          => nSR_We,
              RstDqsDivP   => RstDqsDivOutP,
              RstDqsDivN   => RstDqsDivOutN,
              FifoWe0      => FifoWe0,
              FifoWe1      => FifoWe1,
              Row          => Row,
              WriteAck     => WrAck,
              ReadAck      => RdAck,
              AddrLatEn    => AddrLatEn,
              ModeSetFlag  => ModeSet,
              ModeReg      => ModeReg,
              RfshDone     => RfshDone);

  RfrshReq <= RfshReq;
  RfrshDone <= RfshDone;

  uAck <= WrAck or RdAck;

  -- Refresh control
  Refresh: SDRAMRefresh
    generic map (ClocksPerCycle => 1032,
                 RefreshCount   => 8192)
    port map (Reset          => '0',
              SyncRst        => SyncRst,
              InitWait       => Wait200us,
              RefreshHoldOff => '0',
              SDClk          => Clk,
  	          RfshDone       => RfshDone,
  	          RfshReq        => RfshReq);

  -- Address Mux
  Addr <= uAddr(26 downto 13) when Row = '0' else
  --           Auto-precharge
          "000" & '1' & uAddr(12 downto 5) & "00";

  -- Address Output FF
  AdFF:process(Clk)
  begin
    if Clk'event and Clk = '1' then
      if ModeSet = '1' then
        SR_A <= ModeReg(13 downto 0);
      elsif AddrLatEn = '1' then
        SR_A <= Addr;
      end if;
    end if;
  end process AdFF;

  BaFF:process(Clk, nReset) 
  begin
    if nReset = '0' then
      SR_Ba <= (others => '0');
    elsif Clk'event and Clk = '1' then
      if ModeSet = '1' then
        SR_Ba <= '0' & ModeReg(15 downto 14);
      elsif AddrLatEn = '1' then
        SR_Ba <= uAddr(30 downto 28);
      end if;
    end if;
  end process BaFF;

  Reset <= not nReset;

  RdSize: SPDRead
    port map (Clk   => ClkIn,
              Reset => Reset,
              --
              SCL   => SR_SCL,
              SDA   => SR_SDA,
              SA    => SR_SA,
              --
              Delay => SyncRst,
              Size  => SoDimmSize,
              Valid => SoDimmVal);

end architecture Str;