---------------------------------------------------------------------------
-- NDT Solutions Ltd. Proprietary Information
-- Company Confidential
-- Copyright 2005
--
-- Filename: CtrlSequenceTable.vhd
-- Language: VHDL '93
-- Project:  Pulse Receive Card System FPGA
--
-- Design Description:
-- Implement dual port RAM for sequence table.
-- pico-blaze on one side output control other
--
---------------------------------------------------------------------------

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

entity CtrlSequenceTable is
  port (
    pnReset       : in  std_ulogic;
    pClock        : in  std_ulogic;
    pWE           : in  std_ulogic;
    pPAD          : in  std_logic_vector(7 downto 0);
    pAddress      : in  std_logic_vector(9 downto 0);
    pDataIn       : in  std_logic_vector(7 downto 0);
	  pNewTable     : in  std_ulogic;
    pUpdateTable  : in  std_ulogic;
    pStepSkip     : in  std_logic_vector(4 downto 0);
    pOverSample   : in  std_logic_vector(7 downto 0);
    pFineDelInc   : in  std_logic_vector(7 downto 0);
    pFineDelay    : out std_logic_vector(7 downto 0);
    pAckStart     : out std_ulogic;
    pAckEn        : out std_ulogic;
    pSeqTableEn   : out std_logic_vector(7 downto 0);
    pSeqTable0    : out std_logic_vector(31 downto 0);
    pSeqTable1    : out std_logic_vector(31 downto 0);
    pSeqTable2    : out std_logic_vector(31 downto 0);
    pSeqTable3    : out std_logic_vector(31 downto 0);
    pSeqTable4    : out std_logic_vector(31 downto 0);
    pSeqTable5    : out std_logic_vector(31 downto 0);
    pSeqTable6    : out std_logic_vector(31 downto 0);
    pSeqTable7    : out std_logic_vector(31 downto 0));
end CtrlSequenceTable;


architecture RTL of CtrlSequenceTable is

  component DPBRAM32x256
    port (
      pnReset  : in  std_ulogic;
      pClock   : in  std_ulogic;
      AddressA : in  std_logic_vector(7 downto 0);
      AddressB : in  std_logic_vector(7 downto 0);
      DataInA  : in  std_logic_vector(31 downto 0);
      DataInB  : in  std_logic_vector(31 downto 0);
      WriteEnA : in  std_ulogic;
      WriteEnB : in  std_ulogic;
      DataOutA : out std_logic_vector(31 downto 0);
      DataOutB : out std_logic_vector(31 downto 0));
  end component;
  
  signal A_DataWrite      : std_logic_vector(31 downto 0);
  signal A_DataRead       : std_logic_vector(31 downto 0);
  signal B_DataWrite      : std_logic_vector(31 downto 0);
  signal B_WE             : std_ulogic;
  signal A_WE             : std_ulogic;
  signal TableNo          : unsigned(4 downto 0);
  signal TableRow         : unsigned(2 downto 0);
  signal SkipCount        : unsigned(4 downto 0);
  signal OverSampleCount  : unsigned(7 downto 0);
  signal FineDelay        : unsigned(7 downto 0);
  signal AckEn            : std_ulogic;
  signal SeqTableAddr     : std_logic_vector(7 downto 0);
  signal seqTableData     : std_logic_vector(31 downto 0);
  signal OpEnable         : std_ulogic;
  signal OverSampleEnable : std_ulogic;
  signal FFEnable         : std_ulogic;
  signal FFRow            : unsigned(2 downto 0);

  constant cBE0 : std_logic_vector(7 downto 0) := x"38";

