----------------------------------------------------------------------------------
-- Company:        ETH Zurich, Institute for Particle Physics
-- Engineer:       Q. Weitzel, P. Vogler
-- 
-- Create Date:    08/06/2010
-- Design Name:    
-- Module Name:    FTU_control - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description:    Control FSM of FACT FTU board 										
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Revision 0.02 - change-over to 64 byte RAM, 19.10.2010, Q. Weitzel
-- 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_control is
  port(
    clk_50MHz               : IN  std_logic;
    clk_ready               : IN  std_logic;   -- from DCM
    config_started          : IN  std_logic;   -- from DAC/SPI
    config_ready            : IN  std_logic;   -- from DAC/SPI
    ram_doa                 : IN  STD_LOGIC_VECTOR(7 downto 0);
    ram_dob                 : IN  STD_LOGIC_VECTOR(15 downto 0);
    rate_array              : IN  rate_array_type;  -- from counters
    overflow_array          : IN  STD_LOGIC_VECTOR(7 downto 0);  -- from counters
    new_rates               : IN  std_logic;   -- from counters
    new_DACs                : IN  std_logic;   -- from RS485 module
    new_enables             : IN  std_logic;   -- from RS485 module
    new_prescaling          : IN  std_logic;   -- from RS485 module
    read_rates              : IN  std_logic;   -- from RS485 module
    read_DACs               : IN  std_logic;   -- from RS485 module
    read_enables            : IN  std_logic;   -- from RS485 module
    read_prescaling         : IN  std_logic;   -- from RS485 module
    ping_pong               : IN  std_logic;   -- from RS485 module
    dac_array_rs485_out     : IN  dac_array_type;                -- from RS485 module
    enable_array_rs485_out  : IN  enable_array_type;             -- from RS485 module
    prescaling_rs485_out    : IN  STD_LOGIC_VECTOR(7 downto 0);  -- from RS485 module
    dna_ready               : IN  std_logic;  -- from FTU_dna_gen
    reset                   : OUT std_logic;
    config_start            : OUT std_logic;
    ram_ena                 : OUT std_logic;
    ram_enb                 : OUT std_logic;
    ram_wea                 : OUT STD_LOGIC_VECTOR(0 downto 0);
    ram_web                 : OUT STD_LOGIC_VECTOR(0 downto 0);
    ram_ada                 : OUT STD_LOGIC_VECTOR(5 downto 0);
    ram_adb                 : OUT STD_LOGIC_VECTOR(4 downto 0);
    ram_dia                 : OUT STD_LOGIC_VECTOR(7 downto 0);
    ram_dib                 : OUT STD_LOGIC_VECTOR(15 downto 0);
    rate_array_rs485        : OUT rate_array_type := (0,0,0,0,0);              -- to RS485 module
    overflow_array_rs485_in : OUT STD_LOGIC_VECTOR(7 downto 0) := "00000000";  -- to RS485 module
    rates_ready             : OUT std_logic := '0';   -- to RS485 module
    DACs_ready              : OUT std_logic := '0';   -- to RS485 module
    enables_ready           : OUT std_logic := '0';   -- to RS485 module
    prescaling_ready        : OUT std_logic := '0';   -- to RS485 module
    ping_pong_ready         : OUT std_logic := '0';   -- to RS485 module
    dac_array               : OUT dac_array_type;
    enable_array            : OUT enable_array_type;
    cntr_reset              : OUT STD_LOGIC;
    prescaling              : OUT STD_LOGIC_VECTOR(7 downto 0);
    dna_start               : OUT std_logic := '0'  -- to FTU_dna_gen
  );
end FTU_control;

