triggerInputs_rtl.vhd 15.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
--=============================================================================
--! @file triggerInputs_rtl.vhd
--=============================================================================
--
-------------------------------------------------------------------------------
-- --
-- University of Bristol, High Energy Physics Group.
-- --
------------------------------------------------------------------------------- --
-- VHDL Architecture fmc_mTLU_lib.triggerInputs.rtl
--
--! @brief Measures arrival time of trigger pulses using two deserializers
--! clocked on 14x clock ( 640MHz) \n
--! Based on TDC code by Alvaro Dosil\n
--
--! @author David Cussans , David.Cussans@bristol.ac.uk
--!
--
--! @date 15:43:57 11/08/12
--
--! @version v0.1
--
--! @details
--! IPBus address 0 = control and status
--! bit0 = reset serdes
--! bit1 = reset counter
--! bit2 = calibrate IDELAYs
--! bit3 = not connected
--!
--! bit4 = Thresh discr  IDelay(0) status prompt
--! bit5 = Thresh discr  IDelay(0) status delayed
--! bit6 = Thresh discr  IDelay(1) status prompt
--! bit7 = Thresh discr  IDelay(1) status delayed
--! bit8 = Thresh discr  IDelay(2) status prompt
--! bit9 = Thresh discr  IDelay(2) status delayed
--! bit10= Thresh discr  IDelay(3) status prompt
--! bit11= Thresh discr  IDelay(3) status delayed
--!
--! bit12= CFD discr  IDelay(0) status prompt
--! bit13= CFD discr  IDelay(0) status delayed
--! bit14= CFD discr  IDelay(1) status prompt
--! bit15= CFD discr  IDelay(1) status delayed
--! bit16= CFD discr  IDelay(2) status prompt
--! bit17= CFD discr  IDelay(2) status delayed
--! bit18= CFD discr  IDelay(3) status prompt
--! bit19= CFD discr  IDelay(3) status delayed
--!
--! bit20= Thresh deserialized data monitor(0)
--! bit21= Thresh deserialized data monitor(1)
--! bit22= Thresh deserialized data monitor(2)
--! bit23= Thresh deserialized data monitor(3)
--! bit24= CFD deserialized data monitor(0)
--! bit25= CFD deserialized data monitor(1)
--! bit26= CFD deserialized data monitor(2)
--! bit27= CFD deserialized data monitor(3)
--!
--! IPBus address 1 = edge rising(0) counter
--! IPBus address 2 = edge rising(1) counter
--! IPBus address 3 = edge rising(2) counter
--! IPBus address 4 = edge rising(3) counter
--!
--! <b>Dependencies:</b>\n
--!
--! <b>References:</b>\n
--!
--! <b>Modified by: Alvaro Dosil , alvaro.dosil@usc.es </b>\n
--! Author: 
-------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n
-------------------------------------------------------------------------------
--! @todo Implement a periodic calibration sequence \n
--! <another thing to do> \n
--
--------------------------------------------------------------------------------
-- 
-- Created using using Mentor Graphics HDL Designer(TM) 2010.3 (Build 21)
--
LIBRARY ieee;
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 ;
use unisim.vcomponents.all;

