---------------------------------------------------------------------------
-- NDT Solutions Ltd. Proprietary Information
-- Company Confidential
-- Copyright 2004
--
-- Filename: CurvedGate.vhd
-- Language: VHDL '93
-- Project:  Digitiser Card DSP FPGA
--
-- Design Description:
-- Module to to implement curved Gate
--
---------------------------------------------------------------------------

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

entity CurvedGate is
  port(pnReset         : in  std_ulogic;
       pADC_2xClk      : in  std_ulogic;
       pSampleEn       : in  std_ulogic;
       pTriggersIn     : in  std_logic_vector(15 downto 0);
       pNoTriggersIn   : in  std_logic_vector(15 downto 0);
       pEnable         : in  std_ulogic;
       pStartCount     : in  std_logic_vector(15 downto 0);
       pStopCount      : in  std_logic_vector(15 downto 0);
       pForceStop      : in  std_ulogic;
       pThresPoints    : in  std_logic_vector(2 downto 0);
       pTriggerNum     : in  std_logic_vector(3 downto 0);
       pTriggerMode    : in  std_ulogic;
       pPolarityMode   : in  std_logic_vector(1 downto 0);
       pDistMetric     : in  std_logic_vector(1 downto 0);
       pPeakSelAmp     : in  std_logic_vector(3 downto 0);
       pPeakSelDist    : in  std_logic_vector(3 downto 0);
       pHoldoff        : in  std_logic_vector(6 downto 0);
       pSampleData     : in  std_logic_vector(11 downto 0);
       pRectifiedData  : in  std_logic_vector(10 downto 0);
       pThreshAddr     : out std_logic_vector(11 downto 0);
       pThreshData     : in  std_logic_vector(10 downto 0);
       pStoreNoTrig    : in  std_ulogic;
       pGateDistFire   : out std_ulogic;
       pGateFiring     : out std_ulogic;
       pGateUnTrigger  : out std_ulogic;
       pGateFired      : out std_ulogic;
       pGateDidNotFire : out std_ulogic;
       pGateOutputData : out std_logic_vector(13 downto 0));
end entity CurvedGate;


architecture Rtl of CurvedGate is

  attribute equivalent_register_removal : string;
  attribute register_balancing: string;

  signal PeakSelAmp:     std_logic_vector(3 downto 0);
  signal LastSelAmp:     std_ulogic;
  signal CheckAllPeaks:  std_ulogic;
  signal MaxSelAmp:      std_ulogic;
  signal PeakSelDist:    std_logic_vector(3 downto 0);
  signal LastSelDist:    std_ulogic;
  signal MaxSelDist:     std_ulogic;
  signal DistPeakNext:  std_ulogic;
  signal AmpPeakNext:   std_ulogic;
  
  signal HoldoffCount: integer range 0 to 127;

  signal RawSampleEarly: std_logic_vector(11 downto 0);
  signal RawSampleData:  std_logic_vector(11 downto 0);
  signal NewSampleEarly: std_logic_vector(10 downto 0);
  signal NewSampleData:  std_logic_vector(10 downto 0);

  signal Trigger:        std_ulogic;
  signal NoTrigger:      std_ulogic;
  signal TriggerRst:     std_ulogic;

  signal TimeCount:      std_logic_vector(15 downto 0);
  signal TimeDone:       std_ulogic;
  signal GateOpenE1:     std_ulogic;
  signal GateOpenE2:     std_ulogic;
  signal GateOpen:       std_ulogic;
  signal GateCloseE1:    std_ulogic;
  signal GateCloseE2:    std_ulogic;
  signal GateClose:      std_ulogic;
  signal GateCloseD1:    std_ulogic;
  signal GateActiveE1:   std_ulogic;
  signal GateActiveE2:   std_ulogic;
  signal GateActive:     std_ulogic;
  signal GateFiring:     std_ulogic;
  signal GateFired:      std_ulogic;
  signal GateDidNotFire: std_ulogic;
  signal AmpFired:       std_ulogic;
  signal GateDistFire:   std_ulogic;
  signal GateDistDel:    std_ulogic;
  signal GateDistFiring: std_ulogic;

  signal ThreshData:            std_logic_vector(10 downto 0);
  signal DataLessThreshold:     std_ulogic;
  signal LastDataLessThreshold: std_ulogic;

  signal LeadFlank:       std_ulogic;  -- Signal asserted when a lead flank is seen
  signal TrailFlank:      std_ulogic;  -- Signal asserted wgen a trailing flank is seen
  signal PeakActive:      std_ulogic;
  signal TrigPeakActive:  std_ulogic;
  signal TrigPeakClose:   std_ulogic;
  signal AmpPeakActive:   std_ulogic;
  signal AmpPeakDone:     std_ulogic;
  signal AmpPeakClose:    std_ulogic;
  signal PeakCount:       integer range 0 to 15;
  signal PeakCountValid:  std_ulogic;

  signal MaxTrigPeak:  std_logic_vector(10 downto 0);
  signal NewMaxPeak:   std_ulogic;

  signal LeadEdgeDetectDone:  std_ulogic;
  signal TrailEdgeDetectDone: std_ulogic;

  signal MaxDataValue:    std_logic_vector(10 downto 0);
  signal MaxDataValueRaw: std_logic_vector(11 downto 0);
  signal StoredDataValue: std_logic_vector(11 downto 0);

  signal StatusNibble:    std_logic_vector(3 downto 0);

  signal MaxCurrentPeak: std_logic_vector(10 downto 0);
  signal MaxPeakUpdate:  std_ulogic;
  signal PeakMaxima:     std_ulogic;

  signal ThreshAddr:     std_logic_vector(11 downto 0);
  signal ThreshCE:       std_ulogic;


