---------------------------------------------------------------------------
-- NDT Solutions Ltd. Proprietary Information
-- Company Confidential
-- Copyright 2004
--
-- Filename: SystemFpgaTop.vhd
-- Language: VHDL '93
-- Project:  Digitiser Card System FPGA
--
-- Design Description:
-- Top Level for Digitiser Card System FPGA
---------------------------------------------------------------------------

library IEEE;
use IEEE.Std_Logic_1164.all;
use IEEE.Std_Logic_Arith.all;

library UNISIM;
use UNISIM.vcomponents.all;

entity SystemFpgaTop is
  port(-- Local bus
       pnLRESET    : in    std_ulogic;
       pLCLKA      : in    std_ulogic;
       pLWnR       : in    std_ulogic;
       pnADS       : in    std_ulogic;
       pnBLAST     : in    std_ulogic;
       pLA         : inout std_logic_vector(31 downto 2);
       pLD         : inout std_logic_vector(31 downto 0);
       pLHOLD      : in    std_ulogic;
       pLHOLDA     : out   std_ulogic;
       pnREADY     : out   std_ulogic;
       pnBTERM     : out   std_ulogic;
       pnCCS       : out   std_ulogic;
       pBREQi      : out   std_ulogic;
       pLINTi      : out   std_ulogic;
       -- System SRAM control
       pnSysRamCS  : out   std_ulogic;
       pnSysRamWE  : out   std_ulogic;
       pnSysRamOE  : out   std_ulogic;
       -- EEPROM connections
       pEeprom_C   : out   std_ulogic;
       pEeprom_nS  : out   std_ulogic;
       pEeprom_D   : out   std_ulogic;
       pEeprom_Q   : in    std_ulogic;
       -- Generio IO
       pIO         : inout std_logic_vector(52 downto 0);
       -- FPGA connections
       pFpgaDone   : in    std_ulogic;
       pFpgaInit   : in    std_ulogic;
       pFpgaBusy   : in    std_ulogic;
       pFpgaCClk   : out   std_ulogic;  -- FPGA configuration clock
       pFpgaWrite  : out   std_ulogic;  -- FPGA write
       pFpgaCS     : out   std_logic_vector(3 downto 0);  -- Digitising FPGA cs
       pPFpgaCS    : out   std_logic_vector(3 downto 0);  -- Peripheral fpga cs
       pProgram    : out   std_logic_vector(3 downto 0);
       pIRQ        : in    std_logic_vector(0 downto 0);
       --
       pTestLed    : out   std_ulogic);  -- Test output
end entity SystemFpgaTop;