architecture Behavioral of FTU_control is

  signal new_rates_sr : std_logic_vector(1 downto 0) := (others => '0');
  
  signal reset_sig : STD_LOGIC := '0';  --initialize reset to 0 at power up

  --DAC/SPI interface, default DACs come from RAM during INIT
  signal config_start_sig : STD_LOGIC := '0';
  signal dac_array_sig : dac_array_type := (0,0,0,0,0,0,0,0);

  --enable signals for pixels in trigger, default values come from RAM during INIT
  signal enable_array_sig : enable_array_type := ("0000000000000000", --patch A
                                                  "0000000000000000", --patch B
                                                  "0000000000000000", --patch C
                                                  "0000000000000000");--patch D

  signal rate_array_sig : rate_array_type;  -- initialized in FTU_top
  signal cntr_reset_sig : STD_LOGIC := '0';
  signal prescaling_sig : STD_LOGIC_VECTOR(7 downto 0) := "00011101";  -- 29
  
  signal ram_ena_sig  : STD_LOGIC := '0';  -- RAM enable for port A
  signal ram_enb_sig  : STD_LOGIC := '0';  -- RAM enable for port B
  signal ram_wea_sig  : STD_LOGIC_VECTOR(0 downto 0) := "0";  -- RAM write enable for port A
  signal ram_web_sig  : STD_LOGIC_VECTOR(0 downto 0) := "0";  -- RAM write enable for port B  
  signal ram_ada_sig  : STD_LOGIC_VECTOR(5 downto 0) := (others => '0');  --RAM port A address
  signal ram_adb_sig  : STD_LOGIC_VECTOR(4 downto 0) := (others => '0');  --RAM port B address
  signal ram_dia_sig  : STD_LOGIC_VECTOR(7 downto 0) := (others => '0');  --RAM data in A
  signal ram_dib_sig  : STD_LOGIC_VECTOR(15 downto 0) := (others => '0'); --RAM data in B

  --counter to loop through RAM
  signal ram_ada_cntr     : INTEGER range 0 to 2**RAM_ADDR_WIDTH_A := 0;
  signal ram_dac_cntr     : INTEGER range 0 to (NO_OF_DAC - NO_OF_DAC_NOT_USED + 2) := 0;
  signal ram_enable_cntr  : INTEGER range 0 to (NO_OF_ENABLE + 1) := 0;
  signal ram_counter_cntr : INTEGER range 0 to (NO_OF_COUNTER*RAM_CEF + 2) := 0;  --includes overflow register
  
  signal wait_cntr : INTEGER range 0 to 2**RAM_ADDR_WIDTH_A := 0;

  signal new_rates_sig  : STD_LOGIC := '0';
  signal new_rates_busy : STD_LOGIC := '1';  -- veto the writing of new rates until in RUNNING
  
  signal new_DACs_in_RAM       : STD_LOGIC := '0';
  signal new_enables_in_RAM    : STD_LOGIC := '0';
  signal new_prescaling_in_RAM : STD_LOGIC := '0';

  signal ram_buffer_sig : STD_LOGIC_VECTOR(29 downto 0) := (others => '0');
  
  type FTU_control_StateType is (IDLE, INIT_RAM, INIT_DNA, RUNNING,
                                 CONFIG_ENABLE, CONFIG_DAC, CONFIG_DAC_WAIT, CONFIG_COUNTER,
                                 WRITE_RATES, WRITE_DAC, WRITE_ENABLE, WRITE_PRESCALING,
                                 READOUT_RATES, READOUT_DAC, READOUT_ENABLE, READOUT_PRESCALING,
                                 DO_PING_PONG);
  signal FTU_control_State : FTU_control_StateType;
  
