----------------------------------------------------------------------------------
-- Company:        ETH Zurich, Institute for Particle Physics
-- Engineer:       P. Vogler, Q. Weitzel
-- 
-- Create Date:    07/30/2010
-- Design Name:    
-- Module Name:    FTU_test6 - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description:    Test firmware for FTU board, set enables via RS485 										
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
library ftu_definitions_test6;
USE ftu_definitions_test6.ftu_array_types.all;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;


entity FTU_test6 is
  port(
    -- global control 
    ext_clk   : IN  STD_LOGIC;                      -- external clock from FTU board
    brd_add   : IN  STD_LOGIC_VECTOR(5 downto 0);   -- geographic board/slot address
    brd_id    : in  STD_LOGIC_VECTOR(7 downto 0);   -- local solder-programmable board ID

    -- rate counters LVDS inputs
    -- use IBUFDS differential input buffer
    patch_A_p     : IN  STD_LOGIC;                  -- logic signal from first trigger patch
    patch_A_n     : IN  STD_LOGIC;           
    patch_B_p     : IN  STD_LOGIC;                  -- logic signal from second trigger patch
    patch_B_n     : IN  STD_LOGIC;
    patch_C_p     : IN  STD_LOGIC;                  -- logic signal from third trigger patch
    patch_C_n     : IN  STD_LOGIC;
    patch_D_p     : IN  STD_LOGIC;                  -- logic signal from fourth trigger patch
    patch_D_n     : IN  STD_LOGIC;
    trig_prim_p   : IN  STD_LOGIC;                  -- logic signal from n-out-of-4 circuit
    trig_prim_n   : IN  STD_LOGIC;
    
    -- DAC interface
    sck           : OUT STD_LOGIC;                  -- serial clock to DAC
    mosi          : OUT STD_LOGIC;                  -- serial data to DAC, master-out-slave-in
    clr           : OUT STD_LOGIC;                  -- clear signal to DAC
    cs_ld         : OUT STD_LOGIC;                  -- chip select or load to DAC
    
    -- RS-485 interface to FTM
    rx            : IN  STD_LOGIC;                  -- serial data from FTM
    tx            : OUT STD_LOGIC;                  -- serial data to FTM
    rx_en         : OUT STD_LOGIC;                  -- enable RS-485 receiver
    tx_en         : OUT STD_LOGIC;                  -- enable RS-485 transmitter

    -- analog buffer enable
    enables_A   : OUT STD_LOGIC_VECTOR(8 downto 0);  -- individual enables for analog inputs
    enables_B   : OUT STD_LOGIC_VECTOR(8 downto 0);  -- individual enables for analog inputs
    enables_C   : OUT STD_LOGIC_VECTOR(8 downto 0);  -- individual enables for analog inputs
    enables_D   : OUT STD_LOGIC_VECTOR(8 downto 0);  -- individual enables for analog inputs

    -- testpoints
    TP_A        : out STD_LOGIC_VECTOR(11 downto 0)   -- testpoints    
  );
end FTU_test6;


architecture Behavioral of FTU_test6 is

  component FTU_test6_dcm
    port(
      CLKIN_IN        : IN  STD_LOGIC; 
      RST_IN          : IN  STD_LOGIC; 
      CLKFX_OUT       : OUT STD_LOGIC; 
      CLKIN_IBUFG_OUT : OUT STD_LOGIC; 
      LOCKED_OUT      : OUT STD_LOGIC
    );
  end component;

  component FTU_test6_rs485_interface
    GENERIC( 
      CLOCK_FREQUENCY : integer := 50000000;      -- Hertz
      BAUD_RATE       : integer := 250000         -- bits / sec
    );
    PORT( 
      clk      : IN     std_logic;
      -- RS485
      rx_d     : IN     std_logic;
      rx_en    : OUT    std_logic;
      tx_d     : OUT    std_logic;
      tx_en    : OUT    std_logic;
      -- FPGA
      rx_data  : OUT    std_logic_vector(7 DOWNTO 0);
      rx_busy  : OUT    std_logic := '0';
      rx_valid : OUT    std_logic := '0';
      tx_data  : IN     std_logic_vector(7 DOWNTO 0);
      tx_busy  : OUT    std_logic := '0';
      tx_start : IN     std_logic
    );
  end component;
  
  signal reset_sig   : STD_LOGIC := '0'; -- initialize reset to 0 at power up 
  signal clk_50M_sig : STD_LOGIC;

  signal enable_sig : enable_array_type := DEFAULT_ENABLE;

  signal rx_en_sig    : STD_LOGIC := '0';
  signal tx_en_sig    : STD_LOGIC := '0';
  signal rx_sig       : STD_LOGIC;
  signal tx_sig       : STD_LOGIC := 'X';
  signal rx_data_sig  : STD_LOGIC_VECTOR(7 DOWNTO 0) := (others => '0');
  signal rx_busy_sig  : STD_LOGIC;
  signal rx_valid_sig : STD_LOGIC;
  
  type FTU_test6_StateType is (INIT, RUN1, RUN2, RUN3, RUN4);
  signal FTU_test6_State, FTU_test6_NextState: FTU_test6_StateType;
  
