From d7b4cdf58ae0f2071894a46f960c0fae554738ee Mon Sep 17 00:00:00 2001 From: hadeshyp Date: Sat, 29 Sep 2012 11:50:06 +0000 Subject: [PATCH] Added source directory forgotten last time --- cts/source/cts.vhd | 891 +++++++++++++++++++++++ cts/source/cts_fifo.vhd | 97 +++ cts/source/cts_pkg.vhd | 242 ++++++ cts/source/cts_trg_coin.vhd | 105 +++ cts/source/cts_trg_input.vhd | 109 +++ cts/source/cts_trg_pseudorand_pulser.vhd | 74 ++ cts/source/cts_trigger.vhd | 558 ++++++++++++++ 7 files changed, 2076 insertions(+) create mode 100755 cts/source/cts.vhd create mode 100755 cts/source/cts_fifo.vhd create mode 100755 cts/source/cts_pkg.vhd create mode 100755 cts/source/cts_trg_coin.vhd create mode 100755 cts/source/cts_trg_input.vhd create mode 100755 cts/source/cts_trg_pseudorand_pulser.vhd create mode 100755 cts/source/cts_trigger.vhd diff --git a/cts/source/cts.vhd b/cts/source/cts.vhd new file mode 100755 index 0000000..a805160 --- /dev/null +++ b/cts/source/cts.vhd @@ -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 +-- +-- 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 +-- + +-- Header of data packet written to event builder +-- Bit Description +-- +-- 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" +-- + +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 index 0000000..d0282b9 --- /dev/null +++ b/cts/source/cts_fifo.vhd @@ -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 index 0000000..dcaffa9 --- /dev/null +++ b/cts/source/cts_pkg.vhd @@ -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 +-- +-- 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 +-- + 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 index 0000000..4fbe27f --- /dev/null +++ b/cts/source/cts_trg_coin.vhd @@ -0,0 +1,105 @@ +-- Coincidence detection + +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + +-- COIN Register +-- Bit Description +-- +-- 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) +-- +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 index 0000000..14b080a --- /dev/null +++ b/cts/source/cts_trg_input.vhd @@ -0,0 +1,109 @@ +-- CTS_TRG_INPUT +-- INPUT -> INVERTER -> DELAY -> SPIKE REJECTION -> OVERRIDE -> OUTPUT + +-- Configuration +-- Bit Description +-- +-- 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 +-- + +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 index 0000000..4fd7e29 --- /dev/null +++ b/cts/source/cts_trg_pseudorand_pulser.vhd @@ -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 index 0000000..a255a9f --- /dev/null +++ b/cts/source/cts_trigger.vhd @@ -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 -- 2.43.0