begin
   
  --FTU control finite state machine

  FTU_control_FSM: process (clk_50MHz)

  begin

    reset_sig <= '0';
           
    if Rising_edge(clk_50MHz) then

      case FTU_control_State is

        when IDLE =>  -- wait for DCMs to lock
          if (clk_ready = '1') then
            FTU_control_State <= INIT_DNA;
          else
            FTU_control_State <= IDLE;
          end if;

        when INIT_DNA =>  -- determine FPGA DNA
          if (dna_ready = '1') then
            FTU_control_State <= INIT_RAM;
            dna_start <= '0';
          else
            dna_start <= '1';
            FTU_control_State <= INIT_DNA;
          end if;
                         
        when INIT_RAM =>  -- load default config data to RAM, see also ftu_definitions.vhd for more info
          ram_ena_sig <= '1';
          ram_wea_sig <= "1";
          ram_ada_cntr <= ram_ada_cntr + 1;
          ram_ada_sig <= conv_std_logic_vector(ram_ada_cntr, RAM_ADDR_WIDTH_A);        
          if (ram_ada_cntr < NO_OF_ENABLE*RAM_ADDR_RATIO) then  -- default enables
            if (ram_ada_cntr mod 2 = 0) then
              ram_dia_sig <= DEFAULT_ENABLE(ram_ada_cntr / 2)(7 downto 0);
            else
              ram_dia_sig <= DEFAULT_ENABLE(ram_ada_cntr / 2)(15 downto 8);
            end if;
            FTU_control_State <= INIT_RAM;
          elsif (ram_ada_cntr < (NO_OF_ENABLE*RAM_ADDR_RATIO + NO_OF_COUNTER*RAM_ADDR_RATIO*RAM_CEF)) then  -- default counter values
            ram_dia_sig <= (others => '0');
            FTU_control_State <= INIT_RAM;
          elsif (ram_ada_cntr < (NO_OF_ENABLE*RAM_ADDR_RATIO + NO_OF_COUNTER*RAM_ADDR_RATIO*RAM_CEF + (NO_OF_DAC - NO_OF_DAC_NOT_USED)*RAM_ADDR_RATIO)) then  -- default DACs
            if (ram_ada_cntr < (NO_OF_ENABLE*RAM_ADDR_RATIO + NO_OF_COUNTER*RAM_ADDR_RATIO*RAM_CEF + (NO_OF_DAC - NO_OF_DAC_NOT_USED - 1)*RAM_ADDR_RATIO)) then
              if (ram_ada_cntr mod 2 = 0) then
                ram_dia_sig <= conv_std_logic_vector(DEFAULT_DAC((ram_ada_cntr - (NO_OF_ENABLE*RAM_ADDR_RATIO + NO_OF_COUNTER*RAM_ADDR_RATIO*RAM_CEF)) / 2),16)(7 downto 0);
              else
                ram_dia_sig <= conv_std_logic_vector(DEFAULT_DAC((ram_ada_cntr - (NO_OF_ENABLE*RAM_ADDR_RATIO + NO_OF_COUNTER*RAM_ADDR_RATIO*RAM_CEF)) / 2),16)(15 downto 8);
              end if;
            else
              if (ram_ada_cntr mod 2 = 0) then
                ram_dia_sig <= conv_std_logic_vector(DEFAULT_DAC(((ram_ada_cntr - (NO_OF_ENABLE*RAM_ADDR_RATIO + NO_OF_COUNTER*RAM_ADDR_RATIO*RAM_CEF)) / 2) + NO_OF_DAC_NOT_USED),16)(7 downto 0);
              else
                ram_dia_sig <= conv_std_logic_vector(DEFAULT_DAC(((ram_ada_cntr - (NO_OF_ENABLE*RAM_ADDR_RATIO + NO_OF_COUNTER*RAM_ADDR_RATIO*RAM_CEF)) / 2) + NO_OF_DAC_NOT_USED),16)(15 downto 8);
              end if;
            end if;
            FTU_control_State <= INIT_RAM;
          elsif (ram_ada_cntr = (NO_OF_ENABLE*RAM_ADDR_RATIO + NO_OF_COUNTER*RAM_ADDR_RATIO*RAM_CEF + (NO_OF_DAC - NO_OF_DAC_NOT_USED)*RAM_ADDR_RATIO)) then  -- default prescaling
            ram_dia_sig <= conv_std_logic_vector(DEFAULT_PRESCALING,8);
            FTU_control_State <= INIT_RAM;
          elsif (ram_ada_cntr = (NO_OF_ENABLE*RAM_ADDR_RATIO + NO_OF_COUNTER*RAM_ADDR_RATIO*RAM_CEF + (NO_OF_DAC - NO_OF_DAC_NOT_USED)*RAM_ADDR_RATIO) + 1) then  -- default overflow register
            ram_dia_sig <= (others => '0');
            FTU_control_State <= INIT_RAM;
          elsif (ram_ada_cntr = (NO_OF_ENABLE*RAM_ADDR_RATIO + NO_OF_COUNTER*RAM_ADDR_RATIO*RAM_CEF + (NO_OF_DAC - NO_OF_DAC_NOT_USED)*RAM_ADDR_RATIO) + 2) then  -- default CRC errors
            ram_dia_sig <= (others => '0');
            FTU_control_State <= INIT_RAM;
          elsif (ram_ada_cntr < 2**RAM_ADDR_WIDTH_A) then  -- empty RAM cells
            ram_dia_sig <= (others => '0');
            FTU_control_State <= INIT_RAM;
          else
            ram_dia_sig <= (others => '0');
            ram_ada_cntr <= 0;
            ram_ada_sig <= (others => '0');
            ram_ena_sig <= '0';
            ram_wea_sig <= "0";
            new_DACs_in_RAM <= '1';
            new_enables_in_RAM <= '1';
            new_prescaling_in_RAM <= '1';
            cntr_reset_sig <= '1';
            new_rates_busy <= '0';
            FTU_control_State <= RUNNING;
          end if;
                    
        when RUNNING =>  -- count triggers and react to commands from FTM
          cntr_reset_sig <= '0';
          config_start_sig <= '0';
          if (new_rates_sig = '1') then  -- counters have finished a period
            FTU_control_State <= WRITE_RATES;
          else  -- update FTU settings if necessary
            if (new_DACs_in_RAM = '1') then
              ram_enb_sig <= '1';
              ram_adb_sig <= conv_std_logic_vector((NO_OF_ENABLE + NO_OF_COUNTER*RAM_CEF), RAM_ADDR_WIDTH_B);
              FTU_control_State <= CONFIG_DAC;
            elsif (new_DACs_in_RAM = '0' and new_enables_in_RAM = '1') then
              ram_enb_sig <= '1';
              ram_adb_sig <= conv_std_logic_vector(0, RAM_ADDR_WIDTH_B);
              FTU_control_State <= CONFIG_ENABLE;
            elsif (new_DACs_in_RAM = '0' and new_enables_in_RAM = '0' and new_prescaling_in_RAM = '1') then
              ram_ena_sig <= '1';
              ram_ada_sig <= conv_std_logic_vector((NO_OF_ENABLE*RAM_ADDR_RATIO + NO_OF_COUNTER*RAM_ADDR_RATIO*RAM_CEF + (NO_OF_DAC - NO_OF_DAC_NOT_USED)*RAM_ADDR_RATIO), RAM_ADDR_WIDTH_A);
              FTU_control_State <= CONFIG_COUNTER;
            else  -- nothing to be updated, check new commands from RS485
              if (new_DACs = '1') then
                FTU_control_State <= WRITE_DAC;
              elsif (new_DACs = '0' and new_enables = '1') then
                FTU_control_State <= WRITE_ENABLE;
              elsif (new_DACs = '0' and new_enables = '0' and new_prescaling = '1') then
                FTU_control_State <= WRITE_PRESCALING;
              elsif (new_DACs = '0' and new_enables = '0' and new_prescaling = '0' and
                   read_rates = '1') then
                ram_enb_sig <= '1';
                ram_adb_sig <= conv_std_logic_vector(NO_OF_ENABLE, RAM_ADDR_WIDTH_B);
                FTU_control_State <= READOUT_RATES;
              elsif (new_DACs = '0' and new_enables = '0' and new_prescaling = '0' and
                   read_rates = '0' and read_DACs = '1') then
                ram_enb_sig <= '1';
                ram_adb_sig <= conv_std_logic_vector(NO_OF_ENABLE + NO_OF_COUNTER*RAM_CEF, RAM_ADDR_WIDTH_B);
                FTU_control_State <= READOUT_DAC;
              elsif (new_DACs = '0' and new_enables = '0' and new_prescaling = '0' and
                   read_rates = '0' and read_DACs = '0' and read_enables = '1') then
                ram_enb_sig <= '1';
                ram_adb_sig <= conv_std_logic_vector(0, RAM_ADDR_WIDTH_B);
                FTU_control_State <= READOUT_ENABLE;
              elsif (new_DACs = '0' and new_enables = '0' and new_prescaling = '0' and
                   read_rates = '0' and read_DACs = '0' and read_enables = '0' and read_prescaling = '1') then
                ram_ena_sig <= '1';
                ram_ada_sig <= conv_std_logic_vector((NO_OF_ENABLE*RAM_ADDR_RATIO + NO_OF_COUNTER*RAM_ADDR_RATIO*RAM_CEF + (NO_OF_DAC - NO_OF_DAC_NOT_USED)*RAM_ADDR_RATIO), RAM_ADDR_WIDTH_A);
                FTU_control_State <= READOUT_PRESCALING;
              elsif (new_DACs = '0' and new_enables = '0' and new_prescaling = '0' and
                   read_rates = '0' and read_DACs = '0' and read_enables = '0' and read_prescaling = '0' and
                   ping_pong = '1') then
                FTU_control_State <= DO_PING_PONG;                
              else                
                FTU_control_State <= RUNNING;  --no commands from RS485 -> stay running
              end if;
            end if;
          end if;

        when CONFIG_COUNTER =>
          wait_cntr <= wait_cntr + 1;
          new_rates_busy <= '1';
          if (wait_cntr = 0) then
            FTU_control_State <= CONFIG_COUNTER;
          elsif (wait_cntr = 1) then
            prescaling_sig <= ram_doa;
            FTU_control_State <= CONFIG_COUNTER;
            prescaling_ready <= '1';
          else
            cntr_reset_sig <= '1';
            ram_ada_sig <= (others => '0');
            wait_cntr <= 0;
            new_prescaling_in_RAM <= '0';
            ram_ena_sig <= '0';
            new_rates_busy <= '0';
            prescaling_ready <= '0';
            FTU_control_State <= RUNNING;
          end if;
          
        when CONFIG_ENABLE =>
          ram_enable_cntr <= ram_enable_cntr + 1;
          new_rates_busy <= '1';
          if (ram_enable_cntr = 0) then
            ram_adb_sig <= conv_std_logic_vector(ram_enable_cntr + 1, RAM_ADDR_WIDTH_B);
            FTU_control_State <= CONFIG_ENABLE;
          elsif (ram_enable_cntr > 0 and ram_enable_cntr < NO_OF_ENABLE + 1) then
            ram_adb_sig <= conv_std_logic_vector(ram_enable_cntr + 1, RAM_ADDR_WIDTH_B);
            enable_array_sig(ram_enable_cntr - 1) <= ram_dob;
            enables_ready <= '1';
            FTU_control_State <= CONFIG_ENABLE;
          else
            ram_adb_sig <= (others => '0');
            ram_enable_cntr <= 0;
            new_enables_in_RAM <= '0';
            ram_enb_sig <= '0';
            cntr_reset_sig <= '1';
            new_rates_busy <= '0';
            enables_ready <= '0';
            FTU_control_State <= RUNNING;
          end if;
          
        when CONFIG_DAC =>
          new_rates_busy <= '1';
          ram_dac_cntr <= ram_dac_cntr + 1;
          if (ram_dac_cntr = 0) then
            ram_adb_sig <= conv_std_logic_vector((NO_OF_ENABLE + NO_OF_COUNTER*RAM_CEF + ram_dac_cntr + 1), RAM_ADDR_WIDTH_B);
            FTU_control_State <= CONFIG_DAC;
          elsif (ram_dac_cntr < (NO_OF_DAC - NO_OF_DAC_NOT_USED)) then
            dac_array_sig(ram_dac_cntr - 1) <= conv_integer(unsigned(ram_dob(11 downto 0)));
            ram_adb_sig <= conv_std_logic_vector((NO_OF_ENABLE + NO_OF_COUNTER*RAM_CEF + ram_dac_cntr + 1), RAM_ADDR_WIDTH_B);
            FTU_control_State <= CONFIG_DAC;
          elsif (ram_dac_cntr < (NO_OF_DAC - NO_OF_DAC_NOT_USED + 1)) then
            dac_array_sig(4) <= 0;
            dac_array_sig(5) <= 0;
            dac_array_sig(6) <= 0;
            dac_array_sig(ram_dac_cntr - 1 + NO_OF_DAC_NOT_USED) <= conv_integer(unsigned(ram_dob(11 downto 0)));
            ram_adb_sig <= (others => '0');
            FTU_control_State <= CONFIG_DAC;
            DACs_ready <= '1';
          else
            ram_adb_sig <= (others => '0');
            ram_enb_sig <= '0';
            config_start_sig <= '1';
            ram_dac_cntr <= 0;
            DACs_ready <= '0';
            FTU_control_State <= CONFIG_DAC_WAIT;
          end if;
          
        when CONFIG_DAC_WAIT =>
          if (config_ready = '1') then
            new_DACs_in_RAM <= '0';
            cntr_reset_sig <= '1';
            new_rates_busy <= '0';
            config_start_sig <= '0';
            FTU_control_State <= RUNNING;
          elsif (config_ready = '0' and config_started = '1') then
            new_rates_busy <= '1';
            config_start_sig <= '0';
            FTU_control_State <= CONFIG_DAC_WAIT;
          else
            new_rates_busy <= '1';
            config_start_sig <= '1';
            FTU_control_State <= CONFIG_DAC_WAIT;
          end if;
          
        when WRITE_RATES =>  -- write trigger/patch rates to RAM B and overflow register to RAM A
          new_rates_busy <= '1';
          ram_counter_cntr <= ram_counter_cntr + 1;
          if (ram_counter_cntr < NO_OF_COUNTER*RAM_CEF) then
            ram_enb_sig <= '1';
            ram_web_sig <= "1";         
            ram_adb_sig <= conv_std_logic_vector((NO_OF_ENABLE + ram_counter_cntr), RAM_ADDR_WIDTH_B);
            if (ram_counter_cntr mod 2 = 0) then
              ram_dib_sig <= conv_std_logic_vector(rate_array_sig(ram_counter_cntr / 2), 32)(15 downto 0);
            else
              ram_dib_sig <= conv_std_logic_vector(rate_array_sig(ram_counter_cntr / 2), 32)(31 downto 16);
            end if;
            FTU_control_State <= WRITE_RATES;
          elsif (ram_counter_cntr = NO_Of_COUNTER*RAM_CEF) then
            ram_dib_sig <= (others => '0');
            ram_adb_sig <= (others => '0');
            ram_enb_sig <= '0';
            ram_web_sig <= "0";
            ram_ena_sig <= '1';
            ram_wea_sig <= "1";
            ram_ada_sig <= conv_std_logic_vector(NO_OF_ENABLE*RAM_ADDR_RATIO + NO_OF_COUNTER*RAM_ADDR_RATIO*RAM_CEF + (NO_OF_DAC - NO_OF_DAC_NOT_USED)*RAM_ADDR_RATIO + 1, RAM_ADDR_WIDTH_A);
            ram_dia_sig <= overflow_array;
            FTU_control_State <= WRITE_RATES;
          else              
            ram_ena_sig <= '0';
            ram_wea_sig <= "0";
            ram_counter_cntr <= 0;
            new_rates_busy <= '0';
            FTU_control_State <= RUNNING;
          end if;

        when WRITE_DAC =>  -- write new DAC values from RS485 to RAM
          ram_dac_cntr <= ram_dac_cntr + 1;
          if (ram_dac_cntr < (NO_OF_DAC - NO_OF_DAC_NOT_USED - 1)) then
            ram_enb_sig <= '1';
            ram_web_sig <= "1";         
            ram_adb_sig <= conv_std_logic_vector((NO_OF_ENABLE + NO_OF_COUNTER*RAM_CEF + ram_dac_cntr), RAM_ADDR_WIDTH_B);
            ram_dib_sig <= conv_std_logic_vector(dac_array_rs485_out(ram_dac_cntr), 16);
            FTU_control_State <= WRITE_DAC;
          elsif (ram_dac_cntr = (NO_OF_DAC - NO_OF_DAC_NOT_USED - 1)) then
            ram_enb_sig <= '1';
            ram_web_sig <= "1";         
            ram_adb_sig <= conv_std_logic_vector((NO_OF_ENABLE + NO_OF_COUNTER*RAM_CEF + ram_dac_cntr), RAM_ADDR_WIDTH_B);
            ram_dib_sig <= conv_std_logic_vector(dac_array_rs485_out(ram_dac_cntr + NO_OF_DAC_NOT_USED), 16);
            FTU_control_State <= WRITE_DAC;
          else
            ram_enb_sig <= '0';
            ram_web_sig <= "0";
            new_DACs_in_RAM <= '1';
            ram_dib_sig <= (others => '0');
            ram_adb_sig <= (others => '0');
            ram_dac_cntr <= 0;
            FTU_control_State <= RUNNING;
          end if;

        when WRITE_ENABLE =>  -- write new enable patterns from RS485 to RAM
          ram_enable_cntr <= ram_enable_cntr + 1;
          if (ram_enable_cntr < NO_OF_ENABLE) then
            ram_enb_sig <= '1';
            ram_web_sig <= "1";  
            ram_adb_sig <= conv_std_logic_vector(ram_enable_cntr, RAM_ADDR_WIDTH_B);
            ram_dib_sig <= enable_array_rs485_out(ram_enable_cntr);
          else
            ram_enb_sig <= '0';
            ram_web_sig <= "0";
            new_enables_in_RAM <= '1';
            ram_dib_sig <= (others => '0');
            ram_adb_sig <= (others => '0');
            ram_enable_cntr <= 0;
            FTU_control_State <= RUNNING;
          end if;

        when WRITE_PRESCALING =>  -- write new prescaling from RS485 to RAM
          wait_cntr <= wait_cntr + 1;
          if (wait_cntr = 0) then            
            ram_ena_sig <= '1';
            ram_wea_sig <= "1";
            ram_ada_sig <= conv_std_logic_vector((NO_OF_ENABLE*RAM_ADDR_RATIO + NO_OF_COUNTER*RAM_ADDR_RATIO*RAM_CEF + (NO_OF_DAC - NO_OF_DAC_NOT_USED)*RAM_ADDR_RATIO), RAM_ADDR_WIDTH_A);
            ram_dia_sig <= prescaling_rs485_out;
          else
            ram_ena_sig <= '0';
            ram_wea_sig <= "0";
            new_prescaling_in_RAM <= '1';
            ram_dia_sig <= (others => '0');
            ram_ada_sig <= (others => '0');
            wait_cntr <= 0;
            FTU_control_State <= RUNNING;
          end if;

        when READOUT_RATES =>  -- read most recent rate values from RAM and send them to RS485 module
          ram_counter_cntr <= ram_counter_cntr + 1;
          if (ram_counter_cntr = 0) then
            ram_enb_sig <= '1';
            ram_adb_sig <= conv_std_logic_vector((NO_OF_ENABLE + ram_counter_cntr + 1), RAM_ADDR_WIDTH_B);
            FTU_control_State <= READOUT_RATES;
          elsif (ram_counter_cntr < 3) then
            ram_ena_sig <= '1';
            ram_ada_sig <= conv_std_logic_vector(((NO_OF_ENABLE + NO_OF_COUNTER*RAM_CEF + NO_OF_DAC - NO_OF_DAC_NOT_USED)*RAM_ADDR_RATIO + 1), RAM_ADDR_WIDTH_A);
            ram_enb_sig <= '1';
            ram_adb_sig <= conv_std_logic_vector((NO_OF_ENABLE + ram_counter_cntr + 1), RAM_ADDR_WIDTH_B);
            if (ram_counter_cntr = 1) then
              ram_buffer_sig(15 downto 0) <= ram_dob;
            else
              ram_buffer_sig(29 downto 16) <= ram_dob(13 downto 0);
            end if;
            FTU_control_State <= READOUT_RATES;
          elsif (ram_counter_cntr < NO_OF_COUNTER*RAM_CEF) then
            ram_ena_sig <= '1';
            ram_ada_sig <= conv_std_logic_vector(((NO_OF_ENABLE + NO_OF_COUNTER*RAM_CEF + NO_OF_DAC - NO_OF_DAC_NOT_USED)*RAM_ADDR_RATIO + 1), RAM_ADDR_WIDTH_A);
            ram_enb_sig <= '1';
            ram_adb_sig <= conv_std_logic_vector((NO_OF_ENABLE + ram_counter_cntr + 1), RAM_ADDR_WIDTH_B);
            if (ram_counter_cntr mod 2 = 1) then
              ram_buffer_sig(15 downto 0) <= ram_dob;
              rate_array_rs485((ram_counter_cntr / 2) - 1) <= conv_integer(unsigned(ram_buffer_sig));
            else
              ram_buffer_sig(29 downto 16) <= ram_dob(13 downto 0);
            end if;
            FTU_control_State <= READOUT_RATES;
          elsif (ram_counter_cntr = NO_Of_COUNTER*RAM_CEF) then
            ram_enb_sig <= '0';
            ram_adb_sig <= (others => '0');
            ram_buffer_sig(29 downto 16) <= ram_dob(13 downto 0);
            ram_ena_sig <= '1';
            ram_ada_sig <= conv_std_logic_vector(((NO_OF_ENABLE + NO_OF_COUNTER*RAM_CEF + NO_OF_DAC - NO_OF_DAC_NOT_USED)*RAM_ADDR_RATIO + 1), RAM_ADDR_WIDTH_A);
            FTU_control_State <= READOUT_RATES;
          elsif (ram_counter_cntr = NO_Of_COUNTER*RAM_CEF + 1) then
            rate_array_rs485((ram_counter_cntr / 2) - 1) <= conv_integer(unsigned(ram_buffer_sig));
            ram_buffer_sig <= (others => '0');
            ram_enb_sig <= '0';
            ram_adb_sig <= (others => '0');
            ram_ena_sig <= '0';
            ram_ada_sig <= (others => '0');
            overflow_array_rs485_in <= ram_doa;
            rates_ready <= '1';
            FTU_control_State <= READOUT_RATES;
          else              
            ram_enb_sig <= '0';
            ram_adb_sig <= (others => '0');
            ram_ena_sig <= '0';
            ram_ada_sig <= (others => '0');
            ram_counter_cntr <= 0;
            rates_ready <= '0';
            FTU_control_State <= RUNNING;
          end if;

        when READOUT_DAC =>  -- read most recent DAC values from RAM and send them to RS485 module
          ram_dac_cntr <= ram_dac_cntr + 1;
          if (ram_dac_cntr = 0) then
            ram_enb_sig <= '1';
            ram_adb_sig <= conv_std_logic_vector((NO_OF_ENABLE + NO_OF_COUNTER*RAM_CEF + ram_dac_cntr + 1), RAM_ADDR_WIDTH_B);
            FTU_control_State <= READOUT_DAC;
          elsif (ram_dac_cntr < (NO_OF_DAC - NO_OF_DAC_NOT_USED)) then
            ram_enb_sig <= '1';
            ram_adb_sig <= conv_std_logic_vector((NO_OF_ENABLE + NO_OF_COUNTER*RAM_CEF + ram_dac_cntr + 1), RAM_ADDR_WIDTH_B);
            dac_array_sig(ram_dac_cntr - 1) <= conv_integer(unsigned(ram_dob(11 downto 0)));
            FTU_control_State <= READOUT_DAC;
          elsif (ram_dac_cntr = (NO_OF_DAC - NO_OF_DAC_NOT_USED)) then
            ram_enb_sig <= '0';
            ram_adb_sig <= (others => '0');
            dac_array_sig(ram_dac_cntr + NO_OF_DAC_NOT_USED - 1) <= conv_integer(unsigned(ram_dob(11 downto 0)));
            DACs_ready <= '1';
            FTU_control_State <= READOUT_DAC;
          else
            ram_enb_sig <= '0';
            ram_adb_sig <= (others => '0');
            DACs_ready <= '0';
            ram_dac_cntr <= 0;
            FTU_control_State <= RUNNING;
          end if;

        when READOUT_ENABLE =>  -- read most recent enable patterns from RAM and send them to RS485 module
          ram_enable_cntr <= ram_enable_cntr + 1;
          if (ram_enable_cntr = 0) then
            ram_enb_sig <= '1';
            ram_adb_sig <= conv_std_logic_vector((ram_enable_cntr + 1), RAM_ADDR_WIDTH_B);
            FTU_control_State <= READOUT_ENABLE;
          elsif (ram_enable_cntr < NO_OF_ENABLE) then
            ram_enb_sig <= '1';
            ram_adb_sig <= conv_std_logic_vector((ram_enable_cntr + 1), RAM_ADDR_WIDTH_B);
            enable_array_sig(ram_enable_cntr - 1) <= ram_dob;
            FTU_control_State <= READOUT_ENABLE;
          elsif (ram_enable_cntr = NO_OF_ENABLE) then
            ram_enb_sig <= '0';
            ram_adb_sig <= (others => '0');
            enable_array_sig(ram_enable_cntr - 1) <= ram_dob;
            enables_ready <= '1';
            FTU_control_State <= READOUT_ENABLE;
          else
            ram_enb_sig <= '0';
            ram_adb_sig <= (others => '0');
            enables_ready <= '0';
            ram_enable_cntr <= 0;
            FTU_control_State <= RUNNING;
          end if;

        when READOUT_PRESCALING =>  -- read most recent prescaling value from RAM and send it to RS485 module
          wait_cntr <= wait_cntr + 1;
          if (wait_cntr = 0) then
            ram_ena_sig <= '1';
            ram_ada_sig <= conv_std_logic_vector((NO_OF_ENABLE*RAM_ADDR_RATIO + NO_OF_COUNTER*RAM_ADDR_RATIO*RAM_CEF + (NO_OF_DAC - NO_OF_DAC_NOT_USED)*RAM_ADDR_RATIO) + 1, RAM_ADDR_WIDTH_A);
            FTU_control_State <= READOUT_PRESCALING;
          elsif (wait_cntr = 1) then
            ram_ena_sig <= '1';
            ram_ada_sig <= (others => '0');
            prescaling_sig <= ram_doa;
            FTU_control_State <= READOUT_PRESCALING;
          elsif (wait_cntr = 2) then
            ram_ena_sig <= '0';
            ram_ada_sig <= (others => '0');
            overflow_array_rs485_in <= ram_doa;
            prescaling_ready <= '1';
            FTU_control_State <= READOUT_PRESCALING;
          else
            ram_ena_sig <= '0';
            ram_ada_sig <= (others => '0');
            prescaling_ready <= '0';
            wait_cntr <= 0;
            FTU_control_State <= RUNNING;
          end if;

        when DO_PING_PONG =>  -- just answer to FTM 
          wait_cntr <= wait_cntr + 1;
          if (wait_cntr = 0) then
            ping_pong_ready <= '1';
            FTU_control_State <= DO_PING_PONG;
          else
            ping_pong_ready <= '0';
            wait_cntr <= 0;
            FTU_control_State <= RUNNING;
          end if;
            
      end case;
    end if;
  end process FTU_control_FSM;

  --detect_new_rates: process(new_rates, new_rates_busy)
  --begin
    --if(new_rates_busy = '1') then
      --new_rates_sig <= '0';
    --elsif rising_edge(new_rates) then
      --new_rates_sig <= '1';
    --end if;
  --end process detect_new_rates;

  detect_new_rates: process(clk_50MHz)
  begin
    if rising_edge(clk_50MHz) then
      new_rates_sr <= new_rates_sr(new_rates_sr'left - 1 downto 0) & new_rates;
      if(new_rates_busy = '1') then
        new_rates_sig <= '0';
      else
        if (new_rates_sr(1 downto 0) = "01") then 
          new_rates_sig <= '1';
        end if;
      end if;
    end if;
  end process detect_new_rates;
    
  reset <= reset_sig;

  config_start <= config_start_sig;  
  dac_array    <= dac_array_sig;

  enable_array <= enable_array_sig;
  prescaling   <= prescaling_sig;
  
  rate_array_sig <= rate_array;
  cntr_reset     <= cntr_reset_sig;
    
  ram_ena <= ram_ena_sig;
  ram_enb <= ram_enb_sig;
  ram_wea <= ram_wea_sig;
  ram_web <= ram_web_sig;
  ram_ada <= ram_ada_sig;
  ram_adb <= ram_adb_sig;
  ram_dia <= ram_dia_sig;
  ram_dib <= ram_dib_sig;
      
end Behavioral;
