]> jspc29.x-matter.uni-frankfurt.de Git - trb3.git/commitdiff
Added source directory forgotten last time
authorhadeshyp <hadeshyp>
Sat, 29 Sep 2012 11:50:06 +0000 (11:50 +0000)
committerhadeshyp <hadeshyp>
Sat, 29 Sep 2012 11:50:06 +0000 (11:50 +0000)
cts/source/cts.vhd [new file with mode: 0755]
cts/source/cts_fifo.vhd [new file with mode: 0755]
cts/source/cts_pkg.vhd [new file with mode: 0755]
cts/source/cts_trg_coin.vhd [new file with mode: 0755]
cts/source/cts_trg_input.vhd [new file with mode: 0755]
cts/source/cts_trg_pseudorand_pulser.vhd [new file with mode: 0755]
cts/source/cts_trigger.vhd [new file with mode: 0755]

diff --git a/cts/source/cts.vhd b/cts/source/cts.vhd
new file mode 100755 (executable)
index 0000000..a805160
--- /dev/null
@@ -0,0 +1,891 @@
+library IEEE;
+   use IEEE.STD_LOGIC_1164.ALL;
+   use IEEE.NUMERIC_STD.ALL;
+   
+library work;
+   use work.trb_net_components.all;
+   use work.CTS_PKG.ALL;
+
+-- Debug and status registers
+-- Address        Description
+-- <address_table name="cts_register_block" prefix="0xa0">
+--    0x00        Statistics: Number of clock cycles with trigger asserted
+--    0x01        Statistics: Number of trigger rising edges
+--    0x02        Statistics: Number of triggers accepted
+--
+--    0x03        Current trigger status
+--      15 : 00   Trigger bitmask (before filtering)
+--      19 : 16   Current trigger type
+--           20   Trigger asserted
+--
+--    0x04        Buffered trigger status
+--      15 : 00   Trigger bitmask (before filtering)
+--      19 : 16   Trigger type
+--
+--    0x05        TD FSM State (Trigger Distribution). One-Hot-Encoding:
+--            0   TD_FSM_IDLE
+--            1   TD_FSM_SEND_TRIGGER
+--            2   TD_FSM_WAIT_FEE_RECV_TRIGGER
+--            3   TD_FSM_FEE_COMPLETE
+--            4   TD_FSM_WAIT_TRIGGER_BECOME_IDLE
+--            5   TD_FSM_DEBUG_LIMIT_REACHED
+--
+--    0x06        RO FSM State (Readout Handling). One-Hot-Encoding:
+--            0   RO_FSM_IDLE
+--            1   RO_FSM_SEND_REQUEST
+--            2   RO_FSM_WAIT_BECOME_BUSY
+--            3   RO_FSM_WAIT_BECOME_IDLE
+--            4   RO_FSM_DEBUG_LIMIT_REACHED
+--
+--    0x07        Readout Queue
+--      15 : 00   Words enqueued
+--           30   Empty
+--           31   Full
+--
+--    0x08        Debug FSM limits
+--      15 : 00   Number of Triggers   (0xFFFF means no limit)
+--      31 : 16   Number of Read-Outs  (0xFFFF means no limit)
+--
+--    0x09        Trigger information to be send in read-out (default: 0x00000000)
+--            0   Input Counters
+--            1   Channel Counters
+--            2   Statistics: Idle- and Dead-Time counter
+--            3   Statistics: Trigger asserted, -edges, -accepted
+--
+--    0x0a        Statistics: Dead time of last trigger
+--                   (in clock cycles: 0xffffffff if n/a)
+--
+--    0x0b        Statistics: Time between last two accepted triggers 
+--                   (in clock cycles: 0xffffffff if n/a)
+--
+--    0x0c        Event throttle
+--      09 : 00   Maximal number of events accepted per millisecond
+--        10      Throttle enabled
+--        31      Stop Trigger
+-- </address_table>
+
+-- Header of data packet written to event builder
+--       Bit   Description
+-- <reg_table name="cts_data_header" >
+--    15 : 0      ITC bitmask (state of all channels when trigger was accepted)
+--    19 : 16     Number of Input Counter included (divided by two, as each input has two counters)
+--    24 : 20     Number of Channel Counters included (divided by two, as each channel has two counters)
+--      25        Include last idle, dead time counters
+--      26        Include Counter "Trigger asserted "Trigger Edges", "Triggers Accepted"
+-- </reg_table>
+
+entity CTS is
+   generic (
+      TRIGGER_INPUT_COUNT : integer range 1 to 8 := 4;
+      TRIGGER_COIN_COUNT  : integer range 0 to 15 := 4;
+      TRIGGER_PULSER_COUNT: integer range 0 to 15 := 4;
+      TRIGGER_RAND_PULSER : integer range 0 to  1 := 1;
+      EXTERNAL_TRIGGER_ID  : std_logic_vector(7 downto 0) := X"00";
+
+      TIME_REFERENCE_COUNT : positive := 10;
+      FIFO_ADDR_WIDTH : integer range 1 to 15 := 8
+   );
+
+   port (
+      CLK       : in  std_logic;
+      RESET     : in  std_logic;      
+      
+  -- Trigger Logic
+      TRIGGERS_IN        : in std_logic_vector(TRIGGER_INPUT_COUNT-1 downto 0);
+      TRIGGER_BUSY_OUT   : out std_logic;
+      TIME_REFERENCE_OUT : out std_logic;
+      
+   -- External trigger logic
+      EXT_TRIGGER_IN  : in std_logic;
+      EXT_STATUS_IN   : in std_logic_vector(31 downto 0) := X"00000000";
+      EXT_CONTROL_OUT : out std_logic_vector(31 downto 0);    
+
+  -- CTS Endpoint -----------------------------------------------------------
+      --LVL1 trigger
+      CTS_TRG_SEND_OUT             : out std_logic;
+      CTS_TRG_TYPE_OUT             : out std_logic_vector( 3 downto 0);
+      CTS_TRG_NUMBER_OUT           : out std_logic_vector(15 downto 0);
+      CTS_TRG_INFORMATION_OUT      : out std_logic_vector(23 downto 0);
+      CTS_TRG_RND_CODE_OUT         : out std_logic_vector( 7 downto 0);
+      CTS_TRG_STATUS_BITS_IN       : in  std_logic_vector(31 downto 0);
+      CTS_TRG_BUSY_IN              : in  std_logic;
+
+      --IPU Channel
+      CTS_IPU_SEND_OUT             : out std_logic;
+      CTS_IPU_TYPE_OUT             : out std_logic_vector( 3 downto 0);
+      CTS_IPU_NUMBER_OUT           : out std_logic_vector(15 downto 0);
+      CTS_IPU_INFORMATION_OUT      : out std_logic_vector( 7 downto 0);
+      CTS_IPU_RND_CODE_OUT         : out std_logic_vector( 7 downto 0);
+      
+      --Receiver port
+      CTS_IPU_STATUS_BITS_IN       : in  std_logic_vector(31 downto 0);
+      CTS_IPU_BUSY_IN              : in  std_logic;
+      
+      -- Slow Control
+      CTS_REGIO_ADDR_IN            : in  std_logic_vector(15 downto 0);
+      CTS_REGIO_DATA_IN            : in  std_logic_vector(31 downto 0);
+      CTS_REGIO_READ_ENABLE_IN     : in  std_logic;
+      CTS_REGIO_WRITE_ENABLE_IN    : in  std_logic;
+      
+      CTS_REGIO_DATA_OUT           : out std_logic_vector(31 downto 0);
+      CTS_REGIO_DATAREADY_OUT      : out std_logic;
+      CTS_REGIO_WRITE_ACK_OUT      : out std_logic;
+      CTS_REGIO_UNKNOWN_ADDR_OUT   : out std_logic;
+   
+  -- Frontend Endpoint -----------------------------------------------------
+      --Data Port
+      LVL1_TRG_DATA_VALID_IN       : in std_logic;
+      LVL1_VALID_TIMING_TRG_IN     : in std_logic;
+      LVL1_VALID_NOTIMING_TRG_IN   : in std_logic;
+      LVL1_INVALID_TRG_IN          : in std_logic;
+      
+      FEE_TRG_STATUSBITS_OUT       : out std_logic_vector(31 downto 0) := (others => '0');
+      FEE_DATA_OUT                 : out std_logic_vector(31 downto 0) := (others => '0');
+      FEE_DATA_WRITE_OUT           : out std_logic := '0';
+      FEE_DATA_FINISHED_OUT        : out std_logic := '0'
+   );
+end entity;
+
+architecture RTL of CTS is
+   -- the time reference signal is generated by the time_reference_proc process
+   -- and started by asserting time_reference_start_i for 1 cycle.
+   signal time_reference_start_i : std_logic := '0';
+   
+   signal clk_1khz_i : std_logic := '0';
+
+-- Trigger
+   signal trigger_i : std_logic := '0';
+   signal trigger_type_i, trigger_type_buf_i : std_logic_vector(3 downto 0);
+   signal trigger_bitmask_i, trigger_bitmask_buf_i : std_logic_vector(15 downto 0);
+
+    -- Counters
+   signal input_counters_i,
+          input_counters_buf_i,
+          input_edge_counters_i,
+          input_edge_counters_buf_i    : std_logic_vector(32 * TRIGGER_INPUT_COUNT - 1 downto 0);
+          
+   signal channel_counters_i,
+          channel_counters_buf_i,
+          channel_edge_counters_i,
+          channel_edge_counters_buf_i  : std_logic_vector(32 * 16 - 1 downto 0);
+   
+   signal num_of_itc_used_i : std_logic_vector(4 downto 0);
+   
+   -- Trigger <-> Bus handler 
+   signal trg_regio_addr_in_i : std_logic_vector(15 downto 0);
+   signal trg_regio_data_in_i, trg_regio_data_out_i : std_logic_vector(31 downto 0);
+   signal trg_regio_read_enable_in_i, trg_regio_write_enable_in_i,
+          trg_regio_timeout_in_i, trg_regio_dataready_out_i, 
+          trg_regio_write_ack_out_i, trg_regio_no_more_data_out_i,
+          trg_regio_unknown_addr_out_i : std_logic;      
+   
+-- FIFO
+   signal fifo_data_in_i, fifo_data_out_i : std_logic_vector(31 downto 0);
+   signal fifo_full_i, fifo_empty_i, fifo_enqueue_i, fifo_dequeue_i : std_logic := '0';
+   signal fifo_words_in_fifo_i : std_logic_vector(FIFO_ADDR_WIDTH downto 0);
+
+-- Throttle
+   signal throttle_active_i, throttle_enabled_i : std_logic := '0';
+   signal throttle_threshold_i,
+          throttle_counter_i  : unsigned(9 downto 0) := (others => '0');
+   
+   signal stop_triggers_i : std_logic := '0';
+   
+-- Trigger Distribution
+   type td_fsm_t is (
+         TD_FSM_IDLE, 
+         TD_FSM_SEND_TRIGGER,
+         TD_FSM_WAIT_FEE_RECV_TRIGGER,
+         TD_FSM_FEE_ENQUEUE_INPUT_COUNTER,
+         TD_FSM_FEE_ENQUEUE_CHANNEL_COUNTER,
+         TD_FSM_FEE_ENQUEUE_IDLE_COUNTER,
+         TD_FSM_FEE_ENQUEUE_DEAD_COUNTER,
+         TD_FSM_FEE_ENQUEUE_TRIGGER_ASSERTED_COUNTER,
+         TD_FSM_FEE_ENQUEUE_TRIGGER_EDGES_COUNTER,
+         TD_FSM_FEE_ENQUEUE_TRIGGER_ACCEPTED_COUNTER,
+         TD_FSM_FEE_COMPLETE,
+         TD_FSM_WAIT_TRIGGER_BECOME_IDLE,
+         TD_FSM_DEBUG_LIMIT_REACHED
+   ); 
+   signal td_fsm_i : td_fsm_t := TD_FSM_IDLE;
+   signal td_trigger_id_i : std_logic_vector(15 downto 0);
+   signal td_random_number_i : std_logic_vector(7 downto 0) := (others => '0');
+   
+   type td_fsm_encode_t is array(td_fsm_t) of std_logic_vector(31 downto 0);
+   constant TD_FSM_ENCODE : td_fsm_encode_t := (
+         TD_FSM_IDLE                                  => X"00000001",
+         TD_FSM_SEND_TRIGGER                          => X"00000002",
+         TD_FSM_WAIT_FEE_RECV_TRIGGER                 => X"00000004",
+         TD_FSM_FEE_ENQUEUE_INPUT_COUNTER             => X"00000040",
+         TD_FSM_FEE_ENQUEUE_CHANNEL_COUNTER           => X"00000080",
+         TD_FSM_FEE_COMPLETE                          => X"00000008",
+         TD_FSM_WAIT_TRIGGER_BECOME_IDLE              => X"00000010",
+         TD_FSM_DEBUG_LIMIT_REACHED                   => X"00000020",
+         TD_FSM_FEE_ENQUEUE_IDLE_COUNTER              => X"00000040",
+         TD_FSM_FEE_ENQUEUE_DEAD_COUNTER              => X"00000080",
+         TD_FSM_FEE_ENQUEUE_TRIGGER_ASSERTED_COUNTER  => X"00000100",
+         TD_FSM_FEE_ENQUEUE_TRIGGER_EDGES_COUNTER     => X"00000200",
+         TD_FSM_FEE_ENQUEUE_TRIGGER_ACCEPTED_COUNTER  => X"00000400"
+   );
+   
+-- Read-Out
+   type ro_fsm_t is (
+      RO_FSM_IDLE,
+      RO_FSM_SEND_REQUEST,
+      RO_FSM_WAIT_BECOME_BUSY,
+      RO_FSM_WAIT_BECOME_IDLE,
+      RO_FSM_DEBUG_LIMIT_REACHED
+      
+   );
+   signal ro_fsm_i : ro_fsm_t;
+
+   type ro_fsm_encode_t is array(ro_fsm_t) of std_logic_vector(31 downto 0);
+   constant RO_FSM_ENCODE : ro_fsm_encode_t := (
+         RO_FSM_IDLE                => X"00000001",
+         RO_FSM_SEND_REQUEST        => X"00000002",
+         RO_FSM_WAIT_BECOME_BUSY    => X"00000004",
+         RO_FSM_WAIT_BECOME_IDLE    => X"00000008",
+         RO_FSM_DEBUG_LIMIT_REACHED => X"00000010"
+   );
+   
+   signal ro_configuration_i, ro_configuration_buf_i : std_logic_vector(4 downto 0);
+   
+-- Debug and statistics
+   type cts_status_registers_t is array(0 to 16#0c#) of std_logic_vector(31 downto 0);
+   signal cts_status_registers_i : cts_status_registers_t := (others => (others => '0'));
+   
+   signal debug_lvl1_limit_i, debug_ipu_limit_i, 
+          transfer_debug_lvl1_limit_i, transfer_debug_ipu_limit_i : unsigned(15 downto 0) := (others => '1');
+   signal transfer_debug_limits_i : std_logic := '0';
+   
+   
+   signal stat_trigger_enabled_i,
+          stat_trigger_edges_i, 
+          stat_trigger_accepted_i,
+          stat_dead_time_i,
+          stat_idle_time_i  : unsigned(31 downto 0);
+          
+   signal stat_trigger_enabled_buf_i,
+          stat_trigger_edges_buf_i, 
+          stat_trigger_accepted_buf_i,
+          stat_dead_time_buf_i,
+          stat_idle_time_buf_i : std_logic_vector(31 downto 0);
+   
+   signal cts_regio_addr_in_i : std_logic_vector(15 downto 0); 
+   signal cts_regio_data_in_i, cts_regio_data_out_i : std_logic_vector(31 downto 0);
+   signal cts_regio_read_enable_in_i, cts_regio_write_enable_in_i,
+          cts_regio_timeout_in_i, cts_regio_dataready_out_i, 
+          cts_regio_write_ack_out_i, cts_regio_no_more_data_out_i,
+          cts_regio_unknown_addr_out_i : std_logic := '0';      
+   
+begin
+-- Trigger Distribution
+-----------------------------------------
+   td_proc: process(CLK) is
+      variable fee_input_counter_v : integer range 0 to 2*TRIGGER_INPUT_COUNT - 1 := 0;
+      variable fee_channel_counter_v : integer range 0 to 2* channel_counters_i'LENGTH / 32 - 1 := 0;
+      
+   begin
+      if rising_edge(CLK) then
+         time_reference_start_i <= '0';
+       
+         fifo_enqueue_i <= '0';
+         --fifo_data_in_i <= (others => '-');
+     
+      -- CTS Endpoint Interface
+         -- TODO: Check CTS_TRG_NUMBER_OUT <= (others => '-');
+         -- TODO: Check CTS_TRG_INFORMATION_OUT <= (others => '-');
+         -- TODO: Check CTS_TRG_RND_CODE_OUT <= (others => '-');
+         CTS_TRG_SEND_OUT <= '0';
+
+      -- DATA Endpoint Interface
+         FEE_DATA_OUT <= (others => '0');
+         FEE_DATA_FINISHED_OUT <= '0';
+         FEE_DATA_WRITE_OUT <= '0';
+      
+         if td_fsm_i /= TD_FSM_FEE_ENQUEUE_INPUT_COUNTER then
+            fee_input_counter_v := 0;
+         end if;
+         
+         if td_fsm_i /= TD_FSM_FEE_ENQUEUE_CHANNEL_COUNTER then
+            fee_channel_counter_v := 0;
+         end if;
+      
+         
+         if RESET = '1' then
+            td_fsm_i <= TD_FSM_IDLE;
+            td_trigger_id_i <= (0 => '0', others => '0');
+            debug_lvl1_limit_i <= (others => '1');
+            
+         else      
+            case(td_fsm_i) is
+               when TD_FSM_IDLE =>
+                  if to_integer(debug_lvl1_limit_i) = 0 then
+                     td_fsm_i <= TD_FSM_DEBUG_LIMIT_REACHED;
+                  
+                  elsif trigger_i = '1' and fifo_full_i = '0' and (throttle_active_i = '0' or throttle_enabled_i = '0') and (stop_triggers_i = '0') then
+                     time_reference_start_i <= not trigger_type_i(3); -- if 3. bit is set, no timing ref is needed
+                     trigger_type_buf_i <= trigger_type_i;
+                     trigger_bitmask_buf_i <= trigger_bitmask_i;
+                     
+                     ro_configuration_buf_i <= ro_configuration_i;
+                     if trigger_type_i = X"E" then
+                        -- E-Trigger enqueues all data available
+                        ro_configuration_buf_i <= (others => '1');
+                     end if;
+
+                     -- oh boy, that's gonna be expensive !
+                     input_counters_buf_i        <= input_counters_i;
+                     channel_counters_buf_i      <= channel_counters_i;
+                     input_edge_counters_buf_i   <= input_edge_counters_i;
+                     channel_edge_counters_buf_i <= channel_edge_counters_i;
+                     
+                     stat_trigger_enabled_buf_i  <= STD_LOGIC_VECTOR(stat_trigger_enabled_i);
+                     stat_trigger_edges_buf_i    <= STD_LOGIC_VECTOR(stat_trigger_edges_i);
+                     stat_trigger_accepted_buf_i <= STD_LOGIC_VECTOR(stat_trigger_accepted_i);
+                     
+                     td_fsm_i <= TD_FSM_SEND_TRIGGER;
+
+                     if to_integer(debug_lvl1_limit_i) /= 2**debug_lvl1_limit_i'length-1 then
+                        debug_lvl1_limit_i <= debug_lvl1_limit_i - 1;
+                     end if;
+                     
+                  end if;
+               
+               when TD_FSM_SEND_TRIGGER =>
+                  td_trigger_id_i <= STD_LOGIC_VECTOR(UNSIGNED(td_trigger_id_i) + TO_UNSIGNED(1,1));
+               
+               -- cts
+                  CTS_TRG_NUMBER_OUT <= td_trigger_id_i;
+                  CTS_TRG_INFORMATION_OUT <= (7 => trigger_type_buf_i(3), others => '0');
+                  CTS_TRG_RND_CODE_OUT <= td_random_number_i; 
+                  CTS_TRG_SEND_OUT <= '1';
+
+               -- token header
+                  fifo_data_in_i <= "----" & trigger_type_buf_i & td_random_number_i & td_trigger_id_i;
+
+                  td_fsm_i <= TD_FSM_WAIT_FEE_RECV_TRIGGER;
+
+               when TD_FSM_WAIT_FEE_RECV_TRIGGER =>
+                  if LVL1_TRG_DATA_VALID_IN = '1' then
+
+                  -- write packet header
+                     FEE_DATA_OUT(15 downto  0) <= trigger_bitmask_buf_i;
+                     if ro_configuration_buf_i(0) = '1' then
+                        FEE_DATA_OUT(19 downto 16) <= STD_LOGIC_VECTOR(TO_UNSIGNED(TRIGGER_INPUT_COUNT, 4));
+                     end if;
+                     
+                     if ro_configuration_buf_i(1) = '1' then
+                        FEE_DATA_OUT(24 downto 20) <= num_of_itc_used_i;
+                     end if;
+                     
+                     FEE_DATA_OUT(25) <= ro_configuration_buf_i(2);
+                     FEE_DATA_OUT(26) <= ro_configuration_buf_i(3);
+                     
+                     FEE_DATA_WRITE_OUT <= '1';
+
+                     td_fsm_i <= TD_FSM_FEE_ENQUEUE_INPUT_COUNTER;
+                  else
+                     CTS_TRG_SEND_OUT <= '1';
+                     
+                  end if;
+               
+               when TD_FSM_FEE_ENQUEUE_INPUT_COUNTER =>
+                  if ro_configuration_buf_i(0) = '1' then
+                     FEE_DATA_WRITE_OUT <= '1';
+                     if fee_input_counter_v mod 2 = 0 then
+                        FEE_DATA_OUT <= input_counters_buf_i(32*fee_input_counter_v + 31 downto 32*fee_input_counter_v); 
+                     else
+                        FEE_DATA_OUT <= input_edge_counters_buf_i(32*fee_input_counter_v + 31 downto 32*fee_input_counter_v); 
+                     end if;
+                  end if;
+
+                  if fee_input_counter_v = 2*TRIGGER_INPUT_COUNT - 1 or ro_configuration_buf_i(0) = '0' then
+                     td_fsm_i <= TD_FSM_FEE_ENQUEUE_CHANNEL_COUNTER;
+                  end if;
+
+                  fee_input_counter_v := fee_input_counter_v + 1;
+
+               when TD_FSM_FEE_ENQUEUE_CHANNEL_COUNTER =>
+                  if ro_configuration_buf_i(1) = '1' then
+                     if fee_channel_counter_v mod 2 = 0 then
+                        FEE_DATA_OUT <= channel_counters_buf_i(32*fee_channel_counter_v + 31 downto 32*fee_channel_counter_v/2); 
+                     else
+                        FEE_DATA_OUT <= channel_edge_counters_buf_i(32*fee_channel_counter_v + 31 downto 32*fee_channel_counter_v/2); 
+                     end if; 
+                     
+                     FEE_DATA_WRITE_OUT <= '1';
+                  end if;
+
+                  if fee_channel_counter_v = 2*to_integer(unsigned(num_of_itc_used_i)) - 1 or  ro_configuration_buf_i(1) = '0' then
+                     td_fsm_i <= TD_FSM_FEE_ENQUEUE_IDLE_COUNTER;
+                  end if;
+
+                  fee_channel_counter_v := fee_channel_counter_v + 1;
+
+               when TD_FSM_FEE_ENQUEUE_IDLE_COUNTER =>
+                  FEE_DATA_OUT <= stat_idle_time_buf_i;
+                  FEE_DATA_WRITE_OUT <= ro_configuration_buf_i(2);
+                  
+                  if ro_configuration_buf_i(2) = '1' then
+                     td_fsm_i <= TD_FSM_FEE_ENQUEUE_DEAD_COUNTER;
+                  else
+                     td_fsm_i <= TD_FSM_FEE_ENQUEUE_TRIGGER_ASSERTED_COUNTER;
+                  end if;
+               
+               when TD_FSM_FEE_ENQUEUE_DEAD_COUNTER =>
+                  FEE_DATA_OUT <= stat_dead_time_buf_i;
+                  FEE_DATA_WRITE_OUT <= '1';
+                  
+                  td_fsm_i <= TD_FSM_FEE_ENQUEUE_TRIGGER_ASSERTED_COUNTER;
+                  
+               when TD_FSM_FEE_ENQUEUE_TRIGGER_ASSERTED_COUNTER =>
+                  FEE_DATA_OUT <= stat_trigger_enabled_buf_i;
+                  FEE_DATA_WRITE_OUT <= ro_configuration_buf_i(3);
+
+                  if ro_configuration_buf_i(3) = '1' then
+                     td_fsm_i <= TD_FSM_FEE_ENQUEUE_TRIGGER_EDGES_COUNTER;
+                  else
+                     td_fsm_i <= TD_FSM_FEE_COMPLETE;
+                  end if;
+                  
+               when TD_FSM_FEE_ENQUEUE_TRIGGER_EDGES_COUNTER =>
+                  FEE_DATA_OUT <= stat_trigger_edges_buf_i;
+                  FEE_DATA_WRITE_OUT <= '1';
+                  td_fsm_i     <= TD_FSM_FEE_ENQUEUE_TRIGGER_ACCEPTED_COUNTER;
+
+               when TD_FSM_FEE_ENQUEUE_TRIGGER_ACCEPTED_COUNTER =>                     
+                  FEE_DATA_OUT <= stat_trigger_accepted_buf_i;
+                  FEE_DATA_WRITE_OUT <= '1';
+                  td_fsm_i     <= TD_FSM_FEE_COMPLETE;
+                     
+               when TD_FSM_FEE_COMPLETE =>
+                  FEE_DATA_FINISHED_OUT <= '1';
+                  td_fsm_i <= TD_FSM_WAIT_TRIGGER_BECOME_IDLE;
+                   
+               when TD_FSM_WAIT_TRIGGER_BECOME_IDLE =>
+                  if CTS_TRG_BUSY_IN = '0' then
+                     td_fsm_i <= TD_FSM_IDLE;
+                     fifo_enqueue_i <= '1';
+                  end if;
+                  
+               when TD_FSM_DEBUG_LIMIT_REACHED =>
+                  if to_integer(debug_lvl1_limit_i) /= 0 then
+                     td_fsm_i <= TD_FSM_IDLE;
+                  end if;                  
+                  
+            end case;
+            
+            if transfer_debug_limits_i = '1' then
+               debug_lvl1_limit_i <= transfer_debug_lvl1_limit_i;
+            end if;            
+         end if;
+      end if;
+   end process;
+   
+   CTS_TRG_TYPE_OUT <= trigger_type_buf_i;
+
+   read_out_proc: process(CLK) is
+   begin
+      if rising_edge(CLK) then
+         fifo_dequeue_i <= '0';
+         CTS_IPU_SEND_OUT <= '0';
+
+         if RESET = '1' then
+            ro_fsm_i <= RO_FSM_IDLE;
+            debug_ipu_limit_i <= (others => '1');
+            
+         else
+            case(ro_fsm_i) is
+               when RO_FSM_IDLE =>
+                  if to_integer(debug_ipu_limit_i) = 0 then
+                     ro_fsm_i <= RO_FSM_DEBUG_LIMIT_REACHED;
+                  
+                  elsif fifo_empty_i = '0' then
+                     ro_fsm_i <= RO_FSM_SEND_REQUEST;
+                     if to_integer(debug_ipu_limit_i) /= 2**debug_ipu_limit_i'length-1 then
+                        debug_ipu_limit_i <= debug_ipu_limit_i - 1;
+                     end if;
+
+                  end if;
+                  
+               when RO_FSM_SEND_REQUEST =>
+                  -- TODO: Check whether this can be directly assigned outside of the process
+                  CTS_IPU_NUMBER_OUT <= fifo_data_out_i(15 downto 0);
+                  CTS_IPU_RND_CODE_OUT <= fifo_data_out_i(23 downto 16);
+                  CTS_IPU_TYPE_OUT  <= fifo_data_out_i(27 downto 24);
+                  CTS_IPU_INFORMATION_OUT <= X"00";
+
+                  
+                  CTS_IPU_SEND_OUT <= '1';
+               
+                  fifo_dequeue_i <= '1';
+                  
+                  ro_fsm_i <= RO_FSM_WAIT_BECOME_BUSY;
+
+               when RO_FSM_WAIT_BECOME_BUSY =>
+                  if CTS_IPU_BUSY_IN = '1' then 
+                     ro_fsm_i <= RO_FSM_WAIT_BECOME_IDLE;
+                  end if;
+                  
+               when RO_FSM_WAIT_BECOME_IDLE =>
+                  if CTS_IPU_BUSY_IN = '0' then 
+                     ro_fsm_i <= RO_FSM_IDLE;
+                  end if;
+                  
+               when RO_FSM_DEBUG_LIMIT_REACHED =>
+                  if to_integer(debug_ipu_limit_i) /= 0 then
+                     ro_fsm_i <= RO_FSM_IDLE;
+                  end if;
+             
+            end case;
+            
+            if transfer_debug_limits_i = '1' then
+               debug_ipu_limit_i <= transfer_debug_ipu_limit_i;
+            end if;
+         end if;
+      end if;
+   end process;
+
+-- Time Reference   
+-----------------------------------------
+   time_reference_proc: process(CLK) is
+      variable time_reference_counter_v : integer range 0 to TIME_REFERENCE_COUNT := TIME_REFERENCE_COUNT;
+   begin
+      if rising_edge(CLK) then
+         TIME_REFERENCE_OUT <= '0';
+         if RESET = '1' then
+            time_reference_counter_v := TIME_REFERENCE_COUNT;
+         else
+            if time_reference_start_i = '1' then
+               -- start
+               time_reference_counter_v := 0;
+               TIME_REFERENCE_OUT <= '1';
+            
+            elsif time_reference_counter_v /= TIME_REFERENCE_COUNT - 1 then
+               -- increment
+               time_reference_counter_v := time_reference_counter_v + 1;
+               TIME_REFERENCE_OUT <= '1';
+
+            end if;
+         end if;
+      end if;
+   end process;
+
+-- Pseudo Random Number Generation
+-----------------------------------------
+   random_proc: process(CLK) is
+   begin
+      if rising_edge(CLK) then
+         -- sequence repeats every 256 iterations
+         td_random_number_i <= STD_LOGIC_VECTOR(UNSIGNED(td_random_number_i) + TO_UNSIGNED(113, 8));
+      end if;
+   end process;
+   
+-- FIFO   
+-----------------------------------------
+   my_fifo: CTS_FIFO
+   generic map (
+      WIDTH => fifo_data_in_i'LENGTH,
+      ADDR_WIDTH => FIFO_ADDR_WIDTH
+   )
+   port map (
+      CLK => CLK, RESET => RESET,
+      DATA_IN => fifo_data_in_i,
+      DATA_OUT => fifo_data_out_i,
+      WORDS_IN_FIFO_OUT => fifo_words_in_fifo_i,
+      ENQUEUE_IN => fifo_enqueue_i,
+      DEQUEUE_IN => fifo_dequeue_i,
+      FULL_OUT => fifo_full_i,
+      EMPTY_OUT => fifo_empty_i
+   ); 
+   
+-- Trigger
+-----------------------------------------
+   my_trigger : CTS_TRIGGER
+   generic map (
+      TRIGGER_INPUT_COUNT  => TRIGGER_INPUT_COUNT,
+      TRIGGER_COIN_COUNT   => TRIGGER_COIN_COUNT,
+      TRIGGER_PULSER_COUNT => TRIGGER_PULSER_COUNT,
+      TRIGGER_RAND_PULSER  => TRIGGER_RAND_PULSER,
+      EXTERNAL_TRIGGER_ID  => EXTERNAL_TRIGGER_ID
+   )
+   port map (
+      CLK_IN      => CLK,
+      RESET_IN    => RESET,
+         
+      TRIGGERS_IN => TRIGGERS_IN,
+      
+      EXT_TRIGGER_IN  => EXT_TRIGGER_IN,
+      EXT_STATUS_IN   => EXT_STATUS_IN,
+      EXT_CONTROL_OUT => EXT_CONTROL_OUT,
+
+      TRIGGER_OUT         => trigger_i,
+      TRIGGER_TYPE_OUT    => trigger_type_i,
+      TRIGGER_BITMASK_OUT => trigger_bitmask_i,
+   
+      INPUT_COUNTERS_OUT        => input_counters_i,
+      INPUT_EDGE_COUNTERS_OUT   => input_edge_counters_i,
+      CHANNEL_COUNTERS_OUT      => channel_counters_i,
+      CHANNEL_EDGE_COUNTERS_OUT => channel_edge_counters_i,
+      NUM_OF_ITC_USED_OUT       => num_of_itc_used_i,
+      
+    -- Slow Control
+      REGIO_ADDR_IN            => trg_regio_addr_in_i,
+      REGIO_DATA_IN            => trg_regio_data_in_i,
+      REGIO_READ_ENABLE_IN     => trg_regio_read_enable_in_i,
+      REGIO_WRITE_ENABLE_IN    => trg_regio_write_enable_in_i,
+      REGIO_TIMEOUT_IN         => trg_regio_timeout_in_i,
+      
+      REGIO_DATA_OUT           => trg_regio_data_out_i,
+      REGIO_DATAREADY_OUT      => trg_regio_dataready_out_i,
+      REGIO_WRITE_ACK_OUT      => trg_regio_write_ack_out_i,
+      REGIO_NO_MORE_DATA_OUT   => trg_regio_no_more_data_out_i,
+      REGIO_UNKNOWN_ADDR_OUT   => trg_regio_unknown_addr_out_i      
+   );
+   
+-- Statistics
+-----------------------------------------
+   stat_proc: process(CLK) is
+      variable last_trigger_v : std_logic := '0';
+      variable last_td_fsm_v  : td_fsm_t := TD_FSM_IDLE;
+   begin
+      if rising_edge(CLK) then
+         if RESET='1' or stat_trigger_enabled_i = X"FFFFFFFF" then
+            -- the first counter to overflow is trigger_enabled
+            -- if this happends the remaining counters become worthless for obtaining
+            -- scaling values. hence, all counters are reset
+            
+            stat_trigger_accepted_i <= (others => '0');
+            stat_trigger_edges_i <= (others => '0');
+            stat_trigger_enabled_i <= (others => '0');
+
+         else
+            if trigger_i = '1' then
+               stat_trigger_enabled_i <= stat_trigger_enabled_i + 1;
+            end if;
+            
+            if trigger_i = '1' and last_trigger_v = '0' then
+               stat_trigger_edges_i <= stat_trigger_edges_i + 1;
+            end if;
+            
+            if td_fsm_i /= TD_FSM_IDLE and td_fsm_i /= TD_FSM_DEBUG_LIMIT_REACHED
+               and last_td_fsm_v = TD_FSM_IDLE then
+               
+               stat_trigger_accepted_i <= stat_trigger_accepted_i + 1;
+            end if;
+         end if;
+
+      -- DEAD AND IDLE TIME
+         if RESET='1' then
+            stat_dead_time_i <= (others => '0');
+            stat_idle_time_i <= (others => '0');
+            
+            stat_dead_time_buf_i <= (others => '1');
+            stat_idle_time_buf_i <= (others => '1');
+
+         else
+            if td_fsm_i = TD_FSM_IDLE then
+               if last_td_fsm_v /= TD_FSM_IDLE then
+                  stat_dead_time_buf_i <= STD_LOGIC_VECTOR(stat_dead_time_i);
+                  stat_dead_time_i <= (others => '0');
+               end if;
+               
+               if stat_idle_time_i /= X"ffffffff" then
+                  stat_idle_time_i <= stat_idle_time_i + 1;
+               end if;
+
+            else
+               if last_td_fsm_v = TD_FSM_IDLE then
+                  stat_idle_time_buf_i <= STD_LOGIC_VECTOR(stat_idle_time_i);
+                  stat_idle_time_i <= (others => '0');
+               end if;
+               
+               if stat_dead_time_i /= X"ffffffff" then
+                  stat_dead_time_i <= stat_dead_time_i + 1;
+               end if;
+            end if;
+         end if;
+       
+         last_trigger_v := trigger_i;
+         last_td_fsm_v  := td_fsm_i;
+      end if;
+   end process;   
+
+-- Debug and Runtime information
+-----------------------------------------
+   cts_status_registers_i(16#00#) <= STD_LOGIC_VECTOR(stat_trigger_enabled_i);
+   cts_status_registers_i(16#01#) <= STD_LOGIC_VECTOR(stat_trigger_edges_i);
+   cts_status_registers_i(16#02#) <= STD_LOGIC_VECTOR(stat_trigger_accepted_i);
+   
+   cts_status_registers_i(16#03#)(20 downto 0) <= trigger_i & trigger_type_i & trigger_bitmask_i;
+   cts_status_registers_i(16#04#)(19 downto 0) <= trigger_type_buf_i & trigger_bitmask_buf_i;
+      
+   cts_status_registers_i(16#05#) <= TD_FSM_ENCODE(td_fsm_i);
+   cts_status_registers_i(16#06#) <= RO_FSM_ENCODE(ro_fsm_i);
+   cts_status_registers_i(16#07#)(31 downto 30) <= fifo_full_i & fifo_empty_i;
+   cts_status_registers_i(16#07#)(fifo_words_in_fifo_i'RANGE) <= fifo_words_in_fifo_i;
+
+   -- control registers are mapped to status registers for read access
+   cts_status_registers_i(16#08#) <= STD_LOGIC_VECTOR(debug_ipu_limit_i) & STD_LOGIC_VECTOR(debug_lvl1_limit_i);
+   cts_status_registers_i(16#09#)(ro_configuration_i'RANGE) <= ro_configuration_i;
+   
+   cts_status_registers_i(16#0a#) <= stat_dead_time_buf_i;
+   cts_status_registers_i(16#0b#) <= stat_idle_time_buf_i;
+   cts_status_registers_i(16#0c#)(throttle_threshold_i'RANGE) <= STD_LOGIC_VECTOR(throttle_threshold_i);
+   cts_status_registers_i(16#0c#)(throttle_threshold_i'LENGTH) <= throttle_enabled_i;
+   cts_status_registers_i(16#0c#)(31) <= stop_triggers_i;
+   
+   regio_proc: process(CLK) is
+      variable addr : integer range 0 to 15;
+   begin
+      if rising_edge(CLK) then
+         if RESET ='1' then
+            ro_configuration_i <= (0 => '1', others => '0');
+            throttle_threshold_i <= (others => '0');
+            throttle_enabled_i <= '0';
+            stop_triggers_i <= '0';
+            
+         else
+         
+            addr := TO_INTEGER(UNSIGNED(cts_regio_addr_in_i(3 downto 0)));
+
+            cts_regio_data_out_i <= (others => '0');
+            cts_regio_write_ack_out_i <= '0';
+            cts_regio_unknown_addr_out_i <= cts_regio_write_enable_in_i or cts_regio_read_enable_in_i;
+            transfer_debug_limits_i <= '0';
+            
+            for i in 0 to cts_status_registers_i'HIGH loop
+               if i = addr then
+                  cts_regio_dataready_out_i <= cts_regio_read_enable_in_i;
+                  cts_regio_data_out_i <= cts_status_registers_i(i);
+                  cts_regio_unknown_addr_out_i <= '0';
+               end if;
+            end loop;
+         
+         -- write access to control registers
+            if addr = 16#08# and cts_regio_write_enable_in_i = '1' then
+               transfer_debug_lvl1_limit_i <= UNSIGNED(cts_regio_data_in_i(15 downto 0));
+               transfer_debug_ipu_limit_i  <= UNSIGNED(cts_regio_data_in_i(31 downto 16));
+               transfer_debug_limits_i     <= '1';
+               
+               cts_regio_write_ack_out_i   <= '1';
+            end if;
+            
+            if addr = 16#09# and cts_regio_write_enable_in_i = '1' then
+               ro_configuration_i <= cts_regio_data_in_i(ro_configuration_i'RANGE);
+               cts_regio_write_ack_out_i   <= '1';
+            end if;
+         
+            if addr = 16#0c# and cts_regio_write_enable_in_i = '1' then
+               throttle_threshold_i <= UNSIGNED(cts_regio_data_in_i(throttle_threshold_i'RANGE));
+               throttle_enabled_i   <= cts_regio_data_in_i(throttle_threshold_i'LENGTH);
+               stop_triggers_i      <= cts_regio_data_in_i(31);
+               cts_regio_write_ack_out_i   <= '1';
+            end if;
+         end if;
+      end if;
+   end process;
+
+-- Throttle
+-----------------------------------------
+   process(CLK) is
+      variable last_td_fsm_v  : td_fsm_t := TD_FSM_IDLE;
+   begin
+      if rising_edge(CLK) then
+      -- counter
+         if clk_1khz_i = '1' then
+         
+            throttle_counter_i <= (others => '0');
+         elsif td_fsm_i /= TD_FSM_IDLE and td_fsm_i /= TD_FSM_DEBUG_LIMIT_REACHED
+               and last_td_fsm_v = TD_FSM_IDLE then
+            -- increment each time a new trigger is accepted
+            throttle_counter_i <= throttle_counter_i + "1";
+         
+         end if;
+         last_td_fsm_v := td_fsm_i;
+
+      -- throttle decision
+         throttle_active_i <= '0';
+         if throttle_counter_i > throttle_threshold_i then
+            -- not realy nice, as the inhibit singal asserts one cycle delayed, however
+            -- this is no problem as the td-fsm requires more than one cycle to complete.
+            -- hence we can drop an addiotional adder
+            throttle_active_i <= '1';
+         end if;
+      end if;
+   end process;
+   
+-- 1 KHz clock divider
+-----------------------------------------
+   process(CLK) is
+      variable counter_v : integer range 0 to 99999 := 0;
+   begin
+      if rising_edge(CLK) then
+         if counter_v = 99999 then
+            counter_v := 0;
+            clk_1khz_i <= '1';
+         else
+            counter_v := counter_v + 1;
+            clk_1khz_i <= '0';
+         end if;
+      end if;
+   end process;
+   
+-- Bus Handler
+-----------------------------------------
+  my_bus_handler : trb_net16_regio_bus_handler
+  generic map (
+     PORT_NUMBER => 2,
+     --                 trigger        debug
+     PORT_ADDRESSES => (0 => X"A100", 1 => X"A000", others => X"0000"),
+     PORT_ADDR_MASK => (0 => 8,       1 => 8,       others => 0)
+  )
+  port map (
+     CLK => CLK,
+     RESET => RESET,      
+     
+     DAT_ADDR_IN           => CTS_REGIO_ADDR_IN,
+     DAT_DATA_IN           => CTS_REGIO_DATA_IN,
+     DAT_DATA_OUT          => CTS_REGIO_DATA_OUT,
+     DAT_READ_ENABLE_IN    => CTS_REGIO_READ_ENABLE_IN,
+     DAT_WRITE_ENABLE_IN   => CTS_REGIO_WRITE_ENABLE_IN,
+     DAT_TIMEOUT_IN        => '0',
+     DAT_DATAREADY_OUT     => CTS_REGIO_DATAREADY_OUT,
+     DAT_WRITE_ACK_OUT     => CTS_REGIO_WRITE_ACK_OUT,
+     DAT_NO_MORE_DATA_OUT  => open,
+     DAT_UNKNOWN_ADDR_OUT  => CTS_REGIO_UNKNOWN_ADDR_OUT,
+  
+     BUS_ADDR_OUT(0*16+15 downto 0*16) => trg_regio_addr_in_i,
+     BUS_ADDR_OUT(1*16+15 downto 1*16) => cts_regio_addr_in_i,
+     
+     BUS_DATA_OUT(0*32+31 downto 0*32) => trg_regio_data_in_i,
+     BUS_DATA_OUT(1*32+31 downto 1*32) => cts_regio_data_in_i,
+     
+     BUS_DATA_IN(0*32+31 downto 0*32)  => trg_regio_data_out_i,
+     BUS_DATA_IN(1*32+31 downto 1*32)  => cts_regio_data_out_i,
+
+     BUS_READ_ENABLE_OUT(0)  => trg_regio_read_enable_in_i,
+     BUS_READ_ENABLE_OUT(1)  => cts_regio_read_enable_in_i,
+     
+     BUS_WRITE_ENABLE_OUT(0) => trg_regio_write_enable_in_i,
+     BUS_WRITE_ENABLE_OUT(1) => cts_regio_write_enable_in_i,
+     
+     BUS_TIMEOUT_OUT(0)      => trg_regio_timeout_in_i,
+     BUS_TIMEOUT_OUT(1)      => cts_regio_timeout_in_i,
+
+     BUS_DATAREADY_IN(0)     => trg_regio_dataready_out_i,
+     BUS_DATAREADY_IN(1)     => cts_regio_dataready_out_i,
+     
+     BUS_WRITE_ACK_IN(0)     => trg_regio_write_ack_out_i,
+     BUS_WRITE_ACK_IN(1)     => cts_regio_write_ack_out_i,
+     
+     BUS_NO_MORE_DATA_IN(0)  => trg_regio_no_more_data_out_i,
+     BUS_NO_MORE_DATA_IN(1)  => cts_regio_no_more_data_out_i,
+     
+     BUS_UNKNOWN_ADDR_IN(0)  => trg_regio_unknown_addr_out_i,
+     BUS_UNKNOWN_ADDR_IN(1)  => cts_regio_unknown_addr_out_i,
+
+     STAT_DEBUG            => open
+ );
+end architecture;
\ No newline at end of file
diff --git a/cts/source/cts_fifo.vhd b/cts/source/cts_fifo.vhd
new file mode 100755 (executable)
index 0000000..d0282b9
--- /dev/null
@@ -0,0 +1,97 @@
+library IEEE;
+   use IEEE.STD_LOGIC_1164.ALL;
+   use IEEE.NUMERIC_STD.ALL;
+
+entity CTS_FIFO is
+   generic (
+      ADDR_WIDTH : integer range 1 to 32;
+      WIDTH : positive
+   );
+   
+   port (
+      CLK         : in std_logic;
+      RESET       : in std_logic;
+      
+      DATA_IN     : in  std_logic_vector(WIDTH-1 downto 0);
+      DATA_OUT    : out std_logic_vector(WIDTH-1 downto 0);
+      
+      WORDS_IN_FIFO_OUT : out std_logic_vector(ADDR_WIDTH downto 0);
+      
+      ENQUEUE_IN  : in std_logic;
+      DEQUEUE_IN  : in std_logic;
+      
+      FULL_OUT    : out std_logic;
+      EMPTY_OUT   : out std_logic
+   );
+end entity;
+
+architecture RTL of CTS_FIFO is
+   constant DEPTH : integer := 2**ADDR_WIDTH;
+   
+   type memory_t is array(0 to DEPTH-1) of std_logic_vector(WIDTH-1 downto 0);
+   signal memory_i : memory_t;   
+   signal index_read_i, index_write_i : integer range 0 to DEPTH - 1 := 0;
+   signal full_i, empty_i : std_logic;
+   
+   signal words_in_fifo_i : integer range 0 to DEPTH;
+begin
+   proc: process(CLK) is
+      variable next_read_v, next_write_v : integer range 0 to DEPTH - 1 := 0;
+   begin
+      if rising_edge(CLK) then
+      -- compute next addresses (might be used later !)
+         if index_read_i = DEPTH - 1 then
+            next_read_v := 0;
+         else
+            next_read_v := index_read_i + 1;
+         end if;
+
+         if index_write_i = DEPTH - 1 then
+            next_write_v := 0;
+         else
+            next_write_v := index_write_i + 1;
+         end if;
+
+      -- do the job
+         if RESET = '1' then
+            index_read_i <= 0;
+            index_write_i <= 0;
+            full_i <= '0';
+            empty_i <= '1';
+            words_in_fifo_i <= 0;
+         else
+            if ENQUEUE_IN = '1' and DEQUEUE_IN = '1' and empty_i = '0' then
+               memory_i(index_write_i) <= DATA_IN;
+               index_write_i <= next_write_v;
+               index_read_i <= next_read_v;
+               
+            elsif ENQUEUE_IN = '1' and full_i = '0' then
+               memory_i(index_write_i) <= DATA_IN;
+               index_write_i <= next_write_v;
+               empty_i <= '0';
+
+               if words_in_fifo_i = DEPTH - 1 then
+                  full_i <= '1';
+               end if;
+
+               words_in_fifo_i <= words_in_fifo_i + 1;               
+               
+            elsif DEQUEUE_IN = '1' and empty_i = '0' then
+               index_read_i <= next_read_v;
+               full_i <= '0';
+               
+               if words_in_fifo_i = 1 then
+                  empty_i <= '1';
+               end if;
+            
+               words_in_fifo_i <= words_in_fifo_i - 1;
+            end if;
+         end if;
+      end if;
+   end process;
+   
+   DATA_OUT <= memory_i(index_read_i);
+   WORDS_IN_FIFO_OUT <= STD_LOGIC_VECTOR(TO_UNSIGNED(words_in_fifo_i, WORDS_IN_FIFO_OUT'length));
+   EMPTY_OUT <= empty_i;
+   FULL_OUT <= full_i;   
+end architecture;
\ No newline at end of file
diff --git a/cts/source/cts_pkg.vhd b/cts/source/cts_pkg.vhd
new file mode 100755 (executable)
index 0000000..dcaffa9
--- /dev/null
@@ -0,0 +1,242 @@
+library ieee;
+   use ieee.std_logic_1164.all;
+   use ieee.numeric_std.all;
+
+package cts_pkg is
+   component CTS is
+      generic (
+         -- The total number of trigger units below has to be below 16
+         TRIGGER_INPUT_COUNT : integer range 1 to 8 := 4;
+         TRIGGER_COIN_COUNT  : integer range 0 to 15 := 4;
+         TRIGGER_PULSER_COUNT: integer range 0 to 15 := 4;
+         TRIGGER_RAND_PULSER  : integer range 0 to 15 := 1;
+         EXTERNAL_TRIGGER_ID  : std_logic_vector(7 downto 0) := X"00";
+         
+         TIME_REFERENCE_COUNT : positive := 10;          -- Number of clock cycles the time reference needs to stay asserted (100ns)
+         FIFO_ADDR_WIDTH : integer range 1 to 31 := 9   -- 2**(FIFO_ADDR_WIDTH-1) events can be stored in read-out buffer of CTS
+      );
+
+      port (
+         CLK       : in  std_logic;
+         RESET     : in  std_logic;      
+         
+   -- Trigger Logic
+         TRIGGERS_IN        : in std_logic_vector(TRIGGER_INPUT_COUNT-1 downto 0);
+         TRIGGER_BUSY_OUT   : out std_logic;
+         TIME_REFERENCE_OUT : out std_logic;
+         
+   -- External trigger logic
+         EXT_TRIGGER_IN  : in std_logic;
+         EXT_STATUS_IN   : in std_logic_vector(31 downto 0) := X"00000000";
+         EXT_CONTROL_OUT : out std_logic_vector(31 downto 0);
+
+   -- CTS Endpoint -----------------------------------------------------------
+         --LVL1 trigger
+         CTS_TRG_SEND_OUT             : out std_logic;
+         CTS_TRG_TYPE_OUT             : out std_logic_vector( 3 downto 0);
+         CTS_TRG_NUMBER_OUT           : out std_logic_vector(15 downto 0);
+         CTS_TRG_INFORMATION_OUT      : out std_logic_vector(23 downto 0);
+         CTS_TRG_RND_CODE_OUT         : out std_logic_vector( 7 downto 0);
+         CTS_TRG_STATUS_BITS_IN       : in  std_logic_vector(31 downto 0);
+         CTS_TRG_BUSY_IN              : in  std_logic;
+
+         --IPU Channel
+         CTS_IPU_SEND_OUT             : out std_logic;
+         CTS_IPU_TYPE_OUT             : out std_logic_vector( 3 downto 0);
+         CTS_IPU_NUMBER_OUT           : out std_logic_vector(15 downto 0);
+         CTS_IPU_INFORMATION_OUT      : out std_logic_vector( 7 downto 0);
+         CTS_IPU_RND_CODE_OUT         : out std_logic_vector( 7 downto 0);
+         
+         --Receiver port
+         CTS_IPU_STATUS_BITS_IN       : in  std_logic_vector(31 downto 0);
+         CTS_IPU_BUSY_IN              : in  std_logic;
+         
+         -- Slow Control
+         CTS_REGIO_ADDR_IN            : in  std_logic_vector(15 downto 0);
+         CTS_REGIO_DATA_IN            : in  std_logic_vector(31 downto 0);
+         CTS_REGIO_READ_ENABLE_IN     : in  std_logic;
+         CTS_REGIO_WRITE_ENABLE_IN    : in  std_logic;
+         
+         CTS_REGIO_DATA_OUT           : out std_logic_vector(31 downto 0);
+         CTS_REGIO_DATAREADY_OUT      : out std_logic;
+         CTS_REGIO_WRITE_ACK_OUT      : out std_logic;
+         CTS_REGIO_UNKNOWN_ADDR_OUT   : out std_logic;
+      
+   -- Frontend Endpoint -----------------------------------------------------
+         --Data Port
+         LVL1_TRG_DATA_VALID_IN       : in std_logic;
+         LVL1_VALID_TIMING_TRG_IN     : in std_logic;
+         LVL1_VALID_NOTIMING_TRG_IN   : in std_logic;
+         LVL1_INVALID_TRG_IN          : in std_logic;
+      
+         FEE_TRG_STATUSBITS_OUT       : out std_logic_vector(31 downto 0) := (others => '0');
+         FEE_DATA_OUT                 : out std_logic_vector(31 downto 0) := (others => '0');
+         FEE_DATA_WRITE_OUT           : out std_logic := '0';
+         FEE_DATA_FINISHED_OUT        : out std_logic := '0'
+      );
+   end component;
+
+   component CTS_FIFO is
+      generic (
+         ADDR_WIDTH : integer range 1 to 32;
+         WIDTH : positive
+      );
+      
+      port (
+         CLK         : in std_logic;
+         RESET       : in std_logic;
+         
+         DATA_IN     : in  std_logic_vector(WIDTH-1 downto 0);
+         DATA_OUT    : out std_logic_vector(WIDTH-1 downto 0);
+         
+         WORDS_IN_FIFO_OUT : out std_logic_vector(ADDR_WIDTH downto 0);
+         
+         ENQUEUE_IN  : in std_logic;
+         DEQUEUE_IN  : in std_logic;
+         
+         FULL_OUT    : out std_logic;
+         EMPTY_OUT   : out std_logic
+      );
+   end component;
+
+   component CTS_TRIGGER is
+      generic (
+         TRIGGER_INPUT_COUNT  : integer range 1 to  8 := 4;
+         TRIGGER_COIN_COUNT   : integer range 0 to 15 := 4;
+         TRIGGER_PULSER_COUNT : integer range 0 to 15 := 2;
+         TRIGGER_RAND_PULSER  : integer range 0 to 15 := 1;
+         EXTERNAL_TRIGGER_ID  : std_logic_vector(7 downto 0) := X"00"
+      );
+
+      port (
+         CLK_IN       : in  std_logic;
+         RESET_IN     : in  std_logic;      
+         
+      -- Input pins
+         TRIGGERS_IN : in std_logic_vector(TRIGGER_INPUT_COUNT - 1 downto 0);
+      
+      -- External 
+         EXT_TRIGGER_IN  : in std_logic;
+         EXT_STATUS_IN   : in std_logic_vector(31 downto 0) := X"00000000";
+         EXT_CONTROL_OUT : out std_logic_vector(31 downto 0);
+
+      -- Output
+         TRIGGER_OUT         : out std_logic; -- asserted when trigger detected
+         TRIGGER_TYPE_OUT    : out std_logic_vector(3 downto 0);
+         TRIGGER_BITMASK_OUT : out std_logic_vector(15 downto 0);
+         
+      -- Counters
+         INPUT_COUNTERS_OUT         : out std_logic_vector(32 * TRIGGER_INPUT_COUNT - 1 downto 0) := (others => '0');
+         INPUT_EDGE_COUNTERS_OUT    : out std_logic_vector(32 * TRIGGER_INPUT_COUNT - 1 downto 0) := (others => '0');
+         CHANNEL_COUNTERS_OUT       : out std_logic_vector(32 * 16 - 1 downto 0) := (others => '0');
+         CHANNEL_EDGE_COUNTERS_OUT  : out std_logic_vector(32 * 16 - 1 downto 0) := (others => '0');
+         NUM_OF_ITC_USED_OUT        : out std_logic_vector(4 downto 0);
+         
+      -- Slow Control
+         REGIO_ADDR_IN            : in  std_logic_vector(15 downto 0);
+         REGIO_DATA_IN            : in  std_logic_vector(31 downto 0);
+         REGIO_READ_ENABLE_IN     : in  std_logic;
+         REGIO_WRITE_ENABLE_IN    : in  std_logic;
+         REGIO_TIMEOUT_IN         : in  std_logic;
+         
+         REGIO_DATA_OUT           : out std_logic_vector(31 downto 0);
+         REGIO_DATAREADY_OUT      : out std_logic;
+         REGIO_WRITE_ACK_OUT      : out std_logic;
+         REGIO_NO_MORE_DATA_OUT   : out std_logic := '0';
+         REGIO_UNKNOWN_ADDR_OUT   : out std_logic
+      );
+   end component;
+   
+   component CTS_TRG_INPUT is
+   port (
+      CLK_IN      : in  std_logic;
+      RST_IN      : in  std_logic;
+      DATA_IN     : in  std_logic;
+      DATA_OUT    : out std_logic;
+      CONFIG_IN   : in  std_logic_vector(10 downto 0) := (others => '0')
+   );
+   end component;
+   
+   component CTS_TRG_COIN is
+      generic (
+         INPUT_COUNT       : integer range 1 to 8 := 4
+      );
+   
+      port (
+         CLK_IN          : in  std_logic;
+         RST_IN          : in  std_logic;
+         
+         DATA_IN         : in  std_logic_vector(INPUT_COUNT - 1 downto 0);
+         TRIGGER_OUT     : out std_logic;
+         
+         CONFIG_IN       : in  std_logic_vector(31 downto 0) := (others => '0')
+      );
+   end component;   
+
+   component CTS_TRG_PSEUDORAND_PULSER is
+      generic (
+         DATA_XOR     : std_logic_vector(31 downto 0) := (others => '0')
+      );
+      port (
+         clk_in       : in  std_logic;
+         threshold_in : in  std_logic_vector(31 downto 0); 
+         trigger_out  : out std_logic
+      );
+   end component;
+   
+
+-- Block identification header
+--       Bit   Description
+--    <reg_table name="cts_trg_header" >
+--             Block identification header      
+--       7:0   Block type
+--      15:8   Number of addresses in this block exclusively this header word
+--      20:16  First internal trigger channel assigned to this block (0 if it does not apply)
+--      25:21  Number of internal trigger channel assigned to this block  (0 if it does not apply)
+--       31    Last block indicator. Enumeration stops after reading this block
+--    </reg_table>
+   function CTS_BLOCK_HEADER(
+      constant ID  : integer range 0 to 255;
+      constant LEN : integer range 0 to 255;
+      constant ITC_BASE : integer range 0 to 15 := 0;
+      constant ITC_NUM : integer  range 0 to 15 := 0;
+      constant LAST : boolean := false
+   ) return std_logic_vector;
+   
+   
+   function MIN(x : integer; y : integer) return integer;
+end package cts_pkg;
+
+package body cts_pkg is
+   function CTS_BLOCK_HEADER(
+      constant ID  : integer range 0 to 255;
+      constant LEN : integer range 0 to 255;
+      constant ITC_BASE : integer range 0 to 15 := 0;
+      constant ITC_NUM : integer  range 0 to 15 := 0;
+      constant LAST : boolean := false
+   ) return std_logic_vector 
+   is
+      variable result : std_logic_vector(31 downto 0) := (others => '0');
+   begin
+      result( 7 downto  0) := std_logic_vector(to_unsigned(ID, 8));
+      result(15 downto  8) := std_logic_vector(to_unsigned(LEN, 8));
+      result(20 downto 16) := std_logic_vector(to_unsigned(ITC_BASE, 5));
+      result(25 downto 21) := std_logic_vector(to_unsigned(ITC_NUM,  5));
+      
+      if LAST then
+         result(31) := '1';
+      end if;
+      
+      return result;
+   end CTS_BLOCK_HEADER;
+   
+   function MIN(x : integer; y : integer)
+    return integer is
+   begin
+     if x < y then
+       return x;
+     else
+       return y;
+     end if;
+   end MIN;
+end package body cts_pkg;
diff --git a/cts/source/cts_trg_coin.vhd b/cts/source/cts_trg_coin.vhd
new file mode 100755 (executable)
index 0000000..4fbe27f
--- /dev/null
@@ -0,0 +1,105 @@
+-- Coincidence detection
+
+library ieee;
+   use ieee.std_logic_1164.all;
+   use ieee.numeric_std.all;
+
+-- COIN Register
+--    Bit   Description
+-- <reg_table name="cts_trg_coin_register" >
+--          COIN Module Configuration
+--    7:0   Coincidence bitmask. Each selected channel must be asserted within the
+--          coincidence window.
+--   15:8   Inhibit bitmask. Corresponds to trigger input signals. Each mask channel
+--          has to be asserted.  
+--   19:16  Coincidence window (0 to 15 clock cycles)
+-- </reg_table>
+entity CTS_TRG_COIN is
+   generic (
+      INPUT_COUNT       : integer range 1 to 8 := 4
+   );
+
+   port (
+      CLK_IN          : in  std_logic;
+      RST_IN          : in  std_logic;
+      
+      DATA_IN         : in  std_logic_vector(INPUT_COUNT - 1 downto 0);
+      TRIGGER_OUT     : out std_logic;
+      
+      CONFIG_IN       : in  std_logic_vector(31 downto 0) := (others => '0')
+   );
+end CTS_TRG_COIN;
+
+architecture rtl of CTS_TRG_COIN is
+   alias CONFIG_COIN_MASK_IN : STD_LOGIC_VECTOR(15 downto 0) is CONFIG_IN(15 downto 0);
+   alias CONFIG_WINDOW_IN : STD_LOGIC_VECTOR(3 downto 0) is CONFIG_IN(19 downto 16);
+
+   constant MAX_COIN_WINDOW : integer := 2**CONFIG_WINDOW_IN'LENGTH - 1;
+
+-- configuration mapping
+   signal config_window_i   : integer range 0 to MAX_COIN_WINDOW;
+
+-- edge detection and generation of time window signals
+   signal edge_detection_ref_i : std_logic_vector(INPUT_COUNT-1 downto 0);
+   type COUNTERS_T is array(0 to INPUT_COUNT-1) of integer range 0 to MAX_COIN_WINDOW;
+   signal counters_i : COUNTERS_T;
+
+-- delayed inputs
+   signal synch_inputs_i : std_logic_vector(DATA_IN'RANGE);
+
+   signal coin_frames_i : std_logic_vector(INPUT_COUNT-1 downto 0);
+begin
+   proc_coin_frames: process(CLK_IN) is
+   begin
+      if rising_edge(CLK_IN) then
+         coin_frames_i <= (others => '0');
+         edge_detection_ref_i <= DATA_IN;      
+         synch_inputs_i <=  DATA_IN;    -- as one cycle is needed to detect an
+                                        -- edge, the bypassed signals must be 
+                                        -- delayed for the same amount
+                
+         for i in 0 to INPUT_COUNT - 1 loop
+            if RST_IN = '1' then
+               counters_i(i) <= 0;
+            else 
+               if edge_detection_ref_i(i) = '0' and DATA_IN(i) = '1' then
+                  coin_frames_i(i) <= '1';
+                  counters_i(i) <= config_window_i;
+               elsif counters_i(i) /= 0 then
+                  coin_frames_i(i) <= '1';
+                  counters_i(i) <= counters_i(i) - 1;
+               end if;
+            end if;
+         end loop;        
+      end if;
+   end process;
+
+   proc_mask: process(CLK_IN) is
+      variable values: std_logic_vector(15 downto 0);
+      variable result : std_logic;
+   begin
+      if rising_edge(CLK_IN) then
+         values := X"FFFF";
+         values(  INPUT_COUNT-1 downto   0) := coin_frames_i;
+         values(8+INPUT_COUNT-1 downto 8+0) := synch_inputs_i;
+      
+         result := '1';
+         for i in 0 to 15 loop
+            result := result and (values(i) or not CONFIG_COIN_MASK_IN(i));
+         end loop;
+         
+         TRIGGER_OUT <= result;
+      end if;
+   end process;
+
+   proc_config: process(CONFIG_WINDOW_IN) is
+      variable tmp : integer range 0 to 2**16-1;
+   begin
+      tmp := to_integer(UNSIGNED(CONFIG_WINDOW_IN));
+      if tmp <= MAX_COIN_WINDOW then
+         config_window_i <= tmp;
+      else
+         config_window_i <= MAX_COIN_WINDOW;
+      end if;
+   end process;
+end architecture;
\ No newline at end of file
diff --git a/cts/source/cts_trg_input.vhd b/cts/source/cts_trg_input.vhd
new file mode 100755 (executable)
index 0000000..14b080a
--- /dev/null
@@ -0,0 +1,109 @@
+-- CTS_TRG_INPUT
+--  INPUT -> INVERTER -> DELAY -> SPIKE REJECTION -> OVERRIDE -> OUTPUT
+
+-- Configuration
+--    Bit   Description
+-- <reg_table name="cts_trg_input_register" >
+--          Input Module Configuration
+--    3:0   Delay (0 to 15 cycles)
+--    7:4   Spike Rejection. Number of clock cycles the signal has to be stably asserted until it is interpreted high.
+--    8     Invert (0: Bypass, 1: Invert Input)
+--    9     Override Enable (0: Bypass, 1: Set Value of 10. Bit)
+--    10    Override Value
+-- </reg_table>
+
+library ieee;
+   use ieee.std_logic_1164.all;
+   use ieee.numeric_std.all;
+
+entity CTS_TRG_INPUT is
+   port (
+      CLK_IN      : in  std_logic;
+      RST_IN      : in  std_logic;
+      DATA_IN     : in  std_logic;
+      DATA_OUT    : out std_logic;
+      CONFIG_IN   : in  std_logic_vector(10 downto 0) := (others => '0')
+   );
+end CTS_TRG_INPUT;
+
+architecture rtl of CTS_TRG_INPUT is
+-- setup
+   constant MAX_DELAY      : integer := 16;
+   constant MAX_SPIKE_REJ  : integer := 16;
+
+-- config mapping
+   signal config_delay_i    : integer range 0 to MAX_DELAY-1;
+   signal config_spike_i    : integer range 0 to MAX_SPIKE_REJ-1;
+   signal config_invert_i   : std_logic;
+   signal config_over_ena_i : std_logic;
+   signal config_over_val_i : std_logic;
+
+-- connection between stages
+   signal from_inverter_i, from_delay_i, from_spike_i : std_logic;
+
+   signal delay_line_i : std_logic_vector(15 downto 0);
+   signal spike_rej_counter_i : integer range 0 to MAX_SPIKE_REJ-1;
+begin
+-- inverter
+   proc_delay: process(CLK_IN) is
+   begin
+      if rising_edge(CLK_IN) then
+         from_inverter_i <= (DATA_IN xor config_invert_i) and (not RST_IN);
+      end if;
+   end process;
+   
+-- delays
+   proc_delay: process(CLK_IN) is
+   begin
+      if rising_edge(CLK_IN) then
+         if RST_IN = '1' then
+            delay_line_i <= (others => '0');
+            from_delay_i <= '0';
+         else
+            delay_line_i <= delay_line_i(delay_line_i'HIGH - 1 downto 0) 
+                            & from_inverter_i;
+            from_delay_i <= delay_line_i(config_delay_i);
+         end if;
+      end if;
+   end process;
+   
+-- spike rejection
+   -- TODO: delay must be independent of spike rejection setting
+   proc_spike: process(CLK_IN) is
+   begin
+      if rising_edge(CLK_IN) then
+         if RST_IN = '1' or from_delay_i = '0' then
+            spike_rej_counter_i <= config_spike_i;
+            from_spike_i <= '0';
+         else
+            if spike_rej_counter_i = 0 then
+               from_spike_i <= '1';
+            else
+               spike_rej_counter_i <= spike_rej_counter_i - 1;
+               from_spike_i <= '0';
+            end if;
+         end if;
+      end if;
+   end process;
+
+-- override
+   proc_override: process(CLK_IN) is
+   begin
+      if rising_edge(CLK_IN) then
+         if RST_IN = '1' then
+            DATA_OUT <= '0';
+         elsif config_over_ena_i = '1' then
+            DATA_OUT <= config_over_val_i;
+         else
+            DATA_OUT <= from_spike_i;
+         end if;
+      end if;
+   end process;
+   
+-- config mapping
+   config_delay_i    <= to_integer(unsigned(CONFIG_IN(3 downto 0)));
+   config_spike_i    <= to_integer(unsigned(CONFIG_IN(7 downto 4)));
+   config_invert_i   <= CONFIG_IN(8);
+   config_over_ena_i <= CONFIG_IN(9);
+   config_over_val_i <= CONFIG_IN(10);
+end architecture;
\ No newline at end of file
diff --git a/cts/source/cts_trg_pseudorand_pulser.vhd b/cts/source/cts_trg_pseudorand_pulser.vhd
new file mode 100755 (executable)
index 0000000..4fd7e29
--- /dev/null
@@ -0,0 +1,74 @@
+library ieee;
+   use ieee.std_logic_1164.all;
+   use ieee.numeric_std.all;
+
+entity CTS_TRG_PSEUDORAND_PULSER is
+   generic (
+      DATA_XOR     : std_logic_vector(31 downto 0) := (others => '0')
+   );
+   port (
+      clk_in       : in  std_logic;
+      threshold_in : in  std_logic_vector(31 downto 0); 
+      trigger_out  : out std_logic
+   );
+end CTS_TRG_PSEUDORAND_PULSER;
+
+architecture behave of CTS_TRG_PSEUDORAND_PULSER is
+   SIGNAL crc_i      : std_logic_vector(31 DOWNTO 0);
+   SIGNAL crc_tmp_i  : std_logic_vector(31 DOWNTO 0);
+   constant DATA     : std_logic_vector(31 downto 0) := X"6ED9EBA1" xor DATA_XOR; -- 2**30 * sqrt(3)
+begin
+-- comparator
+   comp_proc: process(clk_in) is
+   begin
+      if rising_edge(clk_in) then
+         if to_integer(unsigned(crc_i)) < to_integer(unsigned(threshold_in)) then
+            trigger_out <= '1';
+         else
+            trigger_out <= '0';
+         end if;
+      end if;
+   end process;
+         
+-- CRC generator created usign http://www.electronicdesignworks.com/utilities/crc_generator/crc_generator.htm
+-- based on polynomial x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x1 + 1
+   crc_tmp_i(0) <= DATA(0) XOR DATA(6) XOR DATA(9) XOR DATA(10) XOR DATA(24) XOR crc_i(0) XOR crc_i(24) XOR DATA(29) XOR crc_i(29) XOR DATA(28) XOR crc_i(28) XOR crc_i(10) XOR DATA(26) XOR crc_i(26) XOR crc_i(9) XOR DATA(25) XOR crc_i(25) XOR DATA(12) XOR DATA(16) XOR DATA(30) XOR crc_i(6) XOR crc_i(30) XOR crc_i(16) XOR DATA(31) XOR crc_i(31) XOR crc_i(12); 
+   crc_tmp_i(1) <= DATA(0) XOR DATA(1) XOR DATA(7) XOR DATA(11) XOR crc_i(1) XOR crc_i(11) XOR DATA(27) XOR crc_i(27) XOR DATA(13) XOR DATA(17) XOR crc_i(7) XOR crc_i(17) XOR crc_i(13) XOR DATA(6) XOR DATA(9) XOR DATA(24) XOR crc_i(0) XOR crc_i(24) XOR DATA(28) XOR crc_i(28) XOR crc_i(9) XOR DATA(12) XOR DATA(16) XOR crc_i(6) XOR crc_i(16) XOR crc_i(12); 
+   crc_tmp_i(2) <= DATA(0) XOR DATA(1) XOR DATA(2) XOR DATA(8) XOR crc_i(2) XOR DATA(14) XOR DATA(18) XOR crc_i(8) XOR crc_i(18) XOR crc_i(14) XOR DATA(7) XOR crc_i(1) XOR DATA(13) XOR DATA(17) XOR crc_i(7) XOR crc_i(17) XOR crc_i(13) XOR DATA(6) XOR DATA(9) XOR DATA(24) XOR crc_i(0) XOR crc_i(24) XOR DATA(26) XOR crc_i(26) XOR crc_i(9) XOR DATA(16) XOR DATA(30) XOR crc_i(6) XOR crc_i(30) XOR crc_i(16) XOR DATA(31) XOR crc_i(31); 
+   crc_tmp_i(3) <= DATA(1) XOR DATA(2) XOR DATA(3) XOR DATA(9) XOR crc_i(3) XOR DATA(15) XOR DATA(19) XOR crc_i(9) XOR crc_i(19) XOR crc_i(15) XOR DATA(8) XOR crc_i(2) XOR DATA(14) XOR DATA(18) XOR crc_i(8) XOR crc_i(18) XOR crc_i(14) XOR DATA(7) XOR DATA(10) XOR DATA(25) XOR crc_i(1) XOR crc_i(25) XOR DATA(27) XOR crc_i(27) XOR crc_i(10) XOR DATA(17) XOR DATA(31) XOR crc_i(7) XOR crc_i(31) XOR crc_i(17); 
+   crc_tmp_i(4) <= DATA(0) XOR DATA(2) XOR DATA(3) XOR DATA(4) XOR crc_i(4) XOR DATA(20) XOR crc_i(20) XOR crc_i(3) XOR DATA(15) XOR DATA(19) XOR crc_i(19) XOR crc_i(15) XOR DATA(8) XOR DATA(11) XOR crc_i(2) XOR crc_i(11) XOR DATA(18) XOR crc_i(8) XOR crc_i(18) XOR DATA(6) XOR DATA(24) XOR crc_i(0) XOR crc_i(24) XOR DATA(29) XOR crc_i(29) XOR DATA(25) XOR crc_i(25) XOR DATA(12) XOR DATA(30) XOR crc_i(6) XOR crc_i(30) XOR DATA(31) XOR crc_i(31) XOR crc_i(12); 
+   crc_tmp_i(5) <= DATA(0) XOR DATA(1) XOR DATA(3) XOR DATA(4) XOR DATA(5) XOR crc_i(5) XOR DATA(21) XOR crc_i(21) XOR crc_i(4) XOR DATA(20) XOR crc_i(20) XOR crc_i(3) XOR DATA(19) XOR crc_i(19) XOR DATA(7) XOR crc_i(1) XOR DATA(13) XOR crc_i(7) XOR crc_i(13) XOR DATA(6) XOR DATA(10) XOR DATA(24) XOR crc_i(0) XOR crc_i(24) XOR DATA(29) XOR crc_i(29) XOR DATA(28) XOR crc_i(28) XOR crc_i(10) XOR crc_i(6); 
+   crc_tmp_i(6) <= DATA(1) XOR DATA(2) XOR DATA(4) XOR DATA(5) XOR DATA(6) XOR crc_i(6) XOR DATA(22) XOR crc_i(22) XOR crc_i(5) XOR DATA(21) XOR crc_i(21) XOR crc_i(4) XOR DATA(20) XOR crc_i(20) XOR DATA(8) XOR crc_i(2) XOR DATA(14) XOR crc_i(8) XOR crc_i(14) XOR DATA(7) XOR DATA(11) XOR DATA(25) XOR crc_i(1) XOR crc_i(25) XOR DATA(30) XOR crc_i(30) XOR DATA(29) XOR crc_i(29) XOR crc_i(11) XOR crc_i(7); 
+   crc_tmp_i(7) <= DATA(0) XOR DATA(2) XOR DATA(3) XOR DATA(5) XOR DATA(7) XOR crc_i(7) XOR DATA(23) XOR crc_i(23) XOR DATA(22) XOR crc_i(22) XOR crc_i(5) XOR DATA(21) XOR crc_i(21) XOR crc_i(3) XOR DATA(15) XOR crc_i(15) XOR DATA(8) XOR crc_i(2) XOR crc_i(8) XOR DATA(10) XOR DATA(24) XOR crc_i(0) XOR crc_i(24) XOR DATA(29) XOR crc_i(29) XOR DATA(28) XOR crc_i(28) XOR crc_i(10) XOR DATA(25) XOR crc_i(25) XOR DATA(16) XOR crc_i(16); 
+   crc_tmp_i(8) <= DATA(0) XOR DATA(1) XOR DATA(3) XOR DATA(4) XOR DATA(8) XOR crc_i(8) XOR DATA(23) XOR crc_i(23) XOR DATA(22) XOR crc_i(22) XOR crc_i(4) XOR crc_i(3) XOR DATA(11) XOR crc_i(1) XOR crc_i(11) XOR DATA(17) XOR crc_i(17) XOR DATA(10) XOR crc_i(0) XOR DATA(28) XOR crc_i(28) XOR crc_i(10) XOR DATA(12) XOR DATA(31) XOR crc_i(31) XOR crc_i(12); 
+   crc_tmp_i(9) <= DATA(1) XOR DATA(2) XOR DATA(4) XOR DATA(5) XOR DATA(9) XOR crc_i(9) XOR DATA(24) XOR crc_i(24) XOR DATA(23) XOR crc_i(23) XOR crc_i(5) XOR crc_i(4) XOR DATA(12) XOR crc_i(2) XOR crc_i(12) XOR DATA(18) XOR crc_i(18) XOR DATA(11) XOR crc_i(1) XOR DATA(29) XOR crc_i(29) XOR crc_i(11) XOR DATA(13) XOR crc_i(13); 
+   crc_tmp_i(10) <= DATA(0) XOR DATA(2) XOR DATA(3) XOR DATA(5) XOR crc_i(5) XOR DATA(13) XOR crc_i(3) XOR crc_i(13) XOR DATA(19) XOR crc_i(19) XOR crc_i(2) XOR DATA(14) XOR crc_i(14) XOR DATA(9) XOR crc_i(0) XOR DATA(29) XOR crc_i(29) XOR DATA(28) XOR crc_i(28) XOR DATA(26) XOR crc_i(26) XOR crc_i(9) XOR DATA(16) XOR crc_i(16) XOR DATA(31) XOR crc_i(31); 
+   crc_tmp_i(11) <= DATA(0) XOR DATA(1) XOR DATA(3) XOR DATA(4) XOR DATA(14) XOR crc_i(4) XOR crc_i(14) XOR DATA(20) XOR crc_i(20) XOR crc_i(3) XOR DATA(15) XOR crc_i(15) XOR crc_i(1) XOR DATA(27) XOR crc_i(27) XOR DATA(17) XOR crc_i(17) XOR DATA(9) XOR DATA(24) XOR crc_i(0) XOR crc_i(24) XOR DATA(28) XOR crc_i(28) XOR DATA(26) XOR crc_i(26) XOR crc_i(9) XOR DATA(25) XOR crc_i(25) XOR DATA(12) XOR DATA(16) XOR crc_i(16) XOR DATA(31) XOR crc_i(31) XOR crc_i(12); 
+   crc_tmp_i(12) <= DATA(0) XOR DATA(1) XOR DATA(2) XOR DATA(4) XOR DATA(5) XOR DATA(15) XOR crc_i(5) XOR crc_i(15) XOR DATA(21) XOR crc_i(21) XOR crc_i(4) XOR crc_i(2) XOR DATA(18) XOR crc_i(18) XOR crc_i(1) XOR DATA(27) XOR crc_i(27) XOR DATA(13) XOR DATA(17) XOR crc_i(17) XOR crc_i(13) XOR DATA(6) XOR DATA(9) XOR DATA(24) XOR crc_i(0) XOR crc_i(24) XOR crc_i(9) XOR DATA(12) XOR DATA(30) XOR crc_i(6) XOR crc_i(30) XOR DATA(31) XOR crc_i(31) XOR crc_i(12); 
+   crc_tmp_i(13) <= DATA(1) XOR DATA(2) XOR DATA(3) XOR DATA(5) XOR DATA(6) XOR DATA(16) XOR crc_i(6) XOR crc_i(16) XOR DATA(22) XOR crc_i(22) XOR crc_i(5) XOR crc_i(3) XOR DATA(19) XOR crc_i(19) XOR crc_i(2) XOR DATA(28) XOR crc_i(28) XOR DATA(14) XOR DATA(18) XOR crc_i(18) XOR crc_i(14) XOR DATA(7) XOR DATA(10) XOR DATA(25) XOR crc_i(1) XOR crc_i(25) XOR crc_i(10) XOR DATA(13) XOR DATA(31) XOR crc_i(7) XOR crc_i(31) XOR crc_i(13); 
+   crc_tmp_i(14) <= DATA(2) XOR DATA(3) XOR DATA(4) XOR DATA(6) XOR DATA(7) XOR DATA(17) XOR crc_i(7) XOR crc_i(17) XOR DATA(23) XOR crc_i(23) XOR crc_i(6) XOR crc_i(4) XOR DATA(20) XOR crc_i(20) XOR crc_i(3) XOR DATA(29) XOR crc_i(29) XOR DATA(15) XOR DATA(19) XOR crc_i(19) XOR crc_i(15) XOR DATA(8) XOR DATA(11) XOR DATA(26) XOR crc_i(2) XOR crc_i(26) XOR crc_i(11) XOR DATA(14) XOR crc_i(8) XOR crc_i(14); 
+   crc_tmp_i(15) <= DATA(3) XOR DATA(4) XOR DATA(5) XOR DATA(7) XOR DATA(8) XOR DATA(18) XOR crc_i(8) XOR crc_i(18) XOR DATA(24) XOR crc_i(24) XOR crc_i(7) XOR crc_i(5) XOR DATA(21) XOR crc_i(21) XOR crc_i(4) XOR DATA(30) XOR crc_i(30) XOR DATA(16) XOR DATA(20) XOR crc_i(20) XOR crc_i(16) XOR DATA(9) XOR DATA(12) XOR DATA(27) XOR crc_i(3) XOR crc_i(27) XOR crc_i(12) XOR DATA(15) XOR crc_i(9) XOR crc_i(15); 
+   crc_tmp_i(16) <= DATA(0) XOR DATA(4) XOR DATA(5) XOR DATA(8) XOR DATA(19) XOR crc_i(19) XOR crc_i(8) XOR DATA(22) XOR crc_i(22) XOR crc_i(5) XOR DATA(17) XOR DATA(21) XOR crc_i(21) XOR crc_i(17) XOR DATA(13) XOR crc_i(4) XOR crc_i(13) XOR DATA(24) XOR crc_i(0) XOR crc_i(24) XOR DATA(29) XOR crc_i(29) XOR DATA(26) XOR crc_i(26) XOR DATA(12) XOR DATA(30) XOR crc_i(30) XOR crc_i(12); 
+   crc_tmp_i(17) <= DATA(1) XOR DATA(5) XOR DATA(6) XOR DATA(9) XOR DATA(20) XOR crc_i(20) XOR crc_i(9) XOR DATA(23) XOR crc_i(23) XOR crc_i(6) XOR DATA(18) XOR DATA(22) XOR crc_i(22) XOR crc_i(18) XOR DATA(14) XOR crc_i(5) XOR crc_i(14) XOR DATA(25) XOR crc_i(1) XOR crc_i(25) XOR DATA(30) XOR crc_i(30) XOR DATA(27) XOR crc_i(27) XOR DATA(13) XOR DATA(31) XOR crc_i(31) XOR crc_i(13); 
+   crc_tmp_i(18) <= DATA(2) XOR DATA(6) XOR DATA(7) XOR DATA(10) XOR DATA(21) XOR crc_i(21) XOR crc_i(10) XOR DATA(24) XOR crc_i(24) XOR crc_i(7) XOR DATA(19) XOR DATA(23) XOR crc_i(23) XOR crc_i(19) XOR DATA(15) XOR crc_i(6) XOR crc_i(15) XOR DATA(26) XOR crc_i(2) XOR crc_i(26) XOR DATA(31) XOR crc_i(31) XOR DATA(28) XOR crc_i(28) XOR DATA(14) XOR crc_i(14); 
+   crc_tmp_i(19) <= DATA(3) XOR DATA(7) XOR DATA(8) XOR DATA(11) XOR DATA(22) XOR crc_i(22) XOR crc_i(11) XOR DATA(25) XOR crc_i(25) XOR crc_i(8) XOR DATA(20) XOR DATA(24) XOR crc_i(24) XOR crc_i(20) XOR DATA(16) XOR crc_i(7) XOR crc_i(16) XOR DATA(27) XOR crc_i(3) XOR crc_i(27) XOR DATA(29) XOR crc_i(29) XOR DATA(15) XOR crc_i(15); 
+   crc_tmp_i(20) <= DATA(4) XOR DATA(8) XOR DATA(9) XOR DATA(12) XOR DATA(23) XOR crc_i(23) XOR crc_i(12) XOR DATA(26) XOR crc_i(26) XOR crc_i(9) XOR DATA(21) XOR DATA(25) XOR crc_i(25) XOR crc_i(21) XOR DATA(17) XOR crc_i(8) XOR crc_i(17) XOR DATA(28) XOR crc_i(4) XOR crc_i(28) XOR DATA(30) XOR crc_i(30) XOR DATA(16) XOR crc_i(16); 
+   crc_tmp_i(21) <= DATA(5) XOR DATA(9) XOR DATA(10) XOR DATA(13) XOR DATA(24) XOR crc_i(24) XOR crc_i(13) XOR DATA(27) XOR crc_i(27) XOR crc_i(10) XOR DATA(22) XOR DATA(26) XOR crc_i(26) XOR crc_i(22) XOR DATA(18) XOR crc_i(9) XOR crc_i(18) XOR DATA(29) XOR crc_i(5) XOR crc_i(29) XOR DATA(31) XOR crc_i(31) XOR DATA(17) XOR crc_i(17); 
+   crc_tmp_i(22) <= DATA(0) XOR DATA(11) XOR DATA(14) XOR crc_i(14) XOR crc_i(11) XOR DATA(23) XOR DATA(27) XOR crc_i(27) XOR crc_i(23) XOR DATA(19) XOR crc_i(19) XOR DATA(18) XOR crc_i(18) XOR DATA(9) XOR DATA(24) XOR crc_i(0) XOR crc_i(24) XOR DATA(29) XOR crc_i(29) XOR DATA(26) XOR crc_i(26) XOR crc_i(9) XOR DATA(12) XOR DATA(16) XOR crc_i(16) XOR DATA(31) XOR crc_i(31) XOR crc_i(12); 
+   crc_tmp_i(23) <= DATA(0) XOR DATA(1) XOR DATA(15) XOR crc_i(15) XOR DATA(20) XOR crc_i(20) XOR DATA(19) XOR crc_i(19) XOR crc_i(1) XOR DATA(27) XOR crc_i(27) XOR DATA(13) XOR DATA(17) XOR crc_i(17) XOR crc_i(13) XOR DATA(6) XOR DATA(9) XOR crc_i(0) XOR DATA(29) XOR crc_i(29) XOR DATA(26) XOR crc_i(26) XOR crc_i(9) XOR DATA(16) XOR crc_i(6) XOR crc_i(16) XOR DATA(31) XOR crc_i(31); 
+   crc_tmp_i(24) <= DATA(1) XOR DATA(2) XOR DATA(16) XOR crc_i(16) XOR DATA(21) XOR crc_i(21) XOR DATA(20) XOR crc_i(20) XOR crc_i(2) XOR DATA(28) XOR crc_i(28) XOR DATA(14) XOR DATA(18) XOR crc_i(18) XOR crc_i(14) XOR DATA(7) XOR DATA(10) XOR crc_i(1) XOR DATA(30) XOR crc_i(30) XOR DATA(27) XOR crc_i(27) XOR crc_i(10) XOR DATA(17) XOR crc_i(7) XOR crc_i(17); 
+   crc_tmp_i(25) <= DATA(2) XOR DATA(3) XOR DATA(17) XOR crc_i(17) XOR DATA(22) XOR crc_i(22) XOR DATA(21) XOR crc_i(21) XOR crc_i(3) XOR DATA(29) XOR crc_i(29) XOR DATA(15) XOR DATA(19) XOR crc_i(19) XOR crc_i(15) XOR DATA(8) XOR DATA(11) XOR crc_i(2) XOR DATA(31) XOR crc_i(31) XOR DATA(28) XOR crc_i(28) XOR crc_i(11) XOR DATA(18) XOR crc_i(8) XOR crc_i(18); 
+   crc_tmp_i(26) <= DATA(0) XOR DATA(3) XOR DATA(4) XOR DATA(18) XOR crc_i(18) XOR DATA(23) XOR crc_i(23) XOR DATA(22) XOR crc_i(22) XOR crc_i(4) XOR DATA(20) XOR crc_i(20) XOR crc_i(3) XOR DATA(19) XOR crc_i(19) XOR DATA(6) XOR DATA(10) XOR DATA(24) XOR crc_i(0) XOR crc_i(24) XOR DATA(28) XOR crc_i(28) XOR crc_i(10) XOR DATA(26) XOR crc_i(26) XOR DATA(25) XOR crc_i(25) XOR crc_i(6) XOR DATA(31) XOR crc_i(31); 
+   crc_tmp_i(27) <= DATA(1) XOR DATA(4) XOR DATA(5) XOR DATA(19) XOR crc_i(19) XOR DATA(24) XOR crc_i(24) XOR DATA(23) XOR crc_i(23) XOR crc_i(5) XOR DATA(21) XOR crc_i(21) XOR crc_i(4) XOR DATA(20) XOR crc_i(20) XOR DATA(7) XOR DATA(11) XOR DATA(25) XOR crc_i(1) XOR crc_i(25) XOR DATA(29) XOR crc_i(29) XOR crc_i(11) XOR DATA(27) XOR crc_i(27) XOR DATA(26) XOR crc_i(26) XOR crc_i(7); 
+   crc_tmp_i(28) <= DATA(2) XOR DATA(5) XOR DATA(6) XOR DATA(20) XOR crc_i(20) XOR DATA(25) XOR crc_i(25) XOR DATA(24) XOR crc_i(24) XOR crc_i(6) XOR DATA(22) XOR crc_i(22) XOR crc_i(5) XOR DATA(21) XOR crc_i(21) XOR DATA(8) XOR DATA(12) XOR DATA(26) XOR crc_i(2) XOR crc_i(26) XOR DATA(30) XOR crc_i(30) XOR crc_i(12) XOR DATA(28) XOR crc_i(28) XOR DATA(27) XOR crc_i(27) XOR crc_i(8); 
+   crc_tmp_i(29) <= DATA(3) XOR DATA(6) XOR DATA(7) XOR DATA(21) XOR crc_i(21) XOR DATA(26) XOR crc_i(26) XOR DATA(25) XOR crc_i(25) XOR crc_i(7) XOR DATA(23) XOR crc_i(23) XOR crc_i(6) XOR DATA(22) XOR crc_i(22) XOR DATA(9) XOR DATA(13) XOR DATA(27) XOR crc_i(3) XOR crc_i(27) XOR DATA(31) XOR crc_i(31) XOR crc_i(13) XOR DATA(29) XOR crc_i(29) XOR DATA(28) XOR crc_i(28) XOR crc_i(9); 
+   crc_tmp_i(30) <= DATA(4) XOR DATA(7) XOR DATA(8) XOR DATA(22) XOR crc_i(22) XOR DATA(27) XOR crc_i(27) XOR DATA(26) XOR crc_i(26) XOR crc_i(8) XOR DATA(24) XOR crc_i(24) XOR crc_i(7) XOR DATA(23) XOR crc_i(23) XOR DATA(10) XOR DATA(14) XOR DATA(28) XOR crc_i(4) XOR crc_i(28) XOR crc_i(14) XOR DATA(30) XOR crc_i(30) XOR DATA(29) XOR crc_i(29) XOR crc_i(10); 
+   crc_tmp_i(31) <= DATA(5) XOR DATA(8) XOR DATA(9) XOR DATA(23) XOR crc_i(23) XOR DATA(28) XOR crc_i(28) XOR DATA(27) XOR crc_i(27) XOR crc_i(9) XOR DATA(25) XOR crc_i(25) XOR crc_i(8) XOR DATA(24) XOR crc_i(24) XOR DATA(11) XOR DATA(15) XOR DATA(29) XOR crc_i(5) XOR crc_i(29) XOR crc_i(15) XOR DATA(31) XOR crc_i(31) XOR DATA(30) XOR crc_i(30) XOR crc_i(11); 
+
+   crc_proc: process(clk_in) is
+   begin
+      if rising_edge(clk_in) then
+         crc_i <= crc_tmp_i;
+      end if;
+   end process;
+end behave;
diff --git a/cts/source/cts_trigger.vhd b/cts/source/cts_trigger.vhd
new file mode 100755 (executable)
index 0000000..a255a9f
--- /dev/null
@@ -0,0 +1,558 @@
+   library IEEE;
+   use IEEE.STD_LOGIC_1164.ALL;
+   use IEEE.NUMERIC_STD.ALL;
+   
+library work;
+   use work.cts_pkg.all;
+   
+entity CTS_TRIGGER is
+   generic (
+      TRIGGER_INPUT_COUNT  : integer range 1 to  8 := 4;
+      TRIGGER_COIN_COUNT   : integer range 0 to 15 := 4;
+      TRIGGER_PULSER_COUNT : integer range 0 to 15 := 2;
+      TRIGGER_RAND_PULSER  : integer range 0 to 15 := 1;
+      EXTERNAL_TRIGGER_ID  : std_logic_vector(7 downto 0) := X"00"
+   );
+
+   port (
+      CLK_IN       : in  std_logic;
+      RESET_IN     : in  std_logic;      
+      
+    -- Trigger Inputs
+      TRIGGERS_IN : in std_logic_vector(TRIGGER_INPUT_COUNT - 1 downto 0);
+      
+    -- External 
+      EXT_TRIGGER_IN  : in std_logic;
+      EXT_STATUS_IN   : in std_logic_vector(31 downto 0) := X"00000000";
+      EXT_CONTROL_OUT : out std_logic_vector(31 downto 0);
+
+    -- Output
+      TRIGGER_OUT         : out std_logic; -- asserted when trigger detected
+      TRIGGER_TYPE_OUT    : out std_logic_vector(3 downto 0);
+      TRIGGER_BITMASK_OUT : out std_logic_vector(15 downto 0);
+      
+    -- Counters
+      INPUT_COUNTERS_OUT         : out std_logic_vector(32 * TRIGGER_INPUT_COUNT - 1 downto 0) := (others => '0');
+      INPUT_EDGE_COUNTERS_OUT    : out std_logic_vector(32 * TRIGGER_INPUT_COUNT - 1 downto 0) := (others => '0');
+      CHANNEL_COUNTERS_OUT       : out std_logic_vector(32 * 16 - 1 downto 0) := (others => '0');
+      CHANNEL_EDGE_COUNTERS_OUT  : out std_logic_vector(32 * 16 - 1 downto 0) := (others => '0');
+      NUM_OF_ITC_USED_OUT        : out std_logic_vector(4 downto 0);
+      
+    -- Slow Control
+      REGIO_ADDR_IN            : in  std_logic_vector(15 downto 0);
+      REGIO_DATA_IN            : in  std_logic_vector(31 downto 0);
+      REGIO_READ_ENABLE_IN     : in  std_logic;
+      REGIO_WRITE_ENABLE_IN    : in  std_logic;
+      REGIO_TIMEOUT_IN         : in  std_logic;
+      
+      REGIO_DATA_OUT           : out std_logic_vector(31 downto 0);
+      REGIO_DATAREADY_OUT      : out std_logic;
+      REGIO_WRITE_ACK_OUT      : out std_logic;
+      REGIO_NO_MORE_DATA_OUT   : out std_logic := '0';
+      REGIO_UNKNOWN_ADDR_OUT   : out std_logic
+   );
+end CTS_TRIGGER;
+
+architecture RTL of CTS_TRIGGER is
+-- Internal Trigger Ports
+   signal channels_i : std_logic_vector(15 downto 0) := (others => '0');
+   signal channel_mask_i : std_logic_vector(15 downto 0);
+   signal channel_edge_select_i : std_logic_vector(15 downto 0);
+
+   constant ITC_NUM_EXT     : integer := MIN(0, to_integer(unsigned(EXTERNAL_TRIGGER_ID)));
+   
+   constant ITC_BASE_EXT    : integer := 0; 
+   constant ITC_BASE_PULSER : integer      := ITC_BASE_EXT         + ITC_NUM_EXT;
+   constant ITC_BASE_RAND_PULSER : integer := ITC_BASE_PULSER      + TRIGGER_PULSER_COUNT;
+   constant ITC_BASE_INPUTS : integer      := ITC_BASE_RAND_PULSER + TRIGGER_RAND_PULSER;
+   constant ITC_BASE_COINS  : integer      := ITC_BASE_INPUTS      + TRIGGER_INPUT_COUNT;
+
+   constant ITC_NUM_USED    : integer := ITC_BASE_EXT + ITC_NUM_EXT;
+
+   alias trigger_inputs_i : std_logic_vector(TRIGGER_INPUT_COUNT - 1 downto 0) 
+      is channels_i(ITC_BASE_INPUTS + TRIGGER_INPUT_COUNT - 1 downto ITC_BASE_INPUTS);
+      
+   alias coins_i          : std_logic_vector(TRIGGER_COIN_COUNT - 1 downto 0) 
+      is channels_i(ITC_BASE_COINS + TRIGGER_COIN_COUNT - 1 downto ITC_BASE_COINS);
+      
+   alias pulser_i         : std_logic_vector(TRIGGER_PULSER_COUNT - 1 downto 0) 
+      is channels_i(ITC_BASE_PULSER + TRIGGER_PULSER_COUNT - 1 downto ITC_BASE_PULSER);
+      
+   alias rand_pulsers_i    : std_logic_vector(TRIGGER_RAND_PULSER - 1 downto 0)
+      is channels_i(ITC_BASE_RAND_PULSER + TRIGGER_RAND_PULSER - 1 downto ITC_BASE_RAND_PULSER);
+   
+   type   channel_counters_t is array(channels_i'HIGH downto 0) of unsigned(31 downto 0);
+   signal channel_counters_i : channel_counters_t;
+   signal channel_edge_counters_i : channel_counters_t;
+   
+-- Trigger Inputs (Spike Rejection, Negation, Override ...)
+   type trigger_input_configs_t is array(TRIGGER_INPUT_COUNT - 1 downto 0) of std_logic_vector(10 downto 0);
+   signal trigger_input_configs_i : trigger_input_configs_t;
+
+   type   trigger_input_counters_t is array(TRIGGER_INPUT_COUNT - 1 downto 0) of unsigned(31 downto 0);
+   signal trigger_input_counters_i : trigger_input_counters_t;
+   signal trigger_input_edge_counters_i : trigger_input_counters_t;
+   
+-- Coincidence Detection
+   type coin_config_t is array(TRIGGER_COIN_COUNT - 1 downto 0) of std_logic_vector(31 downto 0);
+   signal coin_config_i : coin_config_t;
+   
+-- TRIGGER_PULSER_COUNT
+   type   pulser_interval_t is array(TRIGGER_PULSER_COUNT - 1 downto 0) of std_logic_vector(31 downto 0);
+   signal pulser_interval_i : pulser_interval_t;
+   signal pulser_counter_i  : pulser_interval_t := (others => (others => '0'));
+   signal pulser_1us_i  : std_logic;
+   
+-- Random Pulser
+   type   rand_pulser_threshold_t is array(TRIGGER_RAND_PULSER - 1 downto 0) of std_logic_vector(31 downto 0);
+   signal rand_pulser_threshold_i : rand_pulser_threshold_t := (others => (others => '0'));
+
+-- Trigger Type Assoc 
+   type trigger_type_assoc_t is array(0 to 15) of std_logic_vector(3 downto 0);
+   signal trigger_type_assoc_i : trigger_type_assoc_t := (others => X"1");
+
+-- External Trigger Logic
+   signal ext_control_i : std_logic_vector(31 downto 0) := (others => '0');
+begin
+   assert ITC_NUM_USED <= 16
+      report "Number of modules exceeds number of internal trigger channels"
+      severity failure;
+
+   NUM_OF_ITC_USED_OUT <= STD_LOGIC_VECTOR(TO_UNSIGNED(ITC_NUM_USED, 5));
+   EXT_CONTROL_OUT <= ext_control_i;
+   
+   gen_ext_trigger: if EXTERNAL_TRIGGER_ID /= X"00" generate
+      channels_i(ITC_BASE_EXT) <= EXT_TRIGGER_IN;
+   end generate;
+         
+   gen_trigger_inputs: for i in 0 to TRIGGER_INPUT_COUNT-1 generate
+      my_trigger_input: CTS_TRG_INPUT port map (
+         CLK_IN => CLK_IN,
+         RST_IN => RESET_IN,
+         DATA_IN => TRIGGERS_IN(i),
+         DATA_OUT => trigger_inputs_i(i),
+         CONFIG_IN => trigger_input_configs_i(i)
+      );
+   end generate;
+
+   gen_coin: for i in 0 to TRIGGER_COIN_COUNT - 1 generate
+      my_coin: CTS_TRG_COIN 
+      generic map (
+         INPUT_COUNT => TRIGGER_INPUT_COUNT
+      )
+      port map (
+         CLK_IN => CLK_IN,
+         RST_IN => RESET_IN,
+         DATA_IN => trigger_inputs_i,
+         TRIGGER_OUT => coins_i(i),
+         CONFIG_IN => coin_config_i(i)
+      );
+   end generate;
+   
+   gen_rand_pulser: for i in 0 to TRIGGER_RAND_PULSER - 1 generate
+      my_rand_pulser: CTS_TRG_PSEUDORAND_PULSER
+      generic map (
+         DATA_XOR     => STD_LOGIC_VECTOR(TO_UNSIGNED(i, 32))
+      ) port map (
+         CLK_IN       => CLK_IN,
+         THRESHOLD_IN => rand_pulser_threshold_i(i),
+         TRIGGER_OUT  => rand_pulsers_i(i)
+      );
+   end generate;
+   
+   proc_pulser: process(CLK_IN) is
+   begin
+      if rising_edge(CLK_IN) then
+         for i in 0 to TRIGGER_PULSER_COUNT-1 loop
+            pulser_i(i) <= '0';
+            
+            if pulser_counter_i(i) >= pulser_interval_i(i) then
+               pulser_counter_i(i) <= (others => '0');
+               pulser_i(i) <= '1';
+               
+            else
+               pulser_counter_i(i) <= STD_LOGIC_VECTOR(UNSIGNED(pulser_counter_i(i)) + TO_UNSIGNED(1,1));
+               
+            end if;
+         end loop;
+      end if;
+   end process;
+   
+   proc_output: process(CLK_IN) is
+      variable channels_delay_v : std_logic_vector(15 downto 0) := (others => '1');
+   begin
+      if rising_edge(CLK_IN) then
+         TRIGGER_OUT <= '0';
+         TRIGGER_TYPE_OUT <= (others => '-');
+         TRIGGER_BITMASK_OUT <= channels_i;
+         
+         if RESET_IN = '1' then
+            channels_delay_v := (others => '1');
+         else
+            for i in 15 downto 0 loop
+               if channel_edge_select_i(i) = '1' then
+                  -- detect rising edges
+                  if channels_delay_v(i) = '0' and channels_i(i) = '1' and channel_mask_i(i) = '1' then
+                     TRIGGER_OUT <= '1';
+                     TRIGGER_TYPE_OUT <= trigger_type_assoc_i(i);
+                  end if;
+               else
+                  -- sensitive to high level
+                  if channels_i(i) = '1' and channel_mask_i(i) = '1' then
+                     TRIGGER_OUT <= '1';
+                     TRIGGER_TYPE_OUT <= trigger_type_assoc_i(i);
+                  end if;
+               end if;
+            end loop;
+            
+            channels_delay_v := channels_i;
+         end if;
+      end if;
+   end process;
+   
+   proc_counter: process(CLK_IN) is
+      variable last_inputs_v : std_logic_vector(triggers_in'range);
+      variable last_itc_v : std_logic_vector(channels_i'range);
+   
+   begin
+      if rising_edge(CLK_IN) then
+         if RESET_IN = '1' then
+            trigger_input_counters_i      <= (others => (others => '0'));
+            channel_counters_i            <= (others => (others => '0'));
+            trigger_input_edge_counters_i <= (others => (others => '0'));
+            channel_edge_counters_i       <= (others => (others => '0'));
+         
+         else
+            for i in 0 to TRIGGER_INPUT_COUNT-1 loop
+               if TRIGGERS_IN(i) = '1' then
+                  trigger_input_counters_i(i) <= trigger_input_counters_i(i) + "1";
+                  
+                  if last_inputs_v(i) = '0' then
+                     trigger_input_edge_counters_i(i) <= trigger_input_edge_counters_i(i) + "1";
+                  end if;
+               end if;
+            end loop;
+
+            for i in 0 to channels_i'HIGH loop
+               if channels_i(i) = '1' then
+                  channel_counters_i(i) <= channel_counters_i(i) + ("1");
+                  
+                  if last_itc_v(i) = '0' then
+                     channel_edge_counters_i(i) <= channel_edge_counters_i(i) + "1";
+                  end if;
+               end if;
+            end loop;
+            
+         end if;
+         
+         last_inputs_v := TRIGGERS_IN;
+         last_itc_v := channels_i;
+      end if;
+   end process;
+   
+   gen_input_counter: for i in 0 to TRIGGER_INPUT_COUNT-1 generate
+      INPUT_COUNTERS_OUT(i*32 + 31 downto i*32) <= trigger_input_counters_i(i);
+      INPUT_EDGE_COUNTERS_OUT(i*32 + 31 downto i*32) <= trigger_input_edge_counters_i(i);
+   end generate;
+
+   gen_channel_counter: for i in 0 to channels_i'HIGH generate
+      CHANNEL_COUNTERS_OUT(i*32 + 31 downto i*32) <= channel_counters_i(i);
+      CHANNEL_EDGE_COUNTERS_OUT(i*32 + 31 downto i*32) <= channel_edge_counters_i(i);
+   end generate;
+   
+   proc_regio: process(CLK_IN) is
+      variable addr : integer range 0 to 255;
+      variable ref_addr : integer range 0 to 255;
+   begin
+      if rising_edge(CLK_IN) then
+         REGIO_DATA_OUT <= (others => '0');
+         REGIO_DATAREADY_OUT <= '0';
+         REGIO_WRITE_ACK_OUT <= '0';
+         REGIO_UNKNOWN_ADDR_OUT <= REGIO_WRITE_ENABLE_IN or REGIO_READ_ENABLE_IN;
+
+         addr := to_integer(unsigned(REGIO_ADDR_IN(7 downto 0)));
+         ref_addr := 0;
+         
+         if RESET_IN = '1' then
+            -- modelsim want's it that way
+            channel_mask_i <= (others => '0');
+            channel_edge_select_i <= (others => '1');
+            
+            trigger_input_configs_i <= (others => (others => '0'));
+            coin_config_i <= (others => X"000F0000");
+            pulser_interval_i <= (1 => X"00000003",  others => (others => '1'));
+            
+            rand_pulser_threshold_i <= (others => (others => '0'));
+
+            ext_control_i <= (others => '0');
+            
+         else
+
+-- Trigger Channel Masking         
+            if addr = ref_addr then
+               REGIO_UNKNOWN_ADDR_OUT <= '0';
+               REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+               REGIO_DATA_OUT <= CTS_BLOCK_HEADER(id => 16#00#, len => 1);
+            end if;
+            ref_addr := ref_addr + 1;
+            
+            if addr = ref_addr then
+               REGIO_UNKNOWN_ADDR_OUT <= '0';
+               REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+               REGIO_WRITE_ACK_OUT <= REGIO_WRITE_ENABLE_IN;
+               
+               REGIO_DATA_OUT(31 downto 0) <= channel_edge_select_i & channel_mask_i;
+               
+               if REGIO_WRITE_ENABLE_IN = '1' then
+                  channel_mask_i        <= REGIO_DATA_IN(15 downto 0);
+                  channel_edge_select_i <= REGIO_DATA_IN(31 downto 16);
+               end if;
+            end if;
+            ref_addr := ref_addr + 1;
+            
+-- Trigger Channel Counters
+            if addr = ref_addr then
+               REGIO_UNKNOWN_ADDR_OUT <= '0';
+               REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+               REGIO_DATA_OUT <= CTS_BLOCK_HEADER(id => 16#01#, len => 32);
+            end if;
+            ref_addr := ref_addr + 1;
+            
+            for i in 0 to channel_counters_i'HIGH loop
+               if addr = ref_addr then
+                  REGIO_UNKNOWN_ADDR_OUT <= '0';
+                  REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+                  
+                  REGIO_DATA_OUT <= std_logic_vector( channel_counters_i(i) );
+               end if;
+               ref_addr := ref_addr + 1;
+
+               if addr = ref_addr then
+                  REGIO_UNKNOWN_ADDR_OUT <= '0';
+                  REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+                  
+                  REGIO_DATA_OUT <= std_logic_vector( channel_edge_counters_i(i) );
+               end if;
+               ref_addr := ref_addr + 1;
+            end loop;
+            
+-- Input Module Configuration            
+            if addr = ref_addr then
+               REGIO_UNKNOWN_ADDR_OUT <= '0';
+               REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+               REGIO_DATA_OUT <= CTS_BLOCK_HEADER(
+                  id => 16#10#,
+                  len => TRIGGER_INPUT_COUNT,
+                  itc_base => ITC_BASE_INPUTS,
+                  itc_num  => TRIGGER_INPUT_COUNT
+               );
+            end if;
+            ref_addr := ref_addr + 1;            
+
+-- INPUT CONFIGURATION
+            for i in 0 to TRIGGER_INPUT_COUNT - 1 loop
+               if addr = ref_addr then
+                  REGIO_UNKNOWN_ADDR_OUT <= '0';
+                  REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+                  REGIO_WRITE_ACK_OUT <= REGIO_WRITE_ENABLE_IN;
+                  
+                  REGIO_DATA_OUT(10 downto 0) <= trigger_input_configs_i(i);
+                  
+                  if REGIO_WRITE_ENABLE_IN = '1' then
+                     trigger_input_configs_i(i) <= REGIO_DATA_IN(10 downto 0);
+                  end if;
+               end if;
+               ref_addr := ref_addr + 1;            
+            end loop;
+
+-- Trigger Input Counters
+            if addr = ref_addr then
+               REGIO_UNKNOWN_ADDR_OUT <= '0';
+               REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+               REGIO_DATA_OUT <= CTS_BLOCK_HEADER(id => 16#11#, len => 2*TRIGGER_INPUT_COUNT);
+            end if;
+            ref_addr := ref_addr + 1;
+            
+            for i in 0 to TRIGGER_INPUT_COUNT - 1 loop
+               if addr = ref_addr then
+                  REGIO_UNKNOWN_ADDR_OUT <= '0';
+                  REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+                  
+                  REGIO_DATA_OUT <= std_logic_vector( trigger_input_counters_i(i) );
+               end if;
+               ref_addr := ref_addr + 1;
+
+               if addr = ref_addr then
+                  REGIO_UNKNOWN_ADDR_OUT <= '0';
+                  REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+                  
+                  REGIO_DATA_OUT <= std_logic_vector( trigger_input_edge_counters_i(i) );
+               end if;
+               ref_addr := ref_addr + 1;               
+            end loop;
+            
+-- COIN CONFIGURATION
+            if TRIGGER_COIN_COUNT > 0 then
+               if addr = ref_addr then
+                  REGIO_UNKNOWN_ADDR_OUT <= '0';
+                  REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+                  REGIO_DATA_OUT <= CTS_BLOCK_HEADER(
+                     id => 16#20#,
+                     len => TRIGGER_COIN_COUNT,
+                     itc_base => ITC_BASE_COINS,
+                     itc_num  => TRIGGER_COIN_COUNT
+                  );
+               end if;
+               ref_addr := ref_addr + 1;  
+               
+               for i in 0 to TRIGGER_COIN_COUNT - 1 loop
+                  if addr=ref_addr then
+                     REGIO_UNKNOWN_ADDR_OUT <= '0';
+                     REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+                     REGIO_WRITE_ACK_OUT <= REGIO_WRITE_ENABLE_IN;
+                     
+                     REGIO_DATA_OUT <= coin_config_i(i);
+                     
+                     if REGIO_WRITE_ENABLE_IN = '1' then
+                        coin_config_i(i) <= REGIO_DATA_IN;
+                     end if;
+                  end if;
+                  ref_addr := ref_addr + 1;                 
+   
+               end loop;
+            end if;
+
+-- TRIGGER_PULSER_COUNT CONFIGURATION
+            if TRIGGER_PULSER_COUNT > 0 then
+               if addr = ref_addr then
+                  REGIO_UNKNOWN_ADDR_OUT <= '0';
+                  REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+                  REGIO_DATA_OUT <= CTS_BLOCK_HEADER(
+                     id => 16#30#,
+                     len => TRIGGER_PULSER_COUNT,
+                     itc_base => ITC_BASE_PULSER,
+                     itc_num  => TRIGGER_PULSER_COUNT
+                  );
+               end if;
+               ref_addr := ref_addr + 1;  
+               
+               for i in 0 to TRIGGER_PULSER_COUNT - 1 loop
+                  if addr=ref_addr then
+                     REGIO_UNKNOWN_ADDR_OUT <= '0';
+                     REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+                     REGIO_WRITE_ACK_OUT <= REGIO_WRITE_ENABLE_IN;
+                     
+                     REGIO_DATA_OUT <= pulser_interval_i(i);
+                     
+                     if REGIO_WRITE_ENABLE_IN = '1' then
+                        pulser_interval_i(i) <= REGIO_DATA_IN;
+                     end if;
+                  end if;
+                  ref_addr := ref_addr + 1;                 
+
+               end loop;
+            end if;
+            
+-- Pseudo Random Pulser
+            if TRIGGER_RAND_PULSER /= 0 then
+               if addr = ref_addr then
+                  REGIO_UNKNOWN_ADDR_OUT <= '0';
+                  REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+                  REGIO_DATA_OUT <= CTS_BLOCK_HEADER(
+                     id   => 16#50#,
+                     len  => TRIGGER_RAND_PULSER,
+                     itc_base => ITC_BASE_RAND_PULSER,
+                     itc_num  => 1,
+                     last => false
+                  );
+               end if;
+               ref_addr := ref_addr + 1;
+               
+               for i in 0 to TRIGGER_RAND_PULSER - 1 loop
+                  if addr=ref_addr then
+                     REGIO_UNKNOWN_ADDR_OUT <= '0';
+                     REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+                     REGIO_WRITE_ACK_OUT <= REGIO_WRITE_ENABLE_IN;
+                     
+                     REGIO_DATA_OUT <= rand_pulser_threshold_i(i);
+                     
+                     if REGIO_WRITE_ENABLE_IN = '1' then
+                        rand_pulser_threshold_i(i) <= REGIO_DATA_IN;
+                     end if;
+                  end if;
+                  ref_addr := ref_addr + 1;                 
+
+               end loop;              
+            end if;
+
+-- External Trigger
+            if EXTERNAL_TRIGGER_ID /= X"00" then
+               if addr = ref_addr then
+                  REGIO_UNKNOWN_ADDR_OUT <= '0';
+                  REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+                  REGIO_DATA_OUT <= CTS_BLOCK_HEADER(
+                     id => to_integer(unsigned(EXTERNAL_TRIGGER_ID)),
+                     len => 2,
+                     itc_base => ITC_BASE_EXT,
+                     itc_num  => 1,
+                     last => false
+                  );
+               end if;
+               ref_addr := ref_addr + 1;
+             
+             -- status register
+               if addr=ref_addr then
+                  REGIO_UNKNOWN_ADDR_OUT <= '0';
+                  REGIO_DATAREADY_OUT    <= REGIO_READ_ENABLE_IN;
+                  REGIO_DATA_OUT         <= EXT_STATUS_IN;
+               end if;
+               ref_addr := ref_addr + 1;   
+                  
+               -- control register
+               if addr=ref_addr then
+                  REGIO_UNKNOWN_ADDR_OUT <= '0';
+                  REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+                  REGIO_WRITE_ACK_OUT <= REGIO_WRITE_ENABLE_IN;
+                  
+                  REGIO_DATA_OUT <= ext_control_i;
+                  
+                  if REGIO_WRITE_ENABLE_IN = '1' then
+                     ext_control_i <= REGIO_DATA_IN;
+                  end if;
+               end if;
+               ref_addr := ref_addr + 1;   
+            end if;
+            
+-- Trigger Type Assoc
+            if addr = ref_addr then
+               REGIO_UNKNOWN_ADDR_OUT <= '0';
+               REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+               REGIO_DATA_OUT <= CTS_BLOCK_HEADER(
+                  id => 16#40#,
+                  len => 2,
+                  last => true
+               );
+            end if;
+            ref_addr := ref_addr + 1;  
+            
+            for i in 0 to 1 loop
+               if addr=ref_addr then
+                  REGIO_UNKNOWN_ADDR_OUT <= '0';
+                  REGIO_DATAREADY_OUT <= REGIO_READ_ENABLE_IN;
+                  REGIO_WRITE_ACK_OUT <= REGIO_WRITE_ENABLE_IN;
+                  
+                  for j in 0 to 7 loop
+                     REGIO_DATA_OUT(j*4 + 3 downto j*4) <= trigger_type_assoc_i(8*i+j);
+                     
+                     if REGIO_WRITE_ENABLE_IN = '1' then
+                        trigger_type_assoc_i(8*i+j) <= REGIO_DATA_IN(j*4 + 3 downto j*4);
+                     end if;
+                  end loop;
+               end if;
+               ref_addr := ref_addr + 1;
+            end loop;
+
+         end if;
+      end if;
+   end process;
+end RTL;
\ No newline at end of file