architecture Rtl of SystemFpgaTop is

  -- Xilinx components
  component IBUFG
    port (I   : in    std_ulogic;
          O   : out   std_ulogic);
  end component;

  component BUFG
    port (I   : in    std_ulogic;
          O   : out   std_ulogic);
  end component;

  component CLKDLL  -- Xilinx CLKDLL component
    port (CLKIN  : in  std_ulogic;
          CLKFB  : in  std_ulogic;
          RST    : in  std_ulogic;
          CLK0   : out std_ulogic;
          CLK90  : out std_ulogic;
          CLK180 : out std_ulogic;
          CLK270 : out std_ulogic;
          CLK2X  : out std_ulogic;
          CLKDV  : out std_ulogic;
          LOCKED : out std_ulogic);
  end component;

  -- Xilinx IOB (Input) flip-flop
  component IFD
    port (D : in  std_ulogic;
          C : in  std_ulogic;
          Q : out std_ulogic);
  end component;

  -- Xilinx IOB (Output) flip-flop
  component OFD
    port (D : in  std_ulogic;
          C : in  std_ulogic;
          Q : out std_ulogic);
  end component;


  -- Sub-module components
  component BlockRam is
    generic(gAddressWidth: integer range 1 to 32;
            gDataWidth:    integer range 1 to 32);
    port(pClk     : in  std_ulogic;
         pWriteEn : in  std_ulogic;
         pAddr    : in  std_logic_vector(gAddressWidth-1 downto 0);
         pDataIn  : in  std_logic_vector(gDataWidth-1 downto 0);
         pDataOut : out std_logic_vector(gDataWidth-1 downto 0));
  end component BlockRam;


  component LbusCont is
    port(pnReset         : in  std_ulogic;
         pLCLKA          : in  std_ulogic;                 -- local bus clock
         pLAin           : in  std_logic_vector(31 downto 2);
         pLDin           : in  std_logic_vector(31 downto 0);    -- local data bus input
         pLDout          : out std_logic_vector(31 downto 0);  -- local data bus output
         pLDoutEn        : out std_ulogic;            -- output buffer enable
         pLW_R           : in  std_ulogic;                  -- write NOT read
         pnADS           : in  std_ulogic;                  -- ads#
         pnBLAST         : in  std_ulogic;                -- blast#
         pnREADY         : out std_ulogic;               -- ready#
         pnBTERM         : out std_ulogic;               -- bterm#
         pLHOLDA         : out std_ulogic;               -- lholda#
         pLHOLD          : in  std_ulogic;               -- lhold#
         pBREQi          : out std_ulogic;
         pnSysRamWE      : out std_ulogic;
         pnSysRamCS      : out std_ulogic;
         pnSysRamOE      : out std_ulogic;
         -- Generic IO signals
         pSysIo0In   : in  std_logic_vector(31 downto 0);
         pSysIo0Out  : out std_logic_vector(31 downto 0);
         pSysIo0Dir  : out std_logic_vector(31 downto 0);
         pSysIo1In   : in  std_logic_vector(20 downto 0);
         pSysIo1Out  : out std_logic_vector(20 downto 0);
         pSysIo1Dir  : out std_logic_vector(20 downto 0);
         -- Block RAM Signals
         pBlkRamWriteEn  : out std_ulogic;
         pBlkRamAddr     : out std_logic_vector(5 downto 0);
         pBlkRamDataIn   : out std_logic_vector(31 downto 0);
         pBlkRamDataOut  : in  std_logic_vector(31 downto 0);
         -- Control signals for EEPROM access block
         pWriteEeprom    : out std_ulogic;
         pReadEeprom     : out std_ulogic;
         -- Signals for status reg
         pEepromBusy     : in std_ulogic;
         --
         pnDspFpgaProg   : in  std_logic_vector(3 downto 0);   -- DSP FPGA / sample system chip selects
         pnPerFpgaProg   : in  std_logic_vector(3 downto 0);   -- Peripheral chip selects
         --
         pCCS            : out std_ulogic;      -- PCI 9056 configuration chip select
         pWhatFpga       : out std_logic_vector(3 downto 0);
         pnDspFpgaCs     : out std_logic_vector(3 downto 0);   -- DSP FPGA / sample system chip selects
         pnPerFpgaCs     : out std_logic_vector(3 downto 0);   -- Peripheral chip selects
         pFpgaLoad       : out std_ulogic;      -- flag start of fpga progeram sequence
         pFpgaProged     : in std_ulogic;     -- The FPGAs have been programmed
         pFpgaDone       : in  std_logic;    -- feedback from fpga load module
         pTest           : out std_ulogic);
  end component LbusCont;


  component FpgaProg is
    port (pnReset      : in  std_ulogic;
          pLCLKA       : in  std_ulogic;               -- local bus clock
          pLAout       : out std_logic_vector(31 downto 2);  -- local bus address output
          pFpgaLoad    : in  std_ulogic;             -- high starts the fpga configuration cogs
          pFpgaDone    : out std_ulogic;              -- high indicates completion of configuration
          pCClk        : out std_ulogic;               -- configuration clock
          pProgram     : out std_logic_vector(3 downto 0); -- trigger program sequence in fpga
          pDone        : in  std_ulogic;                  -- flags end of sucessfull programming sequence
          pInit        : in  std_ulogic;                  -- flags end of fpga mem clear or programming balls up
          pBusy        : in  std_ulogic;                  -- fpga busy
          pWhatFpga    : in  std_logic_vector(3 downto 0);  -- target fpga pair
          pFpgaWrite   : out std_ulogic;           -- fpga write
          pDspFpgaCS   : out std_logic_vector(3 downto 0); -- sample fpga cs
          pPerFpgaCS   : out std_logic_vector(3 downto 0);  -- peripheral fpga cs
          pSramOeReq   : out std_ulogic;
          pTest        : out std_logic);      -- test flag
  end component FpgaProg;

  component EepromCtrl is
    port (pnReset      : in  std_ulogic;
          pLCLKA       : in  std_ulogic;               -- local bus clock
          pWriteEeprom : in  std_ulogic;
          pReadEeprom  : in  std_ulogic;
          pEepromBusy  : out std_ulogic;
          pDebug       : out std_logic_vector(7 downto 0);
          -- Block RAM control signals
          pBRamWriteEn : out std_ulogic;
          pBRamAddr    : out std_logic_vector(5 downto 0);
          pBRamWrData  : out std_logic_vector(31 downto 0);
          pBRamRdData  : in  std_logic_vector(31 downto 0);
          -- EEPROM control signals
          pEeprom_C    : out std_ulogic;  -- EEPROM Clock
          pEeprom_nS   : out std_ulogic;  -- EEPROM Chip Select
          pEeprom_D    : out std_ulogic;  -- EEPROM Write Data
          pEeprom_Q    : in  std_ulogic);  -- EEPROM Read Data
  end component EepromCtrl;

  signal nADS:          std_ulogic;
  signal nBLAST:        std_ulogic;

  signal LCLKA_ibufg:   std_ulogic;
  signal LCLKA_clkdll:  std_ulogic;
  signal LCLKA:         std_ulogic;

  signal LDout:         std_logic_vector(31 downto 0);
  signal LDoutEn:       std_ulogic;
  signal LAout:         std_logic_vector(31 downto 2);
  signal LAoutEn:       std_ulogic;

  signal WhatFpga:      std_logic_vector(3 downto 0);
  signal iDspFpgaCs:    std_logic_vector(3 downto 0);
  signal iPerFpgaCs:    std_logic_vector(3 downto 0);
  signal FpgaLoad:      std_ulogic;
  signal FpgaDone:      std_ulogic;

  signal nSysRamCS:     std_ulogic;
  signal nSysRamOE:     std_ulogic;
  signal nSysRamWE:     std_ulogic;

  signal DspFpgaCS:     std_logic_vector(3 downto 0);
  signal PerFpgaCS:     std_logic_vector(3 downto 0);

  signal BlkRamWriteEn: std_ulogic;
  signal BlkRamAddr:    std_logic_vector(5 downto 0);
  signal BlkRamDataIn:  std_logic_vector(31 downto 0);
  signal BlkRamDataOut: std_logic_vector(31 downto 0);

  signal BRamWriteEn1:  std_ulogic;
  signal BRamAddr1:     std_logic_vector(5 downto 0);
  signal BRamWrData1:   std_logic_vector(31 downto 0);
  signal BRamWriteEn2:  std_ulogic;
  signal BRamAddr2:     std_logic_vector(5 downto 0);
  signal BRamWrData2:   std_logic_vector(31 downto 0);

  signal WriteEeprom:   std_ulogic;
  signal ReadEeprom:    std_ulogic;
  signal EepromBusy:    std_ulogic;
  signal Debug:         std_logic_vector(7 downto 0);

  signal SysIo0Out:     std_logic_vector(31 downto 0);
  signal SysIo0Dir:     std_logic_vector(31 downto 0);
  signal SysIo1Out:     std_logic_vector(20 downto 0);
  signal SysIo1Dir:     std_logic_vector(20 downto 0);

  constant cVcc:       std_ulogic := '1';
  constant cGnd:       std_ulogic := '0';

begin

  --
  -- Instantiate components to to produce phase corrected LCLKA clock
  -- Start
  --
  IBUFG0: IBUFG
    port map(I   => pLCLKA,
             O   => LCLKA_ibufg);

  CLKDLL0: CLKDLL
    port map(CLKIN  => LCLKA_ibufg,
             CLKFB  => LCLKA,
             RST    => cGnd,
             CLK0   => LCLKA_clkdll,
             CLK90  => open,
             CLK180 => open,
             CLK270 => open,
             CLK2X  => open,
             CLKDV  => open,
             LOCKED => open);

  BUFG0: BUFG
    port map(I   => LCLKA_clkdll,
             O   => LCLKA);
  --
  -- Instantiate components to to produce phase corrected LCLKA clock
  -- Done
  --

  IFD0: IFD
    port map(D => pnADS,
             C => LCLKA,
             Q => nADS);

--  IFD1: IFD
--    port map(D => pnBLAST,
--             C => LCLKA,
--             Q => nBLAST);
  nBLAST <= pnBLAST;

  BlkRamWriteEn  <= BRamWriteEn1 when EepromBusy = '0' else BRamWriteEn2;
  BlkRamAddr     <= BRamAddr1 when EepromBusy = '0' else BRamAddr2;
  BlkRamDataIn   <= BRamWrData1 when EepromBusy = '0' else BRamWrData2;

  BlockRam0: BlockRam
    generic map(gAddressWidth => 6,
                gDataWidth    => 32)
    port map(pClk             => LCLKA,
             pWriteEn         => BlkRamWriteEn,
             pAddr            => BlkRamAddr,
             pDataIn          => BlkRamDataIn ,
             pDataOut         => BlkRamDataOut);


  GenpIO0: for Count in 0 to 31 generate
    pIO(Count) <= SysIo0Out(Count) when SysIo0Dir(Count) = '1' else 'Z';
  end generate;

  GenpIO1: for Count in 32 to 52 generate
    pIO(Count) <= SysIo1Out(Count - 32) when SysIo1Dir(Count - 32) = '1' else 'Z';
  end generate;

  LbusCont0: LbusCont
    port map(pnReset         => pnLRESET,
             pLCLKA          => LCLKA,
             pLAin           => pLA,
             pLDin           => pLD,
             pLDout          => LDout,
             pLDoutEn        => LDoutEn,
             pLW_R           => pLWnR,
             pnADS           => nADS,
             pnBLAST         => nBLAST,
             pnREADY         => pnREADY,
             pnBTERM         => pnBTERM,
             pLHOLDA         => pLHOLDA,
             pLHOLD          => pLHOLD,
             pBREQi          => pBREQi,
             pnSysRamWE      => nSysRamWE,
             pnSysRamCS      => nSysRamCS,
             pnSysRamOE      => nSysRamOE,
             pSysIo0In       => pIO(31 downto 0),
             pSysIo0Out      => SysIo0Out,
             pSysIo0Dir      => SysIo0Dir,
             pSysIo1In       => pIO(52 downto 32),
             pSysIo1Out      => SysIo1Out,
             pSysIo1Dir      => SysIo1Dir,
             pBlkRamWriteEn  => BRamWriteEn1,
             pBlkRamAddr     => BRamAddr1,
             pBlkRamDataIn   => BRamWrData1,
             pBlkRamDataOut  => BlkRamDataOut,
             pWriteEeprom    => WriteEeprom,
             pReadEeprom     => ReadEeprom,
             pEepromBusy     => EepromBusy,
             pnDspFpgaProg   => iDspFpgaCs,
             pnPerFpgaProg   => iPerFpgaCs,
             pCCS            => pnCCS,
             pWhatFpga       => WhatFpga,
             pnDspFpgaCs     => DspFpgaCs,
             pnPerFpgaCs     => PerFpgaCs,
             pFpgaLoad       => FpgaLoad,
             pFpgaProged     => pFpgaDone,
             pFpgaDone       => FpgaDone,
             pTest           => open);

  -- Connect up output side of LD bus
  pLD <= LDout when LDoutEn = '1' else (others => 'Z');

  -- Instantiate IOB flip-flops
  pnSysRamCS <= nSysRamCS;
  pnSysRamOE <= nSysRamOE;
  pnSysRamWE <= nSysRamWE;

