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

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

-- Bring in the constant cFpgaVersion to define the FPGA version
library work;
use work.PeripheralVerPkg.all;

library work;
use work.PeripheralFpgaPkg.all;

entity PeripheralFpgaTop is
  port(-- Local bus
       pnLReset     : in    std_ulogic;
       pnFpgaCs     : in    std_ulogic;
       pLWnR        : in    std_ulogic;
       pLA          : in    std_logic_vector(31 downto 2);
       pLD          : inout std_logic_vector(31 downto 0);
       pLCLK        : in    std_ulogic;
       -- Sample Clock
       pSampleClk   : in    std_ulogic;
       -- Shaft Encoder Inputs
       pEncoder0In  : in    std_logic_vector(1 downto 0);
       pEncoder1In  : in    std_logic_vector(1 downto 0);
       pEncoder2In  : in    std_logic_vector(1 downto 0);
       pEncoder3In  : in    std_logic_vector(1 downto 0);
       pEncoder4In  : in    std_logic_vector(1 downto 0);
       pEncoder5In  : in    std_logic_vector(1 downto 0);
       -- Control Signals
       pSEL_1M_50R  : out   std_ulogic;
       pSEL_AC_DC   : out   std_ulogic;
       pATOD_RANGE  : out   std_ulogic;
       pDATA_FORMAT : out   std_ulogic;
       pPORT_FORMAT : out   std_ulogic;
       pSENSE       : out   std_ulogic;
       pDdsKey      : out   std_ulogic;
       pDdsFsk      : out   std_ulogic;
       pAIN         : out   std_logic_vector(3 downto 0);
       pAUX         : out   std_logic_vector(1 downto 0);
       pGAIN        : out   std_logic_vector(5 downto 0);
       pCAL         : out   std_logic_vector(2 downto 0);
       -- Generic IO
       pPIO         : inout std_logic_vector(62 downto 2);
       -- Sensor Array Connections
       pProbeSense  : in    std_ulogic;
       pProbeAper   : out   std_logic_vector(1 downto 0);
       pProbeDSel   : out   std_ulogic;
       pProbeDClk   : out   std_ulogic;
       pProbeTx     : out   std_ulogic;
       pProbeData   : out   std_logic_vector(7 downto 0);
       -- Connectionns to DSP FPGA
       pZ0          : in    std_ulogic;  -- ClkDll reset control
       pZ1          : out   std_ulogic;  -- Serial shaft encoder results enable
       pZ2          : out   std_ulogic;  -- Serial shaft encoder results
       pZ3          : out   std_ulogic;  -- Serial gate data out
       pZ4          : out   std_ulogic;  -- Serial gate data enable out
       pZ5          : out   std_ulogic;  -- Serial gate sel (bit 0)
       pZ6          : out   std_ulogic;  -- Serial gate sel (bit 1)
       pZ7          : out   std_ulogic;  -- Serial gate sel (bit 2)
       pZ8          : in    std_ulogic;  -- B-Scan is active
       pZ9          : in    std_ulogic;  -- Raw External Trigger signal from DSP FPGA
       pZ10         : out   std_ulogic;  -- Trigger signal for DSP FPGA
       pZ11         : out   std_ulogic;  -- External trigger is selected
       -- Calibration DAC Signals
       pCalDac_SDI  : out   std_ulogic;
       pCalDac_CLK  : out   std_ulogic;
       pCalDac_nLD  : out   std_ulogic;
       pCalDac_nCS  : out   std_ulogic;
       -- LEDs
       pLED_D8      : out   std_ulogic;
       pLED_D9      : out   std_ulogic);
end entity PeripheralFpgaTop;



