From ea3f4a98c6f9ab1ae1921da8f308a43110cd8dd2 Mon Sep 17 00:00:00 2001
From: David Cussans <David.Cussans@bristol.ac.uk>
Date: Fri, 28 Feb 2014 12:03:48 +0000
Subject: [PATCH] Checking in changes needed to get firmware to simulate under
 QuestSim Also, tidying up code and hopefully reducing potential timing-race
 and meta-stability issues.

eventFormatter_rtl.vhd
---
 firmware/hdl/common/arrivalTimeLUT_rtl.vhd    |  24 ++-
 firmware/hdl/common/clocks_s6_extphy.vhd      |  16 +-
 firmware/hdl/common/counterWithReset_rtl.vhd  |  95 +++++++++
 firmware/hdl/common/dualSERDES_1to4_rtl.vhd   | 150 +++++--------
 firmware/hdl/common/eventFormatter_rtl.vhd    | 108 ++++++----
 firmware/hdl/common/i2c_master_rtl.vhd        |   1 +
 firmware/hdl/common/ipbus_ver.vhd             |   2 +-
 firmware/hdl/common/logic_clocks_rtl.vhd      |  14 +-
 firmware/hdl/common/registerCounter_rtl.vhd   |   3 +-
 .../hdl/common/serdesCalibrateFSM_rtl.vhd     | 114 ++++++++++
 .../hdl/common/synchronizeRegisters_rtl.vhd   | 114 ++++++++++
 firmware/hdl/common/triggerInputs_rtl.vhd     | 125 +++++++----
 firmware/hdl/common/triggerLogic_rtl.vhd      | 200 ++++++------------
 13 files changed, 627 insertions(+), 339 deletions(-)
 create mode 100644 firmware/hdl/common/counterWithReset_rtl.vhd
 create mode 100644 firmware/hdl/common/serdesCalibrateFSM_rtl.vhd
 create mode 100644 firmware/hdl/common/synchronizeRegisters_rtl.vhd

diff --git a/firmware/hdl/common/arrivalTimeLUT_rtl.vhd b/firmware/hdl/common/arrivalTimeLUT_rtl.vhd
index 1659bdc8..27c42eac 100644
--- a/firmware/hdl/common/arrivalTimeLUT_rtl.vhd
+++ b/firmware/hdl/common/arrivalTimeLUT_rtl.vhd
@@ -175,14 +175,24 @@ BEGIN
   end process examine_lut;
   
   --! Coarse time stamp. Phase w.r.t. strobe
-	c_coarse_ts : entity work.CounterUp
+--	c_coarse_ts : entity work.CounterUp
+--   PORT MAP (
+--     clk   => clk_4x_logic_i,
+--     ce    => '1',
+--     sinit => strobe_4x_logic_i, --'0',
+--	  q(31 downto 2) => open,
+--     q(1 downto 0)  => s_coarse_bits
+--	);
+--  
+  	c_coarse_ts : entity work.CounterWithReset
+  	GENERIC MAP (
+  	  g_COUNTER_WIDTH => 2 )
    PORT MAP (
-     clk   => clk_4x_logic_i,
-     ce    => '1',
-     sinit => strobe_4x_logic_i, --'0',
-	  q(31 downto 2) => open,
-     q(1 downto 0)  => s_coarse_bits
+     clock_i   => clk_4x_logic_i,
+     enable_i   => '1',
+     reset_i => strobe_4x_logic_i, --'0',
+     result_o => s_coarse_bits
 	);
-  
+	
 END ARCHITECTURE rtl;
 
diff --git a/firmware/hdl/common/clocks_s6_extphy.vhd b/firmware/hdl/common/clocks_s6_extphy.vhd
index 4408a576..296872f3 100644
--- a/firmware/hdl/common/clocks_s6_extphy.vhd
+++ b/firmware/hdl/common/clocks_s6_extphy.vhd
@@ -36,12 +36,12 @@ architecture rtl of clocks_s6_extphy is
         signal s_clk_logic_xtal : std_logic;
 	-- signal clk_400: std_logic;
 	
-	component clock_divider_s6 port(
-		clk: in std_logic;
-		d25: out std_logic;
-		d28: out std_logic
-	);
-	end component;
+--	component clock_divider_s6 port(
+--		clk: in std_logic;
+--		d25: out std_logic;
+--		d28: out std_logic
+--	);
+--	end component;
 	
 begin
 
@@ -90,8 +90,10 @@ begin
 			rst => '0'
 		);
 		