begin

  -- Decode pPeakSelAmp input from registers
  DecodePeakSelAmp: process(pPeakSelAmp)
    variable vSelect: integer range 0 to 15;
  begin
     vSelect := conv_integer(unsigned(pPeakSelAmp));
    case vSelect is
      when 0 to 16#D# =>
        -- Specified peak select
        PeakSelAmp <= pPeakSelAmp;
        LastSelAmp    <= '0';
        CheckAllPeaks <= '0';
        MaxSelAmp     <= '0';
      when 16#E# =>
        -- Last peak select
        PeakSelAmp    <= X"0";
        LastSelAmp    <= '1';
        CheckAllPeaks <= '1';
        MaxSelAmp     <= '0';
      when 16#F# =>
        -- Max peak select
        PeakSelAmp    <= X"0";
        LastSelAmp    <= '0';
        CheckAllPeaks <= '1';
        MaxSelAmp     <= '1';
    end case;
  end process DecodePeakSelAmp;


  -- Decode pPeakSelDist input from registers
  DecodePeakSelDist: process(pPeakSelDist)
    variable vSelect: integer range 0 to 15;
  begin
     vSelect := conv_integer(unsigned(pPeakSelDist));
    case vSelect is
      when 0 to 16#D# =>
        -- Specified peak select
        PeakSelDist <= pPeakSelDist;
        LastSelDist <= '0';
        MaxSelDist  <= '0';
      when 16#E# =>
        -- Last peak select
        PeakSelDist <= pPeakSelDist;
        LastSelDist <= '1';
        MaxSelDist  <= '0';
      when 16#F# =>
        -- Max peak select
        PeakSelDist <= pPeakSelDist;
        LastSelDist <= '1';
        MaxSelDist  <= '1';
    end case;
  end process DecodePeakSelDist;



  GenTrigger: process(pnReset, pADC_2xClk)
  begin
    if pnReset = '0' then
      Trigger   <= '0';
      NoTrigger <= '0';
    elsif rising_edge(pADC_2xClk) then
      if pSampleEn = '1' then
        case pTriggerNum is
          when "0000" => Trigger   <= pTriggersIn(0);
                         NoTrigger <= pNoTriggersIn(0);
          when "0001" => Trigger   <= pTriggersIn(1);
                         NoTrigger <= pNoTriggersIn(1);
          when "0010" => Trigger   <= pTriggersIn(2);
                         NoTrigger <= pNoTriggersIn(2);
          when "0011" => Trigger   <= pTriggersIn(3);
                         NoTrigger <= pNoTriggersIn(3);
          when "0100" => Trigger   <= pTriggersIn(4);
                         NoTrigger <= pNoTriggersIn(4);
          when "0101" => Trigger   <= pTriggersIn(5);
                         NoTrigger <= pNoTriggersIn(5);
          when "0110" => Trigger   <= pTriggersIn(6);
                         NoTrigger <= pNoTriggersIn(6);
          when "0111" => Trigger   <= pTriggersIn(7);
                         NoTrigger <= pNoTriggersIn(7);