architecture Rtl of PeripheralFpgaTop is

  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;

  component IFD
    port (D : in  std_ulogic;
          C : in  std_ulogic;
          Q : out std_ulogic);
  end component;

  component OFD
    port (D : in  std_ulogic;
          C : in  std_ulogic;
          Q : out std_ulogic);
  end component;


  component StrobeExtender is
    generic(gLfsrBits: integer range 3 to 32 := 3);
    port(pnReset    : in  std_ulogic;
         pClk       : in  std_ulogic;
         pStrobeIn  : in  std_ulogic;
         pStrobeOut : out std_ulogic);
  end component StrobeExtender;


  component TriggerDelay is
    port(pnReset            : in  std_ulogic;
         pSampleClk         : in  std_ulogic;
         pTriggerDelay      : in  std_logic_vector(20 downto 0);
         pTriggerIn         : in  std_ulogic;
         pTriggerOut        : out std_ulogic);
  end component TriggerDelay;


  component PerLBusInterface is
    port (-- Local bus signals
          pnReset            : in  std_ulogic;
          pLClk              : in  std_ulogic;
          pnFPGACS           : in  std_ulogic;
          pLAin              : in  std_logic_vector(31 downto 2);
          pLDin              : in  std_logic_vector(31 downto 0);
          pLDout             : out std_logic_vector(31 downto 0);
          pLDoutput_enable   : out std_ulogic;
          pLWnR              : in  std_ulogic;
          -- Generic IO signals
          pPioIn             : in  std_logic_vector(62 downto 2);
          pPioOut            : out std_logic_vector(62 downto 2);
          pPioDdr            : out std_logic_vector(62 downto 2);
          -- Inputs for readable register bits
          pProbeSense        : in  std_ulogic;
          pEncoder0Pos       : in  std_logic_vector(31 downto 0);
          pEncoder1Pos       : in  std_logic_vector(31 downto 0);
          pEncoder2Pos       : in  std_logic_vector(31 downto 0);
          pEncoder3Pos       : in  std_logic_vector(31 downto 0);
          pEncoder4Pos       : in  std_logic_vector(31 downto 0);
          pEncoder5Pos       : in  std_logic_vector(31 downto 0);
          -- Peripheral FPGA Gate data outputs
          pGateDataOut       : out std_ulogic;
          pGateDataEn        : out std_ulogic;
          pGateDataSel       : out std_logic_vector(2 downto 0);
          -- Calibration DAC outputs
          pCalDac_SDI        : out   std_ulogic;
          pCalDac_CLK        : out   std_ulogic;
          pCalDac_nLD        : out   std_ulogic;
          pCalDac_nCS        : out   std_ulogic;
          -- Ping-Pong Block RAM signals
          pBlkRamData        : out std_logic_vector(7 downto 0);
          pBlkRamAddr        : out std_logic_vector(6 downto 0);
          pBlkRamWrEn        : out std_ulogic;
          -- Control signals from registers
          pEncoderReset      : out std_logic_vector(5 downto 0);
          pForceBscan        : out std_ulogic;
          -- Focusing Unit Control Strobe
          pFocusCtrl         : out std_ulogic;
          pFocusWrite        : out std_ulogic;
          -- Delay Value RAM signals
          pDelayValAddr      : out std_logic_vector(8 downto 0);
          pDelayValWr        : out std_ulogic;
          -- Register Outputs
          pRegData           : out tRegSet);
  end component PerLBusInterface;


  component DualPortRam is
    generic(gAddressWidth: integer range 1 to 32 := 6;
            gDataWidth:    integer range 1 to 32 := 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);
         pDpClk     : in  std_ulogic;
         pDpAddr    : in  std_logic_vector(gAddressWidth-1 downto 0);
         pDpDataOut : out std_logic_vector(gDataWidth-1 downto 0));
  end component DualPortRam;


  component EncoderMonitor is
    port (-- Local bus signals
          pnReset          : in  std_ulogic;
          pLCLK            : in  std_ulogic;
          pEncoderReset    : in  std_logic_vector(5 downto 0);
          pEncoderSelect   : in  std_logic_vector(2 downto 0);
          pClicksPerBScan  : in  std_logic_vector(15 downto 0);
          pFractClicks     : in  std_logic_vector(7 downto 0);
          pBScanActive     : in  std_ulogic;
          pEncoder0In      : in  std_logic_vector(1 downto 0);
          pEncoder1In      : in  std_logic_vector(1 downto 0);
          pEncoder2In      : in  std_logic_vector(1 downto 0);
          pEncoder3In      : in  std_logic_vector(1 downto 0);
          pEncoder4In      : in  std_logic_vector(1 downto 0);
          pEncoder5In      : in  std_logic_vector(1 downto 0);
          pSyncIn          : in  std_ulogic;
          pAckIn           : in  std_ulogic;
          pSyncAckEn       : in  std_ulogic;
          pEncoder0Pos     : out std_logic_vector(31 downto 0);
          pEncoder1Pos     : out std_logic_vector(31 downto 0);
          pEncoder2Pos     : out std_logic_vector(31 downto 0);
          pEncoder3Pos     : out std_logic_vector(31 downto 0);
          pEncoder4Pos     : out std_logic_vector(31 downto 0);
          pEncoder5Pos     : out std_logic_vector(31 downto 0);
          pSerialOut       : out std_ulogic;
          pSerialOutEn     : out std_ulogic;
          pBScanTriggerOut : out std_ulogic;
          pBScanTriggerIn  : in  std_ulogic);
  end component EncoderMonitor;


  component BScanCtrl is
    port (-- Local bus signals
          pnReset          : in  std_ulogic;
          pSampleClk       : in  std_ulogic;
          -- Start B-Scan operation
          pBScanTrigger    : in  std_ulogic;
          pBScanFreeRunning: in  std_ulogic;
          -- Register data in
          pNumElements     : in  std_logic_vector(6 downto 0);
          pAScanRepRate    : in  std_logic_vector(16 downto 0);
          pAScanInterleave : in std_logic_vector(1 downto 0);
          pBScanRepRate    : in  std_logic_vector(25 downto 0);
          -- Trigger data out
          pBScanTriggerOut : out std_ulogic;
          pLastBscan       : out std_ulogic;
          pTxCount         : out std_logic_vector(6 downto 0);
          pRxCount         : out std_logic_vector(6 downto 0);
          pTriggerOut      : out std_ulogic);
  end component BScanCtrl;


  component TriggerPulseGen is
    port (-- Local bus signals
          pnReset            : in  std_ulogic;
          pSample2xClk       : in  std_ulogic;
          pTriggerLen        : in  std_logic_vector(11 downto 0);
          pTriggerIn         : in  std_ulogic;
          pTxDone            : out std_ulogic;
          pTriggerOut        : out std_ulogic);
  end component TriggerPulseGen;


  component DelayValueRam is
    port(-- Port 1
         pClk       : in  std_ulogic;
         pWriteEn   : in  std_ulogic;
         pAddr      : in  std_logic_vector(8 downto 0);
         pDataIn    : in  std_logic_vector(31 downto 0);
         -- Port 2
         pDpClk     : in  std_ulogic;
         pDpAddr    : in  std_logic_vector(10 downto 0);
         pDpDataOut : out std_logic_vector(7 downto 0));
  end component DelayValueRam;


  component FocusUnitCtrl is
    port (-- Local bus signals
          pnReset          : in  std_ulogic;
          pSampleClk       : in  std_ulogic;
          -- Register data
          pApertureSize    : in  std_logic_vector(1 downto 0);
          pDisApWrites     : in  std_ulogic;
          pDisDelWrites    : in  std_ulogic;
          -- A-Scan Trigger
          pAScanTrigger    : in  std_ulogic;
          pAScanCount      : in  std_logic_vector(6 downto 0);
          pAScanInterleave : in  std_logic_vector(1 downto 0);
          -- Delay Value RAM Interface
          pDelayValAddr    : out std_logic_vector(10 downto 0);
          pDelayValData    : in  std_logic_vector(7 downto 0);
          -- Element Number
          pElementNumber   : in  std_logic_vector(7 downto 0);
          -- Transmit / Receive out
          pTx_nRx          : out std_ulogic;
          -- Generated signals
          pProbeCtrl       : out std_logic_vector(2 downto 0);
          pProbeData       : out std_logic_vector(7 downto 0);
          pProbeDClock     : out std_ulogic;
          pProbeTx         : out std_ulogic);
  end component FocusUnitCtrl;


  signal RawTrigger:     std_ulogic;
  signal DelayedTrigger: std_ulogic;

  signal ElementNumOut: std_logic_vector(7 downto 0);

  signal RegData:        tRegSet;

  signal LD_Out: std_logic_vector(31 downto 0);
  signal LD_En:  std_ulogic;

  -- Encoder inputs after clocking through flip-flops
  signal iEncoder0In:        std_logic_vector(1 downto 0);
  signal iEncoder1In:        std_logic_vector(1 downto 0);
  signal iEncoder2In:        std_logic_vector(1 downto 0);
  signal iEncoder3In:        std_logic_vector(1 downto 0);
  signal iEncoder4In:        std_logic_vector(1 downto 0);
  signal iEncoder5In:        std_logic_vector(1 downto 0);
  signal Encoder0In:         std_logic_vector(1 downto 0);
  signal Encoder1In:         std_logic_vector(1 downto 0);
  signal Encoder2In:         std_logic_vector(1 downto 0);
  signal Encoder3In:         std_logic_vector(1 downto 0);
  signal Encoder4In:         std_logic_vector(1 downto 0);
  signal Encoder5In:         std_logic_vector(1 downto 0);

  signal SampleClkIn:        std_ulogic;
  signal SampleClk_NoBuff:   std_ulogic;
  signal SampleClk:          std_ulogic;
  signal Sample2xClk:        std_ulogic;
  signal Sample2xClk_NoBuff: std_ulogic;
  signal Sample2xClkValid:   std_ulogic;

  signal LCLK_NoBuff:  std_ulogic;
  signal LCLK:         std_ulogic;

  signal CalDac_SDI:  std_ulogic;
  signal CalDac_CLK:  std_ulogic;
  signal CalDac_nLD:  std_ulogic;
  signal CalDac_nCS:  std_ulogic;

  signal BlkRamDataIn: std_logic_vector(7 downto 0);
  signal BlkRamAddr1:  std_logic_vector(6 downto 0);
  signal BlkRamAddr2:  std_logic_vector(6 downto 0);
  signal BlkRamWrEn:   std_ulogic;

  signal TxCount:      std_logic_vector(6 downto 0);
  signal RxCount:      std_logic_vector(6 downto 0);
  signal TxCountMux:   std_logic_vector(6 downto 0);
  signal RxCountMux:   std_logic_vector(6 downto 0);

  signal AScanTrigger:      std_ulogic;
  signal BScanTrigger:      std_ulogic;
  signal EncBScanTrigger:   std_ulogic;
  signal BScanTriggerExt:   std_ulogic;
  signal BScanTriggerPulse: std_ulogic;
  signal ForceBscan:        std_ulogic;
  signal DoBScan:           std_ulogic;

  signal Tx_nRx:       std_logic;  -- std_logic used instead of std_ulogic to remove systhesis warnings
  signal Tx_nRx2:      std_ulogic;

  signal EncoderReset: std_logic_vector(5 downto 0);
  signal Encoder0Pos:  std_logic_vector(31 downto 0);
  signal Encoder1Pos:  std_logic_vector(31 downto 0);
  signal Encoder2Pos:  std_logic_vector(31 downto 0);
  signal Encoder3Pos:  std_logic_vector(31 downto 0);
  signal Encoder4Pos:  std_logic_vector(31 downto 0);
  signal Encoder5Pos:  std_logic_vector(31 downto 0);

  signal TrigDelay:      std_logic_vector(20 downto 0);
  signal TriggerSeen:    std_ulogic;
  signal TriggerPresent: std_logic;
  signal ProbeData:      std_logic_vector(7 downto 0);
  signal ProbeDSel:      std_logic;  -- Note use of std_logic instead of std_ulogic
  signal ProbeDClk:      std_logic;  -- to remove synthesis warnings
  signal ProbeTx:        std_logic;  --

  -- Serial version of Shaft encoder results for DSP FPGA
  signal SerialOut:   std_ulogic;
  signal SerialOutEn: std_ulogic;
  signal LastBScan:   std_ulogic;

  -- Serial version of gate data for DSP FFPGA
  signal GateDataOut: std_ulogic;
  signal GateDataEn:  std_ulogic;
  signal GateDataSel: std_logic_vector(2 downto 0);

  -- Generic IO signals
  signal PioIn:       std_logic_vector(62 downto 2);
  signal PioOut:      std_logic_vector(62 downto 2);
  signal PioDdr:      std_logic_vector(62 downto 2);

  -- Focusing Unit Control signals
  signal FocusEn:     std_ulogic;
  signal FocusWrite:  std_ulogic;
  signal FocusCtrl:   std_logic_vector(2 downto 0);
  signal FocusData:   std_logic_vector(7 downto 0);

  -- Focusing Unit automatic control signals
  signal DelayValWrAddr: std_logic_vector(8 downto 0);
  signal DelayValWrEn:   std_ulogic;
  signal DelayValAddr:   std_logic_vector(10 downto 0);
  signal DelayValData:   std_logic_vector(7 downto 0);

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


