Block Preview

Introduction

Principle of Operation

Like the V1 Citiroc Analog block, this component owns the analog readout sequence of a single CITIROC 1A: it waits HOLD_TIME cycles after the trigger edge, closes the HG/LG peak-detector hold, walks the ASIC charge shift register and digitises each slot through the board ADC, and publishes the result as a serial stream, as 32 parallel pin triplets and as a packed 1024-bit frame word.

Three mechanisms are added on top.

1 — Time-to-digital conversion. The block instantiates tdc_sync_nofifo, fed by the board’s six-phase TDC clock group. The asynchronous 32-channel trigger OR (T_OR32) is captured on four skewed clocks plus the in-phase and quadrature system clocks, giving a 4-bit fine time inside one clock period (16 steps). The event timestamp is then

$$ t_{\mathrm{event}} ;=; \underbrace{\mathrm{coarse}}{44\ \mathrm{bits}} \times 16 ;+; \underbrace{\mathrm{fine}}{4\ \mathrm{bits}} $$

and is published on TS_OUT, replacing the coarse value captured at the trigger edge.

2 — Validation. An external decision (a coincidence, a downstream veto, a software gate) can confirm or discard an event after the hold has been closed but before the expensive shift-register walk begins. The FSM parks in one state waiting for VALIDATION_IN; if the confirmation does not arrive within a programmable timeout the event is either read out anyway or aborted, depending on the CFG register.

3 — Bookkeeping. A trigger counter, a validation counter and a 32-bit FLAGS word that records why the event was released are exported as pins, so the Citiroc Frame Transfer V2 block can append them to every packet.

Pin Description

