--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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;
--- /dev/null
+-- 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
--- /dev/null
+-- 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
--- /dev/null
+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;
--- /dev/null
+ 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