ENTITY triggerInputs IS
   GENERIC( 
      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
      cfd_discr_n_i       	: IN     std_logic_vector (g_NUM_INPUTS-1 downto 0);--! Input from CFD
      clk_4x_logic          : IN     std_logic; --! Rising edge active. By default = 4*40MHz = 160MHz
      strobe_4x_logic_i     : IN     std_logic;                                     --! Pulses high once every 4 cycles of clk_4x_logic
      threshold_discr_p_i   : IN     std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);    --! inputs from threshold comparators
      threshold_discr_n_i 	: IN     std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);    --! inputs from threshold comparators
		reset_i					: IN 		std_logic;
      trigger_times_o     	: OUT    t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0);  --! trigger arrival time ( w.r.t. logic_strobe)
      trigger_o           	: OUT    std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);--!  Goes high on leading edge of trigger, in sync with clk_4x_logic_i
      trigger_debug_o     	: OUT    std_logic_vector ( ((2*g_NUM_INPUTS)-1) DOWNTO 0);    --! Copy of input trigger level. High bits CFD, Low threshold
      edge_rising_times_o   : OUT    t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0);  --! edge arrival time ( w.r.t. logic_strobe)
      edge_falling_times_o  : OUT    t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0);  --! edge arrival time ( w.r.t. logic_strobe)
      edge_rising_o         : OUT    std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0); --! High when rising edge. Syncronous with clk_4x_logic_i
      edge_falling_o        : OUT    std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);    --! High when falling edge
      ipbus_clk_i           : IN     std_logic;
      ipbus_reset_i         : IN     std_logic;
      ipbus_i               : IN     ipb_wbus;                                      --! Signals from IPBus core to slave
      ipbus_o               : OUT    ipb_rbus;                                      --! signals from slave to IPBus core
      clk_16x_logic_i       : IN     std_logic;                                     --! 640MHz clock ( 16x 40MHz )
      strobe_16x_logic_i    : IN     std_logic                                      --! Pulses one cycle every 4 of 16x clock.
   );

-- Declarations

END ENTITY triggerInputs ;

--
ARCHITECTURE rtl OF triggerInputs IS
  
  signal s_rst_iserdes : std_logic := '0'; --! Reset ISERDES and IDELAY
  
  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_threshold_data_d , s_deserialized_cfd_data, s_deserialized_cfd_data_d : 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_cfd_trigger_times              : t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0);
  
  signal s_CFD_rising_edge                : std_logic_vector(g_NUM_INPUTS-1 downto 0); 
  signal s_CFD_falling_edge               : std_logic_vector(g_NUM_INPUTS-1 downto 0); 
  
  signal s_threshold_previous_late_bit    : std_logic_vector(g_NUM_INPUTS-1 downto 0) := (others => '0');  -- last bit to arrive from previous 4
  signal s_CFD_previous_late_bit          : std_logic_vector(g_NUM_INPUTS-1 downto 0) := (others => '0');  -- last bit to arrive from previous 4
  
  signal s_ipbus_ack                      : std_logic := '0';  -- used to produce a delayed IPBus ack signal

  signal s_edge_rising_times:   t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0);  --! edge arrival time ( w.r.t. logic_strobe)
  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

  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_reg , s_status_reg: std_logic_vector(g_IPBUS_WIDTH-1 downto 0) := (others => '0');
  signal s_counter_reset, s_calibrate_idelay: std_logic := '0';
  
