---------------------------------------------------------------------------
-- NDT Solutions Ltd. Proprietary Information
-- Company Confidential
-- Copyright 2007
--
-- Filename: AD9230.vhd
-- Language: VHDL '93
-- Project:  NDTS2100 System FPGA
--
-- Design Description:
-- ADC model for main high-speed ADC including SPI serial port
---------------------------------------------------------------------------

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;

entity AD9230 is
  port (CLKp  : in    std_ulogic;
        CLKn  : in    std_ulogic;
        RESET : in    std_ulogic; -- active low
        --
        DCOp  : out   std_ulogic;
        DCOn  : out   std_ulogic;
        Dp    : out   std_logic_vector(11 downto 0);
        Dn    : out   std_logic_vector(11 downto 0);
        ORp   : out   std_ulogic;
        ORn   : out   std_ulogic;
        --
        SCLK  : in    std_ulogic;
        CSB   : in    std_ulogic;
        SDIO  : inout std_logic;
        --
        VINp  : in    integer; -- analog input
        VINn  : in    integer);
end entity AD9230;


architecture Beh of AD9230 is
  signal iClk: std_ulogic;
  type tADCSample is array(7 downto 0) of signed(11 downto 0);
  signal ADCSample: tADCSample;
  signal OrSample: std_logic_vector(7 downto 0);

  signal InstCount: integer;
  signal Inst: std_logic_vector(15 downto 0) := (others => '0');
  signal DataCount: integer;
  signal Data: std_logic_vector(7 downto 0) := (others => '0');

  signal ChipIdReg : std_logic_vector(7 downto 0) := x"18";

  constant cRnWBit: integer := 15;
  constant cW1Bit : integer := 14;
  constant cW0Bit : integer := 13;

  -- just model a couple of registers so we can check addressing
  constant cChipPortConfigAddr: integer := 16#0000#;
  constant cChipIdAddr        : integer := 16#0001#;

  constant cChipId            : std_logic_vector(7 downto 0) := x"0C";

begin

  -- internal clock
  iClk <= '1' when CLKp = '1' and CLKn = '0' else
          '0' when CLKp = '0' and CLKn = '1' else
          'X';

  -- Sample data with 7 clock pipeline delay
  Sample : process
  begin
    wait until rising_edge(iClk);
    ADCSample(7 downto 1) <= ADCSample(6 downto 0);
    OrSample(7 downto 1) <= OrSample(6 downto 0);
    
    ADCSample(0) <= conv_signed(VINp - VINn, 12);
    if (VINp - VINn) > 2047 or (VINp - VINn) < -2048 then
      OrSample(0) <= '1';
    else
      OrSample(0) <= '0';
    end if;
  end process Sample;

  -- output assignment
  DCOp <= not iClk after 1.4 ns; -- (3.9 - 2.5) ns
  DCOn <= iClk after 1.4 ns;

  Dp <= std_logic_vector(ADCSample(7)) after 3.8 ns;
  Dn <= not std_logic_vector(ADCSample(7)) after 3.8 ns;
  ORp <= OrSample(7) after 3.8 ns;
  ORn <= OrSample(7) after 3.8 ns;

  -- SPI serial port
  State : process
    variable vData: std_logic_vector(7 downto 0);
  begin
    SDIO <= 'Z';
    wait until falling_edge(CSB);
    InstCount <= 16;
    DataCount <= 0;

    loop
      wait on CSB, SCLK;

      if rising_edge(CSB) then
        exit;
      end if;

      if rising_edge(SClk) then
        if DataCount = 0 then
          if InstCount /= 0 then
            Inst <= Inst(14 downto 0) & SDIO;
            InstCount <= InstCount - 1;
            if InstCount = 1 then
              DataCount <= 8;
            end if; 
          end if;
        else
          if Inst(cRnWBit) = '0' then
            Data <= Data(6 downto 0) & SDIO;
          end if;

          DataCount <= DataCount - 1;
          if DataCount = 1 then
            exit;
          end if;
        end if;
      end if;

      if falling_edge(SClk) then
        if DataCount = 8 then
          if Inst(cRnWBit) = '1' then -- read
            case conv_integer(unsigned(Inst(12 downto 0))) is
              when cChipPortConfigAddr =>
                vData := ChipIdReg;
              when cChipIdAddr =>
                vData := cChipId;
              when others =>
                vData := (others => '0');
            end case;
            SDIO <= vData(7);
            Data <= vData(6 downto 0) & '0';
          end if;
        elsif Inst(cRnWBit) = '1' and DataCount /= 0 then
          SDIO <= Data(7);
          Data <= Data(6 downto 0) & '0';
        end if;
      end if;
    end loop;

    if CSB = '0' then
      wait until rising_edge(CSB);
    end if;
    if Inst(cRnWBit) = '0' then
      case conv_integer(unsigned(Inst(12 downto 0))) is
        when cChipPortConfigAddr =>
          ChipIdReg <= Data;
        when others =>
          null;
      end case;    
    end if;
    SDIO <= 'Z';

  end process State;    

end architecture Beh;
