From aef7f32cf2f00bb7bddbe750ec4c3c0fa594ce85 Mon Sep 17 00:00:00 2001 From: Jan Michel Date: Mon, 9 Aug 2021 14:06:41 +0200 Subject: [PATCH] first version of TDC --- .gitignore | 4 + code/ChannelRegs.vhd | 83 ++++++++++++ code/Decoder.vhd | 76 +++++++++++ code/FFregs.vhd | 39 ++++++ code/FFregs2.vhd | 39 ++++++ code/HitBuffer.vhd | 256 +++++++++++++++++++++++++++++++++++++ code/InpLut.vhd | 37 ++++++ code/ReadoutHandler.vhd | 268 +++++++++++++++++++++++++++++++++++++++ code/TDC_FF.vhd | 239 ++++++++++++++++++++++++++++++++++ code/clocked_tdc_pkg.vhd | 14 ++ 10 files changed, 1055 insertions(+) create mode 100644 .gitignore create mode 100644 code/ChannelRegs.vhd create mode 100644 code/Decoder.vhd create mode 100644 code/FFregs.vhd create mode 100644 code/FFregs2.vhd create mode 100644 code/HitBuffer.vhd create mode 100644 code/InpLut.vhd create mode 100644 code/ReadoutHandler.vhd create mode 100644 code/TDC_FF.vhd create mode 100644 code/clocked_tdc_pkg.vhd diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4b1b83d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +sim/work +transcript +*mti +*wlf diff --git a/code/ChannelRegs.vhd b/code/ChannelRegs.vhd new file mode 100644 index 0000000..4048659 --- /dev/null +++ b/code/ChannelRegs.vhd @@ -0,0 +1,83 @@ +library IEEE; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.trb_net_std.all; + + +entity ChannelRegs is + port( + CLK : in std_logic_vector(3 downto 0); + CLK_TDC : in std_logic; + CLK_SYS : in std_logic; + INP : in std_logic; + + CHANNEL_ENABLE : in std_logic; + CALIB_PULSE : in std_logic; + HIT_OUT : out std_logic_vector(5 downto 0); + HIT_VALID : out std_logic + ); +end entity; + + +architecture arch of ChannelRegs is + + signal FFregs, TDCregs : std_logic_vector(7 downto 0); + +-- signal finetime : std_logic_vector(6 downto 0); -- valid, edge, error, fine_4 + signal gated_inp : std_logic; + + signal nCLK : std_logic_vector(3 downto 0); + + attribute syn_keep : boolean; + attribute syn_preserve : boolean; + attribute syn_keep of gated_inp : signal is true; + attribute syn_preserve of gated_inp : signal is true; + + attribute syn_hier : string; + attribute syn_hier of arch : architecture is "firm,hard"; + +begin + +nCLK <= not CLK; + +THE_INP : entity work.InpLut + port map( + INP => INP, + ENABLE => CHANNEL_ENABLE, + PULSER => CALIB_PULSE, + OUTP => gated_inp + ); + +THE_FF : entity work.FFregs + port map( + CLK => CLK, + INP => gated_inp, + OUTP => FFregs(3 downto 0) + ); + +THE_FFF : entity work.FFregs + port map( + CLK => nCLK, + INP => gated_inp, + OUTP => FFregs(7 downto 4) + ); + +THE_FF2 : entity work.FFregs2 + port map( + CLK => CLK, + INP => FFregs, + OUTP => TDCregs + ); + +THE_DECODER : entity work.Decoder + port map( + CLK_FAST => CLK(0), + CLK_TDC => CLK_TDC, + TDC_IN => TDCregs, + HIT_OUT => HIT_OUT, + HIT_VALID => HIT_VALID + ); + +end architecture; diff --git a/code/Decoder.vhd b/code/Decoder.vhd new file mode 100644 index 0000000..267869f --- /dev/null +++ b/code/Decoder.vhd @@ -0,0 +1,76 @@ +library IEEE; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.trb_net_std.all; + + +entity Decoder is + port( + CLK_FAST: in std_logic; + CLK_TDC : in std_logic; + TDC_IN : in std_logic_vector(7 downto 0); + HIT_OUT : out std_logic_vector(5 downto 0); + HIT_VALID : out std_logic + ); +end entity; + +architecture arch of Decoder is + attribute HGROUP: string; + attribute HGROUP of arch : architecture is "Decoder"; + attribute BBOX: string; +-- attribute BBOX of arch: architecture is "1,16"; + + signal TDCregs, last_TDCregs : std_logic_vector(7 downto 0); + signal TDCregs_slow : std_logic_vector(16 downto 0); + signal final_cycle : std_logic; + signal final : std_logic_vector(8 downto 0); + signal finetime : std_logic_vector(5 downto 0); -- edge, error, fine_4 + + +begin + + +TDCregs <= TDC_IN when rising_edge(CLK_FAST); +last_TDCregs <= TDCregs when rising_edge(CLK_FAST); + +TDCregs_slow <= TDCregs & last_TDCregs & TDCregs_slow(16) when rising_edge(CLK_TDC); + +PROC_SELECT : process begin + wait until rising_edge(CLK_TDC); + if (TDCregs_slow(8) xor TDCregs_slow(0)) = '1' then + final <= TDCregs_slow(8 downto 0); + final_cycle <= '0'; + else + final <= TDCregs_slow(16 downto 8); + final_cycle <= '1'; + end if; +end process; + +PROC_DECODE : process begin + wait until rising_edge(CLK_TDC); + finetime <= (others => '0'); + + + finetime(3) <= final_cycle; --4th Bit + finetime(5) <= final(8); --Edge + HIT_VALID <= final(8) xor final(0); --Valid + + case final(7 downto 0) is + when x"01" | x"fe" => finetime(2 downto 0) <= "000"; + when x"03" | x"fc" => finetime(2 downto 0) <= "001"; + when x"07" | x"f8" => finetime(2 downto 0) <= "010"; + when x"0f" | x"f0" => finetime(2 downto 0) <= "011"; + when x"1f" | x"e0" => finetime(2 downto 0) <= "100"; + when x"3f" | x"c0" => finetime(2 downto 0) <= "101"; + when x"7f" | x"80" => finetime(2 downto 0) <= "110"; + when x"ff" | x"00" => finetime(2 downto 0) <= "111"; + when others => finetime(4) <= '1'; --Error + end case; + +end process; + +HIT_OUT <= finetime; + +end architecture; diff --git a/code/FFregs.vhd b/code/FFregs.vhd new file mode 100644 index 0000000..7ff4c67 --- /dev/null +++ b/code/FFregs.vhd @@ -0,0 +1,39 @@ +library IEEE; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.trb_net_std.all; + + +entity FFregs is + port( + CLK : in std_logic_vector(3 downto 0); + INP : in std_logic; + OUTP : out std_logic_vector(3 downto 0) + ); +end entity; + +architecture arch of FFregs is + attribute HGROUP: string; + attribute BBOX: string; + attribute HGROUP of arch : architecture is "FFregs"; + attribute BBOX of arch: architecture is "1,2"; + + signal CLKa : std_logic_vector(3 downto 0); + signal ffarr : std_logic_vector(3 downto 0); + +begin + +CLKa(3 downto 0) <= CLK(3 downto 0); +-- CLKa(7 downto 4) <= not CLK(3 downto 0); + + +gen_ffarr_first : for i in 0 to 3 generate + ffarr(i) <= INP when rising_edge(CLKa(i)); +-- OUTP(i) <= ffarr(i) when rising_edge(CLKa((i/4)*4)); + +end generate; +OUTP <= ffarr; + +end architecture; diff --git a/code/FFregs2.vhd b/code/FFregs2.vhd new file mode 100644 index 0000000..a4815c9 --- /dev/null +++ b/code/FFregs2.vhd @@ -0,0 +1,39 @@ +library IEEE; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.trb_net_std.all; + + +entity FFregs2 is + port( + CLK : in std_logic_vector(3 downto 0); + INP : in std_logic_vector(7 downto 0); + OUTP : out std_logic_vector(7 downto 0) + ); +end entity; + +architecture arch of FFregs2 is + attribute HGROUP: string; + attribute BBOX: string; + attribute HGROUP of arch : architecture is "FFregs2"; + attribute BBOX of arch: architecture is "1,2"; + + signal CLKa : std_logic_vector(7 downto 0); + signal FFregs : std_logic_vector(7 downto 0); + +begin + +CLKa(3 downto 0) <= CLK(3 downto 0); +CLKa(7 downto 4) <= not CLK(3 downto 0); + + +gen_ffarr_first : for i in 0 to 7 generate + FFregs(i) <= INP(i) when rising_edge(CLKa((i/4)*4)); +end generate; + +OUTP <= FFregs when rising_edge(CLK(0)); + + +end architecture; diff --git a/code/HitBuffer.vhd b/code/HitBuffer.vhd new file mode 100644 index 0000000..767a41d --- /dev/null +++ b/code/HitBuffer.vhd @@ -0,0 +1,256 @@ +library IEEE; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.trb_net_std.all; + + +entity HitBuffer is + port( + CLK_TDC : in std_logic; + CLK_SYS : in std_logic; + RESET_IN : in std_logic; + + HIT_IN : in std_logic_vector(5 downto 0); -- edge, error, fine_4 + HIT_VALID : in std_logic; + + COARSE_TIME_IN : in std_logic_vector(8 downto 0); + READOUT_ACTIVE : in std_logic; + SPIKE_SETTING : in unsigned(3 downto 0); + + DATA_OUT : out std_logic_vector(27 downto 0); + DATA_VALID : out std_logic; + DATA_EMPTY : out std_logic; + DATA_READ : in std_logic; + + STATUS_OUT : out std_logic_vector(95 downto 0) + ); +end entity; + + +architecture arch of HitBuffer is + + attribute HGROUP: string; + attribute HGROUP of arch : architecture is "HitBuffer"; + +signal reg_hit, cdc_data : std_logic_vector(17 downto 0); +signal reg_hit_valid : std_logic; + +signal cdc_empty, cdc_nextvalid, cdc_valid, cdc_read : std_logic; + +signal edge_rising : std_logic_vector(15 downto 0); +alias edge_rising_valid : std_logic is edge_rising(15); +alias edge_rising_error : std_logic is edge_rising(14); + +alias cdc_data_error : std_logic is cdc_data(4); + +signal full_hit : std_logic_vector(35 downto 0); +signal hit_buffer_write, hit_buffer_read : std_logic; +signal hit_buffer_empty, hit_buffer_full : std_logic; +signal last_hit_buffer_full : std_logic; +signal hit_buffer_reset : std_logic; +signal hit_buffer_dout : std_logic_vector(35 downto 0); +signal hit_buffer_level : std_logic_vector(5 downto 0); + +signal spike_timer : unsigned(3 downto 0) := (others => '0'); +signal hit_store : std_logic_vector(35 downto 0); +alias hit_store_coarse : std_logic_vector(8 downto 0) is hit_store(25 downto 17); + +signal count_fallingedges, count_risingedges : unsigned(23 downto 0); + +type buffer_state_t is (EMPTY,WAIT_HIT,WAIT_HIT2,GOT_HIT,HAS_HIT,DO_READOUT,WAIT_READOUT); +signal buffer_state : buffer_state_t; + +begin +---------------------------------------------------------------------- +-- Clock domain transfer +---------------------------------------------------------------------- +reg_hit <= "000" & COARSE_TIME_IN & HIT_IN when rising_edge(CLK_TDC); +reg_hit_valid <= HIT_VALID when rising_edge(CLK_TDC); +-- +-- THE_CDC_BUFFER : entity work.lattice_ecp3_fifo_18x16_dualport_oreg +-- port map( +-- DATA => reg_hit, +-- WrClock => CLK_TDC, +-- RdClock => CLK_SYS, +-- WrEn => reg_hit_valid, +-- RdEn => cdc_read, +-- Reset => RESET_IN, +-- RPReset => RESET_IN, +-- Q => cdc_data, +-- Empty => cdc_empty, +-- Full => open, +-- AlmostFull => open +-- ); +-- +-- cdc_read <= '1'; +-- cdc_nextvalid <= cdc_read and not cdc_empty when rising_edge(CLK_SYS); +-- cdc_valid <= cdc_nextvalid when rising_edge(CLK_SYS); +-- +-- + +cdc_data <= reg_hit; +cdc_valid <= reg_hit_valid; +---------------------------------------------------------------------- +-- Build full hits +---------------------------------------------------------------------- +PROC_BUILD_HIT : process begin + wait until rising_edge(CLK_TDC); + hit_buffer_write <= '0'; + full_hit <= (others => '0'); + if spike_timer /= x"0" then + spike_timer <= spike_timer - 1; + end if; + + + if cdc_valid = '1' and cdc_data(5) = '1' then + edge_rising <= '1' & cdc_data(4) & '0' & cdc_data(14 downto 6) & cdc_data(3 downto 0); +-- count_risingedges <= count_risingedges + 1; + spike_timer <= SPIKE_SETTING; + end if; + + if cdc_valid = '1' and cdc_data(5) = '0' then + full_hit <= x"00" & cdc_data_error & edge_rising_error & edge_rising(12 downto 0) & cdc_data(14 downto 6) & cdc_data(3 downto 0); + edge_rising_valid <= '0'; + if READOUT_ACTIVE = '0' and spike_timer = x"0" then + hit_buffer_write <= '1'; + count_fallingedges <= count_fallingedges + 1; + end if; +-- count_fallingedges <= count_fallingedges + 1; + end if; + + if RESET_IN = '1' then +-- count_risingedges <= (others => '0'); + count_fallingedges <= (others => '0'); + end if; + +end process; + +---------------------------------------------------------------------- +-- Hit Buffer +---------------------------------------------------------------------- +THE_HIT_BUF : entity work.fifo_36x32 + port map ( + Data => full_hit, + Clock => CLK_TDC, + WrEn => hit_buffer_write, + RdEn => hit_buffer_read, + Reset => hit_buffer_reset, + AmFullThresh => "01000", + Q => hit_buffer_dout, + WCNT => hit_buffer_level, + Empty => hit_buffer_empty, + Full => open, + AlmostFull => hit_buffer_full + ); + +last_hit_buffer_full <= hit_buffer_full when rising_edge(CLK_TDC); + +-- hit_buffer_nextvalid <= hit_buffer_read and not hit_buffer_empty when rising_edge(CLK_TDC); +-- hit_buffer_valid <= hit_buffer_nextvalid when rising_edge(CLK_TDC); + + +---------------------------------------------------------------------- +-- Buffer Handling +---------------------------------------------------------------------- +PROC_BUF : process begin + wait until rising_edge(CLK_TDC); + hit_buffer_read <= '0'; + hit_buffer_reset <= '0'; + DATA_EMPTY <= '0'; + + if hit_buffer_read = '1' then + count_risingedges <= count_risingedges + 1; + end if; + + case buffer_state is + when EMPTY => + DATA_EMPTY <= '1'; + if hit_buffer_empty = '0' then + hit_buffer_read <= '1'; + buffer_state <= WAIT_HIT; + end if; + if READOUT_ACTIVE = '1' then + buffer_state <= WAIT_READOUT; + end if; + + when WAIT_HIT => + if hit_buffer_empty = '1' then + if READOUT_ACTIVE = '0' then + buffer_state <= EMPTY; + else + buffer_state <= WAIT_READOUT; + end if; + else + if READOUT_ACTIVE = '0' then + buffer_state <= GOT_HIT; + else + buffer_state <= DO_READOUT; + end if; + end if; + + when WAIT_HIT2 => + buffer_state <= GOT_HIT; + + when GOT_HIT => + hit_store <= hit_buffer_dout; + buffer_state <= HAS_HIT; + + when HAS_HIT => + if READOUT_ACTIVE = '0' then + if hit_buffer_full = '1' then + hit_buffer_read <= '1'; + buffer_state <= WAIT_HIT; + elsif hit_store_coarse = COARSE_TIME_IN then --too old + hit_buffer_read <= '1'; + buffer_state <= WAIT_HIT; + end if; + else + buffer_state <= DO_READOUT; + end if; + + when DO_READOUT => + if DATA_READ = '1' then + hit_buffer_read <= '1'; + buffer_state <= WAIT_HIT; + end if; + + if READOUT_ACTIVE = '0' then + buffer_state <= EMPTY; + hit_buffer_reset <= '1'; + end if; + + when WAIT_READOUT => + DATA_EMPTY <= '1'; + if READOUT_ACTIVE = '0' then + buffer_state <= EMPTY; + hit_buffer_reset <= '1'; + end if; + end case; + + + if RESET_IN = '1' then + buffer_state <= EMPTY; + hit_buffer_reset <= '1'; + count_risingedges <= (others => '0'); + end if; +end process; + +DATA_OUT <= hit_store(27 downto 0); + +---------------------------------------------------------------------- +-- Statistics +---------------------------------------------------------------------- +STATUS_OUT(31 downto 0) <= x"00" & std_logic_vector(count_risingedges) when rising_edge(CLK_SYS); +STATUS_OUT(63 downto 32) <= x"00" & std_logic_vector(count_fallingedges) when rising_edge(CLK_SYS); +STATUS_OUT(71 downto 64) <= "00" & hit_buffer_level when rising_edge(CLK_SYS); +STATUS_OUT(75 downto 72) <= std_logic_vector(spike_timer) when rising_edge(CLK_SYS); + + +---------------------------------------------------------------------- +-- Dummy +---------------------------------------------------------------------- +-- DATA_OUT(5 downto 0) <= hit_buffer_dout(5 downto 0); + +end architecture; diff --git a/code/InpLut.vhd b/code/InpLut.vhd new file mode 100644 index 0000000..af88581 --- /dev/null +++ b/code/InpLut.vhd @@ -0,0 +1,37 @@ +library IEEE; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.trb_net_std.all; + + +entity InpLut is + port( + INP : in std_logic; + ENABLE : in std_logic; + PULSER : in std_logic; + OUTP : out std_logic + ); +end entity; + +architecture arch of InpLut is + attribute HGROUP: string; + attribute BBOX: string; + attribute HGROUP of arch : architecture is "InpLut"; + attribute BBOX of arch: architecture is "1,1"; + + attribute syn_hier : string; + attribute syn_hier of arch : architecture is "firm,hard"; + +-- attribute syn_keep : boolean; +-- attribute syn_preserve : boolean; +-- attribute syn_keep of OUTP : signal is true; +-- attribute syn_preserve of OUTP : signal is true; + + +begin + +OUTP <= (INP and ENABLE) or PULSER; + +end architecture; diff --git a/code/ReadoutHandler.vhd b/code/ReadoutHandler.vhd new file mode 100644 index 0000000..c4d24e5 --- /dev/null +++ b/code/ReadoutHandler.vhd @@ -0,0 +1,268 @@ +library IEEE; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.trb_net_std.all; +use work.clocked_tdc_pkg.all; + +entity ReadoutHandler is + generic( + NUM_CHANNELS : integer range 2 to 32 := 16; + GROUP_NUM : std_logic := '0' + ); + port( + CLK_TDC : in std_logic; + CLK_SYS : in std_logic; + RESET_IN : in std_logic; + + + REFERENCE_IN : in std_logic_vector(12 downto 0); + DATA_IN : in tdc_data_t(NUM_CHANNELS-1 downto 0); + DATA_VALID_IN : in std_logic_vector(NUM_CHANNELS-1 downto 0); + DATA_EMPTY_IN : in std_logic_vector(NUM_CHANNELS-1 downto 0); + DATA_READ_OUT : out std_logic_vector(NUM_CHANNELS-1 downto 0); + READOUT_ACTIVE: out std_logic; + CALIB_PULSE : out std_logic; +-- BUS_RX : in CTRLBUS_RX; +-- BUS_TX : out CTRLBUS_TX; + + READOUT_RX : in READOUT_RX; + READOUT_TX : out READOUT_TX; + STATUS_OUT : out std_logic_vector(31 downto 0) + + ); +end entity; + + +architecture arch of ReadoutHandler is + +signal timer, timer_d : unsigned(7 downto 0); + +type state_rdo_t is (IDLE,CALIB,WAIT_WINDOW, COLLECT, FINISH); +signal state_rdo : state_rdo_t; + +type state_data_t is (IDLE, CHANNEL_FIRST, END1, END2, FINISH); +signal state_data : state_data_t; + +signal cdc_data_out : std_logic_vector(35 downto 0); +signal cdc_data_in : std_logic_vector(31 downto 0); +signal cdc_valid, cdc_nextvalid, cdc_read, cdc_empty, cdc_write : std_logic; +signal last_cdc_empty : std_logic; + +signal collect_start_sys, collect_start_tdc : std_logic; +signal collect_finish_sys, collect_finish_tdc : std_logic; +signal got_collect_finish : std_logic; +signal is_calib_sys : std_logic; + +signal hit_valid, hit_calc_valid, hit_check_valid : std_logic; +signal hit_data : std_logic_vector(31 downto 0); +signal hit_calc_data, hit_check_data : std_logic_vector(31 downto 0); + +signal buf_READOUT_ACTIVE : std_logic; +begin + +READOUT_ACTIVE <= buf_READOUT_ACTIVE when rising_edge(CLK_TDC); + +---------------------------------------------------------------------- +-- Readout Handler +---------------------------------------------------------------------- +PROC_RDO_SYSTEM : process begin + wait until rising_edge(CLK_SYS); + + READOUT_TX.data_finished <= '0'; + READOUT_TX.busy_release <= '0'; + READOUT_TX.data_write <= '0'; + collect_start_sys <= '0'; + got_collect_finish <= '0'; + last_cdc_empty <= cdc_empty; + CALIB_PULSE <= '0'; + + case state_rdo is + when IDLE => + buf_READOUT_ACTIVE <= '0'; + if READOUT_RX.valid_timing_trg = '1' then + state_rdo <= COLLECT; + collect_start_sys <= '1'; + is_calib_sys <= '0'; + buf_READOUT_ACTIVE <= '1'; + elsif READOUT_RX.valid_notiming_trg = '1' then + state_rdo <= CALIB; + is_calib_sys <= '1'; + timer <= (others => '0'); + elsif READOUT_RX.invalid_trg = '1' then + state_rdo <= FINISH; + end if; + + when CALIB => + timer <= timer + 1; + if timer >= x"05" and timer <= x"09" then + CALIB_PULSE <= '1'; + elsif timer = x"F0" then + state_rdo <= COLLECT; + buf_READOUT_ACTIVE <= '1'; + collect_start_sys <= '1'; + end if; + + when WAIT_WINDOW => + null; + + when COLLECT => + READOUT_TX.data <= cdc_data_out(31 downto 0); + READOUT_TX.data_write <= cdc_valid; + got_collect_finish <= got_collect_finish or collect_finish_sys; + if (got_collect_finish = '1') and last_cdc_empty = '1' then + state_rdo <= FINISH; + end if; + + when FINISH => + READOUT_TX.data_finished <= '1'; + READOUT_TX.busy_release <= '1'; + state_rdo <= IDLE; + end case; + + +end process; + +---------------------------------------------------------------------- +-- TDC Data Collector & Processor +---------------------------------------------------------------------- +PROC_RDO_TDC : process + variable channel : integer range 0 to 16 := 0; +begin + wait until rising_edge(CLK_TDC); + collect_finish_tdc <= '0'; + hit_valid <= '0'; + + cdc_write <= hit_check_valid; + cdc_data_in <= hit_check_data; + DATA_READ_OUT <= (others => '0'); + + case state_data is + when IDLE => + channel := 0; + if collect_start_tdc = '1' then + cdc_data_in <= x"1DC0" & "000" & REFERENCE_IN; + if GROUP_NUM = '0' then + cdc_write <= '1'; + end if; + state_data <= CHANNEL_FIRST; + end if; + + when CHANNEL_FIRST => + if DATA_EMPTY_IN(channel) = '0' then + hit_data <= std_logic_vector(to_unsigned(channel,4)) & DATA_IN(channel); + hit_valid <= '1'; + DATA_READ_OUT(channel) <= '1'; + end if; +-- else + if channel < 15 then + channel := channel + 1; + else + state_data <= END1; + end if; +-- end if; + + when END1 => + state_data <= END2; + timer_d <= (others => '0'); + + when END2 => + timer_d <= timer_d + 1; + if timer_d = x"02" and and(DATA_EMPTY_IN) = '0' then + channel := 0; + state_data <= CHANNEL_FIRST; + elsif timer_d = x"03" then + state_data <= FINISH; + end if; + + when FINISH => + collect_finish_tdc <= '1'; + state_data <= IDLE; + end case; + + +end process; + +---------------------------------------------------------------------- +-- Calculate hit data +---------------------------------------------------------------------- +hit_calc_valid <= hit_valid when rising_edge(CLK_TDC); +-- hit_calc_data <= GROUP_NUM & hit_data(31 downto 28) --5 channel +-- & (hit_data(27) or hit_data(26)) --1 error +-- & std_logic_vector(unsigned(REFERENCE_IN) - unsigned(hit_data(25 downto 13))) --13 leading edge +-- & std_logic_vector(unsigned(hit_data(25 downto 13)) - unsigned(hit_data(12 downto 0))) --13 ToT +-- when rising_edge(CLK_TDC); +hit_calc_data <= GROUP_NUM & hit_data(31 downto 28) --5 channel + & (hit_data(27) or hit_data(26)) --1 error + & std_logic_vector(unsigned(hit_data(25 downto 13))) --13 leading edge + & std_logic_vector(unsigned(hit_data(12 downto 0))) --13 ToT + when rising_edge(CLK_TDC); + +hit_check_valid <= hit_calc_valid; +hit_check_data <= hit_calc_data; + +---------------------------------------------------------------------- +-- Signal CDC +---------------------------------------------------------------------- + +THE_SYS_TO_TDC : entity work.pulse_sync + port map( + CLK_A_IN => CLK_SYS, + RESET_A_IN => RESET_IN, + PULSE_A_IN => collect_start_sys, + CLK_B_IN => CLK_TDC, + RESET_B_IN => RESET_IN, + PULSE_B_OUT => collect_start_tdc + ); + +THE_TDC_TO_SYS : entity work.pulse_sync + port map( + CLK_A_IN => CLK_TDC, + RESET_A_IN => RESET_IN, + PULSE_A_IN => collect_finish_tdc, + CLK_B_IN => CLK_SYS, + RESET_B_IN => RESET_IN, + PULSE_B_OUT => collect_finish_sys + ); + + + +---------------------------------------------------------------------- +-- CDC Buffer +---------------------------------------------------------------------- +THE_CDC_BUFFER : entity work.fifo_36x512_dualport_oreg + port map( + DATA(31 downto 0) => cdc_data_in, + DATA(35 downto 32) => x"0", + WrClock => CLK_TDC, + RdClock => CLK_SYS, + WrEn => cdc_write, + RdEn => cdc_read, + Reset => RESET_IN, + RPReset => RESET_IN, + Q => cdc_data_out, + Empty => cdc_empty, + Full => open, + AlmostFull => open + ); + +cdc_read <= '1'; +cdc_nextvalid <= cdc_read and not cdc_empty when rising_edge(CLK_SYS); +cdc_valid <= cdc_nextvalid when rising_edge(CLK_SYS); + + + STATUS_OUT(3 downto 0) <= x"0" when state_rdo = IDLE else + x"1" when state_rdo = CALIB else + x"2" when state_rdo = WAIT_WINDOW else + x"3" when state_rdo = COLLECT else + x"4" when state_rdo = FINISH else x"F"; + STATUS_OUT(7 downto 4) <= x"0" when state_data = IDLE else + x"1" when state_data = CHANNEL_FIRST else + x"2" when state_data = END1 else + x"3" when state_data = END2 else + x"4" when state_data = FINISH else x"F"; + STATUS_OUT(8) <= buf_READOUT_ACTIVE; + STATUS_OUT(9) <= got_collect_finish; + +end architecture; diff --git a/code/TDC_FF.vhd b/code/TDC_FF.vhd new file mode 100644 index 0000000..ebc5ad9 --- /dev/null +++ b/code/TDC_FF.vhd @@ -0,0 +1,239 @@ +library IEEE; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.trb_net_std.all; +use work.clocked_tdc_pkg.all; + +entity TDC_FF is + generic( + NUM_CHANNELS : integer range 2 to 32 := 32 + ); + port( + CLK_FAST : in std_logic; + CLK_SYS : in std_logic; + RESET_IN : in std_logic; + + SIGNAL_IN : in std_logic_vector(31 downto 0); + TRIGGER_IN: in std_logic; + CALIBRATION_OUT : out std_logic; + + BUS_RX : in CTRLBUS_RX; + BUS_TX : out CTRLBUS_TX; + + READOUT_RX : in READOUT_RX; + READOUT_TX : out readout_tx_array_t(0 to 1); + + DUMMY : out std_logic + ); +end entity; + + +architecture arch of TDC_FF is + +signal clk_pll : std_logic_vector(3 downto 0); +type tdc_hit_t is array(0 to 31) of std_logic_vector(5 downto 0); +signal tdc_hit : tdc_hit_t; +signal tdc_valid : std_logic_vector(NUM_CHANNELS-1 downto 0); +signal tdc_data_valid, tdc_data_read, tdc_data_empty : std_logic_vector(NUM_CHANNELS-1 downto 0); + +signal ref_valid : std_logic; +signal ref_hit : std_logic_vector(5 downto 0); +signal ref_timestamp : std_logic_vector(12 downto 0); +signal readout_active_i : std_logic_vector(1 downto 0); +signal calibration_pulse, calibration_pulse_i : std_logic_vector(1 downto 0); + +signal tdc_data : tdc_data_t(NUM_CHANNELS-1 downto 0); + +signal coarse_time : unsigned(8 downto 0) := (others => '0'); + +type status_t is array(0 to 31) of std_logic_vector(95 downto 0); +signal hitbuffer_status : status_t; + +signal CONF_enable : std_logic_vector(31 downto 0) := (others => '1'); +signal CONF_configure : std_logic_vector(31 downto 0) := x"00000300"; +alias CONF_externalcalibration : std_logic is CONF_configure(0); +alias CONF_SPIKE : std_logic_vector(3 downto 0) is CONF_configure(11 downto 8); + +signal status_rdo_handler : std_logic_vector(63 downto 0); +begin +---------------------------------------------------------------------- +-- Infrastructure +---------------------------------------------------------------------- +coarse_time <= coarse_time + 1 when rising_edge(CLK_FAST); + +THE_PLL : entity work.PLL_TDC + port map( + CLKI => CLK_FAST, + CLKOP => clk_pll(0), + CLKOS => clk_pll(1), + CLKOS2 => clk_pll(2), + CLKOS3 => clk_pll(3) + ); + + +---------------------------------------------------------------------- +-- Reference Channel +---------------------------------------------------------------------- + +THE_REF_CHANNEL : entity work.ChannelRegs + port map( + CLK => clk_pll, + CLK_TDC => CLK_FAST, + CLK_SYS => CLK_SYS, + INP => TRIGGER_IN, + CHANNEL_ENABLE => '1', + CALIB_PULSE => calibration_pulse(0), + HIT_OUT => ref_hit, + HIT_VALID => ref_valid + ); + +PROC_REF_CHANNEL : process begin + wait until rising_edge(CLK_FAST); + if ref_valid = '1' and ref_hit(5) = '1' then + ref_timestamp <= std_logic_vector(coarse_time) & ref_hit(3 downto 0); + end if; +end process; + +---------------------------------------------------------------------- +-- The TDCs +---------------------------------------------------------------------- + +gen_CHANNELS : for i in 0 to NUM_CHANNELS-1 generate + THE_CHANNEL : entity work.ChannelRegs + port map( + CLK => clk_pll, + CLK_TDC => CLK_FAST, + CLK_SYS => CLK_SYS, + INP => SIGNAL_IN(i), + CHANNEL_ENABLE => CONF_enable(i), + CALIB_PULSE => calibration_pulse_i(i/16), + HIT_OUT => tdc_hit(i), + HIT_VALID => tdc_valid(i) + ); + + THE_HITBUF : entity work.HitBuffer + port map( + CLK_TDC => CLK_FAST, + CLK_SYS => CLK_SYS, + RESET_IN => RESET_IN, + HIT_IN => tdc_hit(i), + HIT_VALID => tdc_valid(i), + + COARSE_TIME_IN => std_logic_vector(coarse_time), + READOUT_ACTIVE => readout_active_i(i/16), + SPIKE_SETTING => unsigned(CONF_SPIKE), + + DATA_OUT => tdc_data(i), + DATA_VALID => tdc_data_valid(i), + DATA_EMPTY => tdc_data_empty(i), + DATA_READ => tdc_data_read(i), + STATUS_OUT => hitbuffer_status(i) + ); + +end generate; + +---------------------------------------------------------------------- +-- Readout Handler +---------------------------------------------------------------------- +THE_RDO_HANDLER_1 : entity work.ReadoutHandler + generic map( + GROUP_NUM => '0' + ) + port map( + CLK_TDC => CLK_FAST, + CLK_SYS => CLK_SYS, + RESET_IN => RESET_IN, + + REFERENCE_IN => ref_timestamp, + + DATA_IN => tdc_data(15 downto 0), + DATA_VALID_IN => tdc_data_valid(15 downto 0), + DATA_EMPTY_IN => tdc_data_empty(15 downto 0), + DATA_READ_OUT => tdc_data_read(15 downto 0), + READOUT_ACTIVE => readout_active_i(0), + CALIB_PULSE => calibration_pulse(0), + + READOUT_RX => READOUT_RX, + READOUT_TX => READOUT_TX(0), + STATUS_OUT => status_rdo_handler(31 downto 0) + + ); + +THE_RDO_HANDLER_2 : entity work.ReadoutHandler + generic map( + GROUP_NUM => '1' + ) + port map( + CLK_TDC => CLK_FAST, + CLK_SYS => CLK_SYS, + RESET_IN => RESET_IN, + + REFERENCE_IN => ref_timestamp, + + DATA_IN => tdc_data(31 downto 16), + DATA_VALID_IN => tdc_data_valid(31 downto 16), + DATA_EMPTY_IN => tdc_data_empty(31 downto 16), + DATA_READ_OUT => tdc_data_read(31 downto 16), + READOUT_ACTIVE => readout_active_i(1), + CALIB_PULSE => calibration_pulse(1), + + READOUT_RX => READOUT_RX, + READOUT_TX => READOUT_TX(1), + STATUS_OUT => status_rdo_handler(63 downto 32) + + ); + + +CALIBRATION_OUT <= calibration_pulse(0) when CONF_externalcalibration = '1' else '0'; +calibration_pulse_i <= calibration_pulse when CONF_externalcalibration = '0' else "00"; + +---------------------------------------------------------------------- +-- Slow Control +---------------------------------------------------------------------- +PROC_REGS : process + variable addr : integer range 0 to 31; +begin + wait until rising_edge(CLK_SYS); + BUS_TX.ack <= '0'; + BUS_TX.unknown <= '0'; + BUS_TX.nack <= '0'; + BUS_TX.data <= (others => '0'); + addr := to_integer(unsigned(BUS_RX.addr(4 downto 0))); + if BUS_RX.write = '1' then + BUS_TX.ack <= '1'; + if BUS_RX.addr = x"0000" then + CONF_enable <= BUS_RX.data; + elsif BUS_RX.addr = x"0001" then + CONF_configure <= BUS_RX.data; + else + BUS_TX.ack <= '0'; + BUS_TX.unknown <= '1'; + end if; + elsif BUS_RX.read = '1' then + BUS_TX.ack <= '1'; + if BUS_RX.addr = x"0000" then + BUS_TX.data <= CONF_enable; + elsif BUS_RX.addr = x"0001" then + BUS_TX.data <= CONF_configure; + elsif BUS_RX.addr = x"0010" then + BUS_TX.data <= status_rdo_handler(31 downto 0); + elsif BUS_RX.addr = x"0002" then + BUS_TX.data <= status_rdo_handler(63 downto 32); + elsif BUS_RX.addr(15 downto 5) = x"01" & "000" then + BUS_TX.data <= hitbuffer_status(addr)(31 downto 0); + elsif BUS_RX.addr(15 downto 5) = x"01" & "001" then + BUS_TX.data <= hitbuffer_status(addr)(63 downto 32); + elsif BUS_RX.addr(15 downto 5) = x"01" & "010" then + BUS_TX.data <= hitbuffer_status(addr)(95 downto 64); + else + BUS_TX.ack <= '0'; + BUS_TX.unknown <= '1'; + + end if; + end if; +end process; + + +end architecture; diff --git a/code/clocked_tdc_pkg.vhd b/code/clocked_tdc_pkg.vhd new file mode 100644 index 0000000..6ad87d3 --- /dev/null +++ b/code/clocked_tdc_pkg.vhd @@ -0,0 +1,14 @@ +library IEEE; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +package clocked_tdc_pkg is + +type tdc_data_t is array(integer range <>) of std_logic_vector(27 downto 0); + + +end package; + +package body clocked_tdc_pkg is + +end package body; -- 2.43.0