---------------------------------------------------------------------------
-- NDT Solutions Ltd. Proprietary Information
-- Company Confidential
-- Copyright 2004
--
-- Filename: SequenceCtrl.vhd
-- Language: VHDL '93
-- Project:  Digitiser Card Peripheral FPGA
--
-- Design Description:
-- Module to control the multiple A-Scans making up Sequence
---------------------------------------------------------------------------

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


entity SequenceCtrl is
  Port (-- Local bus signals
        pnReset          : in  std_ulogic;
        pSampleClk       : in  std_ulogic;
        pLClk            : in  std_ulogic;
        -- Sequence operation controls
        pStartSequence   : in  std_ulogic;
        pSequenceTrigger : in  std_ulogic;
        pSeqTriggerEn    : in  std_ulogic;
        pStepAck         : in  std_ulogic;
        pSequenceActive  : out std_ulogic;
        -- Register data in
        pSteps           : in  std_logic_vector(4 downto 0);
        pAScanRepRate    : in  std_logic_vector(16 downto 0);
        pOverSample      : in  std_logic_vector(7 downto 0);
        pStepNo          : out std_logic_vector(4 downto 0);
        -- Step control
        pGateStep        : in  std_ulogic;
        pGateStepEn      : in  std_ulogic;
        pDspStep         : out std_ulogic;
        -- Trigger data out
        pTriggerOut      : out std_ulogic;
        pStartNewSequence: out std_ulogic);
end entity SequenceCtrl;


architecture Rtl of SequenceCtrl is

  signal ClkEn:           std_ulogic;
  signal SeqTrigger:      std_ulogic;
  signal StartSequence:   std_ulogic;
  signal StepCount:       integer range 0 to 31;
  signal OverSampleCount: integer range 0 to 255;
  signal RepCount:        std_logic_vector(16 downto 0);
  signal RepCount0:       std_ulogic;
  signal IncStepCount:    std_ulogic;
  signal SequenceActive:  std_ulogic;
  signal DspStep0:        std_ulogic;
  signal DspStep:         std_ulogic;
  signal AckRec:          std_ulogic;

