]> jspc29.x-matter.uni-frankfurt.de Git - trb3.git/commitdiff
scaler update
authorLudwig Maier <lmaier@brett.e12.ph.tum.de>
Sun, 16 Aug 2015 20:51:53 +0000 (22:51 +0200)
committerLudwig Maier <lmaier@brett.e12.ph.tum.de>
Sun, 16 Aug 2015 20:51:53 +0000 (22:51 +0200)
scaler/source/latch_handler.vhd [new file with mode: 0644]
scaler/source/scaler_channel.vhd [new file with mode: 0644]
scaler/source/trigger_handler.vhd [new file with mode: 0644]

diff --git a/scaler/source/latch_handler.vhd b/scaler/source/latch_handler.vhd
new file mode 100644 (file)
index 0000000..9c9cd13
--- /dev/null
@@ -0,0 +1,298 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+use work.scaler_components.all;
+
+entity latch_handler is
+  port (
+    CLK_IN                     : in  std_logic;
+    RESET_IN                   : in  std_logic;
+    CLK_D1_IN                  : in  std_logic;
+    RESET_D1_IN                : in  std_logic;  -- Rest CLK_D1 Domain
+        
+    --Inputs 
+    RESET_CTR_IN               : in std_logic;
+    LATCH_TRIGGER_IN           : in std_logic; -- The raw Timing Trigger Signal
+    LATCH_EXTERN_IN            : in std_logic; -- The raw Latch Signal
+    
+    -- Outputs
+    RESET_CTR_OUT              : out std_logic;
+    LATCH_OUT                  : out std_logic;
+    LATCH_VALID_OUT            : out std_logic;
+    LATCH_INVALID_OUT          : out std_logic;
+    
+    -- Slave bus               
+    SLV_READ_IN                : in  std_logic;
+    SLV_WRITE_IN               : in  std_logic;
+    SLV_DATA_OUT               : out std_logic_vector(31 downto 0);
+    SLV_DATA_IN                : in  std_logic_vector(31 downto 0);
+    SLV_ADDR_IN                : in  std_logic_vector(15 downto 0);
+    SLV_ACK_OUT                : out std_logic;
+    SLV_NO_MORE_DATA_OUT       : out std_logic;
+    SLV_UNKNOWN_ADDR_OUT       : out std_logic;
+    
+    -- Debug Line              
+    DEBUG_OUT                  : out std_logic_vector(15 downto 0)
+    );
+end entity;
+
+architecture Behavioral of latch_handler is
+  
+  -- Reset Counters
+  signal reset_d1_ff                 : std_logic_vector(1 downto 0);
+  signal RESET_D1                    : std_logic;
+
+  signal reset_ctr_ff                : std_logic_vector(2 downto 0);
+  signal reset_ctr_o                 : std_logic;
+
+  -- Latch Handler
+  signal latch_select_ff             :  std_logic_vector(1 downto 0);
+  signal latch_ff                    : std_logic_vector(2 downto 0);
+  
+  signal latch_i                     : std_logic;
+  signal latch                       : std_logic;
+  signal latch_o                     : std_logic;
+  signal latch_valid_o               : std_logic;
+  signal latch_invalid_o             : std_logic;
+  
+--  -- Latch Handler
+--  type LH_STATES is (LH_IDLE,
+--                     LH_VALIDATE,
+--                     LH_WAIT
+--                     );
+--  signal LH_STATE : LH_STATES;
+--
+--  signal lh_wait_timer_reset         : std_logic;
+--  signal lh_wait_timer_start         : std_logic;
+--  signal lh_wait_timer_done          : std_logic;
+--  
+--  signal latch_validate_ctr          : unsigned(4 downto 0);
+--  
+--  signal latch_o                     : std_logic;
+--  signal latch_valid_o               : std_logic;
+--  signal latch_invalid_o             : std_logic;
+--     
+--  -- Rate Calculation
+--  signal accepted_trigger_rate_t     : unsigned(27 downto 0);
+--  signal rate_timer                  : unsigned(27 downto 0);
+  
+  -- TRBNet Slave Bus                
+  signal slv_data_out_o              : std_logic_vector(31 downto 0);
+  signal slv_no_more_data_o          : std_logic;
+  signal slv_unknown_addr_o          : std_logic;
+  signal slv_ack_o                   : std_logic;
+
+  signal latch_select_r              : std_logic;
+
+  -----------------------------------------------------------------------------
+  
+  attribute syn_keep : boolean;
+  attribute syn_keep of latch_select_ff : signal is true;
+  attribute syn_keep of latch_ff        : signal is true;
+  attribute syn_keep of reset_ctr_ff    : signal is true;
+
+  attribute syn_preserve : boolean;
+  attribute syn_preserve of latch_select_ff : signal is true;
+  attribute syn_preserve of latch_ff        : signal is true;
+  attribute syn_preserve of reset_ctr_ff    : signal is true;
+
+  -----------------------------------------------------------------------------
+
+begin
+
+  -- Debug Line
+  DEBUG_OUT(0)            <= CLK_IN;
+  DEBUG_OUT(1)            <= LATCH_TRIGGER_IN;
+
+  DEBUG_OUT(2)            <= latch_i;
+  DEBUG_OUT(3)            <= latch_ff(2);
+  DEBUG_OUT(4)            <= latch_ff(1);
+  DEBUG_OUT(5)            <= latch_ff(0);
+  DEBUG_OUT(6)            <= latch_o;
+
+  DEBUG_OUT(7)            <= RESET_CTR_IN;
+  DEBUG_OUT(8)            <= reset_ctr_ff(2);
+  DEBUG_OUT(9)            <= reset_ctr_ff(1);
+  DEBUG_OUT(10)           <= reset_ctr_ff(0);
+  DEBUG_OUT(11)           <= reset_ctr_o;
+  
+
+  DEBUG_OUT(15 downto 12)  <= (others => '0');
+
+  -----------------------------------------------------------------------------
+  -- Reset Counter Sync
+  -----------------------------------------------------------------------------
+  reset_d1_ff(1)  <= RESET_D1_IN     when rising_edge(CLK_D1_IN);
+  reset_d1_ff(0)  <= reset_d1_ff(1)  when rising_edge(CLK_D1_IN);
+  RESET_D1        <= reset_d1_ff(0)  when rising_edge(CLK_D1_IN);
+  
+  reset_ctr_ff(2) <= RESET_CTR_IN    when rising_edge(CLK_D1_IN);
+  reset_ctr_ff(1) <= reset_ctr_ff(2) when rising_edge(CLK_D1_IN);
+  reset_ctr_ff(0) <= reset_ctr_ff(1) when rising_edge(CLK_D1_IN);
+  reset_ctr_o     <= reset_ctr_ff(0) when rising_edge(CLK_D1_IN);
+  
+  -----------------------------------------------------------------------------
+  -- Latch Handler
+  -----------------------------------------------------------------------------
+
+  latch_select_ff(1) <= latch_select_r     when rising_edge(CLK_D1_IN);
+  latch_select_ff(0) <= latch_select_ff(1) when rising_edge(CLK_D1_IN);
+
+  PROC_LATCH_MULTIPLEXER: process(latch_select_ff(0),
+                                  LATCH_TRIGGER_IN,
+                                  LATCH_EXTERN_IN)
+  begin
+    if (latch_select_ff(0) = '0') then
+      latch_i    <= LATCH_TRIGGER_IN;
+    else
+      latch_i    <= LATCH_EXTERN_IN;
+    end if;     
+  end process PROC_LATCH_MULTIPLEXER;
+  
+  latch_ff(2) <= latch_i     when rising_edge(CLK_D1_IN);
+  latch_ff(1) <= latch_ff(2) when rising_edge(CLK_D1_IN);
+  latch_ff(0) <= latch_ff(1) when rising_edge(CLK_D1_IN);
+
+  latch       <= '1' when latch_ff(1 downto 0) = "10" else '0'; 
+
+  latch_o          <= latch;
+  latch_valid_o    <= latch;
+  latch_invalid_o  <= '0';
+  
+--   -- Timer
+--   lh_timer_static: timer_static
+--     generic map (
+--       CTR_WIDTH => 8,
+--       CTR_END   => 32   -- 128ns
+--       )
+--     port map (
+--       CLK_IN         => CLK_D1_IN,
+--       RESET_IN       => lh_wait_timer_reset,
+--       TIMER_START_IN => lh_wait_timer_start,
+--       TIMER_DONE_OUT => lh_wait_timer_done
+--       );
+--   
+--   PROC_LATCH_HANDLER: process(CLK_D1_IN)
+--   begin
+--     if( rising_edge(CLK_D1_IN) ) then
+--       if (RESET_D1 = '1') then
+--         latch_validate_ctr  <= (others => '0');
+--         latch_o             <= '0';
+--         latch_valid_o       <= '0';
+--         latch_invalid_o     <= '0';
+-- 
+--         lh_wait_timer_start <= '0';
+--         lh_wait_timer_reset <= '1';
+--         
+--         LH_STATE            <= LH_IDLE;
+--       else
+--         lh_wait_timer_start <= '0';
+--         lh_wait_timer_reset <= '0';
+-- 
+--         latch_o             <= '0';
+--         latch_valid_o       <= '0';
+--         latch_invalid_o     <= '0';
+-- 
+--         case LH_STATE is
+--           when  LH_IDLE =>
+--             if (latch = '1') then
+--               latch_validate_ctr  <= (others => '0');
+--               latch_o             <= '1';
+--               LH_STATE            <= LH_VALIDATE;
+--             end if;
+--             LH_STATE              <= LH_IDLE;
+--             
+--           when LH_VALIDATE =>
+--             if (latch_validate_ctr < x"a") then
+--               if (latch = '1') then
+--                 latch_validate_ctr  <= latch_validate_ctr + 1;
+--                 LH_STATE            <= LH_VALIDATE;
+--               else
+--                 latch_invalid_o     <= '1';
+--                 lh_wait_timer_start <= '1';
+--                 LH_STATE            <= LH_WAIT;
+--               end if;
+--             else
+--               latch_valid_o         <= '1';
+--               lh_wait_timer_start   <= '1';
+--               LH_STATE              <= LH_WAIT;
+--             end if;
+-- 
+--           when LH_WAIT =>
+--             if (lh_wait_timer_done = '1') then
+--               LH_STATE              <= LH_IDLE;
+--             else
+--               LH_STATE              <= LH_WAIT;
+--             end if;
+--         end case;
+-- 
+--       end if;
+--     end if;
+--   end process PROC_LATCH_HANDLER;
+
+ ---------------------------------------------------------------------------
+ -- TRBNet Slave Bus
+ ---------------------------------------------------------------------------
+ PROC_SLAVE_BUS: process(CLK_IN)
+ begin
+   if( rising_edge(CLK_IN) ) then
+     if( RESET_IN = '1' ) then
+       slv_data_out_o                 <= (others => '0');
+       slv_no_more_data_o             <= '0';
+       slv_unknown_addr_o             <= '0';
+       slv_ack_o                      <= '0';
+       latch_select_r                 <= '0';
+     else                             
+       slv_unknown_addr_o             <= '0';
+       slv_no_more_data_o             <= '0';
+       slv_data_out_o                 <= (others => '0');
+       slv_ack_o                      <= '0';
+       if (SLV_WRITE_IN  = '1') then
+         case SLV_ADDR_IN is
+           when x"0000" =>
+             latch_select_r               <= SLV_DATA_IN(0); 
+             slv_ack_o                    <= '1';
+            
+           when others =>
+             slv_unknown_addr_o           <= '1';
+         end case;
+       elsif (SLV_READ_IN = '1') then
+         case SLV_ADDR_IN is
+           when x"0000" =>
+             slv_data_out_o(0)            <= latch_select_r;
+             slv_data_out_o(31 downto 1)  <= (others => '0');
+             
+             slv_ack_o                    <= '1';
+
+           when others =>
+             slv_unknown_addr_o           <= '1';
+         end case;
+       end if;
+     end if;
+   end if;           
+ end process PROC_SLAVE_BUS;
+
+-----------------------------------------------------------------------------
+-- Output Signals
+-----------------------------------------------------------------------------
+
+  RESET_CTR_OUT             <= reset_ctr_o;
+  LATCH_OUT                 <= latch_o;
+  LATCH_VALID_OUT           <= latch_valid_o;
+  LATCH_INVALID_OUT         <= latch_invalid_o;
+
+  -- Slave Bus              
+  SLV_DATA_OUT              <= slv_data_out_o;    
+  SLV_NO_MORE_DATA_OUT      <= slv_no_more_data_o; 
+  SLV_UNKNOWN_ADDR_OUT      <= slv_unknown_addr_o;
+  SLV_ACK_OUT               <= slv_ack_o;    
+
+end Behavioral;
diff --git a/scaler/source/scaler_channel.vhd b/scaler/source/scaler_channel.vhd
new file mode 100644 (file)
index 0000000..a758ac3
--- /dev/null
@@ -0,0 +1,329 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+use work.scaler_components.all;
+
+entity scaler_channel is
+  port(
+    CLK_IN                 : in  std_logic;
+    RESET_IN               : in  std_logic;
+    CLK_D1_IN              : in  std_logic;
+    RESET_D1_IN            : in  std_logic;
+    
+    -- Scaler Inputs
+    RESET_CTR_IN           : in  std_logic;
+    LATCH_IN               : in  std_logic;
+    PULSE_IN               : in  std_logic;
+    INHIBIT_IN             : in  std_logic;
+    
+    -- Slave bus           
+    SLV_READ_IN            : in  std_logic;
+    SLV_WRITE_IN           : in  std_logic;
+    SLV_DATA_OUT           : out std_logic_vector(31 downto 0);
+    SLV_DATA_IN            : in  std_logic_vector(31 downto 0);
+    SLV_ADDR_IN            : in  std_logic_vector(15 downto 0);
+    SLV_ACK_OUT            : out std_logic;
+    SLV_NO_MORE_DATA_OUT   : out std_logic;
+    SLV_UNKNOWN_ADDR_OUT   : out std_logic;
+    
+    DEBUG_OUT              : out std_logic_vector(15 downto 0)
+    );
+end entity;
+
+architecture Behavioral of scaler_channel is
+
+  -- Sync Inputs
+  signal reset_d1_ff                 : std_logic_vector(1 downto 0);
+  signal RESET_D1                    : std_logic;
+
+  signal reset_ctr_ff                : std_logic_vector(1 downto 0);
+  signal RESET_CTR                   : std_logic;
+  
+  signal pulse_ff                    : std_logic_vector(2 downto 0);
+  signal pulse_l                     : std_logic;     
+  signal pulse_i                     : std_logic;
+  signal latch_d1                    : std_logic;
+  
+  -- Scaler CLK_SCALER Domain 
+  signal inhibit                     : std_logic;
+
+  signal johnson                     : std_logic_vector(3 downto 0);
+
+  signal counter_low_d1                 : std_logic_vector(2 downto 0);
+  signal counter_low_ovfl_d1         : std_logic;
+  
+  signal counter_latched             : std_logic_vector(47 downto 0);
+
+  -- Counter Clock Domain Transfer
+  signal fifo_reset_i                : std_logic;
+  signal fifo_write_enable           : std_logic;
+  signal fifo_read_enable            : std_logic;
+  signal fifo_empty                  : std_logic;
+  signal fifo_full                   : std_logic;
+  signal fifo_data_clk_t             : std_logic;
+  signal fifo_data_clk               : std_logic;
+  signal fifo_data                   : std_logic_vector(5 downto 0);
+  
+  signal counter_low                 : std_logic_vector(2 downto 0);
+  signal counter_low_ovfl            : std_logic;
+  signal latch                       : std_logic;
+
+  signal counter_high                : unsigned(44 downto 0);
+  
+  signal data_clk                    : std_logic;
+  signal data_reg                    : std_logic_vector(47 downto 0);
+
+  -- Slave Bus
+  signal slv_data_out_o              : std_logic_vector(31 downto 0);
+  signal slv_no_more_data_o          : std_logic;
+  signal slv_unknown_addr_o          : std_logic;
+  signal slv_ack_o                   : std_logic;
+  signal counter_latched_offset      : std_logic_vector(15 downto 0);
+
+  -----------------------------------------------------------------------------
+  
+  attribute syn_keep : boolean;
+  attribute syn_keep of pulse_ff       : signal is true;
+
+  attribute syn_preserve : boolean;
+  attribute syn_preserve of pulse_ff   : signal is true;
+
+  -----------------------------------------------------------------------------
+  
+begin
+
+  ----------------------------------------------------------------------
+  -- DEBUG
+  ----------------------------------------------------------------------
+  DEBUG_OUT(0)            <= CLK_IN;
+  DEBUG_OUT(1)            <= pulse_i; --LATCH_IN; --data_clk;
+  DEBUG_OUT(2)            <= fifo_data_clk;
+  DEBUG_OUT(3)            <= counter_low_ovfl;
+  DEBUG_OUT(4)            <= latch;
+  DEBUG_OUT(5)            <= data_clk;
+  DEBUG_OUT(15 downto 6)  <= counter_latched(9 downto 0);
+
+  -- Sync input signals to Scaler CLK_D1_IN Domain
+  reset_d1_ff(1)  <= RESET_D1_IN     when rising_edge(CLK_D1_IN);
+  reset_d1_ff(0)  <= reset_d1_ff(1)  when rising_edge(CLK_D1_IN);
+  RESET_D1        <= reset_d1_ff(0)  when rising_edge(CLK_D1_IN);
+
+  reset_ctr_ff(1) <= RESET_CTR_IN     when rising_edge(CLK_D1_IN);
+  reset_ctr_ff(0) <= reset_ctr_ff(1)  when rising_edge(CLK_D1_IN);
+  RESET_CTR       <= reset_ctr_ff(0)  when rising_edge(CLK_D1_IN);
+    
+  pulse_ff(2) <= PULSE_IN    when rising_edge(CLK_D1_IN);
+  pulse_ff(1) <= pulse_ff(2) when rising_edge(CLK_D1_IN);
+  pulse_ff(0) <= pulse_ff(1) when rising_edge(CLK_D1_IN);
+
+  pulse_i     <= '1' when pulse_ff(1 downto 0) = "10" else '0'; 
+  
+  -----------------------------------------------------------------------------
+  -- The Primary Counter
+  -----------------------------------------------------------------------------
+  
+  -- Johnson Counter for lower 3 Bits
+  PROC_LOWER_BIT_COUNTER: process(CLK_D1_IN)
+  begin
+    if (rising_edge(CLK_D1_IN)) then
+      if (RESET_D1 = '1' or RESET_CTR = '1') then
+        johnson                 <= (others => '0');
+        counter_low_ovfl_d1     <= '0';
+      else
+        counter_low_ovfl_d1     <= '0';
+        if (pulse_i = '1') then
+          johnson(0)            <= not johnson(3);
+          johnson(1)            <= johnson(0);
+          johnson(2)            <= johnson(1);
+          johnson(3)            <= johnson(2);
+          counter_low_ovfl_d1   <= '0';
+          
+          case johnson is
+            when "0000" => counter_low_d1         <= "001";
+            when "0001" => counter_low_d1         <= "010";
+            when "0011" => counter_low_d1         <= "011";
+            when "0111" => counter_low_d1         <= "100";
+            when "1111" => counter_low_d1         <= "101";
+            when "1110" => counter_low_d1         <= "110";
+            when "1100" => counter_low_d1         <= "111";
+            when "1000" => counter_low_d1         <= "000";
+                           counter_low_ovfl_d1    <= '1';
+            when others => counter_low_d1         <= "000";
+          end case;
+        end if;
+      end if;
+    end if;
+  end process PROC_LOWER_BIT_COUNTER;
+
+  -----------------------------------------------------------------------------
+  -- Clock Domain Transfer in case of latch or overflow
+  -----------------------------------------------------------------------------
+
+  --latch_d1 <= LATCH_IN when rising_edge(CLK_D1_IN);
+  latch_d1 <= counter_low_ovfl_d1 when rising_edge(CLK_D1_IN);
+  
+  COUNTER_LOW_DOMAIN_TRANSFER_1: entity work.fifo_6to6_dc
+    port map (
+      Data(2 downto 0) => counter_low_d1,
+      Data(3)          => counter_low_ovfl_d1,
+      Data(4)          => latch_d1,
+      Data(5)          => RESET_CTR,
+      WrClock          => CLK_D1_IN,
+      RdClock          => CLK_IN,
+      WrEn             => fifo_write_enable,
+      RdEn             => fifo_read_enable,
+      Reset            => fifo_reset_i,
+      RPReset          => fifo_reset_i,
+      Q                => fifo_data,
+      Empty            => fifo_empty,
+      Full             => fifo_full
+      );
+  fifo_reset_i         <= RESET_IN;
+  fifo_write_enable    <= not fifo_full and (counter_low_ovfl_d1 or
+                                             latch_d1 or
+                                             RESET_CTR);
+  fifo_read_enable     <= not fifo_empty;
+
+  PROC_FIFO_READ_ENABLE: process(CLK_IN)
+  begin
+    if (rising_edge(CLK_IN)) then
+      fifo_data_clk_t      <= fifo_read_enable;
+      if (RESET_IN = '1') then
+        fifo_data_clk_t    <= '0';
+        fifo_data_clk      <= '0';
+      else
+        -- Delay read signal by two Clock Cycles
+        fifo_data_clk      <= fifo_data_clk_t;
+      end if;
+    end if;
+  end process PROC_FIFO_READ_ENABLE;
+
+  PROC_FIFO_OUTPUT_HANDLER: process(CLK_IN)
+  begin
+    if (rising_edge(CLK_IN)) then
+      if (RESET_IN = '1') then
+        counter_high         <= (others => '0');
+        counter_low          <= (others => '0');
+        counter_low_ovfl     <= '0';
+        latch                <= '0';
+      else
+        counter_low          <= (others => '0');
+        counter_low_ovfl     <= '0';
+        latch                <= '0';
+        
+        if (fifo_data_clk = '1') then
+          counter_low          <= (others => '0');
+          counter_low_ovfl     <= '0';
+          latch                <= '0';
+
+          -- High Bit Counter
+          if (fifo_data(5) = '1') then    -- in case of Reset Counters 
+            counter_high       <= (others => '0');
+          else
+            if (fifo_data(3) = '1') then  -- in case of overflow
+              counter_low      <= fifo_data(2 downto 0);
+              counter_low_ovfl <= fifo_data(3);
+              counter_high     <= counter_high + 1;
+            end if;
+          
+            if (fifo_data(4) = '1') then
+              latch             <= '1';
+            end if;
+          end if;
+        end if;
+      end if;
+    end if;
+  end process PROC_FIFO_OUTPUT_HANDLER;
+
+  PROC_LATCH: process(CLK_IN)
+  begin
+    if (rising_edge(CLK_IN)) then
+      if (RESET_IN = '1') then
+        counter_latched      <= (others => '0');
+        data_clk             <= '0';
+      else
+        data_clk             <= '0';
+        if (latch = '1') then
+          counter_latched(2 downto 0)   <= counter_low;
+          counter_latched(47 downto 3)  <= counter_high;
+          data_clk                      <= '1';
+        end if;
+      end if;
+    end if;
+  end process PROC_LATCH;
+  
+  -----------------------------------------------------------------------------
+  -- Slave Bus
+  -----------------------------------------------------------------------------
+
+  PROC_TRB3_REGISTERS: process(CLK_IN)
+  begin
+    if( rising_edge(CLK_IN) ) then
+      if( RESET_IN = '1' ) then
+        slv_data_out_o             <= (others => '0');
+        slv_no_more_data_o         <= '0';
+        slv_unknown_addr_o         <= '0';
+        slv_ack_o                  <= '0';
+        
+        counter_latched_offset     <= (others => '0');
+        data_reg                   <= (others => '0');
+      else
+        slv_unknown_addr_o         <= '0';
+        slv_no_more_data_o         <= '0';
+        slv_data_out_o             <= (others => '0');    
+       
+        if (data_clk = '1') then
+          data_reg                 <= counter_latched;
+        end if;
+        
+        if (SLV_WRITE_IN  = '1') then
+          case SLV_ADDR_IN is
+            when x"0000" =>
+              counter_latched_offset       <= SLV_DATA_IN(15 downto 0);
+              slv_ack_o                    <= '1';
+            
+            when others =>                
+              slv_unknown_addr_o           <= '1';
+              slv_ack_o                    <= '0';
+          end case;
+          
+        elsif (SLV_READ_IN = '1') then
+          case SLV_ADDR_IN is
+            when x"0000" =>
+              slv_data_out_o(15 downto 0)  <= counter_latched_offset;
+              slv_data_out_o(31 downto 16) <= (others => '0');
+              slv_ack_o                    <= '1';
+                   
+            when x"0001" =>
+              slv_data_out_o               <= data_reg(31 downto 0);
+              slv_ack_o                    <= '1';
+
+            when x"0002" =>
+              slv_data_out_o(15 downto 0)  <= data_reg(47 downto 32);
+              slv_data_out_o(31 downto 16) <= (others => '0');
+              slv_ack_o                    <= '1';
+              
+            when others =>
+              slv_unknown_addr_o           <= '1';
+              slv_ack_o                    <= '0';
+          end case;
+          
+        else
+          slv_ack_o                        <= '0';
+        end if;
+      end if;
+    end if;           
+  end process PROC_TRB3_REGISTERS;
+
+  ----------------------------------------------------------------------
+  -- Output Signals
+  ----------------------------------------------------------------------
+
+  SLV_DATA_OUT          <= slv_data_out_o;    
+  SLV_NO_MORE_DATA_OUT  <= slv_no_more_data_o; 
+  SLV_UNKNOWN_ADDR_OUT  <= slv_unknown_addr_o;
+  SLV_ACK_OUT           <= slv_ack_o;          
+  
+end Behavioral;
diff --git a/scaler/source/trigger_handler.vhd b/scaler/source/trigger_handler.vhd
new file mode 100644 (file)
index 0000000..15674ad
--- /dev/null
@@ -0,0 +1,776 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+use work.scaler_components.all;
+
+entity trigger_handler is
+  port (
+    CLK_IN                     : in  std_logic;
+    RESET_IN                   : in  std_logic;
+    CLK_D1_IN                  : in  std_logic;
+    RESET_D1_IN                : in  std_logic;  -- Rest CLK_D1 Domain
+    OFFLINE_IN                 : in  std_logic;
+    
+    --Input Triggers          
+    TIMING_TRIGGER_IN          : in std_logic; -- The raw timing Trigger Signal 
+    LVL1_TRG_DATA_VALID_IN     : in std_logic; -- Data Trigger is valid
+    LVL1_VALID_TIMING_TRG_IN   : in std_logic; -- Timin Trigger is valid
+    LVL1_VALID_NOTIMING_TRG_IN : in std_logic; -- calib trigger w/o ref time
+    LVL1_INVALID_TRG_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_INT_TRG_NUMBER_IN     : in std_logic_vector(15 downto 0);
+
+    --Response from FEE        
+    FEE_DATA_OUT               : out std_logic_vector(31 downto 0);
+    FEE_DATA_WRITE_OUT         : out std_logic;
+    FEE_DATA_FINISHED_OUT      : out std_logic;
+    FEE_TRG_RELEASE_OUT        : out std_logic;
+    FEE_TRG_STATUSBITS_OUT     : out std_logic_vector(31 downto 0);
+
+    FEE_DATA_0_IN              : in  std_logic_vector(31 downto 0);
+    FEE_DATA_WRITE_0_IN        : in  std_logic;
+    FEE_DATA_1_IN              : in  std_logic_vector(31 downto 0);
+    FEE_DATA_WRITE_1_IN        : in  std_logic;
+    
+    -- Internal FPGA Trigger
+    INTERNAL_TRIGGER_IN        : in  std_logic;
+
+    -- Trigger FeedBack
+    TRIGGER_VALIDATE_BUSY_IN   : in  std_logic;
+    TRIGGER_BUSY_0_IN          : in  std_logic;
+    TRIGGER_BUSY_1_IN          : in  std_logic;
+    
+    -- OUT
+    VALID_TRIGGER_OUT          : out std_logic;
+    TIMESTAMP_TRIGGER_OUT      : out std_logic;
+    TRIGGER_TIMING_OUT         : out std_logic;
+    TRIGGER_STATUS_OUT         : out std_logic;
+    TRIGGER_CALIBRATION_OUT    : out std_logic;
+    FAST_CLEAR_OUT             : out std_logic;
+    TRIGGER_BUSY_OUT           : out std_logic;
+
+    -- Pulser
+    TESTPULSE_OUT              : out std_logic;
+    
+    -- Slave bus               
+    SLV_READ_IN                : in  std_logic;
+    SLV_WRITE_IN               : in  std_logic;
+    SLV_DATA_OUT               : out std_logic_vector(31 downto 0);
+    SLV_DATA_IN                : in  std_logic_vector(31 downto 0);
+    SLV_ADDR_IN                : in  std_logic_vector(15 downto 0);
+    SLV_ACK_OUT                : out std_logic;
+    SLV_NO_MORE_DATA_OUT       : out std_logic;
+    SLV_UNKNOWN_ADDR_OUT       : out std_logic;
+
+    -- Debug Line              
+    DEBUG_OUT                  : out std_logic_vector(15 downto 0)
+    );
+end entity;
+
+architecture Behavioral of trigger_handler is
+
+  -- Timing Trigger Handler
+  constant NUM_FF                   : integer := 10;
+  signal timing_trigger_ff_p        : std_logic_vector(1 downto 0);
+  signal timing_trigger_ff          : std_logic_vector(NUM_FF - 1 downto 0);
+  signal timing_trigger_l           : std_logic;
+  signal timing_trigger             : std_logic;
+  signal timing_trigger_set         : std_logic;
+  signal timestamp_trigger_o        : std_logic;
+
+  signal invalid_timing_trigger_n   : std_logic;
+
+  signal invalid_timing_trigger_ff  : std_logic;
+  signal invalid_timing_trigger_f   : std_logic;
+  signal invalid_timing_trigger     : std_logic;
+  signal invalid_timing_trigger_ctr : unsigned(15 downto 0);
+
+  signal trigger_busy_ff            : std_logic;
+  signal trigger_busy_f             : std_logic;
+  signal trigger_busy               : std_logic;
+
+  signal fast_clear_ff              : std_logic;
+  signal fast_clear_f               : std_logic;
+  signal fast_clear                 : std_logic;
+  
+  type TS_STATES is (TS_IDLE,
+                     TS_WAIT_VALID_TIMING_TRIGGER,
+                     TS_INVALID_TRIGGER,
+                     TS_WAIT_TRIGGER_END
+                     );
+  signal TS_STATE : TS_STATES;
+
+  signal ts_wait_timer_reset        : std_logic;
+  signal ts_wait_timer_start        : std_logic;
+  signal ts_wait_timer_done         : std_logic;
+  
+  -- Trigger Handler                
+  signal valid_trigger_o            : std_logic;
+  signal timing_trigger_o           : std_logic;
+  signal status_trigger_o           : std_logic;
+  signal calibration_trigger_o      : std_logic;
+  signal calib_downscale_ctr        : unsigned(15 downto 0);
+  signal fast_clear_o               : std_logic;
+  signal trigger_busy_o             : std_logic;
+  signal fee_data_o                 : std_logic_vector(31 downto 0);
+  signal fee_data_write_o           : std_logic;
+  signal fee_data_finished_o        : std_logic;
+  signal fee_trg_release_o          : std_logic;
+  signal fee_trg_statusbits_o       : std_logic_vector(31 downto 0);
+
+  signal timestamp_calib_trigger_c100 : std_logic;
+  signal timestamp_calib_trigger_f    : std_logic;
+  signal timestamp_calib_trigger_o    : std_logic;
+  
+  type STATES is (S_IDLE,
+                  S_IGNORE_TRIGGER,
+                  S_STATUS_TRIGGER,
+                  S_TIMING_TRIGGER,
+                  S_CALIBRATION_TRIGGER,
+                  S_WAIT_TRG_DATA_VALID,
+                  S_WAIT_TIMING_TRIGGER_DONE,
+                  S_FEE_TRIGGER_RELEASE,
+                  S_WAIT_FEE_TRIGGER_RELEASE_ACK,
+                  S_INTERNAL_TRIGGER,
+                  S_WAIT_TRIGGER_VALIDATE_ACK,
+                  S_WAIT_TRIGGER_VALIDATE_DONE
+                  );
+  signal STATE : STATES;
+
+  type TRIGGER_TYPES is (T_UNDEF,
+                         T_IGNORE,
+                         T_TIMING,
+                         T_STATUS,
+                         T_CALIBRATION
+                         );
+  signal TRIGGER_TYPE : TRIGGER_TYPES;
+  
+  
+  -- Testpulse Handler
+  type T_STATES is (T_IDLE,
+                    T_WAIT_TESTPULE_DELAY,
+                    T_SET_TESTPULSE,
+                    T_WAIT_TESTPULE_END
+                    );
+  
+  signal T_STATE : T_STATES;
+  
+  signal internal_trigger_f          : std_logic;
+  signal internal_trigger            : std_logic;
+  
+  -- Rate Calculation
+  signal accepted_trigger_rate_t     : unsigned(27 downto 0);
+  signal rate_timer                  : unsigned(27 downto 0);
+  
+  -- TRBNet Slave Bus                
+  signal slv_data_out_o              : std_logic_vector(31 downto 0);
+  signal slv_no_more_data_o          : std_logic;
+  signal slv_unknown_addr_o          : std_logic;
+  signal slv_ack_o                   : std_logic;
+
+  signal accepted_trigger_rate       : unsigned(27 downto 0);
+  signal invalid_t_trigger_ctr_clear : std_logic;
+  signal bypass_all_trigger          : std_logic;
+  signal bypass_physics_trigger      : std_logic;
+  signal bypass_status_trigger       : std_logic;
+  signal bypass_calibration_trigger  : std_logic;
+  signal calibration_downscale       : unsigned(15 downto 0);
+  signal physics_trigger_type        : std_logic_vector(3 downto 0);
+  signal status_trigger_type         : std_logic_vector(3 downto 0);
+  signal calibration_trigger_type    : std_logic_vector(3 downto 0);
+  
+  attribute syn_keep : boolean;
+
+  attribute syn_keep of trigger_busy_ff             : signal is true;
+  attribute syn_keep of trigger_busy_f              : signal is true;
+
+  attribute syn_keep of fast_clear_ff               : signal is true;
+  attribute syn_keep of fast_clear_f                : signal is true;
+
+  attribute syn_keep of internal_trigger_f          : signal is true;
+  attribute syn_keep of internal_trigger            : signal is true;
+
+  attribute syn_keep of timestamp_calib_trigger_f   : signal is true;
+  attribute syn_keep of timestamp_calib_trigger_o   : signal is true;
+  
+  attribute syn_preserve : boolean;
+
+  attribute syn_preserve of trigger_busy_ff         : signal is true;
+  attribute syn_preserve of trigger_busy_f          : signal is true;
+  
+  attribute syn_preserve of fast_clear_ff           : signal is true;
+  attribute syn_preserve of fast_clear_f            : signal is true;
+
+  attribute syn_preserve of internal_trigger_f      : signal is true;
+  attribute syn_preserve of internal_trigger        : signal is true;
+
+  attribute syn_preserve of timestamp_calib_trigger_f  : signal is true;
+  attribute syn_preserve of timestamp_calib_trigger_o  : signal is true;
+  
+begin
+
+  -- Debug Line
+  DEBUG_OUT(0)            <= CLK_IN;
+  DEBUG_OUT(1)            <= TIMING_TRIGGER_IN;
+  DEBUG_OUT(2)            <= invalid_timing_trigger;
+  DEBUG_OUT(3)            <= LVL1_VALID_TIMING_TRG_IN;
+  DEBUG_OUT(4)            <= LVL1_TRG_DATA_VALID_IN;
+  DEBUG_OUT(5)            <= fee_data_write_o;
+  DEBUG_OUT(6)            <= TRIGGER_VALIDATE_BUSY_IN;
+  DEBUG_OUT(7)            <= TRIGGER_BUSY_0_IN;
+  DEBUG_OUT(8)            <= valid_trigger_o;
+  DEBUG_OUT(9)            <= timing_trigger_o;
+  DEBUG_OUT(10)           <= fee_data_finished_o;
+  DEBUG_OUT(11)           <= fee_trg_release_o;
+  DEBUG_OUT(12)           <= trigger_busy_o;
+  DEBUG_OUT(13)           <= timestamp_trigger_o;
+  DEBUG_OUT(14)           <= '0';
+  DEBUG_OUT(15)           <= '0';
+
+  -----------------------------------------------------------------------------
+  -- Trigger Handler
+  -----------------------------------------------------------------------------
+  
+  PROC_TIMING_TRIGGER_HANDLER: process(CLK_D1_IN)
+    constant pattern : std_logic_vector(NUM_FF - 1 downto 0)
+    := (others => '1');
+  begin
+    if( rising_edge(CLK_D1_IN) ) then
+      timing_trigger_ff_p(1)                   <= TIMING_TRIGGER_IN;
+      if (RESET_D1_IN = '1') then 
+        timing_trigger_ff_p(0)                 <= '0';
+        timing_trigger_ff(NUM_FF - 1 downto 0) <= (others => '0');
+        timing_trigger_l                       <= '0';
+      else
+        timing_trigger_ff_p(0)                 <= timing_trigger_ff_p(1);
+        timing_trigger_ff(NUM_FF - 1)          <= timing_trigger_ff_p(0);
+        
+        for I in NUM_FF - 2 downto 0 loop
+          timing_trigger_ff(I)                 <= timing_trigger_ff(I + 1);    
+        end loop;
+        
+        if (timing_trigger_ff = pattern) then
+          timing_trigger_l                     <= '1';
+        else
+          timing_trigger_l                     <= '0';
+        end if;
+      end if;   
+    end if;
+  end process PROC_TIMING_TRIGGER_HANDLER;
+
+  level_to_pulse_1: level_to_pulse
+    port map (
+      CLK_IN    => CLK_D1_IN,
+      RESET_IN  => RESET_D1_IN,
+      LEVEL_IN  => timing_trigger_l,
+      PULSE_OUT => timing_trigger
+      );
+  
+  -- Signal Domain Transfers to NX Clock
+  trigger_busy_ff  <= trigger_busy_o
+                      when rising_edge(CLK_D1_IN);
+  trigger_busy_f   <= trigger_busy_ff
+                      when rising_edge(CLK_D1_IN);
+  trigger_busy     <= trigger_busy_f
+                      when rising_edge(CLK_D1_IN);
+
+  fast_clear_ff    <= fast_clear_o
+                      when rising_edge(CLK_D1_IN);
+  fast_clear_f     <= fast_clear_ff
+                      when rising_edge(CLK_D1_IN);
+  fast_clear       <= fast_clear_f
+                      when rising_edge(CLK_D1_IN);
+
+  PROC_TIMING_TRIGGER_HANDLER: process(CLK_D1_IN)
+  begin
+    if( rising_edge(CLK_D1_IN) ) then
+      if (RESET_D1_IN = '1') then
+        invalid_timing_trigger_n   <= '1';
+        ts_wait_timer_start        <= '0';
+        ts_wait_timer_reset        <= '1';
+        timestamp_trigger_o        <= '0';
+        TS_STATE                   <= TS_IDLE;     
+      else
+        invalid_timing_trigger_n   <= '0';
+        ts_wait_timer_start        <= '0';
+        ts_wait_timer_reset        <= '0';
+        timestamp_trigger_o        <= '0';
+
+        if (fast_clear = '1') then
+          ts_wait_timer_reset      <= '1';
+          TS_STATE                 <= TS_IDLE;
+        else
+          case TS_STATE is
+            when  TS_IDLE =>
+              -- Wait for Timing Trigger synced to NX_MAIN_CLK_DOMAIN
+              if (timing_trigger = '1') then
+                if (trigger_busy = '1') then
+                  -- If busy is set --> Error
+                  TS_STATE                <= TS_INVALID_TRIGGER;
+                else
+                  timestamp_trigger_o     <= '1';
+                  ts_wait_timer_start     <= '1';
+                  TS_STATE                <= TS_WAIT_VALID_TIMING_TRIGGER;
+                end if;
+              else
+                TS_STATE                  <= TS_IDLE;
+              end if;
+
+            when TS_WAIT_VALID_TIMING_TRIGGER =>
+              -- Wait and test if CLK_IN Trigger Handler does accepted Trigger 
+              if (trigger_busy = '1') then
+                -- Trigger has been accepted, stop timer and wait trigger end
+                ts_wait_timer_reset       <= '1';
+                TS_STATE                  <= TS_WAIT_TRIGGER_END;
+              else
+                if (ts_wait_timer_done = '1') then
+                  -- Timeout after 128ns --> Invalid Trigger Error
+                  TS_STATE                <= TS_INVALID_TRIGGER;
+                else
+                  TS_STATE                <= TS_WAIT_VALID_TIMING_TRIGGER;
+                end if;
+              end if;
+
+            when TS_INVALID_TRIGGER =>
+              invalid_timing_trigger_n    <= '1';
+              TS_STATE                    <= TS_IDLE;
+              
+            when TS_WAIT_TRIGGER_END =>
+              if (trigger_busy = '0') then
+                TS_STATE                  <= TS_IDLE;
+              else
+                TS_STATE                  <= TS_WAIT_TRIGGER_END;
+              end if;
+              
+          end case;
+        end if;
+      end if;
+    end if;
+  end process PROC_TIMING_TRIGGER_HANDLER;
+  
+  PROC_TIMING_TRIGGER_COUNTER: process(CLK_IN)
+  begin
+    if( rising_edge(CLK_IN) ) then
+      if (RESET_IN = '1') then
+        invalid_timing_trigger_ctr    <= (others => '0');
+      else
+        if (invalid_t_trigger_ctr_clear = '1') then
+          invalid_timing_trigger_ctr  <= (others => '0');
+        elsif (invalid_timing_trigger = '1') then
+          invalid_timing_trigger_ctr  <= invalid_timing_trigger_ctr + 1;
+        end if;
+      end if;
+    end if;
+  end process PROC_TIMING_TRIGGER_COUNTER;
+  
+  -- Relax Timing 
+  invalid_timing_trigger_ff  <= invalid_timing_trigger_n
+                                when rising_edge(CLK_D1_IN);
+  invalid_timing_trigger_f   <= invalid_timing_trigger_ff
+                                when rising_edge(CLK_D1_IN);
+
+  pulse_dtrans_INVALID_TIMING_TRIGGER: pulse_dtrans
+    generic map (
+      CLK_RATIO => 4
+      )
+    port map (
+      CLK_A_IN    => CLK_D1_IN,
+      RESET_A_IN  => RESET_D1_IN,
+      PULSE_A_IN  => invalid_timing_trigger_f,
+      CLK_B_IN    => CLK_IN,
+      RESET_B_IN  => RESET_IN,
+      PULSE_B_OUT => invalid_timing_trigger
+      );
+  
+  -----------------------------------------------------------------------------
+  
+  PROC_TRIGGER_HANDLER: process(CLK_IN)
+  begin
+    if( rising_edge(CLK_IN) ) then
+      if (RESET_IN = '1') then
+        valid_trigger_o              <= '0';
+        timing_trigger_o             <= '0';
+        status_trigger_o             <= '0';
+        calibration_trigger_o        <= '0';
+        fee_data_finished_o          <= '0';
+        fee_trg_release_o            <= '0';
+        fee_trg_statusbits_o         <= (others => '0');
+        fast_clear_o                 <= '0';
+        trigger_busy_o               <= '0';
+        timestamp_calib_trigger_c100 <= '0';
+        calib_downscale_ctr          <= (others => '0');
+        TRIGGER_TYPE                 <= T_UNDEF;
+        STATE                        <= S_IDLE;
+      else                           
+        valid_trigger_o              <= '0';
+        timing_trigger_o             <= '0';
+        status_trigger_o             <= '0';
+        calibration_trigger_o        <= '0';
+        fee_data_finished_o          <= '0';
+        fee_trg_release_o            <= '0';
+        fee_trg_statusbits_o         <= (others => '0');
+        fast_clear_o                 <= '0';
+        trigger_busy_o               <= '1';
+        timestamp_calib_trigger_c100 <= '0';
+        
+        if (LVL1_INVALID_TRG_IN = '1') then
+          -- There was no valid Timing Trigger at CTS, do a fast clear
+          fast_clear_o               <= '1';
+          fee_trg_release_o          <= '1';
+          STATE                      <= S_IDLE;
+        else
+          
+          case STATE is
+
+            when  S_IDLE =>
+
+              if (LVL1_VALID_TIMING_TRG_IN = '1') then
+                -- Timing Trigger IN
+                if (OFFLINE_IN              = '1' or
+                    bypass_all_trigger      = '1') then
+
+                  -- Ignore Trigger for nxyter is or pretends to be offline 
+                  TRIGGER_TYPE                     <= T_IGNORE;
+                  STATE                            <= S_IGNORE_TRIGGER;
+                else
+                  -- Check Trigger Type
+                  if (LVL1_TRG_TYPE_IN = physics_trigger_type) then
+                    -- Physiks Trigger
+                    if (bypass_physics_trigger = '1') then
+                      TRIGGER_TYPE                 <= T_IGNORE;
+                      STATE                        <= S_IGNORE_TRIGGER;
+                    else
+                      TRIGGER_TYPE                 <= T_TIMING;
+                      STATE                        <= S_TIMING_TRIGGER;
+                    end if; 
+                  else
+                    -- Unknown Timing Trigger, ignore
+                    TRIGGER_TYPE                 <= T_IGNORE;
+                    STATE                        <= S_IGNORE_TRIGGER;
+                  end if;
+                end if;
+
+              elsif (LVL1_VALID_NOTIMING_TRG_IN = '1') then
+                -- No Timing Trigger IN
+                if (OFFLINE_IN                 = '1' or
+                    bypass_all_trigger         = '1') then
+                  
+                  -- Ignore Trigger for nxyter or pretend to be offline 
+                  TRIGGER_TYPE                     <= T_IGNORE;
+                  STATE                            <= S_IGNORE_TRIGGER;
+                else
+                  -- Check Trigger Type
+                  if (LVL1_TRG_TYPE_IN = calibration_trigger_type) then
+                    -- Calibration Trigger
+                    if (bypass_calibration_trigger = '1') then
+                      TRIGGER_TYPE                 <= T_IGNORE;
+                      STATE                        <= S_IGNORE_TRIGGER;
+                    else
+                      if (calib_downscale_ctr >= calibration_downscale) then
+                        timestamp_calib_trigger_c100 <= '1';
+                        calib_downscale_ctr          <= x"0001";
+                        TRIGGER_TYPE                 <= T_CALIBRATION;
+                        STATE                        <= S_CALIBRATION_TRIGGER;
+                      else
+                        calib_downscale_ctr          <= calib_downscale_ctr + 1;
+                        TRIGGER_TYPE                 <= T_IGNORE;
+                        STATE                        <= S_IGNORE_TRIGGER;
+                      end if;
+                    end if;  
+
+                  elsif (LVL1_TRG_TYPE_IN = status_trigger_type) then
+                    -- Status Trigger
+                    if (bypass_status_trigger = '1') then
+                      TRIGGER_TYPE                 <= T_IGNORE;
+                      STATE                        <= S_IGNORE_TRIGGER;
+                    else
+                      -- Status Trigger  
+                      status_trigger_o               <= '1';
+                      TRIGGER_TYPE                   <= T_STATUS;
+                      STATE                          <= S_STATUS_TRIGGER;
+                    end if;
+
+                  else
+                    -- Some other Trigger, ignore it
+                    TRIGGER_TYPE                     <= T_IGNORE;
+                    STATE                            <= S_IGNORE_TRIGGER;
+                  end if;
+                  
+                end if;
+                
+              else
+                -- No Trigger IN, Nothing to do, Sleep Well
+                trigger_busy_o        <= '0';
+                TRIGGER_TYPE          <= T_UNDEF;
+                STATE                 <= S_IDLE;
+              end if;
+              
+            when S_TIMING_TRIGGER =>
+              valid_trigger_o         <= '1';
+              timing_trigger_o        <= '1';
+              STATE                   <= S_WAIT_TRG_DATA_VALID;
+
+            when S_CALIBRATION_TRIGGER =>
+              calibration_trigger_o   <= '1';
+              valid_trigger_o         <= '1';
+              timing_trigger_o        <= '1';
+              STATE                   <= S_WAIT_TRG_DATA_VALID;
+              
+            when S_WAIT_TRG_DATA_VALID | S_STATUS_TRIGGER | S_IGNORE_TRIGGER =>
+              if (LVL1_TRG_DATA_VALID_IN = '0') then
+                STATE                 <= S_WAIT_TRG_DATA_VALID;
+              else
+                STATE                 <= S_WAIT_TIMING_TRIGGER_DONE;
+              end if;
+
+            when S_WAIT_TIMING_TRIGGER_DONE =>
+              if (((TRIGGER_TYPE = T_TIMING or
+                    TRIGGER_TYPE = T_CALIBRATION)
+                   and TRIGGER_BUSY_0_IN = '1')
+                  or
+                  (TRIGGER_TYPE = T_STATUS  and
+                   TRIGGER_BUSY_1_IN = '1')
+                  ) then
+                STATE                 <= S_WAIT_TIMING_TRIGGER_DONE;
+              else
+                fee_data_finished_o   <= '1';
+                STATE                 <= S_FEE_TRIGGER_RELEASE;
+              end if;
+
+            when S_FEE_TRIGGER_RELEASE =>
+              fee_trg_release_o       <= '1';
+              STATE                   <= S_WAIT_FEE_TRIGGER_RELEASE_ACK;
+              
+            when S_WAIT_FEE_TRIGGER_RELEASE_ACK =>
+              if (LVL1_TRG_DATA_VALID_IN = '1') then
+                STATE                 <= S_WAIT_FEE_TRIGGER_RELEASE_ACK;
+              else
+                STATE                 <= S_IDLE;
+              end if;
+              
+              -- Internal Trigger Handler
+            when S_INTERNAL_TRIGGER =>
+              valid_trigger_o         <= '1';
+              STATE                   <= S_WAIT_TRIGGER_VALIDATE_ACK;
+
+            when S_WAIT_TRIGGER_VALIDATE_ACK =>
+              if (TRIGGER_VALIDATE_BUSY_IN = '0') then
+                STATE                 <= S_WAIT_TRIGGER_VALIDATE_ACK;
+              else
+                STATE                 <= S_WAIT_TRIGGER_VALIDATE_DONE;
+              end if;
+              
+            when S_WAIT_TRIGGER_VALIDATE_DONE =>
+              if (TRIGGER_VALIDATE_BUSY_IN = '1') then
+                STATE                 <= S_WAIT_TRIGGER_VALIDATE_DONE;
+              else
+                STATE                 <= S_IDLE;
+              end if;
+              
+          end case;
+        end if;
+      end if;
+    end if;
+  end process PROC_TRIGGER_HANDLER;
+
+  PROC_EVENT_DATA_MULTIPLEXER: process(TRIGGER_TYPE)
+  begin
+    case TRIGGER_TYPE is
+      when  T_UNDEF | T_IGNORE =>
+        fee_data_o                   <= (others => '0');
+        fee_data_write_o             <= '0';
+        
+      when T_TIMING | T_CALIBRATION =>
+        fee_data_o                   <= FEE_DATA_0_IN;
+        fee_data_write_o             <= FEE_DATA_WRITE_0_IN;
+        
+      when T_STATUS =>
+        fee_data_o                   <= FEE_DATA_1_IN;
+        fee_data_write_o             <= FEE_DATA_WRITE_1_IN;
+
+    end case;
+  end process PROC_EVENT_DATA_MULTIPLEXER;
+
+  internal_trigger_f  <= INTERNAL_TRIGGER_IN or
+                         calibration_trigger_o when rising_edge(CLK_D1_IN);
+  internal_trigger    <= internal_trigger_f  when rising_edge(CLK_D1_IN);
+
+  PROC_CAL_RATES: process (CLK_IN)
+  begin 
+    if( rising_edge(CLK_IN) ) then
+      if (RESET_IN = '1') then
+        accepted_trigger_rate_t     <= (others => '0');
+        accepted_trigger_rate       <= (others => '0');
+        rate_timer                  <= (others => '0');
+      else
+        if (rate_timer < x"5f5e100") then
+          if (timing_trigger_o = '1') then
+            accepted_trigger_rate_t            <= accepted_trigger_rate_t + 1;
+          end if;
+
+          rate_timer                           <= rate_timer + 1;
+        else
+          rate_timer                           <= (others => '0');
+          accepted_trigger_rate                <= accepted_trigger_rate_t;
+          
+          accepted_trigger_rate_t              <= (others => '0');
+        end if;
+      end if;
+    end if;
+  end process PROC_CAL_RATES;
+
+-----------------------------------------------------------------------------
+-- TRBNet Slave Bus
+-----------------------------------------------------------------------------
+
+  PROC_SLAVE_BUS: process(CLK_IN)
+  begin
+    if( rising_edge(CLK_IN) ) then
+      if( RESET_IN = '1' ) then
+        slv_data_out_o                 <= (others => '0');
+        slv_no_more_data_o             <= '0';
+        slv_unknown_addr_o             <= '0';
+        slv_ack_o                      <= '0';
+        invalid_t_trigger_ctr_clear    <= '1';
+        bypass_all_trigger             <= '0';
+        bypass_physics_trigger         <= '0';
+        bypass_status_trigger          <= '1';
+        bypass_calibration_trigger     <= '1';
+        calibration_downscale          <= x"0001";
+        physics_trigger_type           <= x"1";
+        calibration_trigger_type       <= x"9";
+        status_trigger_type            <= x"e";
+      else                             
+        slv_unknown_addr_o             <= '0';
+        slv_no_more_data_o             <= '0';
+        slv_data_out_o                 <= (others => '0');
+        slv_ack_o                      <= '0';
+        invalid_t_trigger_ctr_clear    <= '0';
+
+        if (SLV_WRITE_IN  = '1') then
+          case SLV_ADDR_IN is
+            when x"0003" =>
+              invalid_t_trigger_ctr_clear  <= '1';
+              slv_ack_o                    <= '1'; 
+
+            when x"0006" =>
+              bypass_physics_trigger       <= SLV_DATA_IN(0);
+              bypass_status_trigger        <= SLV_DATA_IN(1);
+              bypass_calibration_trigger   <= SLV_DATA_IN(2);
+              bypass_all_trigger           <= SLV_DATA_IN(3);
+              slv_ack_o                    <= '1'; 
+
+            when x"0007" =>
+              if (unsigned(SLV_DATA_IN(15 downto 0)) > x"0000") then
+                calibration_downscale      <=
+                  unsigned(SLV_DATA_IN(15 downto 0));
+              end if;
+              slv_ack_o                    <= '1';
+
+            when x"0008" =>
+              physics_trigger_type          <= SLV_DATA_IN(3 downto 0);
+              slv_ack_o                    <= '1';  
+
+            when x"0009" =>
+              status_trigger_type          <= SLV_DATA_IN(3 downto 0);
+              slv_ack_o                    <= '1';  
+
+            when x"000a" =>
+              calibration_trigger_type     <= SLV_DATA_IN(3 downto 0);
+              slv_ack_o                    <= '1';  
+              
+            when others =>
+              slv_unknown_addr_o           <= '1';
+
+          end case;
+
+        elsif (SLV_READ_IN = '1') then
+          case SLV_ADDR_IN is
+            when x"0003" =>
+              slv_data_out_o(15 downto 0)  <=
+                std_logic_vector(invalid_timing_trigger_ctr);
+              slv_data_out_o(31 downto 26) <= (others => '0');
+              slv_ack_o                    <= '1';  
+
+            when x"0004" =>
+              slv_data_out_o(27 downto 0)  <=
+                std_logic_vector(accepted_trigger_rate);
+              slv_data_out_o(31 downto 28) <= (others => '0');
+              slv_ack_o                    <= '1';  
+              
+            when x"0006" =>
+              slv_data_out_o(0)            <= bypass_physics_trigger;
+              slv_data_out_o(1)            <= bypass_status_trigger;
+              slv_data_out_o(2)            <= bypass_calibration_trigger;
+              slv_data_out_o(3)            <= bypass_all_trigger;
+              slv_data_out_o(31 downto 4)  <= (others => '0');
+              slv_ack_o                    <= '1';  
+
+            when x"0007" =>
+              slv_data_out_o(15 downto 0)  <= calibration_downscale;
+              slv_data_out_o(31 downto 16) <= (others => '0');
+              slv_ack_o                    <= '1';
+
+            when x"0008" =>
+              slv_data_out_o(3 downto 0)   <= physics_trigger_type;
+              slv_data_out_o(31 downto 4)  <= (others => '0');
+              slv_ack_o                    <= '1';
+
+            when x"0009" =>
+              slv_data_out_o(3 downto 0)   <= status_trigger_type;
+              slv_data_out_o(31 downto 4)  <= (others => '0');
+              slv_ack_o                    <= '1';
+
+            when x"000a" =>
+              slv_data_out_o(3 downto 0)   <= calibration_trigger_type;
+              slv_data_out_o(31 downto 4)  <= (others => '0');
+              slv_ack_o                    <= '1';
+              
+            when others =>
+              slv_unknown_addr_o           <= '1';
+
+          end case;
+
+        end if;
+      end if;
+    end if;           
+  end process PROC_SLAVE_BUS;
+
+-----------------------------------------------------------------------------
+-- Output Signals
+-----------------------------------------------------------------------------
+
+  timestamp_calib_trigger_f  <= timestamp_calib_trigger_c100
+                                when rising_edge(CLK_D1_IN);
+
+  timestamp_calib_trigger_o  <= timestamp_calib_trigger_f
+                                when rising_edge(CLK_D1_IN);
+
+  -- Trigger Output
+  VALID_TRIGGER_OUT         <= valid_trigger_o;
+  TIMESTAMP_TRIGGER_OUT     <= timestamp_trigger_o or timestamp_calib_trigger_o;
+  TRIGGER_TIMING_OUT        <= timing_trigger_o;
+  TRIGGER_STATUS_OUT        <= status_trigger_o;
+  TRIGGER_CALIBRATION_OUT   <= calibration_trigger_o;
+  FAST_CLEAR_OUT            <= fast_clear_o;
+  TRIGGER_BUSY_OUT          <= trigger_busy_o;
+
+  FEE_DATA_OUT              <= fee_data_o;
+  FEE_DATA_WRITE_OUT        <= fee_data_write_o; 
+  FEE_DATA_FINISHED_OUT     <= fee_data_finished_o;
+  FEE_TRG_RELEASE_OUT       <= fee_trg_release_o;
+  FEE_TRG_STATUSBITS_OUT    <= fee_trg_statusbits_o;
+
+  -- Slave Bus              
+  SLV_DATA_OUT              <= slv_data_out_o;    
+  SLV_NO_MORE_DATA_OUT      <= slv_no_more_data_o; 
+  SLV_UNKNOWN_ADDR_OUT      <= slv_unknown_addr_o;
+  SLV_ACK_OUT               <= slv_ack_o;    
+
+end Behavioral;