----------------------------------------------------------------------------------
-- Company:        ETH Zurich, Institute for Particle Physics
-- Engineer:       Q. Weitzel, P. Vogler
-- 
-- Create Date:    09/13/2010 
-- Design Name: 
-- Module Name:    FTU_rs485_interpreter - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description:    command interpreter of FTU RS485 module
--
-- 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;
USE ftu_definitions.ftu_array_types.all;
USE ftu_definitions.ftu_constants.all;

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

entity FTU_rs485_interpreter is
  port(
    clk                    : IN  std_logic;
    data_block             : IN  std_logic_vector(RS485_BLOCK_WIDTH - 1 downto 0);
    block_valid            : IN  std_logic;
    brd_add                : IN  std_logic_vector(5 downto 0);
    int_new_DACs           : OUT std_logic := '0';
    int_new_enables        : OUT std_logic := '0';
    int_new_prescaling     : OUT std_logic := '0';
    int_read_rates         : OUT std_logic := '0';
    int_read_DACs          : OUT std_logic := '0';
    int_read_enables       : OUT std_logic := '0';
    int_read_prescaling    : OUT std_logic := '0';
    int_ping_pong          : OUT std_logic := '0';
    dac_array_rs485_out    : OUT dac_array_type;
    enable_array_rs485_out : OUT enable_array_type;
    prescaling_rs485_out   : OUT STD_LOGIC_VECTOR(7 downto 0)
  );
end FTU_rs485_interpreter;

architecture Behavioral of FTU_rs485_interpreter is

  signal block_valid_sr : std_logic_vector(3 downto 0) := (others => '0');

  signal dac_array_rs485_out_sig    : dac_array_type    := DEFAULT_DAC;
  signal enable_array_rs485_out_sig : enable_array_type := DEFAULT_ENABLE;
  signal prescaling_rs485_out_sig   : STD_LOGIC_VECTOR(7 downto 0) := conv_std_logic_vector(DEFAULT_PRESCALING,8);
  
  type FTU_rs485_interpreter_StateType is (WAIT_FOR_DATA, CHECK_HEADER, DECODE);
  signal FTU_rs485_interpreter_State : FTU_rs485_interpreter_StateType;
  
