Commit aaaffdc7 authored by Alvaro Dosil's avatar Alvaro Dosil

Implementing trigger coincidences

parent 5d6e155b
......@@ -136,6 +136,9 @@ xfile add fmc-mtlu/firmware/hdl/common/handshakes_rtl.vhd
xfile add fmc-mtlu/firmware/hdl/common/TPx3Logic_rtl.vhd
xfile add fmc-mtlu/firmware/hdl/common/pulseClockDomainCrossing_rtl.vhd
xfile add fmc-mtlu/firmware/hdl/common/counterDown.vhd
xfile add fmc-mtlu/firmware/hdl/common/coincidence_logic_rtl.vhd
xfile add fmc-mtlu/firmware/hdl/common/SimplePulse_rtl.vhd
xfile add fmc-mtlu/firmware/hdl/common/ShiftReg_rtl.vhd
# Then add the HDL-Designer generated files..
......
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 14:48:44 11/24/2014
-- Design Name:
-- Module Name: ShiftReg_rtl - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity ShiftReg is
generic( g_MaxDelay : positive := 4;
g_DATA_WIDTH : positive := 32
);
port( clk_i : in std_logic;
data_i : in std_logic_vector(g_DATA_WIDTH-1 downto 0);
delay_i : in integer :=1;
data_o : out std_logic_vector(g_DATA_WIDTH-1 downto 0));
end ShiftReg;
architecture rtl of ShiftReg is
type t_tmpArray is array(natural range <>) of std_logic_vector(g_DATA_WIDTH-1 downto 0) ;
signal tmp: t_tmpArray (g_MaxDelay-1 downto 0);
begin
p_sr:process (clk_i)
begin
if rising_edge(clk_i) then
for i in 0 to g_MaxDelay-2 loop
tmp(i+1) <= tmp(i);
end loop;
tmp(0) <= data_i;
end if;
end process;
data_o <= tmp(delay_i);
end rtl;
\ No newline at end of file
--=============================================================================
--! @file SimplePulse_FSM_rtl.vhd
--=============================================================================
--
-------------------------------------------------------------------------------
-- --
-- UoB , USC
-- --
------------------------------------------------------------------------------- --
--
--! @brief Simple pulse
--
--! @author Alvaro Dosil
--
--! @date 11/Nov/2014
--
--! @version v0.1
--
--! @details
--
-------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n
-------------------------------------------------------------------------------
--! @todo
--! <another thing to do> \n
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity SimplePulse_FSM is
generic(
g_cnt_width : positive := 8
);
port (
clk_i : in std_logic; --! Global clock
start_i : in std_logic; --! Start pulse
PulseWidth_i : in unsigned(g_cnt_width-1 downto 0); --! pulse width
Pulse_o : out std_logic --! Pulse
);
end entity SimplePulse_FSM;
architecture rtl of SimplePulse_FSM is
--! Calibration FSM state values
type state_values is (st0, st1);
signal pres_state, next_state: state_values := st0;
signal s_start_old : std_logic := '0';
signal s_Pulse, s_EoP : std_logic := '0';
signal s_cnt : unsigned(g_cnt_width-1 downto 0); --! pulse width
begin -- rtl
--Reg
p_reg : process(clk_i)
begin
if rising_edge(clk_i) then
s_start_old <= start_i;
end if;
end process;
-- Pulse counter
p_pulse : process(clk_i)
begin
if rising_edge(clk_i) then
if start_i = '1' and s_start_old = '0' then
s_cnt <= PulseWidth_i;
elsif s_Pulse = '1' then
s_cnt <= s_cnt-1;
end if;
end if;
end process;
s_Pulse <= '0' when s_cnt = x"00" else
'1';
Pulse_o <= s_Pulse;
end rtl;
......@@ -174,16 +174,6 @@ BEGIN
end process examine_lut;
--! Coarse time stamp. Phase w.r.t. strobe
-- 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 )
......
--=============================================================================
--! @file coincidence_logic_rtl.vhd
--=============================================================================
--
-------------------------------------------------------------------------------
-- --
-- UoB , USC
-- --
------------------------------------------------------------------------------- --
--
--! @brief Coincidence trigger logic
--
--! @author Alvaro Dosil
--
--! @date 11/Nov/2014
--
--! @version v0.1
--
--! @details
--
-------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n
-------------------------------------------------------------------------------
--! @todo
--! <another thing to do> \n
library IEEE;
LIBRARY UNISIM;
use IEEE.STD_LOGIC_1164.ALL;
USE UNISIM.vcomponents.all;
entity coincidence_logic is
GENERIC(
g_IPBUS_WIDTH : positive := 32;
g_DELAY_WIDTH : positive := 16;
g_DATA_WIDTH : positive := 4
);
PORT(
clk_i : IN std_logic; -- ! clock
rst : IN std_logic;
Data_i : IN std_logic_vector(g_DATA_WIDTH-1 downto 0);
CoincLogic_i : IN std_logic_vector(g_IPBUS_WIDTH-1 downto 0);
StrechDelay_i : IN std_logic_vector(g_DELAY_WIDTH-1 downto 0);
Pulse_o : OUT std_logic
);
end coincidence_logic;
architecture rtl of coincidence_logic is
signal CoincLogic_i_d, s_CDI : std_logic_vector(g_IPBUS_WIDTH-1 downto 0) := (others => '0');
signal s_startCDIPulse, s_en_CDI : std_logic := '0';
signal s_pulse, s_pulse_o6 : std_logic := '0';
signal s_data_i_d : std_logic_vector(g_DATA_WIDTH-1 downto 0);
signal s_data, s_rst : std_logic_vector(g_DATA_WIDTH-1 downto 0);
type t_data is array ( natural range <> ) of std_logic_vector(g_DELAY_WIDTH-1 downto 0);
signal s_tmp, s_StrechDelay : t_data(g_DATA_WIDTH-1 downto 0);
begin
--! Trigger coincidence logic
Coinc_LUT : CFGLUT5
generic map (
INIT => x"00000003")
port map (
CDO => open, -- Reconfiguration cascade output
O5 => open, -- 4-LUT output
O6 => s_pulse, -- 5-LUT output
CDI => s_CDI(g_IPBUS_WIDTH-1), -- Reconfiguration data input
CE => s_en_CDI, -- Reconfiguration enable input
CLK => clk_i, -- Clock input
I0 => s_data(0), -- Logic data input
I1 => s_data(1), -- Logic data input
I2 => s_data(2), -- Logic data input
I3 => s_data(3), -- Logic data input
I4 => '0' -- Logic data input
);
Pulse_o <= s_pulse and not s_en_CDI;
--! CDI pulse
CDIPulse : entity work.SimplePulse_FSM
port map (
clk_i => clk_i,
start_i => s_startCDIPulse,
PulseWidth_i => X"20", -- hex(32)
Pulse_o => s_en_CDI
);
s_startCDIPulse <= '1' when CoincLogic_i /= CoincLogic_i_d or rst='1' else
'0';
p_reg : process(clk_i)
begin
if rising_edge(clk_i) then
CoincLogic_i_d <= CoincLogic_i;
if s_en_CDI='0' then
s_CDI <= CoincLogic_i;
else
for i in 1 to g_IPBUS_WIDTH-1 loop
s_CDI(i) <= s_CDI(i-1);
end loop;
end if;
end if;
end process;
--! DELAYER/STRECHER
gen_strecher : for i in 0 to g_DATA_WIDTH-1 generate
p_DelStrech : process(clk_i,rst)
begin
if rst='1' then
s_tmp(i) <= s_StrechDelay(i);
elsif rising_edge(clk_i) then
if s_rst(i)='1' then
s_tmp(i) <= s_StrechDelay(i);
else
s_tmp(i)(g_DELAY_WIDTH-1) <= '0';
for j in 0 to g_DELAY_WIDTH-2 loop
s_tmp(i)(j) <= s_tmp(i)(j+1);
end loop;
end if;
end if;
end process;
p_SR : process(clk_i)
begin
if rising_edge(clk_i) then
s_data_i_d(i) <= Data_i(i);
s_StrechDelay(i) <= StrechDelay_i;
end if;
end process;
s_rst(i) <= '1' when Data_i(i)='1' and s_data_i_d(i)='0' else -- We assume that Data_i always arrives synchronously and we want to reproduce the strech behaviour
'0';
s_data(i) <= s_tmp(i)(0);
end generate;
end rtl;
......@@ -289,7 +289,7 @@ BEGIN
-------------------------------------------------------------------------------
-- Trigger event formater
-------------------------------------------------------------------------------
s_evttype(0) <= "0000" when unsigned(trigger_inputs_fired_d1) = 0 and trigger_i = '1' else
s_evttype(0) <= "0000" when trigger_inputs_fired_d1 = std_logic_vector(to_unsigned(0,trigger_inputs_fired_d1'length)) and s_event_strobe_d1 = '1' else
"0001";
s_var(0) <= trigger_inputs_fired_d1 & std_logic_vector(to_unsigned(0,s_var(0)'length-g_NUM_TRIG_INPUTS));
......@@ -320,11 +320,11 @@ BEGIN
s_FIFO_wr(0) <= s_event_strobe_d1 or s_event_strobe_d2 or s_event_strobe_d3_opt;
if s_event_strobe_d1 = '1' then
s_FIFO_i(0) <= s_word0_d1;
s_FIFO_i(0) <= s_word0; --s_word0_d1;
elsif s_event_strobe_d2 = '1' then
s_FIFO_i(0) <= s_word1_d2;
s_FIFO_i(0) <= s_word1_d1; --s_word1_d2;
elsif s_event_strobe_d3_opt = '1' then
s_FIFO_i(0) <= s_word2_d3;
s_FIFO_i(0) <= s_word2_d2; --s_word2_d3;
else
s_FIFO_i(0) <= (others=>'0');
end if;
......
......@@ -46,6 +46,7 @@
-- Created using using Mentor Graphics HDL Designer(TM) 2010.3 (Build 21)
--
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
......@@ -57,6 +58,7 @@ USE work.fmcTLU.all;
ENTITY triggerLogic IS
GENERIC(
g_NUM_INPUTS : positive := 4;
g_DELAYSTRECH_WIDTH : positive := 16;
g_IPBUS_WIDTH : positive := 32
);
PORT(
......@@ -93,6 +95,7 @@ ARCHITECTURE rtl OF triggerLogic IS
signal s_pre_veto_trigger_counter_ipb , s_post_veto_trigger_counter_ipb : std_logic_vector(g_IPBUS_WIDTH-1 downto 0) := (others => '0'); -- ! counters for triggers before and after veto, on ipbus clock domain
signal s_triggers : std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0) := (others=>'0');
signal s_ctrigger, s_ctrigger_d : std_logic;
signal s_trigger_times : t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0) := (others=>(others=>'0'));
signal s_internal_trigger, s_internal_trigger_d : std_logic := '0'; -- ! Strobes high for one clock cycle at intervals of s_internal_trigger_interval cycles
-- signal s_internal_trigger_timer : unsigned(g_IPBUS_WIDTH-1 downto 0) := (others => '0'); -- counter for internal trigger generation
......@@ -103,11 +106,8 @@ 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
signal s_AND_Window : std_logic_vector(g_IPBUS_WIDTH-1 downto 0) := (others => '0'); --! Time window for the trigger coincidence
signal s_AND_Mask, s_AND_Mask_ipb : std_logic_vector(g_IPBUS_WIDTH-1 downto 0) := (others => '0'); --! Mask to select the trigger inputs in coincidence
signal s_OR_Mask : std_logic_vector(g_IPBUS_WIDTH-1 downto 0) := (others => '0');
signal s_AND_trigger: std_logic := '0';
signal s_OR_trigger: std_logic := '0';
signal s_CoincidenceFunc : std_logic_vector(g_IPBUS_WIDTH-1 downto 0) := (others => '0');
signal s_StrechDelayFormat : std_logic_vector(g_DELAYSTRECH_WIDTH-1 downto 0);
constant c_N_CTRL : positive := 8;
constant c_N_STAT : positive := 8;
......@@ -163,8 +163,8 @@ BEGIN
s_trigger_inputs_enabled <= s_sync_control_from_ipbus(3);
s_veto_word <= s_sync_control_from_ipbus(4);
s_internal_veto <= s_veto_word(0);
s_AND_Mask_ipb <= s_sync_control_from_ipbus(6);
s_AND_Window <= s_sync_control_from_ipbus(7);
s_CoincidenceFunc <= s_sync_control_from_ipbus(6);
s_StrechDelayFormat <= s_sync_control_from_ipbus(7)(g_DELAYSTRECH_WIDTH-1 downto 0);
-- Map the status registers
s_status_to_ipbus(0) <= std_logic_vector(s_post_veto_trigger_counter);
......@@ -175,60 +175,68 @@ BEGIN
s_status_to_ipbus(5) <= s_external_veto_word;
s_external_veto_word(0) <= veto_i;
s_external_veto_word(g_IPBUS_WIDTH-1 downto 1) <= (others=>'0');
s_status_to_ipbus(6) <= s_AND_Mask;
s_status_to_ipbus(7) <= s_AND_Window;
s_status_to_ipbus(6) <= s_CoincidenceFunc;
s_status_to_ipbus(7) <= x"0000" & s_StrechDelayFormat;
-----------------------------------------------------------------------------
-- Generate triggers
-----------------------------------------------------------------------------
s_AND_Mask <= s_AND_Mask_ipb and s_trigger_inputs_enabled;
s_OR_Mask <= (not s_AND_Mask) and s_trigger_inputs_enabled; -- Inputs not selected for coincidence will work as OR triggers.
--s_OR_trigger <= '0' when (s_OR_Mask(trigger_i'range) and trigger_i) = std_logic_vector(to_unsigned(0,trigger_i'length)) else
-- '1';
-- Trigger Filtering
s_external_trigger <= '0' when (s_trigger_inputs_enabled(trigger_i'range) and trigger_i) = std_logic_vector(to_unsigned(0,trigger_i'length)) else
'1';
--Triggers enabled
s_triggers <= trigger_i and s_trigger_inputs_enabled(trigger_i'range);
trig_masks : process(trigger_times_i, s_trigger_inputs_enabled)
begin
for i in 0 to g_NUM_INPUTS-1 loop
s_trigger_times(i)(4 downto 3) <= trigger_times_i(i)(4 downto 3);
if s_trigger_inputs_enabled(i)='1' then
s_trigger_times(i)(2 downto 0) <= trigger_times_i(i)(2 downto 0);
else
s_trigger_times(i)(2 downto 0) <= "000";
end if;
--if s_triggers/=std_logic_vector(to_unsigned(0,trigger_i'length)) then
s_trigger_times(i)(4 downto 3) <= trigger_times_i(i)(4 downto 3);
if s_trigger_inputs_enabled(i)='1' then
s_trigger_times(i)(2 downto 0) <= trigger_times_i(i)(2 downto 0);
else
s_trigger_times(i)(2 downto 0) <= "000";
end if;
end loop;
end process;
-- Shift registers to synchronize triggers and trigger times
sh_trigtimes : entity work.ShiftReg
generic map(g_DATA_WIDTH => g_NUM_INPUTS)
port map(clk_i => clk_4x_logic_i,
data_i => s_triggers,
delay_i => 1,
data_o => trigger_o);
trigger_o <= s_triggers;
trigger_times_o <= s_trigger_times;
gen_trigtimes : for i in 0 to g_NUM_INPUTS-1 generate
sh_trigtimes : entity work.ShiftReg
generic map(g_DATA_WIDTH => c_NUM_TIME_BITS)
port map(clk_i => clk_4x_logic_i,
data_i => s_trigger_times(i),
delay_i => 1,
data_o => trigger_times_o(i));
end generate;
-- --! Trigger coincidence logic
-- coincicence_logic : entity work.coincidences
-- generic map(
-- g_nInputs => g_NUM_INPUTS,
-- g_IPBUS_WIDTH => g_IPBUS_WIDTH
-- )
-- Port map(
-- trigger_i => trigger_i,
-- data_i => trigger_times_i,
-- clk_i => clk_4x_logic_i,
-- rst_i => logic_reset_i,
-- Window_i => s_AND_Window,
-- mask_i => s_AND_Mask,
-- trigger_o => s_AND_trigger,
-- data_first_trig_o => open,
-- data_o => trigger_times_o
-- );
-- Coincidence logic
coinc : entity work.coincidence_logic
GENERIC map(
g_DELAY_WIDTH => g_DELAYSTRECH_WIDTH,
g_DATA_WIDTH => g_NUM_INPUTS)
PORT map(
clk_i => clk_4x_logic_i,
rst => logic_reset_i,
Data_i => s_triggers,
CoincLogic_i => s_CoincidenceFunc,
StrechDelay_i => s_StrechDelayFormat,
Pulse_o => s_ctrigger);
--s_external_trigger <= s_OR_trigger; -- or s_AND_trigger;
-- -- Trigger Filtering
-- s_external_trigger <= '0' when (s_trigger_inputs_enabled(trigger_i'range) and trigger_i) = std_logic_vector(to_unsigned(0,trigger_i'length)) else
-- '1';
s_external_trigger <= s_ctrigger and not s_ctrigger_d; -- Triger only last for 1 clk_4x clock cycle
--! Produce triggers....
trigGen : process ( clk_4x_logic_i )
......@@ -236,6 +244,8 @@ BEGIN
if rising_edge(clk_4x_logic_i) then
s_post_veto_trigger <= (s_external_trigger or s_internal_trigger) and (not ( s_internal_veto or veto_i) );
s_pre_veto_trigger <= (s_external_trigger or s_internal_trigger);
s_ctrigger_d <= s_ctrigger;
end if;
end process;
......@@ -244,8 +254,10 @@ BEGIN
post_veto_trigger_o <= s_post_veto_trigger;
trigger_active_o <= s_post_veto_trigger;
-----------------------------------------------------------------------------
--! Internal trigger generator
-----------------------------------------------------------------------------
p_internal_triggers: process (clk_4x_logic_i )
begin -- process p_internal_triggers
if rising_edge(clk_4x_logic_i) then
......
......@@ -17,19 +17,22 @@ ThrCount3R 0x0000004c 0xffffffff 1 0
InternalTriggerIntervalW 0x00000062 0xffffffff 1 1
TriggerMaskW 0x00000063 0xffffffff 1 1
TriggerVetoW 0x00000064 0xffffffff 1 1
ResetCountersW 0x00000066 0xffffffff 0 1
CoincidenceFunctionW 0x00000066 0xffffffff 0 1
StrechFormatW 0x00000067 0xffffffff 0 1
PostVetoTriggersR 0x00000068 0xffffffff 1 0
PreVetoTriggersR 0x00000069 0xffffffff 1 0
InternalTriggerIntervalR 0x0000006a 0xffffffff 1 1
TriggerMaskR 0x0000006b 0xffffffff 1 1
TriggerVetoR 0x0000006c 0xffffffff 1 1
ExternalTriggerVetoR 0x0000006d 0xffffffff 1 0
CoincidenceFunctionR 0x0000006e 0xffffffff 1 0
StrechFormatR 0x0000006f 0xffffffff 1 0
*
* event buffer = 0x080
EventFifoData 0x00000080 0xffffffff 1 0
EventFifoFillLevel 0x00000081 0xffffffff 1 0
EventFifoCSR 0x00000082 0xffffffff 1 1
EventFifoFillLevelFlags 0x00000082 0xffffffff 1 0
EventFifoData 0x00000080 0xffffffff 1 0
EventFifoFillLevel 0x00000081 0xffffffff 1 0
EventFifoCSR 0x00000082 0xffffffff 1 1
EventFifoFillLevelFlags 0x00000082 0xffffffff 1 0
*
* logic clocks = 0x0A0
LogicClocksCSR 0x000000A0 0xffffffff 1 1
......
......@@ -3,26 +3,30 @@
FirmwareId 0x00000000 0xffffffff 1 0
* DUT interfaces base = 0x020
DUTMaskW 0x00000020 0xffffffff 0 1
DUTMaskR 0x00000020 0xffffffff 1 0
DUTMaskR 0x00000021 0xffffffff 1 0
*
* trigger inputs = 0x040
SerdesRst 0x00000040 0xffffffff 1 1
ThrCount0 0x00000041 0xffffffff 1 0
ThrCount1 0x00000042 0xffffffff 1 0
ThrCount2 0x00000043 0xffffffff 1 0
ThrCount3 0x00000044 0xffffffff 1 0
SerdesRstW 0x00000040 0xffffffff 0 1
SerdesRstR 0x00000048 0xffffffff 1 0
ThrCount0R 0x00000049 0xffffffff 1 0
ThrCount1R 0x0000004a 0xffffffff 1 0
ThrCount2R 0x0000004b 0xffffffff 1 0
ThrCount3R 0x0000004c 0xffffffff 1 0
*
* trigger logic = 0x060 **Note the different read and write directions
InternalTriggerIntervalW 0x00000062 0xffffffff 1 1
TriggerMaskW 0x00000063 0xffffffff 1 1
TriggerVetoW 0x00000064 0xffffffff 1 1
ResetCountersW 0x00000066 0xffffffff 0 1
CoincidenceFunctionW 0x00000066 0xffffffff 0 1
StrechFormatW 0x00000067 0xffffffff 0 1
PostVetoTriggersR 0x00000068 0xffffffff 1 0
PreVetoTriggersR 0x00000069 0xffffffff 1 0
InternalTriggerIntervalR 0x0000006a 0xffffffff 1 1
TriggerMaskR 0x0000006b 0xffffffff 1 1
TriggerVetoR 0x0000006c 0xffffffff 1 1
ExternalTriggerVetoR 0x0000006d 0xffffffff 1 0
CoincidenceFunctionR 0x0000006e 0xffffffff 1 0
StrechFormatR 0x0000006f 0xffffffff 1 0
*
* event buffer = 0x080
EventFifoData 0x00000080 0xffffffff 1 0
......
......@@ -108,6 +108,10 @@ board.write("TriggerMaskW",0x0)
board.write("TriggerVetoW",0)
print "Trigger inputs enabled: ", board.read("TriggerMaskR")
print "Coincidence logic"
board.write("StrechFormatW",0x1) # strech the pulse 2 clock cycles
board.write("CoincidenceFunctionW",0x8000) # It will only generate triggers when all the inputs will be at high level at the same time
print "Reseting FIFO"
board.write("EventFifoCSR",0x2)
......@@ -124,7 +128,7 @@ board.write("InternalTriggerIntervalW",TriggerInterval) #0->Internal pulse gene
f=open("data/data.dat",'w')
n=600000 #number of measurements
n=1000 #number of measurements
data={"EvtType":[],"InputTrig":[],"CoarseTS":[],"FineTS0":[],"FineTS1":[],"FineTS2":[],"FineTS3":[],"EvtNumber":[], "TS":[]}
read=range(4)
trigger_old=0
......
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