begin


  -- Create the generic IO ports
  GenPio: for Count in 2 to 62 generate
    pPIO(Count) <= PioOut(Count) when PioDdr(Count) = '1' else 'Z';
  end generate;


  -- Connect up the peripheral hardware control outputs
  pAUX         <= RegData(cHardwareCtrl)(24 downto 23);
  pCAL         <= RegData(cHardwareCtrl)(22 downto 20);
  pDdsFsk      <= RegData(cHardwareCtrl)(19);
  pDdsKey      <= RegData(cHardwareCtrl)(18);
  -- 16:15
  pSENSE       <= '1' when (RegData(cHardwareCtrl)(15) = '1') else 'Z';
  pATOD_RANGE  <= RegData(cHardwareCtrl)(14);
  pDATA_FORMAT <= RegData(cHardwareCtrl)(13);
  pPORT_FORMAT <= RegData(cHardwareCtrl)(12);
  pGAIN        <= RegData(cHardwareCtrl)(11 downto 6);
  pAIN         <= RegData(cHardwareCtrl)(5 downto 2);
  pSEL_1M_50R  <= RegData(cHardwareCtrl)(1);
  pSEL_AC_DC   <= RegData(cHardwareCtrl)(0);


  --
  -- Instantiate components to produce frequency doubled pSampleClk
  -- Start
  --
  IBUFG0: IBUFG
    port map(I   => pSampleClk,
             O   => SampleClkIn);


  CLKDLL0: CLKDLL
    port map(CLKIN  => SampleClkIn,
             CLKFB  => SampleClk,
             RST    => pZ0,  -- Need to bring a reset in from DSP FPGA
             CLK0   => SampleClk_NoBuff,
             CLK90  => open,
             CLK180 => open,
             CLK270 => open,
             CLK2X  => open,
             CLKDV  => open,
             LOCKED => open);

  BUFG0: BUFG
    port map(I   => SampleClk_NoBuff,
             O   => SampleClk);

  CLKDLL1: CLKDLL
    port map(CLKIN  => SampleClk,
             CLKFB  => Sample2xClk,
             RST    => pZ0,  -- Need to bring a reset in from DSP FPGA
             CLK0   => open,
             CLK90  => open,
             CLK180 => open,
             CLK270 => open,
             CLK2X  => Sample2xClk_NoBuff,
             CLKDV  => open,
             LOCKED => Sample2xClkValid);

  BUFG1: BUFG
    port map(I   => Sample2xClk_NoBuff,
             O   => Sample2xClk);

  --
  -- Instantiate components to produce frequency doubled pSampleClock
  -- Done
  --

  -- Ensure LCLK is allocated a clock buffer
  IBUFG1: IBUFG
    port map(I   => pLCLK,
             O   => LCLK_NoBuff);

  BUFG2: BUFG
   port map(I   => LCLK_NoBuff,
            O   => LCLK);

  -- Connect generic IO input to PIO pins
  PioIn <= pPio;

  PerLBusInterface0: PerLBusInterface
    Port map(-- Local bus signals
             pnReset            => pnLReset,
             pLClk              => LCLK,
             pnFPGACS           => pnFpgaCs,
             pLAin              => pLA,
             pLDin              => pLD,
             pLDout             => LD_Out,
             pLDoutput_enable   => LD_En,
             pLWnR              => pLWnR,
             -- Generic IO signals
             pPioIn             => PioIn,
             pPioOut            => PioOut,
             pPioDdr            => PioDdr,
             -- Inputs for readable register bits
             pProbeSense        => pProbeSense,
             pEncoder0Pos       => Encoder0Pos,
             pEncoder1Pos       => Encoder1Pos,
             pEncoder2Pos       => Encoder2Pos,
             pEncoder3Pos       => Encoder3Pos,
             pEncoder4Pos       => Encoder4Pos,
             pEncoder5Pos       => Encoder5Pos,
             -- Peripheral FPGA Gate data outputs
             pGateDataOut       => GateDataOut,
             pGateDataEn        => GateDataEn,
             pGateDataSel       => GateDataSel,
             -- Calibration DAC outputs
             pCalDac_SDI        => CalDac_SDI,
             pCalDac_CLK        => CalDac_CLK,
             pCalDac_nLD        => CalDac_nLD,
             pCalDac_nCS        => CalDac_nCS,
             -- Ping-Pong Block RAM signals
             pBlkRamData        => BlkRamDataIn,
             pBlkRamAddr        => BlkRamAddr1,
             pBlkRamWrEn        => BlkRamWrEn,
             -- Control signals from registers
             pEncoderReset      => EncoderReset,
             pForceBscan        => ForceBscan,
             -- Focusing Unit Control Strobe
             pFocusCtrl         => FocusEn,
             pFocusWrite        => FocusWrite,
             -- Delay Value RAM signals
             pDelayValAddr      => DelayValWrAddr,
             pDelayValWr        => DelayValWrEn,
             -- Register Outputs
             pRegData           => RegData);

  FocusCtrl <= RegData(cFocusUnitCtrl)(10 downto 8);
  FocusData <= RegData(cFocusUnitCtrl)(7 downto 0);

  -- Capture Tx_nRx signal in SampleClk domain
  GenTx_nRx2: process(pnLReset, SampleClk)
  begin
    if pnLReset = '0' then
      Tx_nRx2 <= '0';
    elsif rising_edge(SampleClk) then
      Tx_nRx2 <= Tx_nRx;
    end if;
  end process;

  TrigDelay <= RegData(cTriggerCtrl)(24 downto 20) & RegData(cTriggerCtrl)(15 downto 0);

  TriggerDelay0: TriggerDelay
    port map(pnReset          => pnLReset,
             pSampleClk       => SampleClk,
             pTriggerDelay    => TrigDelay,
             pTriggerIn       => RawTrigger,
             pTriggerOut      => DelayedTrigger);


  -- Multiplex signals onto BlkRamAddr2 using tristate buffers
  TxCountMux <= TxCount when Tx_nRx = '1' else (others => 'Z');
  RxCountMux <= RxCount when Tx_nRx = '0' else (others => 'Z');
  BlkRamAddr2 <= TxCountMux;
  BlkRamAddr2 <= RxCountMux;
  --BlkRamAddr2 <= TxCount when Tx_nRx = '1' else RxCount;

  DualPortRam0: DualPortRam
    generic map(gAddressWidth  => 7,
                gDataWidth     => 8)
    port map(pClk       => LCLK,
             pWriteEn   => BlkRamWrEn,
             pAddr      => BlkRamAddr1,
             pDataIn    => BlkRamDataIn,
             pDataOut   => open,
             pDpClk     => SampleClk,
             pDpAddr    => BlkRamAddr2,
             pDpDataOut => ElementNumOut);


  pLD <= LD_Out when LD_En = '1' else (others => 'Z');

  OFD0: OFD
    port map(D => CalDac_SDI,
             C => LCLK,
             Q => pCalDac_SDI);

  OFD1: OFD
    port map(D => CalDac_CLK,
             C => LCLK,
             Q => pCalDac_CLK);

  OFD2: OFD
    port map(D => CalDac_nLD,
             C => LCLK,
             Q => pCalDac_nLD);

  OFD3: OFD
    port map(D => CalDac_nCS,
             C => LCLK,
             Q => pCalDac_nCS);

  -- Clock the encoder inputs thru IOB input flip-flops
  IFD0: IFD
    port map(D => pEncoder0In(0),
             C => LCLK,
             Q => iEncoder0In(0));
  IFD1: IFD
    port map(D => pEncoder0In(1),
             C => LCLK,
             Q => iEncoder0In(1));
  IFD2: IFD
    port map(D => pEncoder1In(0),
             C => LCLK,
             Q => iEncoder1In(0));
  IFD3: IFD
    port map(D => pEncoder1In(1),
             C => LCLK,
             Q => iEncoder1In(1));
  IFD4: IFD
    port map(D => pEncoder2In(0),
             C => LCLK,
             Q => iEncoder2In(0));
  IFD5: IFD
    port map(D => pEncoder2In(1),
             C => LCLK,
             Q => iEncoder2In(1));
  IFD6: IFD
    port map(D => pEncoder3In(0),
             C => LCLK,
             Q => iEncoder3In(0));
  IFD7: IFD
    port map(D => pEncoder3In(1),
             C => LCLK,
             Q => iEncoder3In(1));
  IFD8: IFD
    port map(D => pEncoder4In(0),
             C => LCLK,
             Q => iEncoder4In(0));
  IFD9: IFD
    port map(D => pEncoder4In(1),
             C => LCLK,
             Q => iEncoder4In(1));
  IFD10: IFD
    port map(D => pEncoder5In(0),
             C => LCLK,
             Q => iEncoder5In(0));
  IFD11: IFD
    port map(D => pEncoder5In(1),
             C => LCLK,
             Q => iEncoder5In(1));

  -- Clock encoder data a 2nd time to remove metastability
  ClkEncoderData: process(pnLReset, LCLK)
  begin
    if pnLReset = '0' then
      Encoder0In  <= "00";
      Encoder1In  <= "00";
      Encoder2In  <= "00";
      Encoder3In  <= "00";
      Encoder4In  <= "00";
      Encoder5In  <= "00";
    elsif rising_edge(LCLK) then
      Encoder0In  <= iEncoder0In;
      Encoder1In  <= iEncoder1In;
      Encoder2In  <= iEncoder2In;
      if cFpgaVersion = X"0" then
        Encoder3In  <= iEncoder3In;
        Encoder4In  <= iEncoder4In;
        Encoder5In  <= iEncoder5In;
      else -- Only 3 channels are available in ver 1 of the FPGA
        Encoder3In  <= "00";
        Encoder4In  <= "00";
        Encoder5In  <= "00";
      end if;
    end if;
  end process ClkEncoderData;


  EncoderMonitor0: EncoderMonitor
    Port map(pnReset          => pnLReset,
             pLCLK            => LCLK,
             pEncoderReset    => EncoderReset,
             pEncoderSelect   => RegData(cBScanTriggerCtrl)(18 downto 16),
             pClicksPerBScan  => RegData(cBScanTriggerCtrl)(15 downto 0),
             pFractClicks     => RegData(cBScanTriggerCtrl)(27 downto 20),
             pBScanActive     => pZ8,
             pEncoder0In      => Encoder0In,
             pEncoder1In      => Encoder1In,
             pEncoder2In      => Encoder2In,
             pEncoder3In      => Encoder3In,
             pEncoder4In      => Encoder4In,
             pEncoder5In      => Encoder5In,
             pSyncIn          => PioIn(6),
             pAckIn           => PioIn(7),
             pSyncAckEn       => RegData(cBScanTriggerCtrl)(28),
             pEncoder0Pos     => Encoder0Pos,
             pEncoder1Pos     => Encoder1Pos,
             pEncoder2Pos     => Encoder2Pos,
             pEncoder3Pos     => Encoder3Pos,
             pEncoder4Pos     => Encoder4Pos,
             pEncoder5Pos     => Encoder5Pos,
             pSerialOut       => SerialOut,
             pSerialOutEn     => SerialOutEn,
             pBScanTriggerOut => EncBScanTrigger,
             pBScanTriggerIn  => BScanTriggerPulse);

  -- Connect up the encoder data outputs for the DSP FPGA
  OFD4: OFD
    port map(D => SerialOutEn,
             C => LCLK,
             Q => pZ1);

  OFD5: OFD
    port map(D => SerialOut,
             C => LCLK,
             Q => pZ2);

  -- Connect up Serial gate data outputs for DSP FPGA
  OFD6: OFD
    port map(D => GateDataOut,
             C => LCLK,
             Q => pZ3);

  OFD7: OFD
    port map(D => GateDataEn,
             C => LCLK,
             Q => pZ4);

  OFD8: OFD
    port map(D => GateDataSel(0),
             C => LCLK,
             Q => pZ5);

  OFD9: OFD
    port map(D => GateDataSel(1),
             C => LCLK,
             Q => pZ6);

  OFD10: OFD
    port map(D => GateDataSel(2),
             C => LCLK,
             Q => pZ7);


  DoBScan <= (EncBScanTrigger and RegData(cBScanTriggerCtrl)(30)) or ForceBscan;

  BScanCtrl0: BScanCtrl
    port map(-- Local bus signals
             pnReset          => pnLReset,
             pSampleClk       => SampleClk,
             -- Start B-Scan operation
             pBScanTrigger    => DoBScan,
             pBScanFreeRunning=> RegData(cBScanTriggerCtrl)(29),
             -- Register data in
             pNumElements     => RegData(cSensorSetup)(6 downto 0),
             pAScanRepRate    => RegData(cAScanCtrl)(16 downto 0),
             pAScanInterleave => RegData(cAScanCtrl)(21 downto 20),
             pBScanRepRate    => RegData(cBScanTriggerCtrl)(25 downto 0),
             -- Trigger data out
             pBScanTriggerOut => BScanTrigger,
             pLastBscan       => LastBScan,
             pTxCount         => TxCount,
             pRxCount         => RxCount,
             pTriggerOut      => AScanTrigger);

  -- Extend BScan trigger to 2 cycles
  GenBScanTrigExt: process(pnLReset, SampleClk)
   variable vTemp: std_logic_vector(1 downto 0);
  begin
   if pnLReset = '0' then
     BScanTriggerExt <= '0';
   elsif rising_edge(SampleClk) then
     if vTemp(1 downto 0) = "01" or (vTemp(0) = '0' and  BScanTrigger = '1') then
       BScanTriggerExt <= '1';
     else
       BScanTriggerExt <= '0';
     end if;

     vTemp := vTemp(0) & BScanTrigger;
   end if;
  end process GenBScanTrigExt;

  -- clock into LClk domain
  GenBScanTrigPulse: process(pnLReset, LClk)
    variable vTemp: std_logic_vector(2 downto 0);
  begin
    if pnLReset = '0' then
      BScanTriggerPulse <= '0';
    elsif rising_edge(LClk) then
      if vTemp(2 downto 1) = "01" then
        BScanTriggerPulse <= '1';
      else
        BScanTriggerPulse <= '0';
      end if;

      vTemp := vTemp(1 downto 0) & BScanTriggerExt;
    end if;
  end process GenBScanTrigPulse;

  pZ11 <= RegData(cTriggerCtrl)(16);


-- The following code is only built for Ver. 0 of the Peripheral FPGA
GenV0Trig: if cFpgaVersion = X"0" generate
  signal TriggerOut:  std_ulogic;
  signal DelayedTrig: std_ulogic;
  signal TxDone:      std_ulogic;

begin

  -- Generate a delayed version of the A-Scan Trigger to allow
  -- extra setup time for DI element numbers
  GenDelayedTrig: process(pnLReset, SampleClk)
--    variable vDelayCount: integer range 0 to 15;
    variable vDelayLfsr: std_logic_vector(3 downto 0);
  begin
    if pnLReset = '0' then
  --    vDelayCount := 0;
      DelayedTrig <= '0';
      vDelayLfsr := "1111";
    elsif rising_edge(SampleClk) then
  --    if vDelayCount = 14 or vDelayCount = 15 then
  --      DelayedTrig <= '1';
  --    else
  --      DelayedTrig <= '0';
  --    end if;

  --    if AScanTrigger = '1' then
  --      vDelayCount := 1;
  --    elsif vDelayCount /= 0 then
  --      vDelayCount := (vDelayCount + 1) mod 16;
  --    end if;

      if vDelayLfsr = "0111" or vDelayLfsr = "1011" then
        -- This is the 2 states before the reset state
        DelayedTrig <= '1';
      else
        DelayedTrig <= '0';
      end if;

      if AScanTrigger = '1' then
        vDelayLfsr := vDelayLfsr(2 downto 0) & (vDelayLfsr(3) xor vDelayLfsr(2));
      elsif vDelayLfsr /= "1111" then
        vDelayLfsr := vDelayLfsr(2 downto 0) & (vDelayLfsr(3) xor vDelayLfsr(2));
      end if;

    end if;
  end process GenDelayedTrig;

  -- Generate the Transmit / Receive flag
  GenTx_nRx: process(pnLReset, SampleClk)
    variable vTemp: std_logic_vector(2 downto 0);
  begin
    if pnLReset = '0' then
      Tx_nRx <= '0';
      vTemp  := "000";
    elsif rising_edge(SampleClk) then
      if AScanTrigger = '1' then
        Tx_nRx <= '1';
      elsif vTemp(2 downto 1) = "01" then
        Tx_nRx <= '0';
      end if;

      vTemp := vTemp(1 downto 0) & TxDone;
    end if;
  end process GenTx_nRx;


  TriggerPulseGen0: TriggerPulseGen
    port map(
             pnReset            => pnLReset,
             pSample2xClk       => Sample2xClk,
             pTriggerLen        => RegData(cPulseGenerator)(11 downto 0),
             pTriggerIn         => DelayedTrig,
             pTxDone            => TxDone,
             pTriggerOut        => TriggerOut);

  ProbeData <= ElementNumOut;

  -- Drive Prove outputs for DI Interface Unit
  -- Use open collector outputs so 5V pullups can send a larger
  -- voltage to the DI board
  GenpProbeData: for Count in 0 to 7 generate
    pProbeData(count) <= 'Z' when ProbeData(count) = '1' else '0';
  end generate GenpProbeData;
  pProbeAper(1) <= 'Z' when RegData(cSensorSetup)(9) = '1' else '0';
  pProbeAper(0) <= 'Z' when RegData(cSensorSetup)(8) = '1' else '0';
  ProbeDSel  <= '0';
  ProbeDClk  <= 'Z' when RegData(cSensorSetup)(12) = '1' else '0';
  ProbeTx    <= TriggerOut;  -- Not open collector, would be far too slow!!
end generate GenV0Trig;


-- The following code is only built for Ver. 1 of the Peripheral FPGA
GenV1Trig: if cFpgaVersion = X"1" generate
  signal ProbeCtrl:    std_logic_vector(2 downto 0);
  signal ProbeData:    std_logic_vector(7 downto 0);
  signal iProbeDClock: std_ulogic;
  signal TriggerOut:   std_ulogic;

begin

  DelayValueRam0: DelayValueRam
    port map(-- Port 1
             pClk       => LCLK,
             pWriteEn   => DelayValWrEn,
             pAddr      => DelayValWrAddr,
             pDataIn    => RegData(cDelayValueData)(31 downto 0),
             -- Port 2
             pDpClk     => SampleClk,
             pDpAddr    => DelayValAddr,
             pDpDataOut => DelayValData);


  FocusUnitCtrl0: FocusUnitCtrl
    port map(-- Local bus signals
             pnReset          => pnLReset,
             pSampleClk       => SampleClk,
             -- Register data
             pApertureSize    => RegData(cSensorSetup)(9 downto 8),
             pDisApWrites     => RegData(cSensorSetup)(10),
             pDisDelWrites    => RegData(cSensorSetup)(11),
             -- A-Scan Trigger
             pAScanTrigger    => AScanTrigger,
             pAScanCount      => BlkRamAddr2,
             pAScanInterleave => RegData(cAScanCtrl)(21 downto 20),
             -- Delay Value RAM Interface
             pDelayValAddr    => DelayValAddr,
             pDelayValData    => DelayValData,
             -- Element Number
             pElementNumber   => ElementNumOut,
             -- Transmit / Receive out
             pTx_nRx          => Tx_nRx,
             -- Generated signals
             pProbeCtrl       => ProbeCtrl,
             pProbeData       => ProbeData,
             pProbeDClock     => iProbeDClock,
             pProbeTx         => TriggerOut);


  -- Connect probe outputs to internal signals
  pProbeAper <= ProbeCtrl(1 downto 0) when FocusWrite = '0' else FocusCtrl(1 downto 0);
  ProbeDSel  <= ProbeCtrl(2) when FocusWrite = '0' else FocusCtrl(2);
  ProbeDClk  <= iProbeDClock when FocusWrite = '0' else FocusEn;
  pProbeData <= ProbeData    when FocusWrite = '0' else FocusData;
  ProbeTx    <= TriggerOut;
