use work.trb_net_std.all;
use work.trb_net_components.all;
-
entity handler_lvl1 is
- generic(
- TIMING_TRIGGER_RAW : integer range 0 to 1 := c_YES
- );
- port (
- RESET : in std_logic;
- CLOCK : in std_logic;
- --Timing Trigger
- LVL1_TIMING_TRG_IN : in std_logic; --raw trigger signal input, min. 80 ns or strobe, see generics
- LVL1_PSEUDO_TMG_TRG_IN : in std_logic; --strobe for dummy timing trigger
- --LVL1_handler connection
- LVL1_TRG_RECEIVED_IN : in std_logic;
- LVL1_TRG_TYPE_IN : in std_logic_vector(3 downto 0);
- LVL1_TRG_NUMBER_IN : in std_logic_vector(15 downto 0);
- LVL1_TRG_CODE_IN : in std_logic_vector(7 downto 0);
- LVL1_TRG_INFORMATION_IN : in std_logic_vector(23 downto 0);
- LVL1_ERROR_PATTERN_OUT : out std_logic_vector(31 downto 0); --errorbits to CTS
- LVL1_TRG_RELEASE_OUT : out std_logic := '0'; --release to CTS
-
- LVL1_INT_TRG_NUMBER_OUT : out std_logic_vector(15 downto 0); --increased after trigger release
-
- --FEE logic / Data Handler
- LVL1_TRG_DATA_VALID_OUT : out std_logic; --trigger type, number, code, information are valid
- LVL1_VALID_TIMING_TRG_OUT : out std_logic; --valid timing trigger has been received
- LVL1_VALID_NOTIMING_TRG_OUT : out std_logic; --valid trigger without timing trigger has been received
- LVL1_INVALID_TRG_OUT : out std_logic; --the current trigger is invalid (e.g. no timing trigger, no LVL1...)
-
- LVL1_ERROR_PATTERN_IN : in std_logic_vector(31 downto 0); -- error pattern from FEE
- LVL1_TRG_RELEASE_IN : in std_logic := '0'; -- trigger release from FEE
-
- --Stat/Control
- STATUS_OUT : out std_logic_vector (31 downto 0); --bits for status registers
- TRG_ENABLE_IN : in std_logic; --trigger enable flag
- --Debug
- DEBUG_OUT : out std_logic_vector (15 downto 0)
- );
+generic(
+ TIMING_TRIGGER_RAW : integer range 0 to 1 := c_YES
+);
+port(
+ RESET : in std_logic;
+ CLOCK : in std_logic;
+ --Timing Trigger
+ LVL1_TIMING_TRG_IN : in std_logic; --raw trigger signal input, min. 80 ns or strobe, see generics
+ LVL1_PSEUDO_TMG_TRG_IN : in std_logic; --strobe for dummy timing trigger
+ --LVL1_handler connection
+ LVL1_TRG_RECEIVED_IN : in std_logic;
+ LVL1_TRG_TYPE_IN : in std_logic_vector(3 downto 0);
+ LVL1_TRG_NUMBER_IN : in std_logic_vector(15 downto 0);
+ LVL1_TRG_CODE_IN : in std_logic_vector(7 downto 0);
+ LVL1_TRG_INFORMATION_IN : in std_logic_vector(23 downto 0);
+ LVL1_ERROR_PATTERN_OUT : out std_logic_vector(31 downto 0); --errorbits to CTS
+ LVL1_TRG_RELEASE_OUT : out std_logic := '0'; --release to CTS
+
+ LVL1_INT_TRG_NUMBER_OUT : out std_logic_vector(15 downto 0); -- increased after trigger release
+ LVL1_INT_TRG_RESET_IN : in std_logic; -- reset internal trigger counter
+ LVL1_INT_TRG_LOAD_IN : in std_logic; -- load internal trigger counter
+ LVL1_INT_TRG_COUNTER_IN : in std_logic_vector(15 downto 0); -- load value for internal trigger counter
+
+ --FEE logic / Data Handler
+ LVL1_TRG_DATA_VALID_OUT : out std_logic; --trigger type, number, code, information are valid
+ LVL1_VALID_TIMING_TRG_OUT : out std_logic; --valid timing trigger has been received
+ LVL1_VALID_NOTIMING_TRG_OUT : out std_logic; --valid trigger without timing trigger has been received
+ LVL1_INVALID_TRG_OUT : out std_logic; --the current trigger is invalid (e.g. no timing trigger, no LVL1...)
+
+ LVL1_ERROR_PATTERN_IN : in std_logic_vector(31 downto 0); -- error pattern from FEE
+ LVL1_TRG_RELEASE_IN : in std_logic := '0'; -- trigger release from FEE
+
+ --Stat/Control
+ STATUS_OUT : out std_logic_vector (31 downto 0); -- bits for status registers
+ TRG_ENABLE_IN : in std_logic; -- trigger enable flag
+ TRG_INVERT_IN : in std_logic; -- trigger invert flag
+ --Debug
+ DEBUG_OUT : out std_logic_vector (15 downto 0)
+);
end entity;
architecture handler_lvl1_arch of handler_lvl1 is
+-- Components
+component pulse_stretch is
+port(
+ CLK_IN : in std_logic;
+ RESET_IN : in std_logic;
+ START_IN : in std_logic;
+ PULSE_OUT : out std_logic;
+ DEBUG_OUT : out std_logic_vector(15 downto 0)
+);
+end component pulse_stretch;
+
+-- state machine signals
+type STATES is (IDLE, BADTRG, TRGFND, LVL1FND, WAITREL, TOCFND, RELEASE, DONE);
+signal CURRENT_STATE, NEXT_STATE: STATES;
+
+signal toc_ce : std_logic;
+signal next_toc_ce : std_logic;
+signal toc_rst : std_logic;
+signal next_toc_rst : std_logic;
+signal bsm_x : std_logic_vector(3 downto 0);
+
+-- Signals
+signal lvl1_int_trg_number : unsigned(15 downto 0);
+signal lvl1_int_trg_ce : std_logic;
+signal stretched_fake_trg : std_logic;
+signal synced_timing_trg : std_logic;
+signal timing_trg_reg : std_logic_vector(3 downto 0);
+signal timing_trg_comb : std_logic;
+signal timing_trg_rising : std_logic;
+signal timing_trg_found : std_logic;
+signal timeout_ctr : unsigned(8 downto 0);
+signal timeout_found : std_logic;
+signal next_timeout_found : std_logic;
+
+signal debug : std_logic_vector(15 downto 0);
+
+begin
+
+---------------------------------------------------------------------------
+-- Debug signals
+---------------------------------------------------------------------------
+debug(15 downto 4) <= (others => '0');
+debug(3 downto 0) <= bsm_x; -- state bits
+
+DEBUG_OUT <= debug;
+
+---------------------------------------------------------------------------
+-- fake timing trigger has only 10ns length!
+---------------------------------------------------------------------------
+THE_PULSE_STRETCH: pulse_stretch
+port map(
+ CLK_IN => CLOCK,
+ RESET_IN => RESET,
+ START_IN => LVL1_PSEUDO_TMG_TRG_IN,
+ PULSE_OUT => stretched_fake_trg,
+ DEBUG_OUT => open
+);
+
+---------------------------------------------------------------------------
+-- Sync the external timing trigger, if necessary.
+---------------------------------------------------------------------------
+GEN_SYNC: if ( TIMING_TRIGGER_RAW = 1 ) generate
+ THE_TIMING_TRG_SYNC: signal_sync
+ generic map( WIDTH => 1, DEPTH => 2 )
+ port map(
+ RESET => RESET,
+ CLK0 => CLOCK,
+ CLK1 => CLOCK,
+ D_IN(0) => LVL1_TIMING_TRG_IN,
+ D_OUT(0) => synced_timing_trg
+ );
+end generate GEN_SYNC;
+
+GEN_NOSYNC: if ( TIMING_TRIGGER_RAW = 0 ) generate
+ synced_timing_trg <= LVL1_TIMING_TRG_IN;
+end generate GEN_NOSYNC;
+
+---------------------------------------------------------------------------
+-- Combine both trigger sources, check length, find edges
+---------------------------------------------------------------------------
+timing_trg_comb <= ((synced_timing_trg xor TRG_INVERT_IN) and TRG_ENABLE_IN) or stretched_fake_trg;
+
+THE_TRIGGER_SHIFT_PROC: process( CLOCK )
+begin
+ if( rising_edge(CLOCK) ) then
+ if( RESET = '1' ) then
+ timing_trg_reg <= (others => '0');
+ else
+ timing_trg_reg <= timing_trg_reg(2 downto 0) & timing_trg_comb; -- could be generalized here
+ end if;
+ end if;
+end process THE_TRIGGER_SHIFT_PROC;
+
+-- detect rising edge and valid length
+THE_RISING_EDGE_PROC: process( CLOCK )
+begin
+ if( rising_edge(CLOCK) ) then
+ if( RESET = '1' ) then
+ timing_trg_rising <= '0';
+ else
+ -- 0111 sequence marks the rising edge
+ timing_trg_rising <= not timing_trg_reg(3) and timing_trg_reg(2) and timing_trg_reg(1) and timing_trg_reg(0);
+ end if;
+ end if;
+end process THE_RISING_EDGE_PROC;
+
+-- latch the result for state machine
+-- BUG: reset missing!
+THE_LATCH_PROC: process( CLOCK )
begin
+ if( rising_edge(CLOCK) ) then
+ if ( RESET = '1' ) then
+ timing_trg_found <= '0';
+ elsif( timing_trg_rising = '1' ) then
+ timing_trg_found <= '1';
+ end if;
+ end if;
+end process THE_LATCH_PROC;
+
+LVL1_VALID_TIMING_TRG_OUT <= timing_trg_rising; -- BUG
+
+LVL1_VALID_NOTIMING_TRG_OUT <= timing_trg_comb; -- BUG
+
+---------------------------------------------------------------------------
+-- Timeout counter for LVL1
+---------------------------------------------------------------------------
+THE_TIMEOUT_CTR_PROC: process( CLOCK )
+begin
+ if( rising_edge(CLOCK) ) then
+ if ( (RESET = '1') or (toc_rst = '1') ) then
+ timeout_ctr <= (others => '0');
+ elsif( (toc_ce = '1') and (timeout_found = '0') ) then
+ timeout_ctr <= timeout_ctr + 1;
+ end if;
+ end if;
+end process THE_TIMEOUT_CTR_PROC;
+
+-- 5.12us maximum
+next_timeout_found <= '1' when ( timeout_ctr = b"1_1111_1111" ) else '0';
+
+THE_SYNC_PROC: process( CLOCK )
+begin
+ if( rising_edge(CLOCK) ) then
+ timeout_found <= next_timeout_found;
+ end if;
+end process THE_SYNC_PROC;
+
+---------------------------------------------------------------------------
+-- State machine
+---------------------------------------------------------------------------
+-- state registers
+STATE_MEM: process( CLOCK )
+begin
+ if( rising_edge(CLOCK) ) then
+ if( RESET = '1' ) then
+ CURRENT_STATE <= IDLE;
+ toc_ce <= '0';
+ toc_rst <= '1';
+ else
+ CURRENT_STATE <= NEXT_STATE;
+ toc_ce <= next_toc_ce;
+ toc_rst <= next_toc_rst;
+ end if;
+ end if;
+end process STATE_MEM;
+
+-- state transitions
+STATE_TRANSFORM: process( CURRENT_STATE, LVL1_TRG_RECEIVED_IN, LVL1_TRG_TYPE_IN(3), LVL1_TRG_INFORMATION_IN(7),
+ LVL1_TRG_RELEASE_IN, timing_trg_found, timeout_found )
+begin
+ NEXT_STATE <= IDLE; -- avoid latches
+ next_toc_ce <= '0';
+ next_toc_rst <= '0';
+ case CURRENT_STATE is
+ when IDLE => bsm_x <= x"0";
+ if ( (timing_trg_found = '1') ) then
+ -- timing trigger has a rising edge and valid length
+ NEXT_STATE <= TRGFND;
+ next_toc_rst <= '1';
+ elsif( (timing_trg_found = '0') and (LVL1_TRG_RECEIVED_IN = '1') and
+ (LVL1_TRG_TYPE_IN(3) = '1') and (LVL1_TRG_INFORMATION_IN(7) = '1')) then
+ -- timingtriggerless trigger found
+ NEXT_STATE <= LVL1FND;
+ elsif( (timing_trg_found = '0') and (LVL1_TRG_RECEIVED_IN = '1') and
+ ((LVL1_TRG_TYPE_IN(3) = '0') or (LVL1_TRG_INFORMATION_IN(7) = '0')) ) then
+ -- missing timing trigger
+ NEXT_STATE <= BADTRG;
+ else
+ NEXT_STATE <= IDLE;
+ end if;
+ when TRGFND => bsm_x <= x"1";
+ if ( LVL1_TRG_RECEIVED_IN = '1' ) then
+ -- suitable LVL1 information has arrived
+ NEXT_STATE <= WAITREL;
+ next_toc_rst <= '1';
+ elsif( timeout_found = '1' ) then
+ -- LVL1 did not arrive in time
+ NEXT_STATE <= TOCFND;
+ next_toc_rst <= '1';
+ else
+ -- wait for either timeout or LVL1
+ NEXT_STATE <= TRGFND;
+ next_toc_ce <= '1';
+ end if;
+ when TOCFND => bsm_x <= x"2";
+ NEXT_STATE <= IDLE;
+ when WAITREL => bsm_x <= x"3";
+ if( LVL1_TRG_RELEASE_IN = '1' ) then
+ -- FEE logic releases trigger
+ NEXT_STATE <= DONE;
+ else
+ -- FEE logic still busy
+ NEXT_STATE <= WAITREL;
+ end if;
+ when BADTRG => bsm_x <= x"4";
+ NEXT_STATE <= RELEASE;
+ when RELEASE => bsm_x <= x"5";
+ NEXT_STATE <= DONE;
+ when DONE => bsm_x <= x"6";
+ if( LVL1_TRG_RECEIVED_IN = '0' ) then
+ NEXT_STATE <= IDLE;
+ else
+ NEXT_STATE <= DONE;
+ end if;
+ when others => bsm_x <= x"f";
+ NEXT_STATE <= IDLE;
+ end case;
+end process STATE_TRANSFORM;
+
+--type STATES is (IDLE, BADTRG, TRGFND, LVL1FND, WAITREL, TOCFND, DONE);
+
+
+---------------------------------------------------------------------------
+-- Internal trigger counter
+---------------------------------------------------------------------------
+THE_INTERNAL_TRG_CTR_PROC: process( CLOCK )
+begin
+ if( rising_edge(CLOCK) ) then
+ if ( (RESET = '1') or (LVL1_INT_TRG_RESET_IN = '1') ) then
+ lvl1_int_trg_number <= (others => '0');
+ elsif( LVL1_INT_TRG_LOAD_IN = '1' ) then
+ lvl1_int_trg_number <= unsigned(LVL1_INT_TRG_COUNTER_IN);
+ elsif( lvl1_int_trg_ce = '1' ) then
+ lvl1_int_trg_number <= lvl1_int_trg_number + 1;
+ end if;
+ end if;
+end process THE_INTERNAL_TRG_CTR_PROC;
+
+lvl1_int_trg_ce <= '0';
+
+LVL1_INT_TRG_NUMBER_OUT <= std_logic_vector(lvl1_int_trg_number);
+
+
+---------------------------------------------------------------------------
+---------------------------------------------------------------------------
+---------------------------------------------------------------------------
+---------------------------------------------------------------------------
--This code is copied from endpoint_hades_full
-- -------------------------------------------------