---------------------------------------------------------------------------
-- NDT Solutions Ltd. Proprietary Information
-- Company Confidential
-- Copyright 2007
--
-- Filename: Ddr2IO.vhd
-- Language: VHDL '93
-- Project:  NDTS2100 DSP FPGA
--
-- Design Description:
-- DDR2 SDRAM IO for Spartan 3 FPGA
---------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
library UNISIM;
use UNISIM.Vcomponents.all;

entity Ddr2IO is
  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 entity Ddr2IO;

architecture Str of Ddr2IO is

  signal DOutFF   : std_logic_vector(gDataWidth-1 downto 0);
  signal DTri     : std_logic_vector(gDataWidth-1 downto 0);
  signal DQSOutFF : std_logic_vector((gDataWidth/8-1) downto 0);
  signal nDQSOutFF: std_logic_vector((gDataWidth/8-1) downto 0);
  signal DQSTri0  : std_logic_vector((gDataWidth/8-1) downto 0);
  signal DQSTri1  : std_logic_vector((gDataWidth/8-1) downto 0);
  signal DQSTriD  : std_logic_vector((gDataWidth/8-1) downto 0);
  signal RstDqsDivOutFF: std_ulogic;

  signal CKEInt   : std_ulogic;
  signal Reset    : std_ulogic;

  attribute iob          : string;
  attribute syn_useioff  : boolean;
  attribute syn_keep     : boolean;
  attribute syn_noprune  : boolean;

  attribute iob of CKE0_REG        : label is "true";
  attribute iob of CKE1_REG        : label is "true";
  attribute iob of RstIob_REG      : label is "true";
  
  attribute syn_useioff of CKE0_REG: label is true;
  attribute syn_useioff of CKE1_REG: label is true;
  attribute syn_useioff of RstIob_REG: label is true;
  attribute syn_keep of DQSTriD    : signal is true;
  
  attribute syn_noprune of RstIobInbuf  : label is true;
  attribute syn_noprune of RstIobOutbuf : label is true;
  
  


begin
  Reset <= not nReset;

  -- Clocks
  CKGen: for i in 0 to gClkWidth-1 generate
    CK_REG : FDDRRSE 
      port map (Q => CK(i),
                C0 => nClk90,
                C1 => Clk90,
                CE => '1',
                D0 => '1',
                D1 => '0',
                R => '0',
                S => '0');
   
    CK_REGB : FDDRRSE 
      port map (Q => nCK(i),
                C0 => nClk90,
                C1 => Clk90,
                CE => '1',
                D0 => '0',
                D1 => '1',
                R => '0',
                S => '0');
  end generate;

  -- Data
  DQGen: for i in 0 to gDataWidth-1 generate
    attribute iob : string;

    attribute iob of DT_REG : label is "true";
  begin

    DO_REG : FDDRRSE
      port map (Q  => DOutFF(i),
                C0 => nClk,
                C1 => Clk,
                CE => DOutEn,
                D0 => DOutF(i),
                D1 => DOutR(i),
                R  => '0',
                S  => '0');
  
    DT_REG : FD
      port map (D => DOutTri,
                C => Clk,
                Q => DTri(i));

    DQ(i) <= DOutFF(i) when DTri(i) = '0' else 'Z';

--    DIn(i) <= DQ(i);
    DI_REG : IFDDRRSE
      port map (Q0 => DInF(i),
                Q1 => DInR(i),
                C0 => nMemClk,
                C1 => MemClk,
                CE => '1',
                D => DQ(i),
                R => '0',
                S => '0');
  end generate;

  -- Data Qualifiers
  DQSGen: for i in 0 to (gDataWidth/8-1) generate
    attribute iob : string;
    attribute iob of DQST_REG : label is "true";
  begin

    DQS_REG : FDDRRSE
      port map (Q  => DQSOutFF(i),
                C0 => nClk90,
                C1 => Clk90,
                CE => '1',
                D0 => '1',
                D1 => '0',
                R  => DQSTriD(i),
                S  => '0');

    nDQS_REG : FDDRRSE
      port map (Q  => nDQSOutFF(i),
                C0 => nClk90,
                C1 => Clk90,
                CE => '1',
                D0 => '0',
                D1 => '1',
                R  => '0',
                S  => DQSTriD(i));

    DQST_REG : FD
      port map (D => DQSOutTri,
                Q => DQSTri0(i),
                C => nClk90);

    nDQST_REG : FD
      port map (D => DQSOutTri,
                Q => DQSTri1(i),
                C => nClk90);
  
    DQSTDel_REG : FD
      port map (D => DQSOutTri,
                Q => DQSTriD(i),
                C => nClk90);

    DQS(i) <= DQSOutFF(i) when DQSTri1(i) = '0' else 'Z';
--    nDQS(i) <= nDQSOutFF(i) when DQSTri0(i) = '0' else 'Z';
    nDQS(i) <= 'Z';

    DQSInbuf : IBUF
      port map(I => DQS(i),
               O => DQSIn(i));


    DDR_DM0_OUT : FDDRRSE
      port map (Q  => DM(i),
                C0 => nClk,
                C1 => Clk,
                CE => '1',
                D0 => DmF(i),
                D1 => DmR(i),
                R  => '0',
                S  => '0');
  end generate;

  RstIobInbuf : IBUF
    port map(I => RstDqsDiv,
             O => RstDqsDivIn);

--  RstIob_REG : FD
--    port map (D => RstDqsDivOut,
--              Q => RstDqsDivOutFF,
--              C => nClk);
  RstIob_REG : FDDRRSE
   port map (Q  => RstDqsDivOutFF,
             C0 => nClk90,
             C1 => Clk90,
             CE => DOutEn,
             D0 => RstDqsDivOutP,
             D1 => RstDqsDivOutN,
             R  => '0',
             S  => '0');
         

  RstIobOutbuf : OBUF
    port map (I => RstDqsDivOutFF,
              O => RstDqsDiv);

  -- Control signals
  CKE_REG : FD
    port map (Q => CKEInt,
              D => CKEOut,
              C => Clk);

  CKE0_REG : FDC
    port map (Q => CKE(0),
              D => CKEInt,
              CLR => Reset,
              C => nClk);

  CKE1_REG : FDC
    port map (Q => CKE(1),
              D => CKEInt,
              CLR => Reset,
              C => nClk);

  OdtGen : for i in (gChipSelect-1) downto 0 generate
    attribute IOB of ODT_REG         : label is "true";        
    attribute syn_useioff of ODT_REG : label is true;
  begin
    ODT_REG : FD
      port map (Q => ODT(i),
                D => ODTOut(i),
                C => nClk);
  end generate;

  CsGen : for i in (gChipSelect-1) downto 0 generate
    attribute IOB of CS_REG         : label is "true";        
    attribute syn_useioff of CS_REG : label is true;
  begin
    CS_REG : FDS
      port map (Q => nCS(i),
                D => nCSOut(i),
                S => CSDisable,
                C => Clk);
  end generate;

end architecture Str;