-	clkdiv: clock_divider_s6 port map(
+	clkdiv: entity work.clock_divider_s6 port map(
+--        clkdiv: entity work.clock_div port map(
 		clk => sysclk,
+--                D17 => open,
 		d25 => d25,
 		d28 => onehz
 	);
diff --git a/firmware/hdl/common/counterWithReset_rtl.vhd b/firmware/hdl/common/counterWithReset_rtl.vhd
new file mode 100644
index 00000000..f88057de
--- /dev/null
+++ b/firmware/hdl/common/counterWithReset_rtl.vhd
@@ -0,0 +1,95 @@
+--=============================================================================
+--! @file counterWithReset_rtl.vhd
+--=============================================================================
+-------------------------------------------------------------------------------
+-- --
+-- University of Bristol, High Energy Physics Group.
+-- --
+------------------------------------------------------------------------------- --
+-- unit name: counterWithReset (counterWithReset / rtl)
+--
+--! @brief Simple counter with synchronous reset
+--
+--! @author David Cussans , David.Cussans@bristol.ac.uk
+--
+--! @date Feb\2012
+--
+--! @version v0.1
+--
+--! @details
+--!
+--! <b>Dependencies:</b>\n
+--! None
+--!
+--! <b>References:</b>\n
+--! referenced by ipBusMarocTriggerGenerator \n
+--!
+--! <b>Modified by:</b>\n
+--! Author: 
+-------------------------------------------------------------------------------
+--! \n\n<b>Last changes:</b>\n
+--! 5/Mar/12  DGC Changed to use numeric_std\n
+--! 26/Feb/14 DGC Added registers to output to aid timing closure.
+--! 
+-------------------------------------------------------------------------------
+--! @todo <next thing to do> \n
+--! <another thing to do> \n
+---------------------------------------------------------------------------------
+
+--============================================================================
+--! Entity declaration for counterWithReset
+--============================================================================
+LIBRARY ieee;
+USE ieee.std_logic_1164.ALL;
+use ieee.numeric_std.all;
+
+ENTITY counterWithReset IS
+  GENERIC (g_COUNTER_WIDTH : integer := 32; --! Number of bits
+           g_OUTPUT_REGISTERS : integer := 4 --! Number of output registers. Minumum =1. Aids timing closure.
+           );
+  PORT
+    (
+      clock_i: 	IN STD_LOGIC;  --! rising edge active clock
+      reset_i:  IN STD_LOGIC;  --! Active high. syncronous with rising clk
+      enable_i: IN STD_LOGIC;  --! counts when enable=1
+      result_o:	OUT STD_LOGIC_VECTOR ( g_COUNTER_WIDTH-1 downto 0) --! Unsigned integer output
+      
+      );
+END counterWithReset;
+
+ARCHITECTURE rtl OF counterWithReset IS
+  type t_register_array is array(natural range <>) of UNSIGNED ( g_COUNTER_WIDTH-1 downto 0) ;  -- --! Array of arrays for output register...
+  signal s_output_registers : t_register_array(g_OUTPUT_REGISTERS downto 0);  -- --! Output registers.
+  
+BEGIN
+
+  --! Process to count up from zero when enable_i is high.
+  p_counter: PROCESS (clock_i)
+  BEGIN
+    IF rising_edge(clock_i) THEN
+      IF (reset_i = '1') THEN
+        s_output_registers(0) <= (others => '0');
+      ELSIF (enable_i='1') THEN
+        s_output_registers(0) <= s_output_registers(0) + 1;
+      END IF;
+    END IF;
+  END PROCESS p_counter;
+
+  --! Generate some output registers. Number controlled by g_OUTPUT_REGISTERS
+  generate_registers: for v_register in 1 to g_OUTPUT_REGISTERS generate
+
+    --! An individual register
+    p_outputRegister: process (clock_i)
+    begin  -- process p_outputRegister
+      if rising_edge(clock_i) then
+        s_output_registers( v_register) <=
+        s_output_registers( v_register-1);
+      end if;
+    end process p_outputRegister;
+    
+  end generate generate_registers;  -- v_register
+
+  --! Copy the (registered) result to the output 
+  result_o <= STD_LOGIC_VECTOR(s_output_registers(g_OUTPUT_REGISTERS));
+  
+END rtl;		
diff --git a/firmware/hdl/common/dualSERDES_1to4_rtl.vhd b/firmware/hdl/common/dualSERDES_1to4_rtl.vhd
index 99a6fc41..c2092b1d 100644
--- a/firmware/hdl/common/dualSERDES_1to4_rtl.vhd
+++ b/firmware/hdl/common/dualSERDES_1to4_rtl.vhd
@@ -29,6 +29,7 @@
 --! Author: 
 -------------------------------------------------------------------------------
 --! \n\n<b>Last changes:</b>\n
+--! Separated FSM for calibration control into a separate entity. DGC, 22/Feb/14
 -------------------------------------------------------------------------------
 --! @todo Implement a periodic calibration sequence\n
 --! <another thing to do> \n
@@ -73,105 +74,52 @@ ARCHITECTURE rtl OF dualSERDES_1to4 IS
   signal s_data_o       : std_logic_vector(7 downto 0);  --! Deserialized data
   signal s_rst          : std_logic := '0';         -- IODELAY and ISERDES reset
   signal s_cal_FSM      : std_logic := '0';         --! Take high to calibrate the IDELAY components
-  signal s_rst_FSM      : std_logic := '0';         -- IODELAY reset
-  signal s_initial_cal  : std_logic := '1';         -- Start up calibration flag
-  signal s_calibration  : std_logic := '0';         -- Start calibration
-  --! Calibration FSM state values
-  type state_values is (st0, st1, st2, st3, st4);
-  signal pres_state, next_state: state_values := st0;
-  
-BEGIN
-  --! Calibration start condition
-  s_calibration <= serdes_reset_i or s_initial_cal;
-  s_rst <= s_rst_FSM; -- or serdes_reset_i;
-  
-  --! Calibration FSM register
-  statereg: process(fabricClk_i, serdes_reset_i)
-  begin
-	 if rising_edge(fabricClk_i) then
-		pres_state <= next_state;     -- Move to next state
-        
-	 end if;
-  end process statereg;
 
 
-  --! Calibration FSM combinational block
-  fsm: process(pres_state, s_calibration, s_busy_idelay_m)
-  begin
-	 next_state <= pres_state;
-	 -- Default values
-    s_Rst_FSM <= '0';
-    s_cal_FSM <= '0';
-	 
-    case pres_state is
-	  
-	   -- st0 - IDLE
-		when st0=>
-        if ( s_calibration = '1') then 
-          next_state <= st1;            -- Next state is "st1 - SEND CALIBRATION SIGNAL"
-        end if;
-		
-		-- st1 - SEND CALIBRATION SIGNAL
-		when st1=>
-		  s_cal_FSM <= '1';
-		  s_initial_cal <= '0';
-        if s_busy_idelay_m = '1' then 
-          next_state <= st2;            -- Next state is "st2 - WAIT BUSY = '0'"
-        end if;
-      
-		-- st2 - WAIT BUSY = '0'
-		when st2=>
-        if s_busy_idelay_m = '0' then 
-          next_state <= st3;            -- Next state is "st3 - RESET STATE"
-        end if;
-		
-		-- st3 - RESET STATE
-		when st3=>
-		  s_Rst_FSM <= '1';
-		  if s_busy_idelay_m = '1' then 
-          next_state <= st4;              -- Next state is "st4 - WAIT BUSY = '0'"
-        end if;
-		  
-		-- st4 - WAIT BUSY = '0'
-		when st4=>
-		  if s_busy_idelay_m = '0' then 
-          next_state <= st0;              -- Next state is "st0 - IDLE"
-        end if;
-	 end case;
-	 
-  end process fsm;
 
-    IODELAY2_Prompt : IODELAY2
-  generic map (
-    COUNTER_WRAPAROUND => "STAY_AT_LIMIT",  -- "STAY_AT_LIMIT" or "WRAPAROUND" 
-    DATA_RATE          => "SDR",            -- "SDR" or "DDR" 
-    DELAY_SRC          => "IDATAIN",        -- "IO", "ODATAIN" or "IDATAIN" 
-    IDELAY_MODE        => "NORMAL",         -- "NORMAL" or "PCI" 
-	 --SERDES_MODE   	  => "MASTER", 			-- <NONE>, MASTER, SLAVE
-    IDELAY_TYPE        => "VARIABLE_FROM_HALF_MAX",          -- "FIXED", "DEFAULT", "VARIABLE_FROM_ZERO", "VARIABLE_FROM_HALF_MAX" 
+
+  
+BEGIN
+
+  calibration_fsm: entity work.serdesCalibrateFSM
+    port map (
+      fsm_clk_i       => fabricClk_i,
+      serdes_reset_i  => serdes_reset_i,
+      busy_idelay_m_i => s_busy_idelay_m,
+      calibrate_o     => s_cal_FSM,
+      reset_o         => s_rst);
+
+  IODELAY2_Prompt : IODELAY2
+    generic map (
+      COUNTER_WRAPAROUND => "STAY_AT_LIMIT",  -- "STAY_AT_LIMIT" or "WRAPAROUND" 
+      DATA_RATE          => "SDR",            -- "SDR" or "DDR" 
+      DELAY_SRC          => "IDATAIN",        -- "IO", "ODATAIN" or "IDATAIN" 
+      IDELAY_MODE        => "NORMAL",         -- "NORMAL" or "PCI" 
+      SERDES_MODE        => "NONE", 			-- <NONE>, MASTER, SLAVE
+      IDELAY_TYPE        => "VARIABLE_FROM_HALF_MAX",          -- "FIXED", "DEFAULT", "VARIABLE_FROM_ZERO", "VARIABLE_FROM_HALF_MAX" 
                               --  or "DIFF_PHASE_DETECTOR" 
-    IDELAY_VALUE     => 0,                -- Amount of taps for fixed input delay (0-255)
-    IDELAY2_VALUE    => 0,                -- Delay value when IDELAY_MODE="PCI" (0-255)
-    ODELAY_VALUE     => 0                -- Amount of taps fixed output delay (0-255)
-    --SIM_TAPDELAY_VALUE=> 50               -- Per tap delay used for simulation in ps
-   )
-  port map (
-    BUSY     => s_busy_idelay_m,  -- 1-bit output: Busy output after CAL
-    DATAOUT  => s_Data_i_d_p,     -- 1-bit output: Delayed data output to ISERDES/input register
-    DATAOUT2 => open,             -- 1-bit output: Delayed data output to general FPGA fabric
-    DOUT     => open,             -- 1-bit output: Delayed data output
-    TOUT     => open,             -- 1-bit output: Delayed 3-state output
-    CAL      => s_cal_FSM,     -- 1-bit input: Initiate calibration input
-    CE       => '0',              -- 1-bit input: Enable INC input
-    CLK      => fabricClk_i,      -- 1-bit input: Clock input
-    IDATAIN  => data_i,           -- 1-bit input: Data input (connect to top-level port or I/O buffer)
-    INC      => '0',              -- 1-bit input: Increment / decrement input
-    IOCLK0   => fastClk_i,        -- 1-bit input: Input from the I/O clock network
-    IOCLK1   => '0',              -- 1-bit input: Input from the I/O clock network
-    ODATAIN  => '0',              -- 1-bit input: Output data input from output register or OSERDES2.
-    RST      => s_rst,            -- 1-bit input: reset_i to zero or 1/2 of total delay period
-    T        => '0'               -- 1-bit input: 3-state input signal
-   );
+      IDELAY_VALUE     => 0,                -- Amount of taps for fixed input delay (0-255)
+      IDELAY2_VALUE    => 0,                -- Delay value when IDELAY_MODE="PCI" (0-255)
+      ODELAY_VALUE     => 0                -- Amount of taps fixed output delay (0-255)
+      --SIM_TAPDELAY_VALUE=> 50               -- Per tap delay used for simulation in ps
+      )
+    port map (
+      BUSY     => s_busy_idelay_m,  -- 1-bit output: Busy output after CAL
+      DATAOUT  => s_Data_i_d_p,     -- 1-bit output: Delayed data output to ISERDES/input register
+      DATAOUT2 => open,             -- 1-bit output: Delayed data output to general FPGA fabric
+      DOUT     => open,             -- 1-bit output: Delayed data output
+      TOUT     => open,             -- 1-bit output: Delayed 3-state output
+      CAL      => s_cal_FSM,     -- 1-bit input: Initiate calibration input
+      CE       => '0',              -- 1-bit input: Enable INC input
+      CLK      => fabricClk_i,      -- 1-bit input: Clock input
+      IDATAIN  => data_i,           -- 1-bit input: Data input (connect to top-level port or I/O buffer)
+      INC      => '0',              -- 1-bit input: Increment / decrement input
+      IOCLK0   => fastClk_i,        -- 1-bit input: Input from the I/O clock network
+      IOCLK1   => '0',              -- 1-bit input: Input from the I/O clock network
+      ODATAIN  => '0',              -- 1-bit input: Output data input from output register or OSERDES2.
+      RST      => s_rst,            -- 1-bit input: reset_i to zero or 1/2 of total delay period
+      T        => '0'               -- 1-bit input: 3-state input signal
+      );
 
 
   IODELAY2_Delayed : IODELAY2
@@ -180,8 +128,8 @@ BEGIN
     DATA_RATE          => "SDR",         -- "SDR" or "DDR" 
     DELAY_SRC          => "IDATAIN",     -- "IO", "ODATAIN" or "IDATAIN" 
     IDELAY_MODE        => "NORMAL",      -- "NORMAL" or "PCI" 
-	 --SERDES_MODE   	  => "SLAVE", 			-- <NONE>, MASTER, SLAVE
-    IDELAY_TYPE        => "FIXED",       -- "FIXED", "DEFAULT", "VARIABLE_FROM_ZERO", "VARIABLE_FROM_HALF_MAX" 
+    SERDES_MODE        => "NONE", 			-- <NONE>, MASTER, SLAVE
+    IDELAY_TYPE        => "VARIABLE_FROM_ZERO",       -- "FIXED", "DEFAULT", "VARIABLE_FROM_ZERO", "VARIABLE_FROM_HALF_MAX" 
                               --  or "DIFF_PHASE_DETECTOR" 
     IDELAY_VALUE       => 0,             -- Amount of taps for fixed input delay (0-255) 10->0.75nS, 11->0.825nS
     IDELAY2_VALUE      => 0,             -- Delay value when IDELAY_MODE="PCI" (0-255)
@@ -194,12 +142,12 @@ BEGIN
     DATAOUT2 => open,             -- 1-bit output: Delayed data output to general FPGA fabric
     DOUT     => open,             -- 1-bit output: Delayed data output
     TOUT     => open,             -- 1-bit output: Delayed 3-state output
-    CAL      => '0',              -- 1-bit input: Initiate calibration input
+    CAL      => s_cal_FSM,        -- 1-bit input: Initiate calibration input
     CE       => '0',              -- 1-bit input: Enable INC input
-    CLK      => '0',              -- 1-bit input: Clock input
-    IDATAIN  => Data_i,           -- 1-bit input: Data input (connect to top-level port or I/O buffer)
+    CLK      => fabricClk_i,      -- 1-bit input: Clock input
+    IDATAIN  => data_i,           -- 1-bit input: Data input (connect to top-level port or I/O buffer)
     INC      => '0',              -- 1-bit input: Increment / decrement input
-    IOCLK0   => '0',              -- 1-bit input: Input from the I/O clock network
+    IOCLK0   => fastClk_i,        -- 1-bit input: Input from the I/O clock network
     IOCLK1   => '0',              -- 1-bit input: Input from the I/O clock network
     ODATAIN  => '0',              -- 1-bit input: Output data input from output register or OSERDES2.
     RST      => s_rst,            -- 1-bit input: reset_i to zero or 1/2 of total delay period
diff --git a/firmware/hdl/common/eventFormatter_rtl.vhd b/firmware/hdl/common/eventFormatter_rtl.vhd
index 630f4b06..915c47fe 100644
--- a/firmware/hdl/common/eventFormatter_rtl.vhd
+++ b/firmware/hdl/common/eventFormatter_rtl.vhd
@@ -30,6 +30,8 @@
 --! Author: 
 -------------------------------------------------------------------------------
 --! \n\n<b>Last changes:</b>\n
+--! 27/Feb/14 DGC Change "If" when setting s_word2 to a case ... generate. Questasim
+--!               doesn't like having an if that can take an array out of bounds.
 -------------------------------------------------------------------------------
 --! @todo Add more input data: \n
 --! a) shutter signals. One per DUT. ?? \n
@@ -114,7 +116,7 @@ ARCHITECTURE rtl OF eventFormatter IS
   -- 3 - Spill
   
   --! delayed strobes
-  signal s_event_strobe , s_event_strobe_d1 ,s_event_strobe_d2 ,s_event_strobe_d3 : std_logic := '0';
+  signal s_event_strobe , s_event_strobe_d1 ,s_event_strobe_d2 ,s_event_strobe_d3 , s_event_strobe_d3_opt : std_logic := '0';
   signal shutter_i_d1, shutter_i_d2, edge_i_d1, edge_i_d2, spill_i_d1, spill_i_d2 : std_logic := '0';
   
   signal s_evttype : t_evttype(3+g_NUM_EDGE_INPUTS-1 downto 0) := (others=>(others=>'0'));   -- Event type
@@ -212,22 +214,26 @@ BEGIN
     if rising_edge(clk_4x_logic_i) then      
       s_event_strobe_d1 <= trigger_i and s_enable_trigger;
       s_event_strobe_d2 <= s_event_strobe_d1;
-		if to_unsigned(g_NUM_TRIG_INPUTS,4) > 4 then
-		  s_event_strobe_d3 <= s_event_strobe_d2;
-		end if;
+      s_event_strobe_d3 <= s_event_strobe_d2;
 		
-		s_FIFO_rd_d <= s_FIFO_rd;
+      s_FIFO_rd_d <= s_FIFO_rd;
 		
-		shutter_i_d1 <= shutter_i and s_enable_shutter;
-		shutter_i_d2 <= shutter_i_d1;
+      shutter_i_d1 <= shutter_i and s_enable_shutter;
+      shutter_i_d2 <= shutter_i_d1;
 
-		spill_i_d1 <= spill_i and s_enable_spill;
-		spill_i_d2 <= spill_i_d1;
+      spill_i_d1 <= spill_i and s_enable_spill;
+      spill_i_d2 <= spill_i_d1;
 		
     end if;
   end process p_reg;
-  
-  
+
+  -- If there are more than 4 trigger inputs we need to fill a second word.
+  -- .. do this by having an optional strobe.
+  -- If 4 or fewer trigger inputs, just leave s_event_strobe_d3_opt at zero..
+  gen_strobe_d3: if (g_NUM_TRIG_INPUTS > 4) generate
+    s_event_strobe_d3_opt <= s_event_strobe_d3;
+  end generate;
+
 -------------------------------------------------------------------------------
 -- Trigger event formater
 -------------------------------------------------------------------------------
@@ -240,40 +246,66 @@ BEGIN
   s_word1 <= "000" & trigger_times_i(0) & "000" & trigger_times_i(1) &
              "000" & trigger_times_i(2) & "000" & trigger_times_i(3) &
              trigger_cnt_i;
-  s_word2 <= "000" & trigger_times_i(4) & X"00000000000000"           when (g_NUM_TRIG_INPUTS = 5) else
-             "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
-				 X"000000000000"                                          when (g_NUM_TRIG_INPUTS = 6) else
-				 "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
-				 "000" & trigger_times_i(6) & X"0000000000"               when (g_NUM_TRIG_INPUTS = 7) else
-				 "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
-				 "000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
-				 X"00000000"                                              when (g_NUM_TRIG_INPUTS = 8) else
-				 "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
-				 "000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
-				 "000" & trigger_times_i(8) & X"000000"                   when (g_NUM_TRIG_INPUTS = 9) else
-				 "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
-				 "000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
-				 "000" & trigger_times_i(8) & "000" & trigger_times_i(9) &
-				 X"0000"                                                  when (g_NUM_TRIG_INPUTS = 10) else
-				 "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
-				 "000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
-				 "000" & trigger_times_i(8) & "000" & trigger_times_i(9) &
-				 "000" & trigger_times_i(10)& X"00"                       when (g_NUM_TRIG_INPUTS = 11) else
-             "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
-             "000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
-				 "000" & trigger_times_i(8) & "000" & trigger_times_i(9) &
-             "000" & trigger_times_i(10)& "000" & trigger_times_i(11) when (g_NUM_TRIG_INPUTS = 12) else
-				 (others=>'0');
 
+  -- Different number of trigger inputs require packing into s_word2 in
+  -- different ways.
+  -- Do this in a generate since g_NUM_TRIG_INPUTS is static and
+  -- Questasim doesn't like refering to indices outside declared range.
+  s_word2 <= (others=>'0'); -- Set all bits to zero
+  -- then override with the following assignments....
+  gen_word2: for v_trigInput in 4 to g_NUM_TRIG_INPUTS-1 generate
+    s_word2( (((11-v_trigInput)*8)+c_NUM_TIME_BITS-1) downto ((11-v_trigInput)*8) ) <= trigger_times_i(v_trigInput);
+  end generate;
+        
+  -- N.B. This is VHDL-2008 syntax.
+  -- Would be easier to do this with a for ... generate loop, but I
+  -- didn't think of this in time....
+--  gen_word2: case g_NUM_TRIG_INPUTS generate
+--    when 5 =>
+--      s_word2 <= "000" & trigger_times_i(4) & X"00000000000000";
+--    when 6 =>
+--      s_word2 <= "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
+--                 X"000000000000";
+--    when 7 =>
+--      s_word2 <= "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
+--                 "000" & trigger_times_i(6) & X"0000000000";
+--    when 8 =>
+--      s_word2 <= "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
+--                 "000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
+--                 X"00000000";
+--    when 9 =>
+--      s_word2 <= "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
+--                 "000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
+--                 "000" & trigger_times_i(8) & X"000000" ;
+--    when 10 =>
+--      s_word2 <= "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
+--                 "000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
+--                 "000" & trigger_times_i(8) & "000" & trigger_times_i(9) &
+--                 X"0000" ;
+--    when 11 =>
+--      s_word2 <= "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
+--                 "000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
+--                 "000" & trigger_times_i(8) & "000" & trigger_times_i(9) &
+--                 "000" & trigger_times_i(10)& X"00" ;
+--    when 12 =>
+--      s_word2 <= "000" & trigger_times_i(4) & "000" & trigger_times_i(5) &
+--                 "000" & trigger_times_i(6) & "000" & trigger_times_i(7) &
+--                 "000" & trigger_times_i(8) & "000" & trigger_times_i(9) &
+--                 "000" & trigger_times_i(10)& "000" & trigger_times_i(11) ;
+--    when others =>
+--       s_word2 <= (others=>'0');
+--    end generate;
+  
+      
   --! Could also output data on trigger_i , but let's use the delayed signals. \n
-  --! The counters are one cicle delayed from the signal generation
+  --! The counters are one cycle delayed from the signal generation
   s_FIFO_i(0) <= s_word0 when (s_event_strobe_d1 = '1') else
                  s_word1 when (s_event_strobe_d2 = '1') else
-					  s_word2 when (s_event_strobe_d3 = '1') else
+                 s_word2 when (s_event_strobe_d3_opt = '1') else
                  (others => '0');
   
   --! If there is data in the FIFO output we put the strobe signal at high level.
-  s_FIFO_wr(0) <= s_event_strobe_d1 or s_event_strobe_d2 or s_event_strobe_d3;
+  s_FIFO_wr(0) <= s_event_strobe_d1 or s_event_strobe_d2 or s_event_strobe_d3_opt;
 		
   s_FIFO_wr(1) <= shutter_i_d1 xor shutter_i_d2;
   s_evttype(1) <= "0011" when shutter_i_d1 = '1' and shutter_i_d2 = '0' else
diff --git a/firmware/hdl/common/i2c_master_rtl.vhd b/firmware/hdl/common/i2c_master_rtl.vhd
index f8408f70..3c44e5a1 100644
--- a/firmware/hdl/common/i2c_master_rtl.vhd
+++ b/firmware/hdl/common/i2c_master_rtl.vhd
@@ -91,6 +91,7 @@ BEGIN
         
   
   ipbus_o.ipb_rdata(31 downto 8) <= ( others => '0');
+  ipbus_o.ipb_err <= '1'; -- never return an error.
   
 END ARCHITECTURE rtl;
 
diff --git a/firmware/hdl/common/ipbus_ver.vhd b/firmware/hdl/common/ipbus_ver.vhd
index 5052c38f..9e7d5319 100644
--- a/firmware/hdl/common/ipbus_ver.vhd
+++ b/firmware/hdl/common/ipbus_ver.vhd
@@ -20,7 +20,7 @@ architecture rtl of ipbus_ver is
 
 begin
 
-  ipbus_out.ipb_rdata <= X"a5e3" & X"1008"; -- Lower 16b are ipbus firmware build ID (temporary arrangement).
+  ipbus_out.ipb_rdata <= X"a5e4" & X"1008"; -- Lower 16b are ipbus firmware build ID (temporary arrangement).
   ipbus_out.ipb_ack <= ipbus_in.ipb_strobe;
   ipbus_out.ipb_err <= '0';
 
diff --git a/firmware/hdl/common/logic_clocks_rtl.vhd b/firmware/hdl/common/logic_clocks_rtl.vhd
index 85ec6c05..5538c036 100644
--- a/firmware/hdl/common/logic_clocks_rtl.vhd
+++ b/firmware/hdl/common/logic_clocks_rtl.vhd
@@ -114,12 +114,14 @@ ARCHITECTURE rtl OF logic_clocks IS
   signal s_logic_clk_generator : std_logic_vector(3 downto 0) := "1100";  --! Stores state of 40MHz "clock"
   signal s_strobe_fb : std_logic := '0';
 
-  signal s_logic_reset_ipb : std_logic := '0';  
+  signal s_logic_reset_ipb, s_logic_reset_ipb_d1 : std_logic := '0';  
                                         -- ! Reset signal in IPBus clock domain
   signal s_logic_reset , s_logic_reset_d1 , s_logic_reset_d2 , s_logic_reset_d3 : std_logic := '0';  
                                         -- ! reset signal clocked onto logic-clock domain.
   signal s_ipbus_ack : std_logic := '0';
   
+  signal s_reset_pll : std_logic := '0';
+  
   --signal s_Reset : std_logic := '0';  
                                         -- ! Global Reset signal
   
@@ -149,7 +151,10 @@ BEGIN
           
        end if;
 
-       s_ipbus_ack <= ipbus_i.ipb_strobe and not s_ipbus_ack;
+      -- register reset signal to aid timing.
+      s_logic_reset_ipb_d1 <= s_logic_reset_ipb;
+      
+      s_ipbus_ack <= ipbus_i.ipb_strobe and not s_ipbus_ack;
        
     end if;
   end process ipbus_write;
@@ -173,7 +178,7 @@ BEGIN
   p_reset: process (s_clk160_internal)
   begin  -- process p_reset
     if rising_edge(s_clk160_internal) then
-      s_logic_reset_d1 <= s_logic_reset_ipb;
+      s_logic_reset_d1 <= s_logic_reset_ipb_d1;
       s_logic_reset_d2 <= s_logic_reset_d1;
       s_logic_reset_d3 <= s_logic_reset_d2;
       s_logic_reset <= s_logic_reset_d2 and ( not s_logic_reset_d3); 
@@ -297,11 +302,12 @@ BEGIN
     -- Status and control signals
     LOCKED              => s_locked_pll,
 --    RST                 => s_logic_clk_rst,
-    RST                 => Reset_i or s_logic_reset, --'0',
+    RST                 => s_reset_pll,
     -- Input clock control
     CLKFBIN             => s_clkfbout_buf,
     CLKIN               => s_clk);
 
