---------------------------------------------------------------------------
-- NDT Solutions Ltd. Proprietary Information
-- Company Confidential
-- Copyright 2004
--
-- Filename: Testbench.vhd
-- Language: VHDL '93
-- Project:  Digitiser Card FPGAs
--
-- Design Description:
-- System testbench for the Digitiser card - sequence version
---------------------------------------------------------------------------


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

library work;
use work.LocalBusModelPkg.all;
use work.AdcModelPkg.all;



entity Testbench is
end entity testbench;


architecture Test of Testbench is


  -- Define the LocalBus Model component
  component LocalBusModel is
    port(-- Control signals to/from main simulation module
         ToBusModel  : in  tToBusModel;
         FromBusModel: out tFromBusModel;
         -- Bus Signals
         pnLRESET    : out   std_ulogic;
         pLCLKA      : out   std_ulogic;
         pLWnR       : out   std_ulogic;
         pnADS       : out   std_ulogic;
         pnBLAST     : out   std_ulogic;
         pnREADY     : in    std_ulogic;
         pLA         : inout std_logic_vector(31 downto 0);
         pLD         : inout std_logic_vector(31 downto 0);
         pLHOLD      : out   std_ulogic;
         pLHOLDA     : in    std_ulogic;
         pnBTERM     : in    std_ulogic;
         pnCCS       : in    std_ulogic;
         pBREQi      : in    std_ulogic;
         pLINTI      : in    std_ulogic);
  end component LocalBusModel;


  -- Define the Simulation Control Component
  component SimCtrl
    port(ToBusModel    : out tToBusModel;
         FromBusModel  : in  tFromBusModel;
         ToAdcModel    : out tToAdcModel;
         FromAdcModel  : in tFromAdcModel;
         Trigger       : in std_ulogic;
         Ack           : out std_ulogic);
  end component;


  -- Define the System FPGA component
  component SystemFpgaTop
    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 out?
  end component SystemFpgaTop;


  -- Define ADC model component
  component AdcModel
    port(ToAdcModel   : in  tToAdcModel;
         FromAdcModel : out tFromAdcModel;
         pAdcClk      : out std_ulogic;
         pAdcTrigger  : out std_ulogic;
         pAdcDataA    : out std_logic_vector(11 downto 0);
         pAdcDataB    : out std_logic_vector(11 downto 0);
         -- Trigger input for internal trigger mode
         pTriggerIn  : in  std_ulogic);
  end component AdcModel;


  -- Define the DSP FPGA component
  component DspFpgaTop
    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;  -- (GCK3 input)
         pnIRQ0      : out   std_ulogic;  -- interrupt
         -- Peripheral FPGA Communications signals
         pZ0         : out   std_ulogic;  -- Clock DLL reset signal
         pZ1         : in    std_ulogic;  -- Serial shaft encoder results enable
         pZ2         : in    std_ulogic;  -- Serial shaft encoder results
         pZ3         : in    std_ulogic;  -- Serial gate data in
         pZ4         : in    std_ulogic;  -- Serial gate data enable in
         pZ5         : in    std_ulogic;  -- Serial gate sel (bit 0)
         pZ6         : in    std_ulogic;  -- Serial gate sel (bit 1)
         pZ7         : in    std_ulogic;  -- Serial gate sel (bit 2)
         pZ8         : out   std_ulogic;  -- B-Scan is active
         pZ9         : out   std_ulogic;  -- Raw External Trigger signal to Peripheral FPGA
         pZ10        : in    std_ulogic;  -- Trigger signal from Peripheral FPGA
         pZ11        : in    std_ulogic;  -- Last A-Scan of current B-Scan
         pZ12        : out   std_ulogic;  -- BEA switch (FPGABusy signal on PCB)
         -- A to D Signals
         pADC_Clk    : in    std_ulogic;  -- Clock from AtoD convertor (GCK2 input)
         pADC_DataA  : in    std_logic_vector(11 downto 0);  -- Data stream A from AtoD convertor
         pADC_DataB  : in    std_logic_vector(11 downto 0);  -- Data stream B from AtoD convertor
         pTrigIn     : in    std_ulogic;  -- Sample run started trigger
         pSampleClk  : in    std_ulogic;  -- Sample clock (GCK0 input)
         -- Bank A SRAM Signals
         pSramA_Addr : out   std_logic_vector(17 downto 0);  -- SRAM Bank A Address bus
         pSramA_Data : inout std_logic_vector(31 downto 0);  -- SRAM Bank A Data bus
         pSramA_nWE  : out   std_ulogic;                     -- SRAM Bank A Read strobe
         pSramA_nRD  : out   std_ulogic;                     -- SRAM Bank A Write strobe
         pSramA_nCS  : out   std_logic_vector(3 downto 0);   -- SRAM Bank A chip selects
         -- Bank B SRAM Signals
         pSramB_Addr : out   std_logic_vector(17 downto 0);  -- SRAM Bank B Address bus
         pSramB_Data : inout std_logic_vector(31 downto 0);  -- SRAM Bank B Data bus
         pSramB_nWE  : out   std_ulogic;                     -- SRAM Bank B Read strobe
         pSramB_nRD  : out   std_ulogic;                     -- SRAM Bank B Write strobe
         pSramB_nCS  : out   std_logic_vector(3 downto 0);   -- SRAM Bank B chip selects
         -- DDS Signals
         pDDS_nWR    : out   std_ulogic;
         pDDSA       : out   std_logic_vector(5 downto 0);
         pDDSD       : out   std_logic_vector(7 downto 0);
         pDDSRESET   : out   std_ulogic;
         pDDS_IO     : in    std_ulogic;
         -- DAC Signels
         pDACCLK     : out   std_ulogic;
         pDAC1WRT    : out   std_ulogic;
         pDAC2WRT    : out   std_ulogic;
         pDACSLEEP   : out   std_ulogic;
         pDACD       : out   std_logic_vector(15 downto 0);
         pDACA       : out   std_logic_vector(17 downto 0);
         --
         pSYNC       : in    std_ulogic;
         -- LEDs
         pLED0       : out   std_ulogic;
         pLED1       : out   std_ulogic);
  end component DspFpgaTop;


  -- Define the component for the SRAM Model
  component SramModel is
    generic (gDataBusWidth : integer := 32;
             gAddrBusWidth : integer := 18);
    port (pData : inout std_logic_vector(gDataBusWidth-1 downto 0);
          pAddr : in    std_logic_vector(gAddrBusWidth-1 downto 0);
          pnCS  : in    std_ulogic;
          pnOE  : in    std_ulogic;
          pnWE  : in    std_ulogic);
  end component SramModel;


  component 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;  -- Asserted when DDS is written to
         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;  -- Last A-Scan of current B-Scan
         pZ12         : in    std_ulogic;  -- BEA switch (FPGABusy signal on PCB)
         -- 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 component PeripheralFpgaTop;


  -- Signals to connect to models used in the system simulation
  signal ToBusModel: tToBusModel;
  signal FromBusModel: tFromBusModel;
  signal ToAdcModel: tToAdcModel;
  signal FromAdcModel: tFromAdcModel;
  signal Pulse: std_ulogic;
  signal Ack: std_ulogic;


  signal nLRESET:    std_ulogic;
  signal LCLKA:      std_ulogic;
  signal LWnR:       std_ulogic;
  signal nADS:       std_ulogic;
  signal nBLAST:     std_ulogic;
  signal nREADY:     std_ulogic;
  signal LA:         std_logic_vector(31 downto 0);
  signal LD:         std_logic_vector(31 downto 0);
  signal LHOLD:      std_ulogic;
  signal LHOLDA:     std_ulogic;
  signal nBTERM:     std_ulogic;
  signal nCCS:       std_ulogic;
  signal BREQi:      std_ulogic;
  signal LINTI:      std_ulogic;
  signal DSPnFpgaCs:    std_ulogic;
  signal PERnFpgaCs:    std_ulogic;

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

  -- FPGA configuration connections and counters
  signal FpgaDone   : std_ulogic;
  signal FpgaInit   : std_ulogic;
  signal FpgaBusy   : std_ulogic;
  signal FpgaCClk   : std_ulogic;  -- FPGA configuration clock
  signal FpgaWrite  : std_ulogic;  -- FPGA write
  signal DspFpgaCS  : std_logic_vector(3 downto 0);  -- Digitising FPGA cs
  signal PerFpgaCS  : std_logic_vector(3 downto 0);  -- Peripheral fpga cs
  signal Program    : std_logic_vector(3 downto 0);
  signal nIRQ       : std_logic_vector(0 downto 0);
  signal DspFpgaLoadCount: integer;
  signal PerFpgaLoadCount: integer;
  signal PerSetupCount:    integer;

  -- Sample SRAM signals
  signal SramA_Addr: std_logic_vector(17 downto 0);
  signal SramA_Data: std_logic_vector(31 downto 0);
  signal SramA_nWE:  std_ulogic;
  signal SramA_nRD:  std_ulogic;
  signal SramA_nCS:  std_logic_vector(3 downto 0);
  signal SramB_Addr: std_logic_vector(17 downto 0);
  signal SramB_Data: std_logic_vector(31 downto 0);
  signal SramB_nWE:  std_ulogic;
  signal SramB_nRD:  std_ulogic;
  signal SramB_nCS:  std_logic_vector(3 downto 0);

  -- ADC signals
  signal Trigger:    std_ulogic;
  signal ADC_Clk:    std_ulogic;
  signal ADC_DataA:  std_logic_vector(11 downto 0);
  signal ADC_DataB:  std_logic_vector(11 downto 0);

  -- DDS signals
  signal DDS_nWR:  std_ulogic;
  signal DDSA:     std_logic_vector(5 downto 0);
  signal DDSD:     std_logic_vector(7 downto 0);
  signal DDSRESET: std_ulogic;
  signal DDS_IO:   std_ulogic;

  -- EEPROM Signals
  signal Eeprom_C:  std_ulogic;
  signal Eeprom_nS: std_ulogic;
  signal Eeprom_D:  std_ulogic;
  signal Eeprom_Q:  std_ulogic;
  signal EepromInstr: std_logic_vector(7 downto 0);
  signal EepromAddr:  std_logic_vector(8 downto 0);
  signal EepromData1: std_logic_vector(31 downto 0);
  signal EepromData2: std_logic_vector(31 downto 0);
  signal EepromData3: std_logic_vector(31 downto 0);
  signal EepromData4: std_logic_vector(31 downto 0);

  -- Encoder Signals
  signal Encoder2: std_logic_vector(1 downto 0);

  signal SampleClk:   std_ulogic;

  -- Peripheral FPGA <-> DSP FPGA connections
  signal Z:  std_logic_vector(12 downto 0);

  -- Generic IO signals
  signal PIO: std_logic_vector(62 downto 2);

  signal TI:        std_logic_vector(7 downto 0);
  signal SysIo:     std_logic_vector(52 downto 0);

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


