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

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


entity 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 entity BScanCtrl;


architecture Rtl of BScanCtrl is

  signal ClkEn:        std_ulogic;
  signal BScanTrigger: std_ulogic;
  signal FreeRunningTrigger: std_ulogic;
  signal ScanCount:    integer range 0 to 127;
  signal RxCount:      std_logic_vector(6 downto 0);
  signal ARepCount:    std_logic_vector(16 downto 0);
  signal BRepCount:    std_logic_vector(25 downto 0);
  signal IncScanCount: std_ulogic;
  signal IncRxCount:   std_ulogic;
  signal IncRxCount2:  std_ulogic;
  signal BScanActive:  std_ulogic;
  signal RxActive:     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 pBScanTrigger generated in the LCLK domain
  -- and find the leading edge
  -- Ignore triggers when module is already running
  GenBScanTrigger: process(pnReset, pSampleClk)
    variable vBScanTrigger: std_logic_vector(2 downto 0);
  begin
    if pnReset = '0' then
      BScanTrigger <= '0';
      vBScanTrigger := "000";
    elsif rising_edge(pSampleClk) then
      if vBScanTrigger(2 downto 1) = "01" and RxActive = '0' then
        BScanTrigger <= '1';
      elsif ClkEn = '1' then
        BScanTrigger <= '0';
      end if;

      vBScanTrigger := vBScanTrigger(1 downto 0) & pBScanTrigger;
    end if;
  end process GenBScanTrigger;

  -- 
  GenBRepCount: process(pnReset, pSampleClk)
    variable vBScanFreeRunning: std_logic_vector(1 downto 0);
  begin
    if pnReset = '0' then
      BRepCount          <= (others => '0');
      FreeRunningTrigger <= '0';
      vBScanFreeRunning  := "00";
    elsif rising_edge(pSampleClk) then
      if ClkEn = '1' then
        FreeRunningTrigger <= '0';

        if BRepCount /= "0000000000000000000" then
          BRepCount <= unsigned(BRepCount) - 1;
        elsif vBScanFreeRunning(1) = '1' then
          BRepCount <= pBScanRepRate;
          FreeRunningTrigger <= '1';
        end if;

      end if;
      vBScanFreeRunning := vBScanFreeRunning(0) & pBScanFreeRunning;
    end if;
  end process GenBRepCount;


  GenARepCount: process(pnReset, pSampleClk)
  begin
    if pnReset = '0' then
      ARepCount    <= (others => '0');
      IncScanCount <= '0';
      pBScanTriggerOut <= '0';

    elsif rising_edge(pSampleClk) then
      if ClkEn = '1' then
        IncScanCount <= '0';
        pBScanTriggerOut <= '0';

        if BScanTrigger = '1' or FreeRunningTrigger = '1' then
          pBScanTriggerOut <= '1';
          ARepCount <= pAScanRepRate;
          IncScanCount <= '1';
        else
          if ARepCount /= "00000000000000000" then
            ARepCount <= unsigned(ARepCount) - 1;
          elsif RxActive = '1'then
            ARepCount <= pAScanRepRate;
            IncScanCount <= '1';
          end if;
        end if;

      end if;
    end if;
  end process GenARepCount;


  GenScanCount: process(pnReset, pSampleClk)
    variable vScanCountDone: std_ulogic;
    variable vRxCountDone:   std_ulogic;
  begin
    if pnReset = '0' then
      ScanCount    <= 0;
      BScanActive  <= '0';
      RxActive     <= '0';
      pTxCount     <= (others => '0');
      RxCount      <= (others => '0');
      IncRxCount   <= '0';
      IncRxCount2  <= '0';

      vScanCountDone := '0';

    elsif rising_edge(pSampleClk) then
      if ClkEn = '1' then
        IncRxCount <= '0';

        if BScanTrigger = '1' or FreeRunningTrigger = '1' then
          ScanCount    <= 0;
          RxCount      <= "0000000";
          BScanActive  <= '1';
          RxActive     <= '1';

        elsif IncScanCount = '1' then
          pTxCount <= conv_std_logic_vector(ScanCount, 7);
          if vScanCountDone = '0' then
            ScanCount <= ScanCount + 1;
          else
            BScanActive <= '0';
          end if;

          if RxCount = "0000000" then
            case pAScanInterleave is
              when "00" =>
                if ScanCount = 1 then
                  IncRxCount <= '1';
                end if;
              when "01" =>
                if ScanCount = 2 then
                  IncRxCount <= '1';
                end if;
              when "10" =>
                if ScanCount = 3 then
                  IncRxCount <= '1';
                end if;
              when "11" =>
                if ScanCount = 4 then
                  IncRxCount <= '1';
                end if;
              when others => null;
            end case;

          else
            IncRxCount <= '1';
          end if;

        end if;  -- IncScanCount /= '1' then

        if IncRxCount2 = '1' then
          RxCount <= unsigned(RxCount) + 1;
        end if;
        IncRxCount2 <= IncRxCount;

        -- Stop B-Scan when last A-Scan has been received
        if vRxCountDone = '1' and RxActive = '1' then
          RxActive <= '0';
        end if;

      end if;

      if RxCount = pNumElements then
        vRxCountDone := '1';
      else
        vRxCountDone := '0';
      end if;

      if ScanCount = conv_integer(unsigned(pNumElements)) then
        vScanCountDone := '1';
      else
        vScanCountDone := '0';
      end if;
    end if;
  end process GenScanCount;

  pLastBscan <= not RxActive;


  pRxCount   <= RxCount;


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


end Rtl;