TS_IN Input 64 bit BIT VECTOR
Global timestamp in – 64-bit free-running counter. Bits 43:0 feed the TDC as the coarse time base; bits 59:0 are latched (shifted left by 4) into TS_OUT at the trigger edge before the TDC result arrives.
TS0_IN Input 32 bit BIT VECTOR
Run/T0 timestamp in – 32-bit counter, latched into TS0_OUT at the trigger edge.
TRIG Input 1 bit BIT
Trigger – rising-edge sensitive, starts the analog readout sequence and reloads the validation timeout. Also increments CNT_TRIGGER.
REJECT Input 1 bit BIT
Abort – sampled every clock in every state. High aborts the event in flight and restarts the ASIC channel-reset sequence; no P_DV / P_FRAME_DV is produced.
P_FRAME_ACK Input 1 bit BIT
Frame acknowledge – clears P_FRAME_DV. Drive from ACK_x of the Citiroc Frame Transfer V2 block; unconnected, P_FRAME_DV latches high permanently.
HOLD_TIME Input 16 bit BIT VECTOR
Trigger-to-hold delay in clock cycles, applied between the accepted trigger edge and the assertion of the HG/LG hold. Runtime bus, tunable from a register.
T_OR32 Input 1 bit BIT
Asynchronous trigger OR – the raw 32-channel time-trigger OR of the ASIC, fed to the TDC’s asynchronous hit input. It is intentionally sampled outside the system clock domain; registering it upstream destroys the sub-clock resolution.
T0 Input 1 bit BIT
Time reference – latched together with each TDC hit as the t_ref flag, marking hits that coincide with the reference. Tie low if no external T0 is used.
VALIDATION_IN Input 1 bit BIT
External validation – confirms the event currently held. Level or rising-edge sensitive according to CFG bit 4. A pulse arriving with no event in flight takes the forced-frame path when CFG bit 2 is set and VETO is low. Ignored entirely when CFG bit 0 is 0.
RUNRESET Input 1 bit BIT
Run reset – while high, clears both CNT_TRIGGER and CNT_VAL. Pulse it at the start of every acquisition run so the counters in the packets start from zero.
VETO Input 1 bit BIT
Software veto – blocks the forced-frame path only. When high, a validation pulse with no event in flight is counted but produces no data. It does not veto normal triggered events.
CFG Input 32 bit BIT VECTOR
Validation configuration register – bit 0 enables validation, bit 1 selects the timeout action, bit 2 enables forced frames, bit 4 selects edge vs level, bits 31:16 hold the validation timeout in clock cycles. See the register table above. Drive it from a memory-mapped register so it can be reprogrammed at runtime.
TS_OUT Output 64 bit BIT VECTOR
Event timestamp – TDC-refined: the low 4 bits are the fine time inside one clock period, the bits above are the coarse counter. It is written twice per event (coarse at the trigger, TDC value a few cycles later), so sample it at the end of the readout.
TS0_OUT Output 32 bit BIT VECTOR
Run timestamp of the event – TS0_IN frozen at the trigger edge, no TDC applied.
S_CHID Output 5 bit BIT VECTOR
Serial channel index – 0…31, valid while S_DV is high.
S_ENERGY_LG Output 16 bit BIT VECTOR
Serial low-gain charge. Not driven by the V2 HDL — see S_ENERGY_HG.
S_ENERGY_HG Output 16 bit BIT VECTOR
Serial high-gain charge. Not driven by the V2 HDL — the readout writes an internal debug signal instead of this port. Use P_E_HG_n or P_FRAME_DATA.
S_HIT Output 1 bit BIT
Serial hit flag – the CHARGE_HIT discriminator captured for that channel and re-aligned through the internal HITMEM buffer to match the delayed sampling point. Valid while S_DV is high.
S_DV Output 1 bit BIT
Serial data valid – one-cycle pulse per channel, 32 per event.
P_E_LG_0 Output 16 bit BIT VECTOR
First of a 32-pin bus. Parallel low-gain charge, one pin per channel – qualified by P_DV.
P_E_HG_0 Output 16 bit BIT VECTOR
First of a 32-pin bus. Parallel high-gain charge, one pin per channel – all refreshed together at the end of the readout, qualified by P_DV.
P_H_0 Output 1 bit BIT
First of a 32-pin bus. Parallel hit flag, one pin per channel.
P_E_LG_1 Output 16 bit BIT VECTOR
P_E_HG_1 Output 16 bit BIT VECTOR
P_H_1 Output 1 bit BIT
P_E_LG_2 Output 16 bit BIT VECTOR
P_E_HG_2 Output 16 bit BIT VECTOR
P_H_2 Output 1 bit BIT
P_E_LG_3 Output 16 bit BIT VECTOR
P_E_HG_3 Output 16 bit BIT VECTOR
P_H_3 Output 1 bit BIT
P_E_LG_4 Output 16 bit BIT VECTOR
P_E_HG_4 Output 16 bit BIT VECTOR
P_H_4 Output 1 bit BIT
P_E_LG_5 Output 16 bit BIT VECTOR
P_E_HG_5 Output 16 bit BIT VECTOR
P_H_5 Output 1 bit BIT
P_E_LG_6 Output 16 bit BIT VECTOR
P_E_HG_6 Output 16 bit BIT VECTOR
P_H_6 Output 1 bit BIT
P_E_LG_7 Output 16 bit BIT VECTOR
P_E_HG_7 Output 16 bit BIT VECTOR
P_H_7 Output 1 bit BIT
P_E_LG_8 Output 16 bit BIT VECTOR
P_E_HG_8 Output 16 bit BIT VECTOR
P_H_8 Output 1 bit BIT
P_E_LG_9 Output 16 bit BIT VECTOR
P_E_HG_9 Output 16 bit BIT VECTOR
P_H_9 Output 1 bit BIT
P_E_LG_10 Output 16 bit BIT VECTOR
P_E_HG_10 Output 16 bit BIT VECTOR
P_H_10 Output 1 bit BIT
P_E_LG_11 Output 16 bit BIT VECTOR
P_E_HG_11 Output 16 bit BIT VECTOR
P_H_11 Output 1 bit BIT
P_E_LG_12 Output 16 bit BIT VECTOR
P_E_HG_12 Output 16 bit BIT VECTOR
P_H_12 Output 1 bit BIT
P_E_LG_13 Output 16 bit BIT VECTOR
P_E_HG_13 Output 16 bit BIT VECTOR
P_H_13 Output 1 bit BIT
P_E_LG_14 Output 16 bit BIT VECTOR
P_E_HG_14 Output 16 bit BIT VECTOR
P_H_14 Output 1 bit BIT
P_E_LG_15 Output 16 bit BIT VECTOR
P_E_HG_15 Output 16 bit BIT VECTOR
P_H_15 Output 1 bit BIT
P_E_LG_16 Output 16 bit BIT VECTOR
P_E_HG_16 Output 16 bit BIT VECTOR
P_H_16 Output 1 bit BIT
P_E_LG_17 Output 16 bit BIT VECTOR
P_E_HG_17 Output 16 bit BIT VECTOR
P_H_17 Output 1 bit BIT
P_E_LG_18 Output 16 bit BIT VECTOR
P_E_HG_18 Output 16 bit BIT VECTOR
P_H_18 Output 1 bit BIT
P_E_LG_19 Output 16 bit BIT VECTOR
P_E_HG_19 Output 16 bit BIT VECTOR
P_H_19 Output 1 bit BIT
P_E_LG_20 Output 16 bit BIT VECTOR
P_E_HG_20 Output 16 bit BIT VECTOR
P_H_20 Output 1 bit BIT
P_E_LG_21 Output 16 bit BIT VECTOR
P_E_HG_21 Output 16 bit BIT VECTOR
P_H_21 Output 1 bit BIT
P_E_LG_22 Output 16 bit BIT VECTOR
P_E_HG_22 Output 16 bit BIT VECTOR
P_H_22 Output 1 bit BIT
P_E_LG_23 Output 16 bit BIT VECTOR
P_E_HG_23 Output 16 bit BIT VECTOR
P_H_23 Output 1 bit BIT
P_E_LG_24 Output 16 bit BIT VECTOR
P_E_HG_24 Output 16 bit BIT VECTOR
P_H_24 Output 1 bit BIT
P_E_LG_25 Output 16 bit BIT VECTOR
P_E_HG_25 Output 16 bit BIT VECTOR
P_H_25 Output 1 bit BIT
P_E_LG_26 Output 16 bit BIT VECTOR
P_E_HG_26 Output 16 bit BIT VECTOR
P_H_26 Output 1 bit BIT
P_E_LG_27 Output 16 bit BIT VECTOR
P_E_HG_27 Output 16 bit BIT VECTOR
P_H_27 Output 1 bit BIT
P_E_LG_28 Output 16 bit BIT VECTOR
P_E_HG_28 Output 16 bit BIT VECTOR
P_H_28 Output 1 bit BIT
P_E_LG_29 Output 16 bit BIT VECTOR
P_E_HG_29 Output 16 bit BIT VECTOR
P_H_29 Output 1 bit BIT
P_E_LG_30 Output 16 bit BIT VECTOR
P_E_HG_30 Output 16 bit BIT VECTOR
P_H_30 Output 1 bit BIT
P_E_LG_31 Output 16 bit BIT VECTOR
P_E_HG_31 Output 16 bit BIT VECTOR
P_H_31 Output 1 bit BIT
P_DV Output 1 bit BIT
Parallel data valid – single-cycle pulse when the 96 parallel pins are refreshed. It is also pulsed on the forced-frame path (FLAGS = 3), where the pins keep their previous contents.
P_FRAME_DATA Output 1024 bit BIT VECTOR
Packed event frame – 32 channel words of 32 bits, identical packing to V1: channel 0 in the most significant word (bits 1023:992), channel 31 in the least significant (bits 31:0), each word [31:29]=000, [28]=HIT, [27:14]=LG, [13:0]=HG. Connect to DATA_x of the Citiroc Frame Transfer V2 block, which serialises it LSW-first — so channel 31 reaches the PC first.
P_FRAME_DV Output 1 bit BIT
Frame data valid – level, raised when the frame is refreshed, cleared by P_FRAME_ACK.
BUSY Output 1 bit BIT
Busy – high from the accepted trigger edge until the FSM returns to idle, including the time spent waiting for validation. Use it to veto the trigger generator and to measure live time.
M_ENERGY_LG Output 16 bit BIT VECTOR
Monitor, low gain – continuous filtered LG ADC value.
M_ENERGY_HG Output 16 bit BIT VECTOR
Monitor, high gain – continuous, free-running output of the 8-tap rounded boxcar filter on the HG ADC.
M_CLK Output 1 bit BIT
Monitor of SCLK – copy of the ASIC shift-register clock driven by this block.
M_DIN Output 1 bit BIT
Monitor of SR_IN – copy of the token bit injected into the ASIC shift register.
CNT_TRIGGER Output 32 bit BIT VECTOR
Trigger counter – 32-bit count of accepted TRIG rising edges since the last RUNRESET, published at the moment the trigger is accepted. Wire it to CNT_TRIGGER_x of the Citiroc Frame Transfer V2 block so it is embedded in every packet.
CNT_VAL Output 32 bit BIT VECTOR
Validation counter – 32-bit count of validation pulses since the last RUNRESET. Forced to zero while validation is disabled (CFG bit 0 = 0). Wire it to CNT_VAL_x of the Citiroc Frame Transfer V2 block.
FLAGS Output 32 bit BIT VECTOR
Event status word – 0 = validation disabled, 1 = validated, 2 = validation timeout, 3 = forced frame. Level output, stable until the next decision. Wire it to FLAGS_x of the Citiroc Frame Transfer V2 block.

