---------------------------------------------------------------------------
-- NDT Solutions Ltd. Proprietary Information
-- Company Confidential
-- Copyright 2008
--
-- Filename: ClkRst.vhd
-- Language: VHDL '93
-- Project:  NDTS2100 DSP FPGA
--
-- Design Description:
-- Clock DCM and buffers for SDRAM interface.
-- Reset ciruitry including 200us wait for DDR2 sDRAM
---------------------------------------------------------------------------

library ieee;
library UNISIM;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use UNISIM.VCOMPONENTS.all;

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


architecture Rtl of ClkRst is
  component CalControl
    port (Clk        : in  std_logic;
          ClkDcmLock : in  std_logic;
          nReset     : in  std_logic;
          TapForDqs  : out std_logic_vector(4 downto 0));
  end component;

  signal Reset    : std_ulogic;
  signal Clkx2Dcm : std_ulogic;
  signal Clkx2    : std_ulogic;
  signal Clk0Dcm  : std_ulogic;
  signal Clk90Dcm : std_ulogic;
  signal iClk0    : std_ulogic;
  signal iClk90   : std_ulogic;
  signal MemClk0Dcm : std_ulogic;
  signal iMemClk    : std_ulogic;
  signal Clkx2Locked  : std_ulogic;
  signal DcmLock      : std_ulogic;
  signal SysClkDcmRst : std_ulogic;
  signal nSysClkDcmRst: std_ulogic;
  signal SysClkRst    : std_ulogic;
  signal nSysClkRst   : std_ulogic;

  signal Count200     : unsigned(15 downto 0);
  signal iWait200us   : std_ulogic;
  signal Wait200usD   : std_ulogic;
  signal WaitClk90    : std_ulogic;
  signal WaitClk270   : std_ulogic;
  signal SyncRstD0    : std_ulogic;
  signal SyncRstD1    : std_ulogic;
  signal SyncRst90D0  : std_ulogic;
  signal SyncRst90D1  : std_ulogic;
  signal SyncRst180D0 : std_ulogic;
  signal SyncRst180D1 : std_ulogic;

  signal ResetCalD1   : std_ulogic;
  signal ResetCalD2   : std_ulogic;
  signal DelaySelInt  : std_logic_vector(4 downto 0);