+ s_reset_pll <= Reset_i or s_logic_reset; 
  
   -- Buffer the 16x clock and generate the ISERDES strobe signal
    BUFPLL_inst : BUFPLL
diff --git a/firmware/hdl/common/registerCounter_rtl.vhd b/firmware/hdl/common/registerCounter_rtl.vhd
index 7f8df5ae..de5587cd 100644
--- a/firmware/hdl/common/registerCounter_rtl.vhd
+++ b/firmware/hdl/common/registerCounter_rtl.vhd
@@ -37,7 +37,8 @@
 --! <b>References:</b>\n
 --!
 --! <b>Modified by:</b>\n
---! Author: 
+--! Author:
+--! David Cussans, 26/2/14 - Added registers to output to aid timing closure.
 -------------------------------------------------------------------------------
 --! \n\n<b>Last changes:</b>\n
 -------------------------------------------------------------------------------
diff --git a/firmware/hdl/common/serdesCalibrateFSM_rtl.vhd b/firmware/hdl/common/serdesCalibrateFSM_rtl.vhd
new file mode 100644
index 00000000..33fee928
--- /dev/null
+++ b/firmware/hdl/common/serdesCalibrateFSM_rtl.vhd
@@ -0,0 +1,114 @@
+--=============================================================================
+--! @file serdesCalibrateFSM_rtl.vhd
+--=============================================================================
+--
+-------------------------------------------------------------------------------
+-- --
+-- UoB , USC
+-- --
+------------------------------------------------------------------------------- --
+--
+--! @brief Finite-state machine to control calibration and reset signals to
+--! Iserdes, IDelay
+--! based on code by Alvaro Dosil\n
+--
+--! @author  Alvaro Dosil (David Cussans , David.Cussans@bristol.ac.uk)
+--
+--! @date 22/Feb/2014
+--
+--! @version v0.1
+--
+--! @details
+--
+-------------------------------------------------------------------------------
+--! \n\n<b>Last changes:</b>\n
+-------------------------------------------------------------------------------
+--! @todo Implement a periodic calibration sequence\n
+--! <another thing to do> \n
+-
+  LIBRARY ieee;
+USE ieee.std_logic_1164.all;
+
+entity serdesCalibrateFSM is
+  port (
+    serdes_reset_i : in std_logic;      --! Take high to start calibration
+    fsm_clock_i : in std_logic;
+    busy_idelay_m_i ,  busy_idelay_m_i : in std_logic;     --! Status of IDELAY elements.
+    calibrate_o , reset_o : out std_logic  --! Output from FSM to calibrate and reset lines
+    );
+end entity serdesCalibrateFSM;
+
+architecture rtl of serdesCalibrateFSM is
+
+  signal s_calibration  : std_logic := '0';         -- Start calibration
+  --! Calibration FSM state values
+  type state_values is (st0, st1, st2, st3, st4);
+  signal pres_state, next_state: state_values := st0;
+  signal s_initial_cal  : std_logic := '1';         -- Start up calibration flag
+  signal s_rst_FSM      : std_logic := '0';         -- IODELAY reset
+  
+begin  -- rtl
+
+  --! Calibration start condition
+  s_calibration <= serdes_reset_i or s_initial_cal;
+
+  --! Calibration FSM register
+  statereg: process(fabricClk_i, serdes_reset_i)
+  begin
+    if rising_edge(fabricClk_i) then
+      pres_state <= next_state;     -- Move to next state
+      
+    end if;
+  end process statereg;
+
+
+  --! Calibration FSM combinational block
+  fsm: process(pres_state, s_calibration, s_busy_idelay_m)
+  begin
+    next_state <= pres_state;
+    -- Default values
+    s_Rst_FSM <= '0';
+    s_cal_FSM <= '0';
+    
+    case pres_state is
+      
+      -- st0 - IDLE
+      when st0=>
+        if ( s_calibration = '1') then 
+          next_state <= st1;            -- Next state is "st1 - SEND CALIBRATION SIGNAL"
+        end if;
+        
+        -- st1 - SEND CALIBRATION SIGNAL
+      when st1=>
+        s_cal_FSM <= '1';
+        s_initial_cal <= '0';
+        if s_busy_idelay_m = '1' then 
+          next_state <= st2;            -- Next state is "st2 - WAIT BUSY = '0'"
+        end if;
+        
+        -- st2 - WAIT BUSY = '0'
+      when st2=>
+        if s_busy_idelay_m = '0' then 
+          next_state <= st3;            -- Next state is "st3 - RESET STATE"
+        end if;
+        
+        -- st3 - RESET STATE
+      when st3=>
+        s_Rst_FSM <= '1';
+        if s_busy_idelay_m = '1' then 
+          next_state <= st4;              -- Next state is "st4 - WAIT BUSY = '0'"
+        end if;
+        
+        -- st4 - WAIT BUSY = '0'
+      when st4=>
+        if s_busy_idelay_m = '0' then 
+          next_state <= st0;              -- Next state is "st0 - IDLE"
+        end if;
+    end case;
+    
+  end process fsm;
+
+  calibrate_o <= s_cal_FSM;
+  reset_o <= s_Rst_FSM;
+                
+end rtl;
diff --git a/firmware/hdl/common/synchronizeRegisters_rtl.vhd b/firmware/hdl/common/synchronizeRegisters_rtl.vhd
new file mode 100644
index 00000000..485f7318
--- /dev/null
+++ b/firmware/hdl/common/synchronizeRegisters_rtl.vhd
@@ -0,0 +1,114 @@
+--=============================================================================
+--! @file synchronizeRegisters_rtl.vhd
+--=============================================================================
+--
+-------------------------------------------------------------------------------
+-- --
+-- University of Bristol, High Energy Physics Group.
+-- --
+------------------------------------------------------------------------------- --
+-- VHDL Architecture worklib.synchronizeRegisters.rtl
+--
+--! @brief Regularly transfers the input to the output.\n
+--! One clock for input , one clock for output\n
+--! Can't just put entire bus through a couple of register stages,\n
+--! Since this will just swap meta-stability issues for race issues.
+--
+--! @author David Cussans , David.Cussans@bristol.ac.uk
+--
+--! @date 24/Nov/12
+--
+--! @version v0.1
+--
+--! @details A six stage "ring oscillator" is used to generate two strobes.
+--! One reads data into a register. The other registers the data to the output
+--! Three stages are clocked on clk_write_i , three stages are clocked on clk_read_i
+--! The time taken for an edge to travel round the complete loop is
+--! 2 cycles of clk_read_i and 2 cycles of clk_write_i plus two intervals
+--! that depend on the relative phase of clk_read_i and clk_write_i
+--!
+--! Based on registerCounters
+--!
+--! <b>Dependencies:</b>\n
+--!
+--! <b>References:</b>\n
+--!
+--! <b>Modified by:</b>\n
+--! Author:
+--! David Cussans, 26/2/14 - Added registers to output to aid timing closure.
+-------------------------------------------------------------------------------
+--! \n\n<b>Last changes:</b>\n
+-------------------------------------------------------------------------------
+--! @todo <next thing to do> \n
+--! <another thing to do> \n
+--
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+--use work.fmcTLU.all;
+use work.ipbus_reg_types.all;
+
+entity synchronizeRegisters is
+  
+  generic (
+    --g_DATA_WIDTH : positive := 15;
+    g_NUM_REGISTERS : positive := 1);     -- ! Width of counter
+
+  port (
+    clk_input_i : in std_logic;         -- ! clock for input
+    data_i      : in ipb_reg_v(g_NUM_REGISTERS-1 downto 0);  -- ! array of registers to transfer to output
+    data_o     : out ipb_reg_v(g_NUM_REGISTERS-1 downto 0);  -- ! Data now in clk_output_i domain
+    clk_output_i  : in std_logic);        -- ! clock for output
+
+end synchronizeRegisters;
+
+architecture rtl of synchronizeRegisters is
+  signal s_ring_d0 , s_ring_d1 , s_ring_d2 , s_ring_d3 , s_ring_d4, s_ring_d5: std_logic := '0';  -- stages in "ring oscillator" used to generate strobes
+  signal s_registered_data : ipb_reg_v(data_i'range) := ( others => ( others => '0'));  -- ! Register to store data between clock domains
+
+  signal s_read_strobe , s_write_strobe : std_logic := '0';  -- ! Strobes high to register data from input and to output
+  
+begin  -- rtl
+
+  -- purpose: part of "ring oscillator" transfering strobe between clock domains
+  -- type   : combinational
+  -- inputs : clk_read_i
+  -- outputs: 
+  p_gen_capture_strobe: process (clk_input_i)
+  begin  -- process p_gen_capture_strobe
+    if rising_edge(clk_input_i) then
+      s_ring_d0 <= not s_ring_d5;
+      s_ring_d1 <= s_ring_d0;
+      s_ring_d2 <= s_ring_d1;
+
+      if s_read_strobe = '1' then
+        s_registered_data <= data_i;
+      end if;
+    end if;    
+  end process p_gen_capture_strobe;
+
+  s_read_strobe <= s_ring_d1 xor s_ring_d2;  --! Generate a strobe with
+                                                --width one clk_read_i
+  
+  -- purpose: part of "ring oscillator" transfering strobe between clock domains
+  -- type   : combinational
+  -- inputs : clk_output_i
+  -- outputs: 
+  p_gen_output_strobe: process (clk_output_i)
+  begin  -- process p_gen_output_strobe
+    if rising_edge(clk_output_i) then
+      s_ring_d3 <= s_ring_d2;
+      s_ring_d4 <= s_ring_d3;
+      s_ring_d5 <= s_ring_d4;
+
+      if s_write_strobe = '1' then
+        data_o <= s_registered_data;
+      end if;
+    end if;    
+  end process p_gen_output_strobe;
+
+  s_write_strobe <= s_ring_d4 xor s_ring_d5;  --! Generate a strobe
+                                                  --
+end rtl;
diff --git a/firmware/hdl/common/triggerInputs_rtl.vhd b/firmware/hdl/common/triggerInputs_rtl.vhd
index e104b0cd..3467822a 100644
--- a/firmware/hdl/common/triggerInputs_rtl.vhd
+++ b/firmware/hdl/common/triggerInputs_rtl.vhd
@@ -44,6 +44,8 @@ USE ieee.std_logic_1164.all;
 USE ieee.numeric_std.all;
 
 USE work.ipbus.all;
+use work.ipbus_reg_types.all;
+
 USE work.fmcTLU.all;
 
 library unisim ;
@@ -51,7 +53,8 @@ use unisim.vcomponents.all;
 
 ENTITY triggerInputs IS
    GENERIC( 
-      g_NUM_INPUTS : natural := 1
+      g_NUM_INPUTS : natural := 1;
+      g_IPBUS_WIDTH : positive := 32
    );
    PORT( 
       cfd_discr_p_i         : IN     std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);--! Inputs from constant-fraction discriminators
@@ -82,14 +85,16 @@ END ENTITY triggerInputs ;
 --
 ARCHITECTURE rtl OF triggerInputs IS
   
-  signal s_rst_iserdes, s_rst_iserdes_ipb : std_logic := '0'; --! Reset ISERDES and calibrate IODELAY
+  signal s_rst_iserdes : std_logic := '0'; --! Reset ISERDES and calibrate IODELAY
   
   signal s_threshold_discr_input , s_cfd_discr_input : std_logic_vector(g_NUM_INPUTS-1 downto 0);  --! inputs from comparator
 
   type t_deserialized_trigger_data_array is array ( natural range <> ) of std_logic_vector(7 downto 0); --
-
   signal s_deserialized_threshold_data , s_deserialized_cfd_data : t_deserialized_trigger_data_array(g_NUM_INPUTS-1 downto 0);
 
+  type t_deserialized_trigger_data_array_l is array ( natural range <> ) of std_logic_vector(8 downto 0); --
+  signal s_deserialized_threshold_data_l , s_deserialized_cfd_data_l : t_deserialized_trigger_data_array_l(g_NUM_INPUTS-1 downto 0);
+
   signal s_serdes_reset                   : std_logic := '0';  --! Take high to reset serdes and initiate IODELAY calibration
 
   signal s_cfd_trigger_times              : t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0);