Properties

Property window

ASIC ASIC

Select the ASIC to be connected to the Endpoint

Selects which of the four CITIROC 1A chips this instance drives. It changes no pin; it renames the board nets the block binds to (Citiroc_<ASIC>_ADC_ENERGY_HG/LG, Citiroc_<ASIC>_CHARGE_HIT_s, Citiroc_<ASIC>_SRIN_s, Citiroc_<ASIC>_SCLK_s, Citiroc_<ASIC>_RESET_READ_s, <ASIC>_VAL_EVT_s, <ASIC>_RAZ_CHN_s, <ASIC>_HOLD_HG_s, <ASIC>_HOLD_LG_s).

Value ASIC
A chip A
B chip B
C chip C
D chip D

Two instances must never carry the same value. This is the only property of the block — unlike V1 there is no readout-frequency setting, CLKDIV is fixed at 25 in CompileHDL. The property is flagged isVisible = False in the component definition, so it is not shown in the standard property dialog.

Default: A

Default: A

Options: A B C D

⚙️ Detailed Operation

Emitted HDL

CompileHDL writes two files into pcores/:

File written From embedded resource
CitirocAnalogReadoutV2.vhd (entity CITIROCAnalogReadoutV2) CitirocAnalogReadout_NEW.vhd
tdc_sync_nofifo.vhd tdc_sync_nofifo.vhd