begin

  Inst_FTU_test6_dcm : FTU_test6_dcm
    port map(
      CLKIN_IN => ext_clk,
      RST_IN => reset_sig,
      CLKFX_OUT => clk_50M_sig,
      CLKIN_IBUFG_OUT => open,
      LOCKED_OUT => open
    );

  Inst_FTU_test6_rs485_interface : FTU_test6_rs485_interface
    generic map(
      CLOCK_FREQUENCY => 50000000,
      BAUD_RATE       => 10000000       --simulation
      --BAUD_RATE       => 19600       --implement
    )
    port map(
      clk      => clk_50M_sig,
      -- RS485
      rx_d     => rx_sig,
      rx_en    => rx_en_sig,
      tx_d     => tx_sig,
      tx_en    => tx_en_sig,
      -- FPGA
      rx_data  => rx_data_sig,
      rx_busy  => rx_busy_sig,
      rx_valid => rx_valid_sig,
      tx_data  => (others => '0'),
      tx_busy  => open,
      tx_start => '0'
    );
  
  enables_A <= enable_sig(0)(8 downto 0);
  enables_B <= enable_sig(1)(8 downto 0);
  enables_C <= enable_sig(2)(8 downto 0);
  enables_D <= enable_sig(3)(8 downto 0);

  rx_en  <= rx_en_sig;
  tx_en  <= tx_en_sig;
  tx     <= tx_sig;
  rx_sig <= rx;
  
  --FTU main state machine (two-process implementation)

  FTU_test6_Registers: process (clk_50M_sig)
  begin
    if Rising_edge(clk_50M_sig) then
      FTU_test6_State <= FTU_test6_NextState;
    end if;
  end process FTU_test6_Registers;

  FTU_test6_C_logic: process (FTU_test6_State, rx_data_sig, rx_valid_sig)
  begin
    FTU_test6_NextState <= FTU_test6_State;
    case FTU_test6_State is
      when INIT =>
        reset_sig <= '0';
        enable_sig <= DEFAULT_ENABLE;
        if (rx_data_sig = "00110001" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN1;
        elsif (rx_data_sig = "00110010" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN2;
        elsif (rx_data_sig = "00110011" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN3;
        elsif (rx_data_sig = "00110100" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN4;
        else
          FTU_test6_NextState <= INIT;
        end if;
      when RUN1 =>
        reset_sig <= '0';
        enable_sig <= ("0000000000000000","0000000111111111","0000000111111111","0000000111111111");
        if (rx_data_sig = "00110000" and rx_valid_sig = '1') then
          FTU_test6_NextState <= INIT;
        elsif (rx_data_sig = "00110010" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN2;
        elsif (rx_data_sig = "00110011" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN3;
        elsif (rx_data_sig = "00110100" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN4;
        else
          FTU_test6_NextState <= RUN1;
        end if;
      when RUN2 =>
        reset_sig <= '0';
        enable_sig <= ("0000000111111111","0000000000000000","0000000111111111","0000000111111111");
        if (rx_data_sig = "00110000" and rx_valid_sig = '1') then
          FTU_test6_NextState <= INIT;
        elsif (rx_data_sig = "00110001" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN1;
        elsif (rx_data_sig = "00110011" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN3;
        elsif (rx_data_sig = "00110100" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN4;
        else
          FTU_test6_NextState <= RUN2;
        end if;
      when RUN3 =>
        reset_sig <= '0';
        enable_sig <= ("0000000111111111","0000000111111111","0000000000000000","0000000111111111");
        if (rx_data_sig = "00110000" and rx_valid_sig = '1') then
          FTU_test6_NextState <= INIT;
        elsif (rx_data_sig = "00110001" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN1;
        elsif (rx_data_sig = "00110010" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN2;
        elsif (rx_data_sig = "00110100" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN4;
        else
          FTU_test6_NextState <= RUN3;
        end if;
      when RUN4 =>
        reset_sig <= '0';
        enable_sig <= ("0000000111111111","0000000111111111","0000000111111111","0000000000000000");
        if (rx_data_sig = "00110000" and rx_valid_sig = '1') then
          FTU_test6_NextState <= INIT;
        elsif (rx_data_sig = "00110001" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN1;
        elsif (rx_data_sig = "00110010" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN2;
        elsif (rx_data_sig = "00110011" and rx_valid_sig = '1') then
          FTU_test6_NextState <= RUN3;
        else
          FTU_test6_NextState <= RUN4;
        end if;
    end case;
  end process FTU_test6_C_logic;
  
end Behavioral;
