---------------------------------------------------------------------------
-- NDT Solutions Ltd. Proprietary Information
-- Company Confidential
-- Copyright 2004-2007
--
-- Filename: DataRectifier.vhd
-- Language: VHDL '93
-- Project:  NDTS2100 DSP FPGA
--
-- Design Description:
-- Module to rectify ADC datastream and format ouptut data
--
-- Type of rectification used depends on Mode control input
--
-- Mode | Rectification
--  00  | Bipolar mode, no rectification
--  01  | Fullwave rectification
--  10  | +Ve 1/2 wave rectification
--  11  | -Ve 1/2 wave rectification
---------------------------------------------------------------------------

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

library UNISIM;
use UNISIM.vcomponents.all;

entity DataRectifier is
  port(nReset         : in  std_ulogic;
       Clk            : in  std_ulogic;
       AdcOffset      : in  std_logic_vector(12 downto 0);
       DropSamples    : in  std_logic_vector(15 downto 0);
       Mode           : in  std_logic_vector(1 downto 0);
       Mod8Bit        : in  std_ulogic;
       SignExtendMode : in  std_ulogic;
       SignAndMagMode : in  std_ulogic;
       DataIn         : in  std_logic_vector(11 downto 0);
       SampleEn       : out std_ulogic;                     -- Sample valid
       SampleData     : out std_logic_vector(15 downto 0);  -- Formatted sample data
       DataOut        : out std_logic_vector(11 downto 0);  -- Raw data in sync with formatted
       RectifiedOut   : out std_logic_vector(10 downto 0)); -- Rect data in sync with formatted
end entity DataRectifier;


architecture Rtl of DataRectifier is

  signal DataInSum:     std_logic_vector(13 downto 0);  -- Sum for offset data calculation
  signal DataInOffset:  std_logic_vector(11 downto 0);  -- Offset data
  signal DataInMod:     std_logic_vector(11 downto 0);  -- 12/8 bit unrectified data
  signal PipelineData1: std_logic_vector(11 downto 0);  -- Pipeline stage 1 for data
  signal PipelineData2: std_logic_vector(11 downto 0);  -- Pipeline stage 2 for data
  signal Data2Comp:     std_logic_vector(10 downto 0);  -- data + 1
  signal RectifiedData: std_logic_vector(10 downto 0);  -- Pipeline stage for rectified data
  signal CatchFlag    : std_ulogic;                     -- Catch value with no wrap
  signal Data         : std_logic_vector(11 downto 0);
  signal Rectified    : std_logic_vector(10 downto 0);

  signal DropCount: integer range 0 to 65535;
  signal iSampleEn:  std_ulogic;

begin

  -- Generate the enable for the sample data stream
  GenSampleEn: process(nReset, Clk)
  begin
    if nReset = '0' then
      DropCount <= 0;
      iSampleEn  <= '1';
    elsif rising_edge(Clk) then

      if DropCount = 0 then
        iSampleEn <= '1';
      else
        iSampleEn <= '0';
      end if;

      if DropCount = 0 then
        DropCount <= conv_integer(unsigned(DropSamples));
      else
        DropCount <= DropCount - 1;
      end if;
    end if;
  end process GenSampleEn;

  SampleEn <= iSampleEn;

  -- Offset ADC Input Data
  OffsetDataIn: process(nReset, Clk)
  begin
    if nReset = '0' then
      DataInSum <= (others => '0');
      DataInOffset <= (others => '0');
    elsif rising_edge(Clk) then
      DataInSum <= unsigned(DataIn(11) & DataIn(11) & DataIn) + unsigned(AdcOffset(12) & AdcOffset);
      if DataInSum(13 downto 12) = "01" then
        DataInOffset <= x"7FF";
      elsif DataInSum(13 downto 12) = "10" then
        DataInOffset <= x"800";
      else
        DataInOffset <= DataInSum(11 downto 0);
      end if;
    end if;
  end process OffsetDataIn;

  -- Truncate to 8 bits of data if required
  GenDataIn: process(nReset, Clk)
  begin
    if nReset = '0' then
      DataInMod <= (others => '0');
    elsif rising_edge(Clk) then
      if Mod8Bit = '0' then
        DataInMod <= DataInOffset;
      else
        DataInMod(11 downto 7) <= (others => DataInOffset(11));
        DataInMod(6 downto 0)  <= DataInOffset(10 downto 4);
      end if;
    end if;
  end process GenDataIn;


  -- Generate the rectified sample datastream
  GenRectData: process(Clk)
    variable vTemp: std_logic_vector(10 downto 0);
  begin
    if rising_edge(Clk) then
      if iSampleEn = '1' then
        PipelineData1 <= DataInMod;
        PipelineData2 <= PipelineData1;
        
        -- fullwave rectified data
        vTemp := not DataInMod(10 downto 0);
        Data2Comp <= (unsigned(vTemp) + 1);
        if DataInMod = X"800" then
          -- Catch condition when Data in = -2048 (0x800)
          -- This must be converted to +2047 (0x7FF)
          CatchFlag <= '1';
        else
          CatchFlag <= '0';
        end if;

        if CatchFlag = '1' then
          RectifiedData <= "11111111111";
        elsif PipelineData1(11) = '1' then
          RectifiedData <= Data2Comp;
        else
          RectifiedData <= PipelineData1(10 downto 0);
        end if;

        case Mode is
          when "00" =>
            -- Bipolar mode, no rectification
            Data      <= PipelineData2;
            Rectified <= RectifiedData;

          when "01" =>
            -- Fullwave rectification
            Data      <= '0' & RectifiedData;
            Rectified <= RectifiedData;

          when "10" =>
            -- +Ve 1/2 wave rectification
            if PipelineData2(11) = '1' then  -- -Ve value
              Data      <= X"000";
              Rectified <= (others => '0');
            else  -- +Ve value
              Data      <= '0' & RectifiedData;
              Rectified <= RectifiedData;
            end if;

          when others => --"11" =>
            -- -Ve 1/2 wave rectification
            if PipelineData2(11) = '1' then  -- -Ve value
              Data      <= '0' & RectifiedData;
              Rectified <= RectifiedData;
            else  -- +Ve value
              Data      <= X"000";
              Rectified <= (others => '0');
            end if;

        end case;
      end if;
    end if;
  end process GenRectData;

  -- Format output data
  GenDataOut: process(Clk)
    variable vTemp: std_logic_vector(10 downto 0);
  begin
    if rising_edge(Clk) then
      if iSampleEn = '1' then
        SampleData <= "0000" & Data;
        if SignExtendMode = '1' then
          SampleData(15 downto 12) <= (others => Data(11));
        elsif Mod8Bit = '1' then
          SampleData(11 downto 8) <= (others => '0');
        end if;
        if SignAndMagMode = '1' then
          if Mod8Bit = '0' then
            SampleData <= "0000" & Data(11) & Rectified;
          else
            SampleData <= "00000000" & Data(11) & Rectified(6 downto 0);
          end if;
        end if;
        DataOut      <= Data;
        RectifiedOut <= Rectified;
      end if;
    end if;
  end process GenDataOut;


end architecture Rtl;