begin

  -- Generate a divide by 5 clock enable
  GenClkEn: process(pnReset, pSampleClk)
    variable vCount: integer range 0 to 7;
  begin
    if pnReset = '0' then
      ClkEn <= '0';
    elsif rising_edge(pSampleClk) then
      if vCount = 4 then
        ClkEn <= '1';
      else
        ClkEn <= '0';
      end if;

      if vCount /= 4 then
        vCount := vCount + 1;
      else
        vCount := 0;
      end if;
    end if;
  end process GenClkEn;


  -- Remove metastability from pSequenceTrigger generated in the LCLK domain
  -- and find the leading edge
  -- Ignore triggers when module is already running
  GenSeqTrigger: process(pnReset, pSampleClk)
    variable vSeqTrigger: std_logic_vector(2 downto 0);
  begin
    if pnReset = '0' then
      SeqTrigger <= '0';
      vSeqTrigger := "000";
    elsif rising_edge(pSampleClk) then
      if vSeqTrigger(2 downto 1) = "01" and SequenceActive = '0' then
        SeqTrigger <= '1';
      elsif ClkEn = '1' then
        SeqTrigger <= '0';
      end if;

      vSeqTrigger := vSeqTrigger(1 downto 0) & pSequenceTrigger;
    end if;
  end process GenSeqTrigger;


  GenRepCount: process(pnReset, pSampleClk)
  begin
    if pnReset = '0' then
      RepCount     <= (others => '0');
      RepCount0    <= '1';
      IncStepCount <= '0';

    elsif rising_edge(pSampleClk) then
      if ClkEn = '1' then
        IncStepCount <= '0';
        if RepCount = "00000000000000001" then
          RepCount0 <= '1';
        end if;

        if SeqTrigger = '1' then
          RepCount <= pAScanRepRate;
          IncStepCount <= '1';
          RepCount0    <= '0';
        else
          if RepCount0 = '0' then
            RepCount <= unsigned(RepCount) - 1;
          elsif SequenceActive = '1' and AckRec = '1' then
            RepCount <= pAScanRepRate;
            IncStepCount <= '1';
            RepCount0    <= '0';
          end if;
        end if;

      end if;
    end if;
  end process GenRepCount;


  GenStepCount: process(pnReset, pSampleClk)
  begin
    if pnReset = '0' then
      StepCount      <= 0;
      OverSampleCount <= 0;
      SequenceActive <= '0';
      pStartNewSequence <= '0';
    elsif rising_edge(pSampleClk) then
      pStartNewSequence <= '0';
      if ClkEn = '1' then
        if IncStepCount = '1' then
          if StepCount /= conv_integer(unsigned(pSteps)) or OverSampleCount /= conv_integer(unsigned(pOverSample)) then
            if OverSampleCount /= conv_integer(unsigned(pOverSample)) then
              OverSampleCount <= OverSampleCount + 1;
            else
              StepCount <= StepCount + 1;
              OverSampleCount <= 0;
            end if;
          else
            StepCount <= 0;
            OverSampleCount <= 0;
            -- Stop Sequence if We need to wait for Trigger for next sequence or disabled
            if pSeqTriggerEn = '1' or StartSequence = '0' then
              SequenceActive <= '0';
            end if;
          end if;
          if StepCount = 0 and OverSampleCount = 0 then
            pStartNewSequence <= '1';
          end if;
        elsif SequenceActive = '0' and StartSequence = '1' then
          StepCount <= 0;
          OverSampleCount <= 0;
          -- if trigger is disabled start now otherwise wait for trigger
          if pSeqTriggerEn = '0' or SeqTrigger = '1' then
            SequenceActive <= '1';
          end if;
        end if;
      end if;
    end if;
  end process GenStepCount;

  pSequenceActive <= SequenceActive;

  -- Remove metastability from pStepAck and update step count on the leading edge
  -- also on leading edge of StartSequence
  GenStepNo: process(pnReset, pLClk)
    variable vStepAck: std_logic_vector(2 downto 0);
    variable vStartSequence: std_logic_vector(2 downto 0);
  begin
    if pnReset = '0' then
      pStepNo <= (others => '0');
      DspStep0 <= '0';
      DspStep <= '0';
      vStepAck := "000";
      vStartSequence := "000";
    elsif rising_edge(pLClk) then
      DspStep0 <= '0';
      DspStep <= '0';
      if pGateStepEn = '1' then -- control step from Gate serial transfer
        DspStep <= pGateStep;
      else
        if vStepAck(2 downto 1) = "01" or vStartSequence(2 downto 1) = "01" then
          pStepNo <= conv_std_logic_vector(StepCount, 5);
          if OverSampleCount = 0 then
            DspStep0 <= '1';
            DspStep <= '1';                        -- inc step count
          end if;
        end if;
        if DspStep0 = '1' and StepCount = 0 then -- reset step count
          DspStep <= '1';
        end if;
      end if;

      vStepAck := vStepAck(1 downto 0) & pStepAck;
      vStartSequence := vStartSequence(1 downto 0) & pStartSequence;
    end if;
  end process GenStepNo;

  pDspStep <= DspStep;

  -- Remove metastability from pStepAck and produce AckRec on the falling edge
  -- also on leading edge of StartSequence
  GenAckRec: process(pnReset, pSampleClk)
    variable vSampleAck: std_logic_vector(2 downto 0);
    variable vSampleStart: std_logic_vector(1 downto 0);
  begin
    if pnReset = '0' then
      AckRec <= '0';
      vSampleAck := "000";
      StartSequence <= '0';
      vSampleStart := "00";
    elsif rising_edge(pSampleClk) then
      if vSampleAck(2 downto 1) = "10" or vSampleStart(1 downto 0) = "01" then
        AckRec <= '1';
      elsif ClkEn = '1' and IncStepCount = '1' then
        AckRec <= '0';
      end if;

      vSampleAck := vSampleAck(1 downto 0) & pStepAck;
      StartSequence <= pStartSequence;
      vSampleStart := vSampleStart(0) & StartSequence;
    end if;
  end process GenAckRec;

  GenpTriggerOut: process(pnReset, pSampleClk)
  begin
    if pnReset = '0' then
      pTriggerOut <= '0';
    elsif rising_edge(pSampleClk) then
      if ClkEn = '1' then
        if SequenceActive = '1' then
          pTriggerOut <= IncStepCount;
        else
          pTriggerOut <= '0';
        end if;
      end if;
    end if;
  end process GenpTriggerOut;

end Rtl;