begin


  -- Instantiate the LocalBus model component
  LocalBusModel0: LocalBusModel
    port map(-- Control signals to/from main simulation module
             ToBusModel    => ToBusModel,
             FromBusModel  => FromBusModel,
             -- Actual bus signals
             pnLRESET      => nLRESET,
             pLCLKA        => LCLKA,
             pLWnR         => LWnR,
             pnADS         => nADS,
             pnBLAST       => nBLAST,
             pnREADY       => nREADY,
             pLA           => LA,
             pLD           => LD,
             pLHOLD        => LHOLD,
             pLHOLDA       => LHOLDA,
             pnBTERM       => nBTERM,
             pnCCS         => nCCS,
             pBREQi        => BREQi,
             pLINTI        => LINTI);

  AdcModel0: AdcModel
    port map(ToAdcModel   => ToAdcModel,
             FromAdcModel => FromAdcModel,
             pAdcClk      => ADC_Clk,
             pAdcTrigger  => Trigger,
             pAdcDataA    => ADC_DataA,
             pAdcDataB    => ADC_DataB,
             pTriggerIn   => Pulse);


  -- Instantiate the Simulation Control component
  SimCtrl0: SimCtrl
    port map(ToBusModel    => ToBusModel,
             FromBusModel  => FromBusModel,
             ToAdcModel    => ToAdcModel,
             FromAdcModel  => FromAdcModel,
             Trigger       => Pulse,
             Ack           => Ack);

  TI <= "00000000";
  SysIo <= (others => 'Z');

  -- Instantiate the DSP FPGA component
  SystemFpgaTop0: SystemFpgaTop
    port map(-- Local bus
             pnLRESET    => nLRESET,
             pLCLKA      => LCLKA,
             pLWnR       => LWnR,
             pnADS       => nADS,
             pnBLAST     => nBLAST,
             pLA         => LA(31 downto 2),
             pLD         => LD,
             pLHOLD      => LHOLD,
             pLHOLDA     => LHOLDA,
             pnREADY     => nREADY,
             pnBTERM     => nBTERM,
             pnCCS       => nCCS,
             pBREQi      => BREQi,
             pLINTI      => LINTI,
             -- System SRAM control
             pnSysRamCS  => nSysRamCS,
             pnSysRamWE  => nSysRamWE,
             pnSysRamOE  => nSysRamOE,
             -- EEPROM connections
             pEeprom_C   => Eeprom_C,
             pEeprom_nS  => Eeprom_nS,
             pEeprom_D   => Eeprom_D,
             pEeprom_Q   => Eeprom_Q,
             -- Generio IO
             pIO         => SysIo,
             -- FPGA connections
             pFpgaDone   => FpgaDone,
             pFpgaInit   => FpgaInit,
             pFpgaBusy   => FpgaBusy,
             pFpgaCClk   => FpgaCClk,
             pFpgaWrite  => FpgaWrite,
             pFpgaCS     => DspFpgaCS,
             pPFpgaCS    => PerFpgaCS,
             pProgram    => Program,
             pIRQ        => nIRQ,
             --
             pTestLed    => open);

  SramModel0: SramModel
    generic map(gDataBusWidth => 32,
                gAddrBusWidth => 18)
    port map(pData => LD,
             pAddr => LA(19 downto 2),
             pnCS  => nSysRamCS,
             pnOE  => nSysRamOE,
             pnWE  => nSysRamWE);

  -- Process to check FPGA's are configured correctly
  process
    variable vLine: Line;
  begin
    FpgaDone  <= '1';
    FpgaInit  <= '1';
    FpgaBusy  <= '1';
    DspFpgaLoadCount <= 0;
    PerFpgaLoadCount <= 0;
    PerSetupCount    <= 0;

    -- Wait for Program to be asserted (low) and then remove Done
    wait on Program until rising_edge(Program(0));
    wait for 300 ns;
    FpgaDone  <= '0';

    -- Take Init low for a time
    wait for 300 ns;
    FpgaInit  <= '0';
    wait for 300 ns;
    FpgaInit  <= '1';
    FpgaBusy  <= '0';

    while FpgaDone = '0' loop
      wait on FpgaCClk until rising_edge(FpgaCClk);

      if DspFpgaCS(0) = '0'  and FpgaWrite = '0' then
        case DspFpgaLoadCount is
          when 0 =>
            if LD = X"DEADBEEF" then
              -- Skip FPGA configuration when magic word is received
              report "Testbench: FPGA configuration simulation skipped"
                severity warning;
              FpgaDone  <= '1';
              wait;
            else
              write (vLine, string'("Testbench: DSP FPGA configuration 0% complete"));
              writeline (OUTPUT, vLine);
            end if;
          when 166980*10/100 - 1 =>
              write (vLine, string'("Testbench: DSP FPGA configuration 10% complete"));
              writeline (OUTPUT, vLine);
          when 166980*20/100 - 1 =>
              write (vLine, string'("Testbench: DSP FPGA configuration 20% complete"));
              writeline (OUTPUT, vLine);
          when 166980*30/100 - 1 =>
              write (vLine, string'("Testbench: DSP FPGA configuration 30% complete"));
              writeline (OUTPUT, vLine);
          when 166980*40/100 - 1 =>
              write (vLine, string'("Testbench: DSP FPGA configuration 40% complete"));
              writeline (OUTPUT, vLine);
          when 166980*50/100 - 1 =>
              write (vLine, string'("Testbench: DSP FPGA configuration 50% complete"));
              writeline (OUTPUT, vLine);
          when 166980*60/100 - 1 =>
              write (vLine, string'("Testbench: DSP FPGA configuration 60% complete"));
              writeline (OUTPUT, vLine);
          when 166980*70/100 - 1 =>
              write (vLine, string'("Testbench: DSP FPGA configuration 70% complete"));
              writeline (OUTPUT, vLine);
          when 166980*80/100 - 1 =>
              write (vLine, string'("Testbench: DSP FPGA configuration 80% complete"));
              writeline (OUTPUT, vLine);
          when 166980*90/100 - 1 =>
              write (vLine, string'("Testbench: DSP FPGA configuration 90% complete"));
              writeline (OUTPUT, vLine);
          when 166980*100/100 - 1 =>
              write (vLine, string'("Testbench: DSP FPGA configuration 100% complete"));
              writeline (OUTPUT, vLine);
          when 166980 =>
            report "Testbench: DSP FPGA has be written with too much configuration data"
              severity error;
          when others => null;
        end case;

        -- Check config data is correct (we only check first and last 10 values!)
        case DspFpgaLoadCount is
          when 0 to 9 =>
            if conv_integer(unsigned(LD(7 downto 0))) /= DspFpgaLoadCount then
              write (vLine, string'("Testbench: Error - DSP FPGA got unexpected config data at position "));
              write (vLine, DspFpgaLoadCount);
              writeline (OUTPUT, vLine);
              report "Testbench: Stop sim" severity failure;
            end if;
          when 166970 to 166979 =>
            if conv_integer(unsigned(LD(7 downto 0))) /= (DspFpgaLoadCount - 166900) then
              write (vLine, string'("Testbench: Error - DSP FPGA got unexpected config data at position "));
              write (vLine, DspFpgaLoadCount);
              writeline (OUTPUT, vLine);
              report "Testbench: Stop sim" severity failure;
            end if;
          when others => null;
        end case;

        DspFpgaLoadCount <= DspFpgaLoadCount + 1;
      end if;


      if PerFpgaCS(0) = '0' and FpgaWrite = '0' then
        case PerFpgaLoadCount is
          when 0 =>
            write (vLine, string'("Testbench: Peripheral FPGA configuration 0% complete"));
            writeline (OUTPUT, vLine);
          when 69900*10/100 - 1 =>
            write (vLine, string'("Testbench: Peripheral FPGA configuration 10% complete"));
            writeline (OUTPUT, vLine);
          when 69900*20/100 - 1 =>
            write (vLine, string'("Testbench: Peripheral FPGA configuration 20% complete"));
            writeline (OUTPUT, vLine);
          when 69900*30/100 - 1 =>
            write (vLine, string'("Testbench: Peripheral FPGA configuration 30% complete"));
            writeline (OUTPUT, vLine);
          when 69900*40/100 - 1 =>
            write (vLine, string'("Testbench: Peripheral FPGA configuration 40% complete"));
            writeline (OUTPUT, vLine);
          when 69900*50/100 - 1 =>
            write (vLine, string'("Testbench: Peripheral FPGA configuration 50% complete"));
            writeline (OUTPUT, vLine);
          when 69900*60/100 - 1 =>
            write (vLine, string'("Testbench: Peripheral FPGA configuration 60% complete"));
            writeline (OUTPUT, vLine);
          when 69900*70/100 - 1 =>
            write (vLine, string'("Testbench: Peripheral FPGA configuration 70% complete"));
            writeline (OUTPUT, vLine);
          when 69900*80/100 - 1 =>
            write (vLine, string'("Testbench: Peripheral FPGA configuration 80% complete"));
            writeline (OUTPUT, vLine);
          when 69900*90/100 - 1 =>
            write (vLine, string'("Testbench: Peripheral FPGA configuration 90% complete"));
            writeline (OUTPUT, vLine);
          when 69900*100/100 - 8 =>
            write (vLine, string'("Testbench: Peripheral FPGA configuration 100% complete"));
            writeline (OUTPUT, vLine);
          when 69900 =>
            report "Testbench: Peripheral FPGA has be written with too much configuration data"
              severity error;
          when others => null;
        end case;

        -- Check config data is correct (we only check first and last 10 values!)
        case PerFpgaLoadCount is
          when 0 to 9 =>
            if conv_integer(unsigned(LD(7 downto 0))) /= PerFpgaLoadCount then
              write (vLine, string'("Testbench: Error - Peripheral FPGA got unexpected config data at position "));
              write (vLine, PerFpgaLoadCount);
              write (vLine, string'(" (Expected "));
              write (vLine, (PerFpgaLoadCount));
              write (vLine, string'(" got "));
              write (vLine, (conv_integer(unsigned(LD(7 downto 0)))));
              write (vLine, string'(")"));
              writeline (OUTPUT, vLine);
              report "Testbench: Stop sim" severity failure;
            end if;
          when 69890 to 69892 =>  -- Very wrong should be 69900, but seems to work...
            if conv_integer(unsigned(LD(7 downto 0))) /= (PerFpgaLoadCount - 69800) then
              write (vLine, string'("Testbench: Error - Peripheral FPGA got unexpected config data at position "));
              write (vLine, PerFpgaLoadCount);
              write (vLine, string'(" (Expected "));
              write (vLine, (PerFpgaLoadCount - 69800));
              write (vLine, string'(" got "));
              write (vLine, (conv_integer(unsigned(LD(7 downto 0)))));
              write (vLine, string'(")"));
              writeline (OUTPUT, vLine);
              report "Testbench: Stop sim" severity failure;
            end if;
          when others => null;
        end case;

        PerFpgaLoadCount <= PerFpgaLoadCount + 1;
      elsif DspFpgaCS(0) = '1' and PerFpgaCS(0) = '1' then
        if DspFpgaLoadCount = 166980 and PerFpgaLoadCount = 69893 and PerSetupCount = 7 then
          -- Both FPGAs have had the correct number of bytes written to them
          FpgaDone  <= '1';
        end if;

        PerSetupCount <= PerSetupCount + 1;
      end if;


    end loop;

    wait;

  end process;


  DSPnFpgaCs <= DspFpgaCS(0) when FpgaDone = '1' else '1';
  PERnFpgaCs <= PerFpgaCS(0) when FpgaDone = '1' else '1';


  -- Generate a DDS_IO signal
  GenDDsIO: process
  begin
    DDS_IO <= '0';
    wait for 250 ns;
    DDS_IO <= '1';
    wait for 120 ns;
  end process GenDDsIO;


  -- Instantiate the DSP FPGA component
  DspFpgaTop0: DspFpgaTop
    port map(-- Local bus
             pnLReset    => nLRESET,
             pnFpgaCs    => DSPnFpgaCs,
             pLWnR       => LWnR,
             pLA         => LA(31 downto 2),
             pLD         => LD,
             pLCLK       => LCLKA,
             pnIRQ0      => nIRQ(0),
             -- Peripheral FPGA communications signals
             pZ0         => Z(0),
             pZ1         => Z(1),
             pZ2         => Z(2),
             pZ3         => Z(3),
             pZ4         => Z(4),
             pZ5         => Z(5),
             pZ6         => Z(6),
             pZ7         => Z(7),
             pZ8         => Z(8),
             pZ9         => Z(9),
             pZ10        => Z(10),
             pZ11        => Z(11),
             pZ12        => Z(12),
             -- A to D Signals
             pADC_Clk    => ADC_Clk,
             pADC_DataA  => ADC_DataA,
             pADC_DataB  => ADC_DataB,
             pTrigIn     => Trigger,
             pSampleClk  => cGnd,  -- Not used
             -- Bank A SRAM Signals
             pSramA_Addr => SramA_Addr,
             pSramA_Data => SramA_Data,
             pSramA_nWE  => SramA_nWE,
             pSramA_nRD  => SramA_nRD,
             pSramA_nCS  => SramA_nCS,
             -- Bank B SRAM Signals
             pSramB_Addr => SramB_Addr,
             pSramB_Data => SramB_Data,
             pSramB_nWE  => SramB_nWE,
             pSramB_nRD  => SramB_nRD,
             pSramB_nCS  => SramB_nCS,
             -- DDS Signals
             pDDS_nWR    => DDS_nWR,
             pDDSA       => DDSA,
             pDDSD       => DDSD,
             pDDSRESET   => DDSRESET,
             pDDS_IO     => DDS_IO,
             -- DAC Signels
             pDACCLK     => open,
             pDAC1WRT    => open,
             pDAC2WRT    => open,
             pDACSLEEP   => open,
             pDACD       => open,
             pDACA       => open,
             --
             pSYNC       => Ack,
             -- LEDs
             pLED0       => open,
             pLED1       => open);

-- Debug
--SramA_Data <= "00000000000000" & SramA_Addr when SramA_nRD = '0' else "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
--SramB_Data <= "00000000000000" & SramB_Addr when SramB_nRD = '0' else "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";

  SampleSramModelA0: SramModel
    generic map(gDataBusWidth => 32,
                gAddrBusWidth => 18)
    port map(pData => SramA_Data,
             pAddr => SramA_Addr,
             pnCS  => SramA_nCS(0),
             pnOE  => SramA_nRD,
             pnWE  => SramA_nWE);

  SampleSramModelA1: SramModel
    generic map(gDataBusWidth => 32,
                gAddrBusWidth => 18)
    port map(pData => SramA_Data,
             pAddr => SramA_Addr,
             pnCS  => SramA_nCS(1),
             pnOE  => SramA_nRD,
             pnWE  => SramA_nWE);

  SampleSramModelA2: SramModel
    generic map(gDataBusWidth => 32,
                gAddrBusWidth => 18)
    port map(pData => SramA_Data,
             pAddr => SramA_Addr,
             pnCS  => SramA_nCS(2),
             pnOE  => SramA_nRD,
             pnWE  => SramA_nWE);

  SampleSramModelA3: SramModel
    generic map(gDataBusWidth => 32,
                gAddrBusWidth => 18)
    port map(pData => SramA_Data,
             pAddr => SramA_Addr,
             pnCS  => SramA_nCS(3),
             pnOE  => SramA_nRD,
             pnWE  => SramA_nWE);

  SampleSramModelB0: SramModel
    generic map(gDataBusWidth => 32,
                gAddrBusWidth => 18)
    port map(pData => SramB_Data,
             pAddr => SramB_Addr,
             pnCS  => SramB_nCS(0),
             pnOE  => SramB_nRD,
             pnWE  => SramB_nWE);

  SampleSramModelB1: SramModel
    generic map(gDataBusWidth => 32,
                gAddrBusWidth => 18)
    port map(pData => SramB_Data,
             pAddr => SramB_Addr,
             pnCS  => SramB_nCS(1),
             pnOE  => SramB_nRD,
             pnWE  => SramB_nWE);

  SampleSramModelB2: SramModel
    generic map(gDataBusWidth => 32,
                gAddrBusWidth => 18)
    port map(pData => SramB_Data,
             pAddr => SramB_Addr,
             pnCS  => SramB_nCS(2),
             pnOE  => SramB_nRD,
             pnWE  => SramB_nWE);

  SampleSramModelB3: SramModel
    generic map(gDataBusWidth => 32,
                gAddrBusWidth => 18)
    port map(pData => SramB_Data,
             pAddr => SramB_Addr,
             pnCS  => SramB_nCS(3),
             pnOE  => SramB_nRD,
             pnWE  => SramB_nWE);


  PeripheralFpgaTop0: PeripheralFpgaTop
    port map(-- Local bus
             pnLReset     => nLRESET,
             pnFpgaCs     => PERnFpgaCs,
             pLWnR        => LWnR,
             pLA          => LA(31 downto 2),
             pLD          => LD,
             pLCLK        => LCLKA,
             pSampleClk   => SampleClk,
             pEncoder0In  => "00",
             pEncoder1In  => "00",
             pEncoder2In  => Encoder2,
             pEncoder3In  => "00",
             pEncoder4In  => "00",
             pEncoder5In  => "00",
             pSEL_1M_50R  => open,
             pSEL_AC_DC   => open,
             pATOD_RANGE  => open,
             pDATA_FORMAT => open,
             pPORT_FORMAT => open,
             pSENSE       => open,
             pDdsKey      => open,
             pDdsFsk      => open,
             pAIN         => open,
             pAUX         => open,
             pGAIN        => open,
             pCAL         => open,
             pPIO         => PIO,
             pProbeSense  => cGnd,
             pProbeAper   => open,
             pProbeDSel   => open,
             pProbeDClk   => open,
             pProbeTx     => Pulse,
             pProbeData   => open,
             pZ0          => Z(0),
             pZ1          => Z(1),
             pZ2          => Z(2),
             pZ3          => Z(3),
             pZ4          => Z(4),
             pZ5          => Z(5),
             pZ6          => Z(6),
             pZ7          => Z(7),
             pZ8          => Z(8),
             pZ9          => Z(9),
             pZ10         => Z(10),
             pZ11         => Z(11),
             pZ12         => z(12),
             pCalDac_SDI  => open,
             pCalDac_CLK  => open,
             pCalDac_nLD  => open,
             pCalDac_nCS  => open,
             pLED_D8      => open,
             pLED_D9      => open);


  EepromModel: process
    constant cReadData1: std_logic_vector(7 downto 0) := X"12";
    constant cReadData2: std_logic_vector(7 downto 0) := X"34";
    constant cReadData3: std_logic_vector(7 downto 0) := X"56";
    constant cReadData4: std_logic_vector(7 downto 0) := X"78";
    constant cReadData5: std_logic_vector(7 downto 0) := X"DE";
    constant cReadData6: std_logic_vector(7 downto 0) := X"AD";
    constant cReadData7: std_logic_vector(7 downto 0) := X"BE";
    constant cReadData8: std_logic_vector(7 downto 0) := X"EF";
    constant cReadData9: std_logic_vector(7 downto 0) := X"FE";
    constant cReadData10: std_logic_vector(7 downto 0) := X"ED";
    constant cReadData11: std_logic_vector(7 downto 0) := X"B0";
    constant cReadData12: std_logic_vector(7 downto 0) := X"0B";
    constant cReadData13: std_logic_vector(7 downto 0) := X"FE";
    constant cReadData14: std_logic_vector(7 downto 0) := X"DC";
    constant cReadData15: std_logic_vector(7 downto 0) := X"BA";
    constant cReadData16: std_logic_vector(7 downto 0) := X"98";

    constant cStatus:   std_logic_vector(7 downto 0) := X"FE";
  begin
    Eeprom_Q <= '1';

    wait on Eeprom_nS until falling_edge(Eeprom_nS);

    for Count in 7 downto 0 loop
      wait on Eeprom_C until rising_edge(Eeprom_C);
      EepromInstr(Count) <= Eeprom_D;
    end loop;

    wait for 1 ps;

    if EepromInstr = X"05" then  -- Read Status reg
        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cStatus(Count);
        end loop;
        wait on Eeprom_C until falling_edge(Eeprom_C);
    end if;

    if EepromInstr = X"03" then  -- Read Memory Array
      -- Get past address
      EepromAddr(8) <= EepromInstr(3);
      for Count in 7 downto 0 loop
        wait on Eeprom_C until rising_edge(Eeprom_C);
        EepromAddr(Count) <= Eeprom_D;
      end loop;

      for MyLoop in 0 to 31 loop
        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData1(Count);
        end loop;
        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData2(Count);
        end loop;
        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData3(Count);
        end loop;
        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData4(Count);
        end loop;

        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData5(Count);
        end loop;
        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData6(Count);
        end loop;
        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData7(Count);
        end loop;
        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData8(Count);
        end loop;

        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData9(Count);
        end loop;
        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData10(Count);
        end loop;
        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData11(Count);
        end loop;
        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData12(Count);
        end loop;

        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData13(Count);
        end loop;
        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData14(Count);
        end loop;
        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData15(Count);
        end loop;
        for Count in 7 downto 0 loop
          wait on Eeprom_C until falling_edge(Eeprom_C);
          Eeprom_Q <= cReadData16(Count);
        end loop;

      end loop;
    end if;

    if EepromInstr = X"02" or EepromInstr = X"0A" then  -- Write Memory Array
      -- Get past address
      EepromAddr(8) <= EepromInstr(3);
      for Count in 7 downto 0 loop
        wait on Eeprom_C until rising_edge(Eeprom_C);
        EepromAddr(Count) <= Eeprom_D;
      end loop;

      for Count in 31 downto 0 loop
        wait on Eeprom_C until rising_edge(Eeprom_C);
        EepromData1(Count) <= Eeprom_D;
      end loop;
      for Count in 31 downto 0 loop
        wait on Eeprom_C until rising_edge(Eeprom_C);
        EepromData2(Count) <= Eeprom_D;
      end loop;
      for Count in 31 downto 0 loop
        wait on Eeprom_C until rising_edge(Eeprom_C);
        EepromData3(Count) <= Eeprom_D;
      end loop;
      for Count in 31 downto 0 loop
        wait on Eeprom_C until rising_edge(Eeprom_C);
        EepromData4(Count) <= Eeprom_D;
      end loop;

    end if;
  end process EepromModel;


  GenEncoderData: process

    function IncEncoderValue(EncValue: in std_logic_vector(1 downto 0)) return std_logic_vector is
    begin
      case EncValue is
        when "00"   => return "10";
        when "01"   => return "00";
        when "10"   => return "11";
        when others => return "01";
      end case;
    end function IncEncoderValue;

    function DecEncoderValue(EncValue: in std_logic_vector(1 downto 0)) return std_logic_vector is
    begin
      case EncValue is
        when "00"   => return "01";
        when "01"   => return "11";
        when "10"   => return "00";
        when others => return "10";
      end case;
    end function DecEncoderValue;

  begin
    Encoder2 <= "00";

    for Count in 1 to 200 loop
      wait for 2 us;
      Encoder2 <= IncEncoderValue(Encoder2);
    end loop;

    for Count in 1 to 45 loop
      wait for 2 us;
      Encoder2 <= IncEncoderValue(Encoder2);
    end loop;

    for Count in 1 to 242 loop
      wait for 2 us;
      Encoder2 <= IncEncoderValue(Encoder2);
    end loop;

    for Count in 1 to 400 loop
      wait for 2 us;
      Encoder2 <= DecEncoderValue(Encoder2);
    end loop;
  end process GenEncoderData;




  GenSampleClk: process
  begin
    SampleClk <= '0';
    wait for 5 ns;
    SampleClk <= '1';
    wait for 5 ns;
  end process GenSampleClk;


end architecture Test;