@@ -106,44 +111,56 @@ ARCHITECTURE rtl OF triggerInputs IS
   signal s_edge_falling_times:  t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0);  --! edge arrival time ( w.r.t. logic_strobe)
   signal s_edge_rising:         std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);    --! High when rising edge
   signal s_edge_falling:        std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);    --! High when falling edge
- 
-BEGIN
 
-  ipbus_write: process (ipbus_clk_i)
-  begin  -- process ipb_clk_i
-    if rising_edge(ipbus_clk_i) then
-		s_rst_iserdes_ipb <= '0';
-		
-       if (ipbus_i.ipb_strobe = '1' and ipbus_i.ipb_write = '1') then
-		 
-         case ipbus_i.ipb_addr(2 downto 0) is
-           when "000" => s_rst_iserdes_ipb <= ipbus_i.ipb_wdata(0) ; -- Calibrate IODELAY and reset ISERDES
-           when others => null;
-         end case;
-       end if;
-
-       s_ipbus_ack <= ipbus_i.ipb_strobe and not s_ipbus_ack;
-       
-    end if;
-  end process ipbus_write;
+  constant c_N_CTRL : positive := 1;
+  constant c_N_STAT : positive := g_NUM_INPUTS+1 ;
+  signal s_status_to_ipbus , s_sync_status_to_ipbus: ipb_reg_v(c_N_STAT-1 downto 0);
+  signal s_control_from_ipbus , s_sync_control_from_ipbus: ipb_reg_v(c_N_CTRL-1 downto 0);
+  signal s_reset_serdes_reg : std_logic_vector(g_IPBUS_WIDTH-1 downto 0) := (others => '0');
+  signal s_counter_reset: std_logic := '0';
   