and instantiates the top entity with one generic:

Generic Value written by the compiler
CLKDIV 25, hard-coded

V1’s ReadoutFrequency combo box is gone (it is commented out in the component source). One shift-register step costs 2·(CLKDIV+1) = 52 clock cycles, so on the 160 MHz global clock of the DT5550W-Citiroc1A-V2 the ASIC shift clock runs at roughly 3.1 MHz — more than an order of magnitude faster than V1’s default.

Besides the pins, the block binds one extra internal board bus that is not drawn on the canvas: TDC_CLOCKS ← TDC_SYNC_CLK (6 bits). Bit 0 is the system clock, bit 1 its 90°-shifted copy, bits 5:2 the four skewed fast clocks. Those come from the board’s dedicated TDC PLL and cannot be rewired from the schematic.

What changed in the analog datapath

V1 (Citiroc Analog) V2 (this block)
Boxcar filter length 32 taps 8 taps (16-entry shift register, tap0 − tap8)
Accumulator 24 bit, result = bits [20:5] 32 bit, result = bits [18:3]
Rounding truncation round to nearest (adds 1 when accumulator bit 2 is set)
ADC sampled in the SCLK-high state, at the end of the count mid-phase, at counter = CLKDIV/2 + 1
Shift-register slots walked 35 37
First slots discarded none 3 (I > 2 guard)
Channel index the slot number separate CH_IDX, decoupled from the slot
Chip temperature slot 32 CH_IDX = 32
Charge-SR reset pulse 5 cycles 17 cycles

The shorter, rounded filter and the mid-phase sampling point are deliberate: the in-source comment states the sampling instant was chosen empirically with a logic analyser to land in the middle of the settled ADC output, and that the first three slots are skipped to absorb the ADC pipeline latency. The result is lower INL at a much higher shift rate.

Validation protocol

After the hold is closed (state 2) the FSM consults CFG (the VALIDATION_REG port):

flowchart TD
  A[hold closed] --> B{CFG bit 0}
  B -- 0 --> C["read out immediately<br/>FLAGS = 0x00000000<br/>CNT_VAL = 0"]
  B -- 1 --> D{validation latched?}
  D -- yes --> E["read out<br/>FLAGS = 0x00000001"]
  D -- no --> F{timeout expired?}
  F -- no --> D
  F -- yes --> G{CFG bit 1}
  G -- 0 --> H["read out anyway<br/>FLAGS = 0x00000002"]
  G -- 1 --> I["abort event, reset ASIC<br/>FLAGS = 0x00000002"]

A validation pulse arriving while no event is in flight is handled separately: if CFG bit 2 is set and VETO is low, the block re-issues P_DV and P_FRAME_DV with the buffer it already holds and tags the event FLAGS = 0x00000003. This is the “unsolicited / externally forced frame” path — it does not perform a new analog readout, it republishes the previous one.

CFG register map (the VALIDATION_REG port)