--          when "1000" => Trigger   <= pTriggersIn(8);
--                         NoTrigger <= pNoTriggersIn(8);
--          when "1001" => Trigger   <= pTriggersIn(9);
--                         NoTrigger <= pNoTriggersIn(9);
          when "1111" => Trigger   <= pTriggersIn(15);
                         NoTrigger <= pNoTriggersIn(15);
          when others => Trigger   <= pTriggersIn(15);
                         NoTrigger <= pNoTriggersIn(15);
        end case;
      end if;
    end if;
  end process GenTrigger;

  TriggerRst <= pTriggersIn(15) or Trigger;

  -- Create a rectified datastream depending on the pPolarityMode control input
  ProcessSampleData: process(pnReset, pADC_2xClk)
  begin
    if pnReset = '0' then
      RawSampleEarly <= X"000";
      RawSampleData  <= X"000";
      NewSampleEarly <= (others => '0');
      NewSampleData  <= (others => '0');

    elsif rising_edge(pADC_2xClk) then
      if pSampleEn = '1' then
        RawSampleEarly <= pSampleData;
        RawSampleData  <= RawSampleEarly;

        -- Create a rectified version of the data depending on the Polarity Mode
        case pPolarityMode is
          when "00" =>  -- Bipolar mode
            NewSampleEarly <= pRectifiedData;

          when "01" =>  -- +Ve threshold
            if pSampleData(11) = '0' then  -- +Ve Sample
              NewSampleEarly <= pRectifiedData;
            else
              NewSampleEarly <= (others => '0');
            end if;

          when others =>  -- "10" -Ve threshold
            if pSampleData(11) = '1' then
              NewSampleEarly <= pRectifiedData;
            else
              NewSampleEarly <= (others => '0');
            end if;
        end case;

        NewSampleData <= NewSampleEarly;
      end if;
    end if;
  end process ProcessSampleData;


  GenGateActive: process(pnReset, pADC_2xClk)
  begin
    if pnReset = '0' then
      TimeCount    <= (others => '1');
      GateOpenE1   <= '0';
      GateOpenE2   <= '0';
      GateOpen     <= '0';
      GateCloseE1  <= '0';
      GateCloseE2  <= '0';
      GateClose    <= '0';
      GateActiveE1 <= '0';
      GateActiveE2 <= '0';
      GateActive   <= '0';
      TimeDone     <= '0';
    elsif rising_edge(pADC_2xClk) then
      GateOpenE1    <= '0';
      GateCloseE1   <= '0';

      if GateActive = '1' and (TimeDone = '1' or pForceStop = '1') then
        GateCloseE1  <= '1';
        GateActiveE1 <= '0';
         
      elsif TimeCount = pStopCount and TimeDone = '0' then
        -- Gate has closed
        GateCloseE1   <= '1';
        GateActiveE1  <= '0';
        TimeDone      <= '1';

      elsif TimeCount = pStartCount and TimeDone = '0' then
        -- Gate has become active
        GateOpenE1    <= '1';
        GateActiveE1  <= '1';
      end if;

      GateOpenE2   <= GateOpenE1;
      GateOpen     <= GateOpenE2;
      GateCloseE2  <= GateCloseE1;
      GateClose    <= GateCloseE2;
      GateActiveE2 <= GateActiveE1;
      GateActive   <= GateActiveE2;

      if Trigger = '1' then
        GateActiveE1 <= '0';
        GateActiveE2 <= '0';
        GateActive   <= '0';
      end if;

      if pSampleEn = '1' then
        if Trigger = '1' then
          TimeCount <= (others => '0');
        elsif TimeDone = '0' then
          TimeCount <= unsigned(TimeCount) + 1;
        end if;

        if Trigger = '1' then
          TimeDone  <= '0';
        elsif TimeCount = "1111111111111111" then
          TimeDone  <= '1';
        end if;

        if (pEnable = '0' or pForceStop = '1') then
          TimeDone <= '1';
        end if;
      end if;
    end if;
  end process GenGateActive;


  -- Process to analyse data stream and detect edges and so on
  AnalyseDatastream:  process(pnReset, pADC_2xClk)
    variable vTemp: std_logic_vector(1 downto 0);
  begin
    if pnReset = '0' then
      LeadFlank           <= '0';
      TrailFlank          <= '0';
      LeadEdgeDetectDone  <= '0';
      TrailEdgeDetectDone <= '0';
      PeakActive          <= '0';
      TrigPeakActive      <= '0';
      AmpPeakActive       <= '0';
      AmpPeakClose        <= '0';
      AmpPeakDone         <= '0';
      TrigPeakClose       <= '0';
      AmpFired            <= '0';

    elsif rising_edge(pADC_2xClk) then
      if pSampleEn = '1' then
        AmpPeakClose  <= '0';
        TrigPeakClose <= '0';
      end if;

        if GateActive = '1' then
          if pTriggerMode = '1' then
            --
            -- Edge trigger detection
            --
            if LastDataLessThreshold = '1' and DataLessThreshold = '0' then
              -- Leading edge crossing of a +ve threshold
              LeadFlank  <= '1';
              PeakActive <= '1';

              if DistPeakNext = '1' or LastSelDist = '1' then
                TrigPeakActive <= '1';
              end if;

              if AmpPeakNext = '1' or CheckAllPeaks = '1' then
                AmpPeakActive <= '1';
                AmpFired      <= '1';
              end if;

            else
              LeadFlank <= '0';
            end if;

          else  -- pTriggerMode = '0'
            --
            -- Level trigger detection
            --
            if GateActive = '1' and DataLessThreshold = '0' and PeakActive = '0' then
              -- Leading edge reaches a +ve threshold
              LeadFlank  <= '1';
              PeakActive <= '1';

              if DistPeakNext = '1' or LastSelDist = '1' then
                TrigPeakActive <= '1';
              end if;

              if AmpPeakNext = '1' or CheckAllPeaks = '1' then
                AmpPeakActive <= '1';
                AmpFired      <= '1';
              end if;

            else
              LeadFlank <= '0';
            end if;
          end if;

          if DataLessThreshold = '1' and PeakActive = '1' then
            -- Trailing edge crossing of a +ve threshold
            TrailFlank <= '1';
            PeakActive <= '0';
            if TrigPeakActive = '1' then
              TrigPeakClose <= '1';
            end if;
            TrigPeakActive <= '0';
            if AmpPeakActive = '1' then
              AmpPeakDone  <= '1';
              AmpPeakClose <= '1';
            end if;
            if MaxSelAmp /= '1' then
              AmpPeakActive  <= '0';
            end if;

          elsif pSampleEn = '1' then
            TrailFlank <= '0';
          end if;

        else  -- GateActive = '0'
          -- Force a Trailing Flank if we are in active peak when the gate closes
          if PeakActive = '1' then
            PeakActive     <= '0';
            if TrigPeakActive = '1' then
              TrigPeakClose <= '1';
            end if;
            TrigPeakActive <= '0';
            if AmpPeakActive = '1' then
              AmpPeakDone  <= '1';
              AmpPeakClose <= '1';
            end if;
            if MaxSelAmp /= '1' then
              AmpPeakActive  <= '0';
            end if;
            TrailFlank <= '1';

          elsif pSampleEn = '1' then  -- PeakActive = '0'
            TrailFlank <= '0';
          end if;
        end if;

        -- Reset for signals at the beginning of each A-Scan
        if TriggerRst = '1' then
          LeadEdgeDetectDone  <= '0';
          TrailEdgeDetectDone <= '0';
          PeakActive          <= '0';
          TrigPeakActive      <= '0';
          AmpPeakDone         <= '0';
          AmpPeakActive       <= '0';
          AmpFired            <= '0';
        end if;
    end if;
  end process AnalyseDatastream;



  -- Generate a CE for the threshold data
  GenThreshCE: process(pnReset, pADC_2xClk)
    variable vCount: integer range 0 to 7;
  begin
    if pnReset = '0' then
      ThreshCE <= '0';
      vCount   := 0;
    elsif rising_edge(pADC_2xClk) then
      if pSampleEn = '1' then
        if GateActiveE1 = '1' then
          if vCount = 0 then
            ThreshCE <= '1';
          else
            ThreshCE <= '0';
          end if;
        else