begin

  ClkDcmRstGen : SRL16
    generic map(INIT => X"FFFF")
    port map (Q   => Reset,
              A0  => '1',
              A1  => '1',
              A2  => '1',
              A3  => '1',
              CLK => Clk,
              D   => '0');

  ClkDcm: DCM
    generic map(DLL_FREQUENCY_MODE    => "LOW",
                CLKIN_PERIOD => 15.2,
                CLK_FEEDBACK => "2X",
                DUTY_CYCLE_CORRECTION => true)
    port map (CLKIN    => Clk,
              CLKFB    => Clkx2,
              DSSEN    => '0',
              PSINCDEC => '0',
              PSEN     => '0',
              PSCLK    => '0',
              RST      => Reset,
              CLK0     => open,
              CLK90    => open,
              CLK180   => open,
              CLK270   => open,
              CLK2X    => Clkx2Dcm,
              CLK2X180 => open,
              CLKDV    => open,
              CLKFX    => open,
              CLKFX180 => open,
              LOCKED   => Clkx2Locked,
              PSDONE   => open,
              STATUS   => open);

  Clkx2Bufg: BUFG
    port map(I  => Clkx2Dcm,
             O  => Clkx2);

  SysClkDcmRstGen : SRL16
    generic map(INIT => X"0000")
    port map (Q   => nSysClkDcmRst,
              A0  => '1',
              A1  => '1',
              A2  => '1',
              A3  => '1',
              CLK => Clkx2,
              D   => Clkx2Locked);

  SysClkDcmRst <= not nSysClkDcmRst;

  SysClkDcm: DCM
    generic map(DLL_FREQUENCY_MODE    => "LOW",
                CLKIN_PERIOD => 7.6,
                CLK_FEEDBACK => "1X",
                DUTY_CYCLE_CORRECTION => true)
    port map (CLKIN    => Clkx2,
              CLKFB    => iClk0,
              DSSEN    => '0',
              PSINCDEC => '0',
              PSEN     => '0',
              PSCLK    => '0',
              RST      => SysClkDcmRst,
              CLK0     => Clk0Dcm,
              CLK90    => Clk90Dcm,
              CLK180   => open,
              CLK270   => open,
              CLK2X    => open,
              CLK2X180 => open,
              CLKDV    => open,
              CLKFX    => open,
              CLKFX180 => open,
              LOCKED   => DcmLock,
              PSDONE   => open,
              STATUS   => open);

  Clk0Bufg: BUFG
    port map(I  => Clk0Dcm,
             O  => iClk0);
  Clk0 <= iClk0;

  Clk90Bufg: BUFG
    port map(I  => Clk90Dcm,
             O  => iClk90);
  Clk90 <= iClk90;

  SysClkRstGen : SRL16
    generic map(INIT => X"0000")
    port map (Q   => nSysClkRst,
              A0  => '1',
              A1  => '1',
              A2  => '1',
              A3  => '1',
              CLK => iClk0,
              D   => DcmLock);

  SysClkRst <= not nSysClkRst;

  MemClkDcm: DCM
    generic map(DLL_FREQUENCY_MODE    => "LOW",
                CLKIN_PERIOD => 7.6,
                CLK_FEEDBACK => "1X",
                DUTY_CYCLE_CORRECTION => true,
                CLKOUT_PHASE_SHIFT => "FIXED",
                PHASE_SHIFT => 140) -- 110
    port map (CLKIN    => Clkx2,
              CLKFB    => iMemClk,
              DSSEN    => '0',
              PSINCDEC => '0',
              PSEN     => '0',
              PSCLK    => '0',
              RST      => SysClkDcmRst,
              CLK0     => MemClk0Dcm,
              CLK90    => open,
              CLK180   => open,
              CLK270   => open,
              CLK2X    => open,
              CLK2X180 => open,
              CLKDV    => open,
              CLKFX    => open,
              CLKFX180 => open,
              LOCKED   => open,
              PSDONE   => open,
              STATUS   => open);

  MemClkBufg: BUFG
    port map(I  => MemClk0Dcm,
             O  => iMemClk);
  MemClk <= iMemClk;

  -- 200 us wait for DDR2 init
  WaitGen: process(SysClkRst, iClk0)
  begin
    if SysClkRst = '1' then
        iWait200us <= '1';
        Count200 <= (others => '0');
    elsif iClk0'event and iClk0 = '1' then
      if Count200 <= (200*gClkFreq*2) then  -- 200us
        iWait200us <= '1';
        Count200 <= Count200 + 1;
      else
        iWait200us <= '0';
      end if;
    end if;
  end process WaitGen;

  WaitFF: process(SysClkRst, iClk0)
  begin
    if SysClkRst = '1' then
        Wait200us <= '1';
    elsif iClk0'event and iClk0 = '1' then
      Wait200us <= iWait200us;
    end if;
  end process WaitFF;

  WaitDel: process(SysClkRst, iClk0)
  begin
    if SysClkRst = '1' then
        Wait200usD <= '1';
    elsif iClk0'event and iClk0 = '1' then
      Wait200usD <= iWait200us;
    end if;
  end process WaitDel;

  Wait270: process(SysClkRst, iClk90)
  begin
    if SysClkRst = '1' then
      WaitClk270 <= '1';
    elsif iClk90'event and iClk90 = '0' then
      WaitClk270 <= Wait200usD;
    end if;
  end process Wait270;

  Wait90: process(SysClkRst, iClk90)
  begin
    if SysClkRst = '1' then
      WaitClk90 <= '1';
    elsif iClk90'event and iClk90 = '1' then
      WaitClk90 <= WaitClk270;
    end if;
  end process Wait90;

  process(SysClkRst, iClk0)
  begin
    if SysClkRst = '1' then
      SyncRstD0 <= '1';
      SyncRstD1 <= '1';
      SyncRst   <= '1';
    elsif iClk0'event and iClk0 = '1' then
      if Wait200usD = '1' then
        SyncRstD0 <= '1';
        SyncRstD1 <= '1';
        SyncRst   <= '1';
      else
        SyncRstD0 <= '0';
        SyncRstD1 <= SyncRstD0;
        SyncRst   <= SyncRstD1;
      end if;
    end if;
  end process;

  process(SysClkRst, iClk90)
  begin
    if SysClkRst = '1' then
      SyncRst90D0 <= '1';
      SyncRst90D1 <= '1';
      SyncRst90   <= '1';
    elsif iClk90'event and iClk90 = '1' then
      if WaitClk90 = '1' then
        SyncRst90D0 <= '1';
        SyncRst90D1 <= '1';
        SyncRst90   <= '1';
      else
        SyncRst90D0 <= '0';
        SyncRst90D1 <= SyncRst90D0;
        SyncRst90   <= SyncRst90D1;
      end if;
    end if;
  end process;

  process(SysClkRst, iClk0)
  begin
    if SysClkRst = '1' then
      SyncRst180D0 <= '1';
      SyncRst180D1 <= '1';
      SyncRst180   <= '1';
    elsif iClk0'event and iClk0 = '0' then
      if WaitClk270 = '1' then
        SyncRst180D0 <= '1';
        SyncRst180D1 <= '1';
        SyncRst180   <= '1';
      else
        SyncRst180D0 <= '0';
        SyncRst180D1 <= SyncRst180D0;
        SyncRst180   <= SyncRst180D1;
      end if;
    end if;
  end process;

  -- Delay Calibration control
  Cal: CalControl
    port map (Clk        => iClk0,
              ClkDcmLock => DcmLock,
              nReset     => nReset,
              TapForDqs  => DelaySelInt);

  RstCal: process(iClk0)
  begin
    if iClk0 'event and iClk0 = '1' then
      ResetCalD1 <= ResetCal;
      ResetCalD2 <= ResetCalD1;
    end if;
  end process RstCal;

  DelSelFF: process(iClk0)
  begin
    if iClk0 'event and iClk0 = '1' then
      if ResetCalD2 = '0' then
        DelaySel <= DelaySelInt;
      end if;
    end if;
  end process DelSelFF;

end architecture Rtl;