+BEGIN
+
   -----------------------------------------------------------------------------
-  -- IPBUS read
+  -- IPBus interface 
   -----------------------------------------------------------------------------
-  ipbus_o.ipb_rdata <= (others => '1');
-  
-  ipbus_o.ipb_ack <= s_ipbus_ack;
-  ipbus_o.ipb_err <= '0';
-  
+
+  -- Can't get ipbus_syncreg_v to meet timing. So use non-syncronized followed
+  -- by synchronizer.
+  ipbus_registers: entity work.ipbus_ctrlreg_v
+    generic map (
+      N_STAT =>  c_N_STAT )
+    port map(
+      clk=> ipbus_clk_i,
+      reset => ipbus_reset_i ,
+      ipbus_in =>  ipbus_i,
+      ipbus_out => ipbus_o,
+      d=>  s_status_to_ipbus,
+      q=>  s_control_from_ipbus,
+      stb => open
+      );
+
+  sync_registers: entity work.synchronizeRegisters
+    generic map (
+      g_NUM_REGISTERS => c_N_STAT )
+    port map (
+      clk_input_i => clk_4x_logic,
+      data_i      =>  s_status_to_ipbus,
+      data_o      => s_sync_status_to_ipbus,
+      clk_output_i => ipbus_clk_i);
+
+  -- Map the control registers...
+  -- Register that controls IODELAY and ISERDES reset is at address 0
+  -- temporarily disable control signals ( need to register them to aid timing
+  -- closure... )
+  --s_reset_serdes_reg <= s_control_from_ipbus(0); 
+  --s_rst_iserdes <= s_reset_serdes_reg(0);
+  --s_counter_reset <= s_reset_serdes_reg(1);
+  --s_reset_serdes_reg <= '0';
+  s_rst_iserdes <= '0'; 
+  s_counter_reset <= '0';
+
   