begin

  A_WE <= '1' when (pPAD = cBE0 and pWE = '1') else '0';

  DataMux : process (pAddress, pDataIn, A_DataRead) is
    begin
      A_DataWrite <= A_DataRead;
      case pAddress(1 downto 0) is
        when "00" =>
          A_DataWrite(7 downto 0) <= pDataIn;
        when "01" =>
          A_DataWrite(15 downto 8) <= pDataIn;
        when "10" =>
          A_DataWrite(23 downto 16) <= pDataIn;
        when "11" =>
          A_DataWrite(31 downto 24) <= pDataIn;
        when others =>
          null;
      end case;    
    end process;     

  B_DataWrite <= (others => '0');
  B_WE <= '0';

  DPBRAM32x256_1 : DPBRAM32x256
    port map (
      pnReset  => pnReset,
      pClock   => pClock,
      AddressA => pAddress(9 downto 2),
      AddressB => SeqTableAddr,
      DataInA  => A_DataWrite,
      DataInB  => B_DataWrite,
      WriteEnA => A_WE,
      WriteEnB => B_WE,
      DataOutA => A_DataRead,
      DataOutB => SeqTableData);

  AddrCount : process (pClock, pnReset) is
    begin
      if (pnReset = '0') then
        TableNo <= (others => '0');
        TableRow <= (others => '0');
        SkipCount <= (others => '0');
        OverSampleCount <= (others => '0');
        FineDelay <= (others => '0');
        AckEn <= '1';
        OpEnable <= '0';
        OverSampleEnable <= '0';
        FFEnable <= '0';
        FFRow <= (others => '0');
        pAckStart <= '0';
      elsif (pClock'event and pClock = '1') then
        FFEnable <= OpEnable;
        FFRow <= TableRow;
        pAckStart <= '0';
        if (pNewTable = '1') then
          TableNo <= (others => '0');
          TableRow <= (others => '0');
          SkipCount <= (others => '0');
          OverSampleCount <= (others => '0');
        elsif (pUpdateTable = '1') then
          if (SkipCount /= 0) then
            SkipCount <= Skipcount - 1;
          elsif (OverSampleCount /= 0) then
            OverSampleCount <= OverSampleCount - 1;
            FineDelay <= FineDelay + unsigned(pFineDelInc);
            OverSampleEnable <= '1';
          else
            OpEnable <= '1';
            if (SeqTableData(31) = '0') then -- not active entry
              TableNo <= (others => '0');
            end if;
          end if;
        end if;
        if (OpEnable = '1') then
          TableRow <= TableRow + 1;
          if (TableRow = 7) then
            TableNo <= TableNo + 1;
            if (unsigned(pStepSkip) /= 0) then
              SkipCount <= unsigned(pStepSkip) - 1;
              AckEn <= '0';
            end if;
            if (unsigned(pOverSample) /= 0) then
              OverSampleCount <= unsigned(pOverSample);
              FineDelay <= (others => '0');
            else
              FineDelay <= unsigned(pFineDelInc); -- if not oversampling just load value
            end if;
            OpEnable <= '0';
            if AckEn = '1' then
              pAckStart <= '1';
            else
              AckEn <= '1';
            end if;
          end if;
        end if;
        if (OverSampleEnable = '1') then
          OverSampleEnable <= '0';
          pAckStart <= '1';
        end if;
      end if;
    end process AddrCount;

  pFineDelay <= std_logic_vector(FineDelay);
  pAckEn <= AckEn;

  SeqTableAddr <= std_logic_vector(TableNo) & std_logic_vector(TableRow);

  OpFF : process (pClock, pnReset) is
    begin
      if (pnReset = '0') then
        pSeqTableEn <= (others => '0');
        pSeqTable0 <= (others => '0');
        pSeqTable1 <= (others => '0');
        pSeqTable2 <= (others => '0');
        pSeqTable3 <= (others => '0');
        pSeqTable4 <= (others => '0');
        pSeqTable5 <= (others => '0');
        pSeqTable6 <= (others => '0');
        pSeqTable7 <= (others => '0');
      elsif (pClock'event and pClock = '1') then
        pSeqTableEn <= (others => '0');
        if (FFEnable = '1') then
          pSeqTableEn(conv_integer(FFRow)) <= '1';
          case FFRow is
            when "000" =>
              pSeqTable0 <= SeqTableData;
            when "001" =>
              pSeqTable1 <= SeqTableData;
            when "010" =>
              pSeqTable2 <= SeqTableData;
            when "011" =>
              pSeqTable3 <= SeqTableData;
            when "100" =>
              pSeqTable4 <= SeqTableData;
            when "101" =>
              pSeqTable5 <= SeqTableData;
            when "110" =>
              pSeqTable6 <= SeqTableData;
            when "111" =>
              pSeqTable7 <= SeqTableData;
            when others =>
              null;
          end case;
        end if;
      end if;
    end process OpFF;

end architecture RTL;