Bits Name Meaning
0 Validation enable 0 = read out every trigger immediately (V1 behaviour). 1 = wait for VALIDATION_IN.
1 Timeout action 0 = on timeout read the event out anyway. 1 = on timeout abort the event and reset the ASIC.
2 Forced-frame enable 1 = a validation pulse with no event in flight republishes the last buffer (FLAGS = 3), gated by VETO.
4 Validation sensitivity 0 = level sensitive on VALIDATION_IN. 1 = rising-edge sensitive.
31:16 Validation timeout 16-bit countdown, preloaded at every accepted trigger, decremented one per clock.

Bits 3 and 15:5 are not decoded by the HDL.

FLAGS output values

Value Meaning
0x00000000 Validation disabled — the event was read out unconditionally.
0x00000001 Validated: VALIDATION_IN arrived in time.
0x00000002 Validation timeout. Whether data follows depends on CFG[1].
0x00000003 Forced frame: a validation arrived with no event in flight and CFG[2] = 1, VETO = 0.

FLAGS is a level output, updated when the decision is taken and stable until the next event — which is what makes it safe to sample it in the frame builder.

Counters

  • CNT_TRIGGER — total accepted trigger edges. Incremented on every TRIG rising edge (including events later aborted), and published at the moment the trigger is accepted.
  • CNT_VAL — total validation pulses seen. Published when the validation decision is taken; forced to 0x00000000 when validation is disabled.
  • Both are cleared by RUNRESET, which is the natural “start of run” strobe.

Because CNT_TRIGGER counts triggers and the frame counter inside the Frame Transfer block counts transmitted packets, comparing the two on the host gives the exact number of events lost to vetoes, timeouts and FIFO back-pressure.

TDC path in detail

   T_OR32 (asynchronous) ─┬─► rising-edge capture of {clk, clk90, sclk[3:0]} ─► fine[3:0]
                        └─► synchroniser (rising + falling edge FSMs) ─► coarse capture
 T0 ───────────────────────► t_ref, latched with the hit
 TS_IN[43:0] ──────────────► abstime (coarse)
                                      │
                                      ▼
                            evnt_absolute_time[47:0] = coarse[43:0] & fine[3:0]
  
  • The TDC is instantiated with TS_BITS = 44 and TOT_BITS = 9; only the timestamp is used, the time-over-threshold output is left open.
  • It carries a hold-off of 10 TDC clock cycles after each accepted hit (holdoff_time is hard-wired to x"000A" inside the core), during which a second hit is not timestamped.
  • On the accepted trigger edge the FSM first writes the coarse value TS_OUT <= TS_IN(59:0) & "0000" — the coarse counter shifted left by 4 so that it shares the LSB weight of the TDC — and arms a capture. When the TDC reports a valid measurement, TS_OUT is overwritten with "0000" & x"000" & TDC_TS(47:0).
  • TS0_OUT is always the plain latched TS0_IN, unchanged from V1.

The fine field is 1/16 of the TDC reference clock period. The absolute picosecond value depends on which frequency the board PLL delivers on TDC_SYNC_CLK and is not determined from the sources read here (the core’s own comments and the PLL instance name suggest a 0.5 ns target, while the board model declares a 160 MHz global clock — measure it rather than assuming).

T_OR32 must stay asynchronous

T_OR32 is wired to the TDC’s hit_asyn input and is sampled by clock-edge capture on six different phases. Feeding it a signal that has already been registered in the system clock domain destroys the fine-time information — the fine field will lock to one value. Drive it from the ASIC trigger OR directly.

Resources & Timing

  • Latency: Trigger edge to P_DV ≈ HOLD_TIME + validation wait + 37·52 clock cycles (≈1900 clocks ≈ 12 µs of shift-register walk at 160 MHz)

  • Throughput: One event per readout cycle; BUSY covers the whole cycle including the validation wait

  • Emits pcores/CitirocAnalogReadoutV2.vhd from the CitirocAnalogReadout_NEW.vhd resource, plus pcores/tdc_sync_nofifo.vhd. V1 emits only the plain CitirocAnalogReadout.vhd and no TDC.
  • CLKDIV is hard-coded to 25 (V1 derives it from the ReadoutFrequency property).
  • The frame word layout is byte-for-byte the same as V1; what changed is what the Frame Transfer V2 block appends after it.
  • Extra board binding not visible as a pin: TDC_CLOCKS ← TDC_SYNC_CLK (6 bits).
  • No memory-mapped registers and no SDK code — CompileMMC and CompileSDK are empty.
  • Supported board: DT5550W-Citiroc1A-V2 (26E86B08-6FEF-4B0F-8872-793CC478DA97). Not available inside subpages or state machines.