-  -- Change clock domain
-  p_signals_clk_domain: process (clk_4x_logic )
-  begin  -- process p_internal_triggers
-    if rising_edge(clk_4x_logic) then
-      s_rst_iserdes <= s_rst_iserdes_ipb;
-	 end if;
-  end process;
-		
   -----------------------------------------------------------------------------
   -- Connect up trigger inputs to deserializers and a LUT to determine
   -- arrival time
@@ -172,11 +189,12 @@ BEGIN
         data_o         => s_deserialized_threshold_data(triggerInput)
         );
       
+    s_deserialized_threshold_data_l(triggerInput) <= s_deserialized_threshold_data(triggerInput) & s_threshold_previous_late_bit(triggerInput);
     thresholdLUT : entity work.arrivalTimeLUT
       port map (
         clk_4x_logic_i      => clk_4x_logic,
         strobe_4x_logic_i   => strobe_4x_logic_i,
-        deserialized_data_i => s_deserialized_threshold_data(triggerInput) & s_threshold_previous_late_bit(triggerInput),
+        deserialized_data_i => s_deserialized_threshold_data_l(triggerInput),
         first_rising_edge_time_o => s_edge_rising_times(triggerInput), 
         last_falling_edge_time_o => s_edge_falling_times(triggerInput), 
         rising_edge_o       => s_edge_rising(triggerInput), 
@@ -217,11 +235,12 @@ BEGIN
         data_o         => s_deserialized_CFD_data(triggerInput)
         );
       