--  OFD0: OFD
--    port map(D => nSysRamCS,
--             C => LCLKA,
--             Q => pnSysRamCS);

--  OFD1: OFD
--    port map(D => nSysRamOE,
--             C => LCLKA,
--             Q => pnSysRamOE);

--  OFD2: OFD
--    port map(D => nSysRamWE,
--             C => LCLKA,
--             Q => pnSysRamWE);

  FpgaProg0: FpgaProg
    port map(pnReset      => pnLRESET,
             pLCLKA       => LCLKA,
             pLAout       => LAout,
             pFpgaLoad    => FpgaLoad,
             pFpgaDone    => FpgaDone,
             pCClk        => pFpgaCClk,
             pProgram     => pProgram,
             pDone        => pFpgaDone,
             pInit        => pFpgaInit,
             pBusy        => pFpgaBusy,
             pWhatFpga    => WhatFpga,
             pFpgaWrite   => pFpgaWrite,
             pDspFpgaCS   => iDspFpgaCS,
             pPerFpgaCS   => iPerFpgaCS,
             pSramOeReq   => LAoutEn,
             pTest        => pTestLed);

  EepromCtrl0: EepromCtrl
    port map(pnReset       => pnLRESET,
             pLCLKA        => LCLKA,
             pWriteEeprom  => WriteEeprom,
             pReadEeprom   => ReadEeprom,
             pEepromBusy   => EepromBusy,
             pDebug        => Debug,
             pBRamWriteEn  => BRamWriteEn2,
             pBRamAddr     => BRamAddr2,
             pBRamWrData   => BRamWrData2,
             pBRamRdData   => BlkRamDataOut,
             pEeprom_C     => pEeprom_C,
             pEeprom_nS    => pEeprom_nS,
             pEeprom_D     => pEeprom_D,
             pEeprom_Q     => pEeprom_Q);


  -- Connect up output side of LA bus
  pLA <= LAout when LAoutEn = '1' else (others => 'Z');
  pFpgaCS  <= DspFpgaCS;
  pPFpgaCS <= PerFpgaCS;

--  OFD3: OFD
--    port map(D => DspFpgaCS(0),
--             C => LCLKA,
--             Q => pFpgaCS(0));

--  OFD4: OFD
--    port map(D => DspFpgaCS(1),
--             C => LCLKA,
--             Q => pFpgaCS(1));

--  OFD5: OFD
--    port map(D => DspFpgaCS(2),
--            C => LCLKA,
--             Q => pFpgaCS(2));

--  OFD6: OFD
--    port map(D => DspFpgaCS(3),
--             C => LCLKA,
--             Q => pFpgaCS(3));

--  OFD7: OFD
--    port map(D => PerFpgaCS(0),
--             C => LCLKA,
--             Q => pPFpgaCS(0));

--  OFD8: OFD
--    port map(D => PerFpgaCS(1),
--             C => LCLKA,
--             Q => pPFpgaCS(1));

--  OFD9: OFD
--    port map(D => PerFpgaCS(2),
--             C => LCLKA,
--             Q => pPFpgaCS(2));

--  OFD610: OFD
--    port map(D => PerFpgaCS(3),
--             C => LCLKA,
--             Q => pPFpgaCS(3));

  -- Connect interrupt for DSP FPGA to PLX interface
  pLINTi <= pIRQ(0);

end architecture Rtl;