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