end generate GenV1Trig;

  -- Connect internal trigger signals to outputs
  pProbeDSel <= ProbeDSel;
  pProbeDClk <= ProbeDClk;
  pProbeTx   <= ProbeTx;


  -- Connect up DSP interconnection outputs
  RawTrigger <= pZ9 when RegData(cTriggerCtrl)(16) = '0' else AScanTrigger;
  pZ10 <= DelayedTrigger;


  -- Clock trigger signal into LCLK domain
  DetectTrigger: process(pnLReset, LCLK)
    variable vTriggerDelayed: std_ulogic;
  begin
    if pnLReset = '0' then
      TriggerSeen     <= '0';
      vTriggerDelayed := '0';
    elsif rising_edge(LCLK) then
      -- Clock pTrigIn through 2 D-types
      TriggerSeen  <=  vTriggerDelayed;
      vTriggerDelayed := (BScanTrigger or ForceBscan);
    end if;
  end process DetectTrigger;


--  GenV0TriggerPresent: if cFpgaVersion = X"0" generate
--  -- Generate a 1/4 second pulse each time a new trigger is seen
--  StrobeExtender0: StrobeExtender
--    generic map(gLfsrBits => 23)
--    port map(pnReset    => pnLReset,
--             pClk       => LCLK,
--             pStrobeIn  => TriggerSeen,
--             pStrobeOut => TriggerPresent);
--  end generate GenV0TriggerPresent;

--  GenV1TriggerPresent: if cFpgaVersion = X"1" generate
--    -- Not enough free logic gates in this version to generate pulse
--    TriggerPresent <= '1';
--  end generate GenV1TriggerPresent;

  -- Drive LED outputs
  pLED_D8      <= not Sample2xClkValid;
  pLED_D9      <= cGnd;  -- LED not used


end architecture Rtl;