Commit 14eb481d authored by David Cussans's avatar David Cussans

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
parent eb9752c5
...@@ -175,14 +175,24 @@ BEGIN ...@@ -175,14 +175,24 @@ BEGIN
end process examine_lut; end process examine_lut;
--! Coarse time stamp. Phase w.r.t. strobe --! 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 ( PORT MAP (
clk => clk_4x_logic_i, clock_i => clk_4x_logic_i,
ce => '1', enable_i => '1',
sinit => strobe_4x_logic_i, --'0', reset_i => strobe_4x_logic_i, --'0',
q(31 downto 2) => open, result_o => s_coarse_bits
q(1 downto 0) => s_coarse_bits
); );
END ARCHITECTURE rtl; END ARCHITECTURE rtl;
...@@ -36,12 +36,12 @@ architecture rtl of clocks_s6_extphy is ...@@ -36,12 +36,12 @@ architecture rtl of clocks_s6_extphy is
signal s_clk_logic_xtal : std_logic; signal s_clk_logic_xtal : std_logic;
-- signal clk_400: std_logic; -- signal clk_400: std_logic;
component clock_divider_s6 port( -- component clock_divider_s6 port(
clk: in std_logic; -- clk: in std_logic;
d25: out std_logic; -- d25: out std_logic;
d28: out std_logic -- d28: out std_logic
); -- );
end component; -- end component;
begin begin
...@@ -90,8 +90,10 @@ begin ...@@ -90,8 +90,10 @@ begin
rst => '0' 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, clk => sysclk,
-- D17 => open,
d25 => d25, d25 => d25,
d28 => onehz d28 => onehz
); );
......
--=============================================================================
--! @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;
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
--! Author: --! Author:
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n --! \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 --! @todo Implement a periodic calibration sequence\n
--! <another thing to do> \n --! <another thing to do> \n
...@@ -73,105 +74,52 @@ ARCHITECTURE rtl OF dualSERDES_1to4 IS ...@@ -73,105 +74,52 @@ ARCHITECTURE rtl OF dualSERDES_1to4 IS
signal s_data_o : std_logic_vector(7 downto 0); --! Deserialized data signal s_data_o : std_logic_vector(7 downto 0); --! Deserialized data
signal s_rst : std_logic := '0'; -- IODELAY and ISERDES reset 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_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" BEGIN
DATA_RATE => "SDR", -- "SDR" or "DDR"
DELAY_SRC => "IDATAIN", -- "IO", "ODATAIN" or "IDATAIN" calibration_fsm: entity work.serdesCalibrateFSM
IDELAY_MODE => "NORMAL", -- "NORMAL" or "PCI" port map (
--SERDES_MODE => "MASTER", -- <NONE>, MASTER, SLAVE fsm_clk_i => fabricClk_i,
IDELAY_TYPE => "VARIABLE_FROM_HALF_MAX", -- "FIXED", "DEFAULT", "VARIABLE_FROM_ZERO", "VARIABLE_FROM_HALF_MAX" 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" -- or "DIFF_PHASE_DETECTOR"
IDELAY_VALUE => 0, -- Amount of taps for fixed input delay (0-255) IDELAY_VALUE => 0, -- Amount of taps for fixed input delay (0-255)
IDELAY2_VALUE => 0, -- Delay value when IDELAY_MODE="PCI" (0-255) IDELAY2_VALUE => 0, -- Delay value when IDELAY_MODE="PCI" (0-255)
ODELAY_VALUE => 0 -- Amount of taps fixed output delay (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 --SIM_TAPDELAY_VALUE=> 50 -- Per tap delay used for simulation in ps
) )
port map ( port map (
BUSY => s_busy_idelay_m, -- 1-bit output: Busy output after CAL 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 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 DATAOUT2 => open, -- 1-bit output: Delayed data output to general FPGA fabric
DOUT => open, -- 1-bit output: Delayed data output DOUT => open, -- 1-bit output: Delayed data output
TOUT => open, -- 1-bit output: Delayed 3-state output TOUT => open, -- 1-bit output: Delayed 3-state output
CAL => s_cal_FSM, -- 1-bit input: Initiate calibration input CAL => s_cal_FSM, -- 1-bit input: Initiate calibration input
CE => '0', -- 1-bit input: Enable INC input CE => '0', -- 1-bit input: Enable INC input
CLK => fabricClk_i, -- 1-bit input: Clock 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) 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 INC => '0', -- 1-bit input: Increment / decrement input
IOCLK0 => fastClk_i, -- 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 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. 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 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 T => '0' -- 1-bit input: 3-state input signal
); );
IODELAY2_Delayed : IODELAY2 IODELAY2_Delayed : IODELAY2
...@@ -180,8 +128,8 @@ BEGIN ...@@ -180,8 +128,8 @@ BEGIN
DATA_RATE => "SDR", -- "SDR" or "DDR" DATA_RATE => "SDR", -- "SDR" or "DDR"
DELAY_SRC => "IDATAIN", -- "IO", "ODATAIN" or "IDATAIN" DELAY_SRC => "IDATAIN", -- "IO", "ODATAIN" or "IDATAIN"
IDELAY_MODE => "NORMAL", -- "NORMAL" or "PCI" IDELAY_MODE => "NORMAL", -- "NORMAL" or "PCI"
--SERDES_MODE => "SLAVE", -- <NONE>, MASTER, SLAVE SERDES_MODE => "NONE", -- <NONE>, MASTER, SLAVE
IDELAY_TYPE => "FIXED", -- "FIXED", "DEFAULT", "VARIABLE_FROM_ZERO", "VARIABLE_FROM_HALF_MAX" IDELAY_TYPE => "VARIABLE_FROM_ZERO", -- "FIXED", "DEFAULT", "VARIABLE_FROM_ZERO", "VARIABLE_FROM_HALF_MAX"
-- or "DIFF_PHASE_DETECTOR" -- or "DIFF_PHASE_DETECTOR"
IDELAY_VALUE => 0, -- Amount of taps for fixed input delay (0-255) 10->0.75nS, 11->0.825nS 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) IDELAY2_VALUE => 0, -- Delay value when IDELAY_MODE="PCI" (0-255)
...@@ -194,12 +142,12 @@ BEGIN ...@@ -194,12 +142,12 @@ BEGIN
DATAOUT2 => open, -- 1-bit output: Delayed data output to general FPGA fabric DATAOUT2 => open, -- 1-bit output: Delayed data output to general FPGA fabric
DOUT => open, -- 1-bit output: Delayed data output DOUT => open, -- 1-bit output: Delayed data output
TOUT => open, -- 1-bit output: Delayed 3-state 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 CE => '0', -- 1-bit input: Enable INC input
CLK => '0', -- 1-bit input: Clock 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) 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 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 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. 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 RST => s_rst, -- 1-bit input: reset_i to zero or 1/2 of total delay period
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
--! Author: --! Author:
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n --! \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 --! @todo Add more input data: \n
--! a) shutter signals. One per DUT. ?? \n --! a) shutter signals. One per DUT. ?? \n
...@@ -114,7 +116,7 @@ ARCHITECTURE rtl OF eventFormatter IS ...@@ -114,7 +116,7 @@ ARCHITECTURE rtl OF eventFormatter IS
-- 3 - Spill -- 3 - Spill
--! delayed strobes --! 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 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 signal s_evttype : t_evttype(3+g_NUM_EDGE_INPUTS-1 downto 0) := (others=>(others=>'0')); -- Event type
...@@ -212,22 +214,26 @@ BEGIN ...@@ -212,22 +214,26 @@ BEGIN
if rising_edge(clk_4x_logic_i) then if rising_edge(clk_4x_logic_i) then
s_event_strobe_d1 <= trigger_i and s_enable_trigger; s_event_strobe_d1 <= trigger_i and s_enable_trigger;
s_event_strobe_d2 <= s_event_strobe_d1; 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;
s_event_strobe_d3 <= s_event_strobe_d2;
end if;
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_d1 <= shutter_i and s_enable_shutter;
shutter_i_d2 <= shutter_i_d1; shutter_i_d2 <= shutter_i_d1;
spill_i_d1 <= spill_i and s_enable_spill; spill_i_d1 <= spill_i and s_enable_spill;
spill_i_d2 <= spill_i_d1; spill_i_d2 <= spill_i_d1;
end if; end if;
end process p_reg; 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 -- Trigger event formater
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
...@@ -240,40 +246,66 @@ BEGIN ...@@ -240,40 +246,66 @@ BEGIN
s_word1 <= "000" & trigger_times_i(0) & "000" & trigger_times_i(1) & s_word1 <= "000" & trigger_times_i(0) & "000" & trigger_times_i(1) &
"000" & trigger_times_i(2) & "000" & trigger_times_i(3) & "000" & trigger_times_i(2) & "000" & trigger_times_i(3) &
trigger_cnt_i; 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 --! 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_FIFO_i(0) <= s_word0 when (s_event_strobe_d1 = '1') else
s_word1 when (s_event_strobe_d2 = '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'); (others => '0');
--! If there is data in the FIFO output we put the strobe signal at high level. --! 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_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 s_evttype(1) <= "0011" when shutter_i_d1 = '1' and shutter_i_d2 = '0' else
......
...@@ -91,6 +91,7 @@ BEGIN ...@@ -91,6 +91,7 @@ BEGIN
ipbus_o.ipb_rdata(31 downto 8) <= ( others => '0'); ipbus_o.ipb_rdata(31 downto 8) <= ( others => '0');
ipbus_o.ipb_err <= '1'; -- never return an error.
END ARCHITECTURE rtl; END ARCHITECTURE rtl;
...@@ -20,7 +20,7 @@ architecture rtl of ipbus_ver is ...@@ -20,7 +20,7 @@ architecture rtl of ipbus_ver is
begin 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_ack <= ipbus_in.ipb_strobe;
ipbus_out.ipb_err <= '0'; ipbus_out.ipb_err <= '0';
......
...@@ -114,12 +114,14 @@ ARCHITECTURE rtl OF logic_clocks IS ...@@ -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_logic_clk_generator : std_logic_vector(3 downto 0) := "1100"; --! Stores state of 40MHz "clock"
signal s_strobe_fb : std_logic := '0'; 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 -- ! 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'; 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. -- ! reset signal clocked onto logic-clock domain.
signal s_ipbus_ack : std_logic := '0'; signal s_ipbus_ack : std_logic := '0';
signal s_reset_pll : std_logic := '0';
--signal s_Reset : std_logic := '0'; --signal s_Reset : std_logic := '0';
-- ! Global Reset signal -- ! Global Reset signal
...@@ -149,7 +151,10 @@ BEGIN ...@@ -149,7 +151,10 @@ BEGIN
end if; 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 if;
end process ipbus_write; end process ipbus_write;
...@@ -173,7 +178,7 @@ BEGIN ...@@ -173,7 +178,7 @@ BEGIN
p_reset: process (s_clk160_internal) p_reset: process (s_clk160_internal)
begin -- process p_reset begin -- process p_reset
if rising_edge(s_clk160_internal) then 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_d2 <= s_logic_reset_d1;
s_logic_reset_d3 <= s_logic_reset_d2; s_logic_reset_d3 <= s_logic_reset_d2;
s_logic_reset <= s_logic_reset_d2 and ( not s_logic_reset_d3); s_logic_reset <= s_logic_reset_d2 and ( not s_logic_reset_d3);
...@@ -297,11 +302,12 @@ BEGIN ...@@ -297,11 +302,12 @@ BEGIN
-- Status and control signals -- Status and control signals
LOCKED => s_locked_pll, LOCKED => s_locked_pll,
-- RST => s_logic_clk_rst, -- RST => s_logic_clk_rst,
RST => Reset_i or s_logic_reset, --'0', RST => s_reset_pll,
-- Input clock control -- Input clock control
CLKFBIN => s_clkfbout_buf, CLKFBIN => s_clkfbout_buf,
CLKIN => s_clk); CLKIN => s_clk);
s_reset_pll <= Reset_i or s_logic_reset;
-- Buffer the 16x clock and generate the ISERDES strobe signal -- Buffer the 16x clock and generate the ISERDES strobe signal
BUFPLL_inst : BUFPLL BUFPLL_inst : BUFPLL
......
...@@ -37,7 +37,8 @@ ...@@ -37,7 +37,8 @@
--! <b>References:</b>\n --! <b>References:</b>\n
--! --!
--! <b>Modified by:</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 --! \n\n<b>Last changes:</b>\n
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
......
--=============================================================================
--! @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;
--=============================================================================
--! @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;
...@@ -44,6 +44,8 @@ USE ieee.std_logic_1164.all; ...@@ -44,6 +44,8 @@ USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all; USE ieee.numeric_std.all;
USE work.ipbus.all; USE work.ipbus.all;
use work.ipbus_reg_types.all;
USE work.fmcTLU.all; USE work.fmcTLU.all;
library unisim ; library unisim ;
...@@ -51,7 +53,8 @@ use unisim.vcomponents.all; ...@@ -51,7 +53,8 @@ use unisim.vcomponents.all;
ENTITY triggerInputs IS ENTITY triggerInputs IS
GENERIC( GENERIC(
g_NUM_INPUTS : natural := 1 g_NUM_INPUTS : natural := 1;
g_IPBUS_WIDTH : positive := 32
); );
PORT( PORT(
cfd_discr_p_i : IN std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);--! Inputs from constant-fraction discriminators 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 ; ...@@ -82,14 +85,16 @@ END ENTITY triggerInputs ;
-- --
ARCHITECTURE rtl OF triggerInputs IS 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 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); -- 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); 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_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); signal s_cfd_trigger_times : t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0);
...@@ -106,44 +111,56 @@ ARCHITECTURE rtl OF triggerInputs IS ...@@ -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_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_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 signal s_edge_falling: std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0); --! High when falling edge
BEGIN
ipbus_write: process (ipbus_clk_i) constant c_N_CTRL : positive := 1;
begin -- process ipb_clk_i constant c_N_STAT : positive := g_NUM_INPUTS+1 ;
if rising_edge(ipbus_clk_i) then signal s_status_to_ipbus , s_sync_status_to_ipbus: ipb_reg_v(c_N_STAT-1 downto 0);
s_rst_iserdes_ipb <= '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');
if (ipbus_i.ipb_strobe = '1' and ipbus_i.ipb_write = '1') then signal s_counter_reset: std_logic := '0';
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;
BEGIN
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- IPBUS read -- IPBus interface
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
ipbus_o.ipb_rdata <= (others => '1');
-- Can't get ipbus_syncreg_v to meet timing. So use non-syncronized followed
ipbus_o.ipb_ack <= s_ipbus_ack; -- by synchronizer.
ipbus_o.ipb_err <= '0'; 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 -- Connect up trigger inputs to deserializers and a LUT to determine
-- arrival time -- arrival time
...@@ -172,11 +189,12 @@ BEGIN ...@@ -172,11 +189,12 @@ BEGIN
data_o => s_deserialized_threshold_data(triggerInput) 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 thresholdLUT : entity work.arrivalTimeLUT
port map ( port map (
clk_4x_logic_i => clk_4x_logic, clk_4x_logic_i => clk_4x_logic,
strobe_4x_logic_i => strobe_4x_logic_i, 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), first_rising_edge_time_o => s_edge_rising_times(triggerInput),
last_falling_edge_time_o => s_edge_falling_times(triggerInput), last_falling_edge_time_o => s_edge_falling_times(triggerInput),
rising_edge_o => s_edge_rising(triggerInput), rising_edge_o => s_edge_rising(triggerInput),
...@@ -217,11 +235,12 @@ BEGIN ...@@ -217,11 +235,12 @@ BEGIN
data_o => s_deserialized_CFD_data(triggerInput) 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 CFDLUT : entity work.arrivalTimeLUT
port map ( port map (
clk_4x_logic_i => clk_4x_logic, clk_4x_logic_i => clk_4x_logic,
strobe_4x_logic_i => strobe_4x_logic_i, 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), first_rising_edge_time_o => s_cfd_trigger_times(triggerInput),
last_falling_edge_time_o => open, last_falling_edge_time_o => open,
rising_edge_o => s_CFD_rising_edge(triggerInput), rising_edge_o => s_CFD_rising_edge(triggerInput),
...@@ -229,18 +248,30 @@ BEGIN ...@@ -229,18 +248,30 @@ BEGIN
multiple_edges_o => open multiple_edges_o => open
); );
p_register_delayed_bits : process ( clk_4x_logic ) p_register_delayed_bits : process ( clk_4x_logic )
begin begin
if rising_edge(clk_4x_logic) then if rising_edge(clk_4x_logic) then
s_threshold_previous_late_bit(triggerInput) <= s_deserialized_threshold_data(triggerInput)(7); s_threshold_previous_late_bit(triggerInput) <= s_deserialized_threshold_data(triggerInput)(7);
s_CFD_previous_late_bit(triggerInput) <= s_deserialized_CFD_data(triggerInput)(7); s_CFD_previous_late_bit(triggerInput) <= s_deserialized_CFD_data(triggerInput)(7);
end if ; end if ;
end process; 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; end generate trigger_input_loop;
trigger_debug_o( (g_NUM_INPUTS-1) downto 0) <= s_threshold_discr_input; 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; END ARCHITECTURE rtl;
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
--! Author: --! Author:
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n --! \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 --! @todo <next thing to do> \n
--! <another thing to do> \n --! <another thing to do> \n
...@@ -48,6 +50,7 @@ USE ieee.std_logic_1164.all; ...@@ -48,6 +50,7 @@ USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all; USE ieee.numeric_std.all;
USE work.ipbus.all; USE work.ipbus.all;
use work.ipbus_reg_types.all;
ENTITY triggerLogic IS ENTITY triggerLogic IS
GENERIC( GENERIC(
...@@ -92,73 +95,68 @@ ARCHITECTURE rtl OF triggerLogic IS ...@@ -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_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 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 BEGIN
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';
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- IPBUS read -- IPBus interface
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
with ipbus_i.ipb_addr(2 downto 0) select ipbus_registers: entity work.ipbus_ctrlreg_v
ipbus_o.ipb_rdata <= generic map(
s_post_veto_trigger_counter_ipb when "000", N_CTRL => c_N_CTRL,
s_pre_veto_trigger_counter_ipb when "001", N_STAT => c_N_STAT
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)
port map( port map(
clk_i => clk_4x_logic_i, clk => ipbus_clk_i,
async_i => s_trigger_pattern_ipb, reset=> ipbus_reset_i ,
sync_o => s_trigger_pattern ipbus_in=> ipbus_i,
); ipbus_out=> ipbus_o,
d=> s_sync_status_to_ipbus,
-- Move the trigger pattern onto the logic clock domain to allow timing q=> s_control_from_ipbus,
-- constraints to be met. stb=> open
-- register_trigger_pattern : entity work.registerCounter );
-- generic map (
-- g_DATA_WIDTH => s_trigger_pattern_ipb'length ) -- Synchronize registers from logic clock to ipbus.
-- port map ( sync_status: entity work.synchronizeRegisters
-- clk_input_i => ipbus_clk_i, generic map (
-- data_i => s_trigger_pattern_ipb, g_NUM_REGISTERS => c_N_STAT )
-- data_o => s_trigger_pattern, port map (
-- clk_output_i => clk_4x_logic_i 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 -- Generate triggers
...@@ -181,42 +179,18 @@ BEGIN ...@@ -181,42 +179,18 @@ BEGIN
pre_veto_trigger_o <= s_pre_veto_trigger ; pre_veto_trigger_o <= s_pre_veto_trigger ;
post_veto_trigger_o <= s_post_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 ) p_internal_triggers: process (clk_4x_logic_i )
begin -- process p_internal_triggers begin -- process p_internal_triggers
if rising_edge(clk_4x_logic_i) then if rising_edge(clk_4x_logic_i) then
s_internal_trigger_active <= s_internal_trigger_active_ipb; -- move from if (s_internal_trigger_interval = x"00000000") then
-- IPBus clock to trigger s_internal_trigger_active <= '0';
s_internal_veto <= s_internal_veto_ipb; else
s_internal_trigger_active <= '1';
s_internal_trigger_timer_d <= s_internal_trigger_timer; -- Signal delayed end if;
s_internal_trigger_timer_d <= s_internal_trigger_timer; -- Signal delayed
end if; end if;
end process p_internal_triggers; end process p_internal_triggers;
...@@ -255,47 +229,7 @@ BEGIN ...@@ -255,47 +229,7 @@ BEGIN
end if; end if;
end process p_trigger_counter; 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); event_number_o <= std_logic_vector(s_post_veto_trigger_counter);
END ARCHITECTURE rtl; END ARCHITECTURE rtl;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment