Block Preview

Introduction

Principle of Operation

The List ESS block is the list-mode front end of the ESS FEA framework (the firmware bundle used for detectors at the European Spallation Source). It is a fixed-length event recorder: every accepted trigger produces exactly WordCount 32-bit words, taken in one shot from the IN_PACKET bus.

What makes it “ESS”

The standard List block ends in a read-out FIFO that the PC drains through the register bus (BUS_<endpoint>_READ_DATA), and SciSDK reads it as a ListModule. The List ESS block ends somewhere completely different: its output is an AXI-Stream master wired to the board’s bulk data port (bkdata_s_axis_*), which in the ESS top level goes into the fea_top core and out over the gigabit transceivers to the ESS back-end.

List List ESS
Where the data goes PC, over the register/USB/Ethernet bus ESS back-end, over the FEA bulk-data link
Read-out interface FIFO read port + STATUS register 32-bit AXI-Stream with TLAST
Event framing none — a raw word stream one TLAST-terminated frame per event
Software registers STATUS (R) + CONFIG (W) CONFIG (W) only
Event size 1 word of Wordsize bits WordCount x 32 bits
Event counter not exposed HIT_COUNTER output pin
Read out with SciSDK yes no — nothing to read

Because the FPGA-side read-out is gone, the only thing software can do with this block is start, stop, reset and flush it through one CONFIG register. Everything else — where the events end up, how they are packed into UDP/ESS frames, how they are timestamped downstream — is the job of the ESS FEA framework, not of this block.

Pin Description

IN_PACKET Input WordCount x 32 bit BIT VECTOR

Event payload – the whole event, presented in parallel. Word i of the transmitted frame is IN_PACKET(32*i+31 downto 32*i), so bits [31:0] are sent first and the most significant slice last.

Sampled on the second clock edge after TRIG rises; it must still be valid at that moment.

TRIG Input 1 bit BIT

Event trigger – a rising edge requests one event. Double-registered internally, so the capture happens two clock edges later. The request is dropped if CONFIG[0] = 0 or if an overflow flag is set.

Level-holding this pin high yields one event, not a burst.

CLK Input 1 bit BIT
Write clock – the acquisition-side clock. The capture registers, the per-word FIFOs and the serialising FSM all run on it. Defaults to the project acquisition clock when left unconnected.
Default: Default Board Clock
RESET Input 1 bit BIT
Reset – asserts the FIFO reset, clears HIT_COUNTER and forces BUSY high. Defaults to the project global reset when left unconnected.
Default: Default Board Reset
HIT_COUNTER Output 32 bit BIT VECTOR

Accepted-event counter – free-running 32-bit count of the triggers this block has actually accepted (not of the triggers presented). It wraps at 2³² and is cleared by RESET or by CONFIG[1].

Comparing it against your own trigger count is the cheapest way to detect that events are being dropped.

BUSY Output 1 bit BIT

Stopped indicator – BUSY = NOT CONFIG[0].

It is high while the block is stopped (and during reset) and low while it is running. Note that, unlike the standard List block, it does not go high on a full buffer — watch FULL for that.

FULL Output 1 bit BIT
Overrun flag – high when any of the per-word FIFOs reports an XPM overflow, i.e. a write has just been lost. It is an after-the-fact, short-lived indication, not a back-pressure signal.

Properties

Property window

Name EndpointName

Set the name of the endpoint

Name of the memory-mapped endpoint. It is what the CONFIG register is named after in the register map (REG_<EndpointName>_CONFIG_WR) and what identifies the block in RegisterFile.json.

Must be unique in the design.

Default: ESSList_0

Default: ESSList_0

Size of buffer BufferSize

Size of the readout buffer. Buffer must be large enought to compensate readout bus stalls.

Depth of each per-word FIFO, in events, and also the depth of the cross-domain FIFO (in words). It maps to the memLength generic.

Available values: 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536.

This is the burst tolerance of the block: it is how many events can arrive faster than the ESS link drains them before writes start being lost. Larger values cost WordCount more block-RAM lanes.

Default: 1024

Default: 1024

Options: 128 256 512 1024 2048 4096 8192 16384 32768 65536

Number of Word WordCount

Set the number of 32 bits words

Number of 32-bit words in one event — that is, the size of the IN_PACKET pin (WordCount x 32 bits) and the number of AXI-Stream beats in the frame sent for each trigger. Maps to the G_NUM_WORDS generic.

Available values: 1 … 32.

Changing it rebuilds the symbol (the IN_PACKET pin changes width) and costs one 32-bit FIFO lane per word. It also sets the drain cost per event (WordCount + 2 clocks).

Note that the value published in RegisterFile.json is fixed at 4 words and does not follow this property.

Default: 4

Default: 4

Options: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

⚙️ Detailed Operation

Data flow

                 CLK (acquisition domain)          BUS_CLK (bulk-data domain)
 ┌───────────────────────────────────────────┐ ┌────────────────────────────┐
 │                                           │ │                            │
 │  IN_PACKET ──┬─[31:0]──►  FIFO word 0  ──┐│ │                            │
 │  (N x 32)    ├─[63:32]─►  FIFO word 1  ──┤│ │                            │
 │              ├─  ...  ─►     ...       ──┼┼─┼──► bkdata_s_axis_tdata[31:0]
 │              └─[32N-1:  ►  FIFO word N-1─┘│ │     bkdata_s_axis_tvalid    │
 │                 32N-32]      ▲            │ │     bkdata_s_axis_tlast     │
 │                              │            │ │  ◄──bkdata_s_axis_tready    │
 │  TRIG ──► edge detect ───────┘            │ │                            │
 │            │                              │ │                            │
 │            └──► HIT_COUNTER (32 bit)      │ │                            │
 └───────────────────────────────────────────┘ └────────────────────────────┘
          N per-word synchronous FIFOs            one 33-bit async FIFO
          (depth = BufferSize, XPM sync)          (data[31:0] + last)
  

The block is built from two stages:

  1. Capture. WordCount independent xpm_fifo_sync buffers, each 32 bits wide and BufferSize deep, all written on the same write strobe. Word i of the event is IN_PACKET(32*i+31 downto 32*i), so the least significant 32 bits of IN_PACKET are sent first.
  2. Serialise + cross. A small FSM reads the N buffers one after the other and writes a 33-bit {data, last} token into an xpm_fifo_async that crosses from CLK to BUS_CLK. The FIFO runs in FWFT mode, so its output is the AXI-Stream master: data_valid → TVALID, dout(32:1) → TDATA, dout(0) → TLAST, and TREADY drives the read enable.

Trigger acceptance and sampling instant

TRIG is put through two registers before the edge is detected (iTrig <= TRIG; oTrig <= iTrig; then iTrig='1' and oTrig='0'). The consequence matters for the surrounding logic:

  • The event is accepted on the second clock edge after TRIG goes high.
  • IN_PACKET is sampled on that same edge — so the payload must still be valid two clock edges after the TRIG rising edge, not on the edge that raises TRIG.
  • Because the detector is edge based, holding TRIG high does not produce a stream of events: it produces exactly one.

A trigger is accepted only when all of these hold:

  accept = rising_edge(TRIG)  AND  CONFIG[0] = 1  AND  no per-word overflow flag set
  
 

Draining an event

Once the N per-word buffers hold an event, the FSM walks through them:

  s_idle : wait for (buffer 0 not empty) and (async FIFO not prog_full)
s_read : one word per clock, word_index = 0 .. WordCount-1
         on the last word: set TLAST, pop all N buffers
s_last : one turnaround clock
→ s_idle
  

So one event costs WordCount + 2 clock cycles on the acquisition clock to move into the cross-domain FIFO. That is the sustained event-rate ceiling of the block; the per-word buffers absorb bursts above it, up to BufferSize events.

The FSM also stalls while the async FIFO’s prog_full is asserted. That threshold is set to BufferSize - 3 * WordCount, i.e. it always leaves room for three whole events, so a frame is never cut in half by back pressure from the ESS link.

CONFIG register

This is the only register the block owns (write only).

Bit Function
0 Run. 0 holds the block stopped: triggers are ignored and BUSY is high.
1 Force reset. Clears HIT_COUNTER, asserts the FIFO reset, forces BUSY high.
2 FIFO flush. Level-sensitive: while it is 1 the FIFO reset is held asserted.

There is no STATUS register — the memory-mapped component is declared as a generic endpoint with a single CONFIG register, not as a list. Use the HIT_COUNTER, BUSY and FULL pins in the design if you need visibility.

Overflow behaviour

Word order and byte order

Words are streamed exactly as they appear on IN_PACKET, least significant 32-bit slice first, with no byte swapping. (If you need the ESS on-the-wire big-endian order, do it upstream of this block, or use Custom Packet ESS, which has a Byte Swap option.)

Simulation

The compiler writes a different core when the project is simulated: it has no CONFIG port and hardwires the configuration word to x"00000001", so the block is permanently running. Everything else — the FIFOs, the FSM, the AXI-Stream output — is identical. There is no file dump: to observe the data in a simulation, probe bkdata_s_axis_* in the waveform viewer.

Compiler messages

Message Meaning
Generating HDL code for <designator> normal, informational
Generating memory mapped component: <endpoint> the CONFIG register is being placed
SDK address undefined for <endpoint> error — the endpoint got no base address; the design cannot be built

Software / SciSDK

There is no SciSDK read-out path for this block. CompileSDK emits a JSON descriptor only, of type ListModuleESS, carrying the endpoint name, base address and the CONFIG register. Software uses it to find CONFIG; the event data never reaches SciSDK.

One bulk-data master per design

The AXI-Stream ports are connected directly to the top-level bkdata_s_axis_* signals (the compiler does not create a signal, it binds to the existing one). There is no arbiter between several producers, so a design must contain exactly one block driving the bulk-data stream — one List ESS or one Custom Packet ESS, not two of either and not one of each.

Quick reference

Item Value
Event size WordCount x 32 bits (1 … 32 words)
Buffer BufferSize events per word lane
Output 32-bit AXI-Stream, one TLAST frame per event
Output clock BUS_CLK (bulk-data domain)
Drain cost WordCount + 2 acquisition clocks per event
Registers CONFIG (write) only
Boards R5560-B / DAQ14125-B with FPGA model Z-7035-ESS

Resources & Timing

  • Throughput: One event per WordCount + 2 acquisition clock cycles, sustained
  • WordCount synchronous 32-bit FIFOs of BufferSize entries, plus one 33-bit asynchronous FIFO of BufferSize entries (all XPM, block RAM).
  • The only clock-domain crossing is the async FIFO between CLK and BUS_CLK.
  • No multipliers, no DSP.
  • Requires the ESS FEA framework: the board must be an R5560-B / DAQ14125-B with FPGA model Z-7035-ESS, and the framework path must be configured in boards/<board>_dll/ess.txt, otherwise the compiler stops with “You need to specify the ESS FEA framework path … to use the ESS FEA framework.”