begin

  FTU_rs485_interpreter_FSM: process (clk)
  begin
    if Rising_edge(clk) then
      case FTU_rs485_interpreter_State is
        
        when WAIT_FOR_DATA => -- default state, waiting for valid 16-byte block 
          block_valid_sr <= block_valid_sr(2 downto 0) & block_valid;
          int_new_DACs        <= '0';
          int_new_enables     <= '0';
          int_new_prescaling  <= '0';
          int_read_rates      <= '0';
          int_read_DACs       <= '0'; 
          int_read_enables    <= '0';  
          int_read_prescaling <= '0';
          int_ping_pong       <= '0';
          if (block_valid_sr(3 downto 2) = "01") then  -- rising edge of valid signal
            FTU_rs485_interpreter_State <= CHECK_HEADER;
          else
            FTU_rs485_interpreter_State <= WAIT_FOR_DATA;
          end if;

        when CHECK_HEADER => -- check start delimiter and addresses
          int_new_DACs        <= '0';
          int_new_enables     <= '0';
          int_new_prescaling  <= '0';
          int_read_rates      <= '0';
          int_read_DACs       <= '0'; 
          int_read_enables    <= '0';  
          int_read_prescaling <= '0';
          int_ping_pong       <= '0';
          if (data_block(7 downto 0) = RS485_START_DELIM) and
             (data_block(15 downto 8) = ("00" & brd_add)) and  
             (data_block(23 downto 16) = FTM_ADDRESS) then
            FTU_rs485_interpreter_State <= DECODE;
           else
            FTU_rs485_interpreter_State <= WAIT_FOR_DATA;
          end if;

        when DECODE => -- decode instruction
          if(data_block(39 downto 32) = "00000000") then -- set DACs
            int_new_DACs        <= '1';
            int_new_enables     <= '0';
            int_new_prescaling  <= '0';
            int_read_rates      <= '0';
            int_read_DACs       <= '0'; 
            int_read_enables    <= '0';  
            int_read_prescaling <= '0';
            int_ping_pong       <= '0';
            dac_array_rs485_out_sig <= (conv_integer(unsigned(data_block(51 downto 40))),
                                        conv_integer(unsigned(data_block(67 downto 56))),
                                        conv_integer(unsigned(data_block(83 downto 72))),
                                        conv_integer(unsigned(data_block(99 downto 88))),
                                        DEFAULT_DAC(4),
                                        DEFAULT_DAC(5),
                                        DEFAULT_DAC(6),
                                        conv_integer(unsigned(data_block(115 downto 104)))
                                        );
            FTU_rs485_interpreter_State <= WAIT_FOR_DATA;
          elsif (data_block(39 downto 32) = "00000001") then -- read DACs
            int_new_DACs        <= '0';
            int_new_enables     <= '0';
            int_new_prescaling  <= '0';
            int_read_rates      <= '0';
            int_read_DACs       <= '1'; 
            int_read_enables    <= '0';  
            int_read_prescaling <= '0';
            int_ping_pong       <= '0';
            FTU_rs485_interpreter_State <= WAIT_FOR_DATA;
          elsif (data_block(39 downto 32) = "00000010") then -- read rates
            int_new_DACs        <= '0';
            int_new_enables     <= '0';
            int_new_prescaling  <= '0';
            int_read_rates      <= '1';
            int_read_DACs       <= '0'; 
            int_read_enables    <= '0';  
            int_read_prescaling <= '0';
            int_ping_pong       <= '0';
            FTU_rs485_interpreter_State <= WAIT_FOR_DATA;
          elsif (data_block(39 downto 32) = "00000011") then -- set enables
            int_new_DACs        <= '0';
            int_new_enables     <= '1';
            int_new_prescaling  <= '0';
            int_read_rates      <= '0';
            int_read_DACs       <= '0'; 
            int_read_enables    <= '0';  
            int_read_prescaling <= '0';
            int_ping_pong       <= '0';
            enable_array_rs485_out_sig <= (data_block(55 downto 40),
                                           data_block(71 downto 56),
                                           data_block(87 downto 72),
                                           data_block(103 downto 88)
                                           );
            FTU_rs485_interpreter_State <= WAIT_FOR_DATA;
          elsif (data_block(39 downto 32) = "00000100") then -- read enables
            int_new_DACs        <= '0';
            int_new_enables     <= '0';
            int_new_prescaling  <= '0';
            int_read_rates      <= '0';
            int_read_DACs       <= '0'; 
            int_read_enables    <= '1';  
            int_read_prescaling <= '0';
            int_ping_pong       <= '0';
            FTU_rs485_interpreter_State <= WAIT_FOR_DATA;
          elsif (data_block(39 downto 32) = "00000110") then -- set counter mode
            int_new_DACs        <= '0';
            int_new_enables     <= '0';
            int_new_prescaling  <= '1';
            int_read_rates      <= '0';
            int_read_DACs       <= '0'; 
            int_read_enables    <= '0';  
            int_read_prescaling <= '0';
            int_ping_pong       <= '0';
            prescaling_rs485_out_sig <= data_block(47 downto 40);
            FTU_rs485_interpreter_State <= WAIT_FOR_DATA;
          elsif (data_block(39 downto 32) = "00000111") then -- read counter mode
            int_new_DACs        <= '0';
            int_new_enables     <= '0';
            int_new_prescaling  <= '0';
            int_read_rates      <= '0';
            int_read_DACs       <= '0'; 
            int_read_enables    <= '0';  
            int_read_prescaling <= '1';
            int_ping_pong       <= '0';
            FTU_rs485_interpreter_State <= WAIT_FOR_DATA;
          elsif (data_block(39 downto 32) = "00000101") then -- ping pong
            int_new_DACs        <= '0';
            int_new_enables     <= '0';
            int_new_prescaling  <= '0';
            int_read_rates      <= '0';
            int_read_DACs       <= '0'; 
            int_read_enables    <= '0';  
            int_read_prescaling <= '0';
            int_ping_pong       <= '1';
            FTU_rs485_interpreter_State <= WAIT_FOR_DATA;
          else
            int_new_DACs        <= '0';
            int_new_enables     <= '0';
            int_new_prescaling  <= '0';
            int_read_rates      <= '0';
            int_read_DACs       <= '0'; 
            int_read_enables    <= '0';  
            int_read_prescaling <= '0';
            int_ping_pong       <= '0';
            FTU_rs485_interpreter_State <= WAIT_FOR_DATA;
          end if;
          
      end case;
    end if;
  end process FTU_rs485_interpreter_FSM;

  dac_array_rs485_out <= dac_array_rs485_out_sig;
  enable_array_rs485_out <= enable_array_rs485_out_sig;
  prescaling_rs485_out <= prescaling_rs485_out_sig;
  
end Behavioral;