--          if pThresPoints = "000" then
            ThreshCE <= '1';
--          else
--            ThreshCE <= '0';
--          end if;
        end if;

        if GateActiveE1 = '1' then
          if vCount = 0 then
            vCount := conv_integer(unsigned(pThresPoints));
          else
            vCount := vCount - 1;
          end if;
        else
          vCount := conv_integer(unsigned(pThresPoints));
        end if;
      end if;
    end if;
  end process GenThreshCE;


  -- Generate the address for the threshold data
  GenThreshAddr: process(pnReset, pADC_2xClk)
  begin
    if pnReset = '0' then
      ThreshAddr <= X"000";
    elsif rising_edge(pADC_2xClk) then
      if pSampleEn = '1' and ThreshCE = '1' then
        if GateActiveE1 = '1' then
          if ThreshAddr /= X"FFF" then
            ThreshAddr <= unsigned(ThreshAddr) + 1;
          end if;
        else
          ThreshAddr <= X"000";
        end if;
      end if;
    end if;
  end process GenThreshAddr;

  pThreshAddr <= ThreshAddr;


  GenDataLessThreshold: process(pnReset, pADC_2xClk)
  begin
    if pnReset = '0' then
      ThreshData            <= (others => '0');
      DataLessThreshold     <= '0';
      LastDataLessThreshold <= '0';
      HoldoffCount          <= 0;

    elsif rising_edge(pADC_2xClk) then
      if pSampleEn = '1' then
        ThreshData <= pThreshData;
        
        if NewSampleEarly >= ThreshData and PeakCount = 0 then
          HoldoffCount <= conv_integer(unsigned(pHoldoff));  -- Reset holdoff count
        else
          if HoldoffCount /= 0 then
            HoldoffCount <= HoldoffCount - 1;  -- Count down holdoff count
          end if;
        end if;

        if NewSampleEarly < ThreshData and HoldoffCount = 0 then
          DataLessThreshold <= '1';
        else
          DataLessThreshold <= '0';
        end if;

        -- Latch the last value of signal
        LastDataLessThreshold <= DataLessThreshold;
      end if;
    end if;
  end process;


  GenPeakCount: process(pnReset, pADC_2xClk)
  begin
    if pnReset = '0' then
      PeakCount <= 0;
      PeakCountValid <= '1';
      DistPeakNext <= '0';
      AmpPeakNext  <= '0';

    elsif rising_edge(pADC_2xClk) then
      if pSampleEn = '1' then
        -- Count how many peaks we have seen
        if TriggerRst = '1' then
          PeakCount <= 0;
          PeakCountValid <= '1';
        elsif LeadFlank = '1' then
          if (PeakCount = 15) then 
            PeakCountValid <= '0'; -- disable when max peak count reached
          else
            PeakCount <= (PeakCount + 1) mod 16;
          end if;
        end if;

        if (PeakCountValid ='1') then
          -- Check if the next peak is the selected distance metric peak
          -- Only update at the end of a peak unless first peak is selected
          if TrailFlank = '1' or PeakCount = 0 then
            if PeakCount = conv_integer(unsigned(PeakSelDist)) then
              DistPeakNext <= '1';
            else
              DistPeakNext <= '0';
            end if;
          end if;

          -- Check if the next peak is the selected amplitude metric peak
          if PeakCount = conv_integer(unsigned(PeakSelAmp)) then
            AmpPeakNext <= '1';
          else
            AmpPeakNext <= '0';
          end if;
        end if;
      end if;
    end if;
  end process GenPeakCount;



  GenGateOutputs: process(pnReset, pADC_2xClk)
  begin
    if pnReset = '0' then
      GateCloseD1    <= '0';
      GateFired      <= '0';
      GateFiring     <= '0';
      GateDidNotFire <= '0';
    elsif rising_edge(pADC_2xClk) then
      if pSampleEn = '1' then
        GateFiring <= '0';

        if NoTrigger = '1' then
          -- Our reference gate did not trigger, therefore we cannot fire either
          GateFired      <= '0';
          GateDidNotFire <= '1';

        elsif Trigger = '1' then
          -- Reset flags on trigger
          GateFired      <= '0';
          GateDidNotFire <= '0';

        elsif GateActive = '1' then
          case pDistMetric is
            when "00" =>  -- Leading Edge
              if LeadFlank = '1' then
                if (GateFired = '0' and DistPeakNext = '1') or LastSelDist = '1' then
                  GateFired  <= '1';
                  GateFiring <= '1';
                end if;
              end if;

            when "01" =>  -- Trailing Edge
              if TrailFlank = '1' then
                if (GateFired = '0' and DistPeakNext = '1') or LastSelDist = '1' then
                  if MaxSelDist /= '1' or NewMaxPeak /= '0' then
                    -- Only trigger on Max peak when Max peak selected
                    GateFired  <= '1';
                    GateFiring <= '1';
                  end if;
                end if;
              end if;

            when others =>  -- (10) Peak
              if PeakMaxima = '1' then
                if DistPeakNext = '1' or LastSelDist = '1' then
                  if MaxSelDist /= '1' or NewMaxPeak /= '0' then
                    -- Only trigger on Max peak when Max peak selected
                    GateFired  <= '1';
                    GateFiring <= '1';
                  end if;
                end if;
              end if;
          end case;

        elsif TrigPeakClose = '1' and (MaxSelDist /= '1' or GateFired = '0') then
          -- Gate closed before trailing edge trigger
          GateFired       <= '1';
          GateFiring      <= '1';

        elsif GateCloseD1 = '1' and GateFired = '0' then
          -- Gate closed with no active trigger
          GateDidNotFire <= '1';
        end if;

      end if;
    end if;
  end process GenGateOutputs;


  -- Find Max point of peak
  FindMaxPoint: process(pnReset, pADC_2xClk)
  begin
    if pnReset = '0' then
      MaxCurrentPeak <= (others => '0');
      MaxPeakUpdate  <= '0';
      PeakMaxima     <= '0';

    elsif rising_edge(pADC_2xClk) then
      if pSampleEn = '1' then
        PeakMaxima <= '0';
      end if;

      if PeakActive = '0' then
        -- Reset values between peaks
        MaxCurrentPeak <= NewSampleData;
        MaxPeakUpdate  <= '1';
        PeakMaxima     <= '0';
      else
        if MaxCurrentPeak < NewSampleData then
          MaxCurrentPeak <= NewSampleData;
          MaxPeakUpdate <= '1';
        else
          if MaxPeakUpdate = '1' then
            PeakMaxima <= '1';
          end if;

          MaxPeakUpdate <= '0';
        end if;
      end if;

    end if;
  end process FindMaxPoint;



  AnalysePeaksForTrigger: process(pnReset, pADC_2xClk)
    variable vSampleLessPeakValue: std_ulogic;
  begin
    if pnReset = '0' then
      MaxTrigPeak <= (others => '0');
      NewMaxPeak  <= '0';
      pGateUnTrigger <= '0';

    elsif rising_edge(pADC_2xClk) then

        if unsigned(NewSampleData) < unsigned(MaxTrigPeak) then
          vSampleLessPeakValue := '1';
        else
          vSampleLessPeakValue := '0';
        end if;
      if pSampleEn = '1' then
        pGateUnTrigger <= '0';
      end if;

      if TriggerRst = '1' then
        -- Reset MaxTrigPeak
        MaxTrigPeak <= (others => '0');

      elsif TrigPeakClose = '1' then
        -- Trigger Peak closing
        if pDistMetric = "00" then
        --Distance metric is leading edge
          if NewMaxPeak = '0' and MaxSelDist = '1' then
            -- This peak is not a new maximum, untrigger it
            pGateUnTrigger <= '1';
          end if;
        end if;
        if pSampleEn = '1' then
          NewMaxPeak  <= '0';
        end if;

      elsif TrigPeakActive = '1' then
        -- Update max data if sample data is greater (than current max data)
        -- Positive threshold value
        if vSampleLessPeakValue = '0' then
          MaxTrigPeak <= NewSampleData;
          NewMaxPeak  <= '1';
        end if;

      end if;
    end if;
  end process AnalysePeaksForTrigger;



  GenPeakDataValue: process(pnReset, pADC_2xClk)
    variable vSampleLessPeakValue: std_ulogic;
  begin
    if pnReset = '0' then
      MaxDataValue    <= (others => '0');
      MaxDataValueRaw <= X"000";
      StoredDataValue <= X"000";
      GateDistFire    <= '0';
      GateDistDel     <= '0';
      GateDistFiring  <= '0';

    elsif rising_edge(pADC_2xClk) then
      if unsigned(NewSampleData) < unsigned(MaxDataValue) then
        vSampleLessPeakValue := '1';
      else
        vSampleLessPeakValue := '0';
      end if;

      if pSampleEn = '1' then
        GateDistFire <= '0';
        GateDistDel <= '0';

        if AmpPeakActive = '0' and not (pStoreNoTrig = '1' and GateActive = '1') then
          if AmpPeakDone = '0' or LastSelAmp = '1' then
            -- Capture first data sample of peak
            -- Actually captures all data up to this point!
            MaxDataValue    <= NewSampleData;
            MaxDataValueRaw <= RawSampleData;
          end if;

        else  -- AmpPeakActive = '1'
          -- Update max data if sample data is greater (than current max data)
          -- Positive threshold value
          if vSampleLessPeakValue = '0' then
            MaxDataValue    <= NewSampleData;
            MaxDataValueRaw <= RawSampleData;
            GateDistFire <= '1';
          end if;
        end if;

        if AmpPeakClose = '1' or (pStoreNoTrig = '1' and GateClose = '1' and MaxSelAmp = '1') then
          StoredDataValue <= MaxDataValueRaw;
        elsif GateOpen = '1' then
         StoredDataValue <= X"000";
        end if;

        if (pStoreNoTrig = '1' and MaxSelDist = '1' and pDistMetric = "10") then
          GateDistDel <= GateDistFire;
        end if;
        GateDistFiring <= GateDistDel;
      end if;
    end if;
  end process GenPeakDataValue;


  pGateDistFire   <= pEnable and (GateFiring or GateDistFiring);
  pGateFiring     <= '0' when pEnable = '0' else GateFiring;
  pGateFired      <= '0' when pEnable = '0' else GateFired;
  pGateDidNotFire <= '1' when pEnable = '0' else GateDidNotFire;

  -- Generate the status nibble
  StatusNibble(0) <= GateFired;  -- The distance metric was measured
  StatusNibble(1) <= AmpFired;   -- The amplitude metric was measured
  StatusNibble(3 downto 2) <= "10";  -- A value that cannot occur in sample data

  pGateOutputData <= StatusNibble(1 downto 0) & StoredDataValue;


end architecture Rtl;