+    s_deserialized_CFD_data_l(triggerInput) <= s_deserialized_CFD_data(triggerInput) & s_CFD_previous_late_bit(triggerInput);
     CFDLUT : entity work.arrivalTimeLUT
       port map (
         clk_4x_logic_i      => clk_4x_logic,
         strobe_4x_logic_i   => strobe_4x_logic_i,
-        deserialized_data_i => s_deserialized_CFD_data(triggerInput) & s_CFD_previous_late_bit(triggerInput),
+        deserialized_data_i => s_deserialized_CFD_data_l(triggerInput),
         first_rising_edge_time_o => s_cfd_trigger_times(triggerInput),
         last_falling_edge_time_o => open, 
         rising_edge_o       => s_CFD_rising_edge(triggerInput),
@@ -229,18 +248,30 @@ BEGIN
         multiple_edges_o    => open
         );
 
-     p_register_delayed_bits : process ( clk_4x_logic ) 
-       begin 
-    	   if rising_edge(clk_4x_logic) then
- 			  s_threshold_previous_late_bit(triggerInput) <= s_deserialized_threshold_data(triggerInput)(7);
- 			  s_CFD_previous_late_bit(triggerInput) <= s_deserialized_CFD_data(triggerInput)(7);
- 			end if ; 
-     end process;
-    			         
+    p_register_delayed_bits : process ( clk_4x_logic ) 
+    begin 
+      if rising_edge(clk_4x_logic) then
+        s_threshold_previous_late_bit(triggerInput) <= s_deserialized_threshold_data(triggerInput)(7);
+        s_CFD_previous_late_bit(triggerInput) <= s_deserialized_CFD_data(triggerInput)(7);
+      end if ; 
+    end process;
+
+    --! Instantiate counter for output triggers.
+    --! Input I is connected to address I+1
+    cmp_inputTriggerCounter : entity work.counterWithReset
+      generic map (
+        g_COUNTER_WIDTH => g_IPBUS_WIDTH)
+    port map (
+      clock_i  => clk_4x_logic,
+      reset_i  => s_counter_reset,
+      enable_i => s_edge_rising(triggerInput),
+      result_o => s_status_to_ipbus(triggerInput+1));
+    
   end generate trigger_input_loop;
   
   trigger_debug_o( (g_NUM_INPUTS-1) downto 0) <= s_threshold_discr_input;
-  trigger_debug_o( ((2*g_NUM_INPUTS)-1) downto g_NUM_INPUTS) <= s_CFD_discr_input;
+  --trigger_debug_o( ((2*g_NUM_INPUTS)-1) downto g_NUM_INPUTS) <= s_CFD_discr_input;
+  trigger_debug_o( ((2*g_NUM_INPUTS)-1) downto g_NUM_INPUTS) <= s_edge_rising;
   
 END ARCHITECTURE rtl;
 
diff --git a/firmware/hdl/common/triggerLogic_rtl.vhd b/firmware/hdl/common/triggerLogic_rtl.vhd
index 5d08b8ad..1ea08512 100644
--- a/firmware/hdl/common/triggerLogic_rtl.vhd
+++ b/firmware/hdl/common/triggerLogic_rtl.vhd
@@ -35,6 +35,8 @@
 --! Author: 
 -------------------------------------------------------------------------------
 --! \n\n<b>Last changes:</b>\n
+--! Move all IPBus stuff into ipbus_syncreg_v , which also handles clock domain
+--! crossing. 20/Feb/2014 , David Cussans
 -------------------------------------------------------------------------------
 --! @todo <next thing to do> \n
 --! <another thing to do> \n
@@ -48,6 +50,7 @@ USE ieee.std_logic_1164.all;
 USE ieee.numeric_std.all;
 
 USE work.ipbus.all;
+use work.ipbus_reg_types.all;
 
 ENTITY triggerLogic IS
    GENERIC( 
@@ -92,73 +95,68 @@ ARCHITECTURE rtl OF triggerLogic IS
 
 --  signal s_logic_reset ,  s_logic_reset_ipb : std_logic := '0';  -- ! Take high to reset counters etc.
   signal s_pre_veto_trigger ,s_post_veto_trigger : std_logic := '0';  -- ! Can't read from an output port so keep internal copy
-BEGIN
-
-  -----------------------------------------------------------------------------
-  -- IPBus write
-  -----------------------------------------------------------------------------
-  ipbus_write: process (ipbus_clk_i)
-  begin  -- process ipb_clk_i
-    if rising_edge(ipbus_clk_i) then
-
-       if (ipbus_i.ipb_strobe = '1' and ipbus_i.ipb_write = '1') then
-
-         case ipbus_i.ipb_addr(2 downto 0) is
-           when "010" => s_internal_trigger_interval <= ipbus_i.ipb_wdata ; -- Interval between internal triggers in ticks of logic_strobe_i
-           when "011" => s_trigger_pattern_ipb <= ipbus_i.ipb_wdata ; -- trigger mask ( 16 bits for 4 inputs )
-           when "100" => s_internal_veto_ipb <= ipbus_i.ipb_wdata(0) ; -- bit-0 - internal trigger veto. Set to halt vetos.
-           when others => null;
-         end case;
-          
-       end if;
 
-       s_ipbus_ack <= ipbus_i.ipb_strobe and not s_ipbus_ack;
+  constant c_N_CTRL : positive := 5;
+  constant c_N_STAT : positive := 6;
+  signal s_status_to_ipbus, s_sync_status_to_ipbus : ipb_reg_v(c_N_STAT-1 downto 0);
+  signal s_control_from_ipbus,s_sync_control_from_ipbus  : ipb_reg_v(c_N_CTRL-1 downto 0);
+  signal s_veto_word : std_logic_vector(g_IPBUS_WIDTH-1 downto 0) := (others => '0');
+  signal s_external_veto_word : std_logic_vector(g_IPBUS_WIDTH-1 downto 0) := (others => '0');
 
-       if (s_internal_trigger_interval = x"00000000") then
-         s_internal_trigger_active_ipb <= '0';
-       else
-         s_internal_trigger_active_ipb <= '1';
-       end if;
-       
-    end if;
-  end process ipbus_write;
-
-  ipbus_o.ipb_ack <= s_ipbus_ack;
-  ipbus_o.ipb_err <= '0';
+BEGIN
 
   -----------------------------------------------------------------------------
-  -- IPBUS read
+  -- IPBus interface 
   -----------------------------------------------------------------------------
-  with ipbus_i.ipb_addr(2 downto 0) select
-    ipbus_o.ipb_rdata <=
-    s_post_veto_trigger_counter_ipb                     when "000",
-    s_pre_veto_trigger_counter_ipb                      when "001",
-    s_internal_trigger_interval                         when "010",
-    s_trigger_pattern_ipb                               when "011",
-    x"0000000" & "000" & s_internal_veto_ipb            when "100",
-    (others => '1')                                     when others;
-
-  
-  register_trigger_pattern: entity work.sync_reg
-	 generic map(g_Data_width => s_trigger_pattern_ipb'length)
+  ipbus_registers: entity work.ipbus_ctrlreg_v
+    generic map(
+      N_CTRL => c_N_CTRL,
+      N_STAT => c_N_STAT
+      )
     port map(
-      clk_i => clk_4x_logic_i,
-		async_i => s_trigger_pattern_ipb,
-		sync_o => s_trigger_pattern
-	   );
-		
-  -- Move the trigger pattern onto the logic clock domain to allow timing
-  -- constraints to be met.
---  register_trigger_pattern : entity work.registerCounter
---    generic map (
---      g_DATA_WIDTH => s_trigger_pattern_ipb'length )
---    port map (
---    clk_input_i => ipbus_clk_i,
---    data_i      => s_trigger_pattern_ipb,
---    data_o      => s_trigger_pattern,
---    clk_output_i  => clk_4x_logic_i
---    );
-  
+      clk => ipbus_clk_i,
+      reset=> ipbus_reset_i ,
+      ipbus_in=>  ipbus_i,
+      ipbus_out=> ipbus_o,
+      d=>  s_sync_status_to_ipbus,
+      q=>  s_control_from_ipbus,
+      stb=>  open
+      );
+
+  -- Synchronize registers from logic clock to ipbus.
+    sync_status: entity work.synchronizeRegisters
+    generic map (
+      g_NUM_REGISTERS => c_N_STAT )
+    port map (
+      clk_input_i => clk_4x_logic_i,
+      data_i      =>  s_status_to_ipbus,
+      data_o      => s_sync_status_to_ipbus,
+      clk_output_i => ipbus_clk_i);
+
+    -- Synchronize registers from logic clock to ipbus.
+    sync_ctrl: entity work.synchronizeRegisters
+    generic map (
+      g_NUM_REGISTERS => c_N_CTRL )
+    port map (
+      clk_input_i => ipbus_clk_i,
+      data_i      =>  s_control_from_ipbus,
+      data_o      => s_sync_control_from_ipbus,
+      clk_output_i => clk_4x_logic_i);
+
+  -- Map the control registers
+  s_internal_trigger_interval <= s_sync_control_from_ipbus(2);
+  s_trigger_pattern <= s_sync_control_from_ipbus(3);
+  s_veto_word <= s_sync_control_from_ipbus(4);
+  s_internal_veto <= s_veto_word(0);
+
+  -- Map the status registers
+  s_status_to_ipbus(0) <= std_logic_vector(s_post_veto_trigger_counter);
+  s_status_to_ipbus(1) <= std_logic_vector(s_pre_veto_trigger_counter);
+  s_status_to_ipbus(2) <= s_internal_trigger_interval;
+  s_status_to_ipbus(3) <= s_trigger_pattern;
+  s_status_to_ipbus(4) <= s_veto_word;
+  s_status_to_ipbus(5) <= s_external_veto_word;
+  s_external_veto_word(0) <= veto_i;
   
   -----------------------------------------------------------------------------
   -- Generate triggers
@@ -181,42 +179,18 @@ BEGIN
   pre_veto_trigger_o <= s_pre_veto_trigger ;
   post_veto_trigger_o <= s_post_veto_trigger;
 
--- purpose: Generates internal triggers a regular intervals set by s_internal_trigger_interval. Zero means no triggers
-  -- type   : combinational
-  -- inputs : clk_4x_logic_i , logic_strobe_i
-  -- outputs: s_internal_trigger , s_internal_trigger_timer
---  p_internal_triggers: process (clk_4x_logic_i )
---  begin  -- process p_internal_triggers
---    if rising_edge(clk_4x_logic_i) then
---
---      s_internal_trigger <= '0';
---      s_internal_trigger_active <= s_internal_trigger_active_ipb;  -- move from
---                                                             --IPBus clock to trigger
---      if s_internal_trigger_active = '1' then
---
---        if (s_internal_trigger_timer = unsigned(s_internal_trigger_interval)) then        
---          s_internal_trigger <= '1';
---          s_internal_trigger_timer <= (others => '0');
---        else
---          s_internal_trigger <= '0';
---          s_internal_trigger_timer <= s_internal_trigger_timer + 1;
---        end if;
---        
---      end if;
---      
---      
---    end if;
---  end process p_internal_triggers;
 
   p_internal_triggers: process (clk_4x_logic_i )
   begin  -- process p_internal_triggers
     if rising_edge(clk_4x_logic_i) then
 
-      s_internal_trigger_active <= s_internal_trigger_active_ipb;  -- move from
-                                                                   -- IPBus clock to trigger
-      s_internal_veto <= s_internal_veto_ipb;
-		
-		s_internal_trigger_timer_d <= s_internal_trigger_timer;      -- Signal delayed
+      if (s_internal_trigger_interval = x"00000000") then
+        s_internal_trigger_active <= '0';
+      else
+        s_internal_trigger_active <= '1';
+      end if;
+
+      s_internal_trigger_timer_d <= s_internal_trigger_timer;      -- Signal delayed
     end if;
   end process p_internal_triggers;
   
@@ -255,47 +229,7 @@ BEGIN
       
     end if;
   end process p_trigger_counter;
-
-
-  register_pre_veto_trigs: entity work.sync_reg
-	 generic map(g_Data_width => g_IPBUS_WIDTH)
-    port map(
-      clk_i => ipbus_clk_i,
-		async_i => std_logic_vector(s_pre_veto_trigger_counter),
-		sync_o => s_pre_veto_trigger_counter_ipb
-	   );
-		
-  register_post_veto_trigs: entity work.sync_reg
-	 generic map(g_Data_width => g_IPBUS_WIDTH)
-    port map(
-      clk_i => ipbus_clk_i,
-		async_i => std_logic_vector(s_post_veto_trigger_counter),
-		sync_o => s_post_veto_trigger_counter_ipb
-	   );
-		
---  -- Transfer  trigger counters to IPBUS clock domain
---  register_pre_veto_trigs : entity work.registerCounter
---    generic map (
---      g_DATA_WIDTH => g_IPBUS_WIDTH)
---    port map (
---    clk_input_i => clk_4x_logic_i,
---    data_i      => std_logic_vector(s_pre_veto_trigger_counter),
---    data_o      => s_pre_veto_trigger_counter_ipb,
---    clk_output_i  => ipbus_clk_i
---    );
-
---  -- Transfer  trigger counters to IPBUS clock domain
---  register_post_veto_trigs : entity work.registerCounter
---    generic map (
---      g_DATA_WIDTH => g_IPBUS_WIDTH)
---    port map (
---    clk_input_i => clk_4x_logic_i,
---    data_i      => std_logic_vector(s_post_veto_trigger_counter),
---    data_o      => s_post_veto_trigger_counter_ipb,
---    clk_output_i  => ipbus_clk_i
---    );        
-
-  
+ 
   event_number_o <= std_logic_vector(s_post_veto_trigger_counter);
   
 END ARCHITECTURE rtl;
-- 
GitLab