BEGIN
  -----------------------------------------------------------------------------
  -- IPBus interface 
  -----------------------------------------------------------------------------

  -- 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_sync_status_to_ipbus,
      q=>  s_control_from_ipbus,
      stb => open
      );

  -- sync data from I/O logic to IPBus
  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);

  -- sync data from I/O logic to IPBus
  sync_ipbus: 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);

  -- Map the control registers...
  -- Register that controls IODELAY and ISERDES reset is at address 0
  s_rst_iserdes <= reset_i or s_sync_control_from_ipbus(0)(0);
  s_counter_reset <= s_sync_control_from_ipbus(0)(1);
  s_calibrate_idelay <= s_sync_control_from_ipbus(0)(2);
  
  s_status_to_ipbus(0)(0) <= s_rst_iserdes;
  s_status_to_ipbus(0)(1) <= s_counter_reset;
  s_status_to_ipbus(0)(2) <= s_calibrate_idelay;
  -- Connect up unused lines in status regiser to 0.
  s_status_to_ipbus(0)(3) <= '0';
  s_status_to_ipbus(0)(g_IPBUS_WIDTH-1 downto 28) <= (others => '0');

  -----------------------------------------------------------------------------
  -- Connect up trigger inputs to deserializers and a LUT to determine
  -- arrival time
  -----------------------------------------------------------------------------
 
  
  trigger_input_loop: for triggerInput in 0 to (g_NUM_INPUTS-1) generate

    thresholdInputBuffer: IBUFDS
      generic map (
        DIFF_TERM        => true,
        IBUF_LOW_PWR     => false,
        IOSTANDARD       => "LVDS_25")
      port map (
        O  => s_threshold_discr_input(triggerInput),
        I  => threshold_discr_p_i(triggerInput),
        IB => threshold_discr_n_i(triggerInput)
        );

    thresholdDeserializer: entity work.dualSERDES_1to4
      port map (
        reset_i 			=> s_rst_iserdes,
        --calibrate_i 		=> s_calibrate_idelay,
        data_i         => s_threshold_discr_input(triggerInput),
        fastClk_i      => clk_16x_logic_i,
        fabricClk_i    => clk_4x_logic,
        strobe_i       => strobe_16x_logic_i,
        data_o         => s_deserialized_threshold_data(triggerInput),
        status_o       => s_status_to_ipbus(0)(5+(2*triggerInput) downto 4+(2*triggerInput))
        );
		  
      --s_deserialized_threshold_data_l(triggerInput) <= s_deserialized_threshold_data(triggerInput)(3 downto 0) & s_deserialized_threshold_data_d(triggerInput)(7 downto 3);
    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_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), 
        falling_edge_o      => s_edge_falling(triggerInput),
        multiple_edges_o    => open
        );

    -- The leading edge may be a high-->low or a low-->high transition (
    -- depending on polarity of input signal. ). For now assume that leading
    -- edge is low-->high and connect trigger times and trigger output accordingly.
    -- In the future have this selectable.
    edge_rising_times_o(triggerInput) <= s_edge_rising_times(triggerInput);
    edge_falling_times_o(triggerInput) <= s_edge_falling_times(triggerInput);
    edge_rising_o(triggerInput) <= s_edge_rising(triggerInput);
    edge_falling_o(triggerInput) <= s_edge_falling(triggerInput);
    trigger_times_o(triggerInput) <= s_edge_rising_times(triggerInput);
    trigger_o(triggerInput) <= s_edge_rising(triggerInput);
    
    
    CFDInputBuffer: IBUFDS
      generic map (
        DIFF_TERM        => true,
        IBUF_LOW_PWR     => false,
        IOSTANDARD       => "LVDS_25")
      port map (
        O  => s_CFD_discr_input(triggerInput),
        I  => CFD_discr_p_i(triggerInput),
        IB => CFD_discr_n_i(triggerInput)
        );

    CFDDeserializer: entity work.dualSERDES_1to4
      port map (
        reset_i => s_rst_iserdes,
        --calibrate_i => s_calibrate_idelay,
        data_i         => s_CFD_discr_input(triggerInput),
        fastClk_i      => clk_16x_logic_i,
        fabricClk_i    => clk_4x_logic,
        strobe_i       => strobe_16x_logic_i,
        data_o         => s_deserialized_CFD_data(triggerInput),
        status_o       => s_status_to_ipbus(0)(13+(2*triggerInput) downto 12+(2*triggerInput))
        );
	--s_deserialized_CFD_data(triggerInput) <= (others=>'0');
      
    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_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),
        falling_edge_o      => s_CFD_falling_edge(triggerInput),
        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_deserialized_threshold_data_d(triggerInput) <= s_deserialized_threshold_data(triggerInput);
        s_CFD_previous_late_bit(triggerInput) <= s_deserialized_CFD_data(triggerInput)(7);

        -- Monitor output of serdes - just look at one per serdes
        -- Don't care about latency so put a couple of registers in to aid
        -- timing closure.
        s_status_to_ipbus(0)(20+triggerInput) <= s_threshold_previous_late_bit(triggerInput);
        s_status_to_ipbus(0)(24+triggerInput) <= s_CFD_previous_late_bit(triggerInput);
        
      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( ((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;
  --! Monitor output of deserializer
  -- trigger_debug_o( ((2*g_NUM_INPUTS)-1) downto g_NUM_INPUTS) <=  s_status_to_ipbus(0)(23 downto 20);
  --trigger_debug_o( (g_NUM_INPUTS-1) downto 0) <=  s_edge_rising;
  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_edge_rising;
  
END ARCHITECTURE rtl;