]> jspc29.x-matter.uni-frankfurt.de Git - clocked_tdc.git/commitdiff
first version of TDC
authorJan Michel <j.michel@gsi.de>
Mon, 9 Aug 2021 12:06:41 +0000 (14:06 +0200)
committerJan Michel <j.michel@gsi.de>
Mon, 9 Aug 2021 12:06:41 +0000 (14:06 +0200)
.gitignore [new file with mode: 0644]
code/ChannelRegs.vhd [new file with mode: 0644]
code/Decoder.vhd [new file with mode: 0644]
code/FFregs.vhd [new file with mode: 0644]
code/FFregs2.vhd [new file with mode: 0644]
code/HitBuffer.vhd [new file with mode: 0644]
code/InpLut.vhd [new file with mode: 0644]
code/ReadoutHandler.vhd [new file with mode: 0644]
code/TDC_FF.vhd [new file with mode: 0644]
code/clocked_tdc_pkg.vhd [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..4b1b83d
--- /dev/null
@@ -0,0 +1,4 @@
+sim/work
+transcript
+*mti
+*wlf
diff --git a/code/ChannelRegs.vhd b/code/ChannelRegs.vhd
new file mode 100644 (file)
index 0000000..4048659
--- /dev/null
@@ -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 (file)
index 0000000..267869f
--- /dev/null
@@ -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 (file)
index 0000000..7ff4c67
--- /dev/null
@@ -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 (file)
index 0000000..a4815c9
--- /dev/null
@@ -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 (file)
index 0000000..767a41d
--- /dev/null
@@ -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 (file)
index 0000000..af88581
--- /dev/null
@@ -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 (file)
index 0000000..c4d24e5
--- /dev/null
@@ -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 (file)
index 0000000..ebc5ad9
--- /dev/null
@@ -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 (file)
index 0000000..6ad87d3
--- /dev/null
@@ -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;