How to Integrate the Pix2PGP FPGA Receiver in Your FPGA

This page describes how to drop the Pix2PGP FPGA receiver into an FPGA design. The receiver is a VHDL design that expects one PGP4 receiver core per data lane on its input side, and delivers a single consolidated AXI-Stream per trigger on its output side.

The top-level entity is Pix2PgpAsicStreamRx, defined in firmware/fpga/rtl/Pix2PgpAsicStreamRx.vhd. Unlike the ASIC-side Pix2PgpTop, the FPGA receiver is a full-featured module — it carries an integrated AXI-Lite crossbar, a trigger-buffer for the ASIC’s SRO signal, per-lane monitoring, and clock-domain-crossing logic between the ASIC-facing clock and the PGP RX clock. Instantiate one ``Pix2PgpAsicStreamRx`` per ASIC in your FPGA design.

Prerequisites

  • The same Pix2PgpAsicPkg.vhd package used by the ASIC (or an identical copy — the receiver depends on NUM_OF_COL_MANAGERS_C, NUM_OF_SERIALIZERS_C, ASIC_DATABUS_DWIDTH_C, header/metadata bitfield positions, etc.)

  • One PGP4 receiver core per lane (NUM_OF_SERIALIZERS_C cores). Their AXI-Stream masters and linkUp signals are wired to the receiver

  • Three clock domains:

    • pgpRxClk — the PGP4 receivers’ recovered clock. The receiver logic runs here

    • asicClk — the clock associated with the SRO trigger forwarded to the ASIC. The Trigger Manager crosses this into pgpRxClk internally

    • axilClk — the AXI-Lite bus clock. The receiver crosses this into pgpRxClk internally via an AxiLiteAsync

  • An AXI-Lite master (a register file, an embedded processor, etc.) that can address the receiver’s AXIL_BASE_ADDR_G region

Generics

Pix2PgpAsicStreamRx generics

Name

Type

Default

Description

TPD_G

time

1 ns

Simulation-only propagation delay applied to registers. Ignored by synthesis

RST_ASYNC_G

boolean

false

true → asynchronous reset; false → synchronous reset for the receiver logic

RST_POLARITY_G

sl

'1'

Reset active-high ('1') or active-low ('0') for the receiver logic

ASIC_RST_POLARITY_G

sl

'0'

Reset polarity for the ASIC-facing asicRst input. Independent of RST_POLARITY_G because the ASIC and the FPGA logic often use different conventions

ASIC_ID_G

natural

0

Numeric identifier for this ASIC, written into the consolidated Pix2PGP frame preamble. Unique per receiver instance if the FPGA services multiple ASICs

LANE_MON_GEN_G

boolean

false

Generate the Pix2PgpLaneMon per-lane monitoring module. Set true to enable AXI-Lite readback of per-lane statistics (occupancy trends, hit counts, etc.). Costs additional resources; disable if AXI-Lite budget is tight

LANE_MON_CNT_WIDTH_G

positive

20

Bit width of the per-lane monitoring counters

TRG_FIFO_ADDR_WIDTH_G

positive

6

Trigger-buffer FIFO depth, as log2. 6 → 64 pending triggers. Size it against the maximum in-flight event count between an SRO issued to the ASIC and the corresponding frame arriving on pgp4RxMaster

META_FIFO_ADDR_WIDTH_G

positive

6

Depth of each LaneRx Status FIFO (metadata), as log2

LANE_FIFO_ADDR_WIDTH_G

positive

9

Depth of each LaneRx Data FIFO, as log2. 9 → 512 entries. Increase for very large per-event frames (e.g. long Pause-fragmented events during full-matrix calibration)

AXIL_BASE_ADDR_G

slv(31 downto 0)

(no default)

Base address of this receiver’s AXI-Lite region. Required — the internal crossbar sizes its address windows by taking the base and stepping through in 16-bit strides (NUM_OF_SERIALIZERS_C + 1 master ports total: one for the receiver’s global registers, one for each LaneRx monitor)

Ports

General Interface

Name

Direction

Description

pgpRxClk

in

PGP4 receiver’s recovered clock. Every LaneRx, the Lane Supervisor, the Lane Merger, and the internal AXI-Lite crossbar run on this clock

pgpRxRst

in

Reset on pgpRxClk, polarity per RST_POLARITY_G. Defaults to not(RST_POLARITY_G) (i.e. inactive) if left open

ASIC Domain Interface

Name

Direction

Description

asicClk

in

Clock of the ASIC-facing side (the clock the SRO trigger is synchronous to)

asicRst

in

ASIC-side reset. Polarity governed by ASIC_RST_POLARITY_G (documented as active-low in the source header)

asicSro

in

Start-of-Readout trigger issued to the ASIC. On every SRO assertion, the Trigger Manager pushes an entry into the trigger buffer

asicSroEn

in

Enable for asicSro. Low disables trigger buffering (useful during ASIC reset / configuration)

sysDaq

in

System-level DAQ enable. When high, every buffered trigger forwards the merged frame to the back-end; when low, frames are either discarded or handled per config — see FPGA Receiver Architecture for the LCLS Run / DAQ trigger model

PGP4 RX Input Interface (pgpRxClk domain)

Name

Direction

Description

pgp4RxMaster

in

Array of NUM_OF_SERIALIZERS_C AXI-Stream masters from the PGP4 receiver cores — one per lane. Each carries the decoded Pix2PGP Lane Frame from its associated ASIC-side Pix2PGP core

pgp4RxSlave

out

Matching array of AXI-Stream slaves (handshake back to each PGP4 receiver)

pgp4RxLinkUp

in

Per-lane link-up flag from each PGP4 receiver. When a lane goes down mid-run, the Lane Supervisor emits drop-frames until the receiver returns to idle

AXI-Stream Output Interface (pgpRxClk domain)

Name

Direction

Description

asicRxMaster

out

Consolidated Pix2PGP frame, as a single AXI-Stream per trigger. This is the output that goes on to the back-end (a second-tier PGP4 transmitter, a DMA channel to a rogue-managed CPU, etc.). See Data Frame Format for the byte-level layout

asicRxSlave

in

AXI-Stream slave handshake from the downstream consumer

ASIC Monitoring Status Output

Name

Direction

Description

asicMonStatus

out

Array of Pix2PgpLaneStatusType records — the live per-lane monitoring snapshot (last-seen header flags, Column Hitmask, Trigger Counter, etc.), one entry per lane. Wire into your system-level monitoring path if you want fast, register-free access to lane state (e.g. for embedded trigger throttling)

AXI-Lite Interface

Name

Direction

Description

axilClk

in

AXI-Lite bus clock

axilRst

in

AXI-Lite bus reset

axilReadMaster

in

AXI-Lite read master, initialized to AXI_LITE_READ_MASTER_INIT_C if left open

axilReadSlave

out

AXI-Lite read slave response

axilWriteMaster

in

AXI-Lite write master, initialized to AXI_LITE_WRITE_MASTER_INIT_C if left open

axilWriteSlave

out

AXI-Lite write slave response

Internally, Pix2PgpAsicStreamRx places an AxiLiteAsync on this port (so axilClk can differ from pgpRxClk) followed by a NUM_OF_SERIALIZERS_C + 1-port AXI-Lite crossbar. Index 0 of the crossbar addresses the receiver’s global registers (Pix2PgpAxiLiteManager); indices 1 … NUM_OF_SERIALIZERS_C each address one LaneRx monitor. The 16-bit stride is fixed by the crossbar generator inside the entity.

Instantiation Template

For an ASIC with 8 lanes (SparkPix-S-style):

library ieee;
use ieee.std_logic_1164.all;

library surf;
use surf.StdRtlPkg.all;
use surf.AxiLitePkg.all;
use surf.AxiStreamPkg.all;

library pix2pgp;
use pix2pgp.Pix2PgpAsicPkg.all;
use pix2pgp.Pix2PgpPkg.all;

-- ...

U_Pix2PgpAsicRx : entity pix2pgp.Pix2PgpAsicStreamRx
   generic map (
      TPD_G                  => 1 ns,
      RST_ASYNC_G            => false,
      RST_POLARITY_G         => '1',
      ASIC_RST_POLARITY_G    => '0',
      ASIC_ID_G              => 0,       -- unique per ASIC in the system
      LANE_MON_GEN_G         => true,    -- enable per-lane monitoring
      LANE_MON_CNT_WIDTH_G   => 20,
      TRG_FIFO_ADDR_WIDTH_G  => 6,       -- 64 in-flight triggers
      META_FIFO_ADDR_WIDTH_G => 6,
      LANE_FIFO_ADDR_WIDTH_G => 9,       -- 512 words per lane
      AXIL_BASE_ADDR_G       => x"A000_0000")
   port map (
      -- Clocks / resets
      pgpRxClk        => pgpRxClk,
      pgpRxRst        => pgpRxRst,
      asicClk         => asicClk,
      asicRst         => asicRst,
      -- ASIC control
      asicSro         => asicSro,
      asicSroEn       => asicSroEn,
      sysDaq          => sysDaq,
      -- PGP4 RX inputs (from your 8 PGP4 receiver cores)
      pgp4RxMaster    => pgp4RxMasters,
      pgp4RxSlave     => pgp4RxSlaves,
      pgp4RxLinkUp    => pgp4RxLinkUps,
      -- Consolidated AXI-Stream output to the back-end
      asicRxMaster    => asicRxMaster,
      asicRxSlave     => asicRxSlave,
      -- Per-lane monitoring snapshot
      asicMonStatus   => asicMonStatus,
      -- AXI-Lite
      axilClk         => axilClk,
      axilRst         => axilRst,
      axilReadMaster  => axilReadMaster,
      axilReadSlave   => axilReadSlave,
      axilWriteMaster => axilWriteMaster,
      axilWriteSlave  => axilWriteSlave);

If the FPGA services multiple ASICs, replicate the instantiation with distinct ASIC_ID_G and AXIL_BASE_ADDR_G values.

Instantiation Checklist

  • The Pix2PgpAsicPkg.vhd compiled into the FPGA design is the same as the one used by the ASIC. A mismatch (e.g. different NUM_OF_COL_MANAGERS_C, or a shifted header bitfield) causes silent decoding failures manifested as Lane Decoding Error flags

  • The PGP4 receiver instances driving pgp4RxMaster deliver 64-bit AXI-Stream with the SURF PGP4 conventions. If you roll your own PGP4 RX, verify the AXI-Stream config record matches SURF’s PIX2PGP_FPGA_AXI_CONFIG_C

  • pgp4RxLinkUp is driven per lane. Tying it high defeats the Lane Supervisor’s link-down handling

  • AXIL_BASE_ADDR_G is set to a legal region of your system’s AXI-Lite map. The receiver’s internal crossbar consumes NUM_OF_SERIALIZERS_C + 1 × 16 bits of address space starting from this base

  • asicSro and asicSroEn are on the asicClk domain — do not drive them from pgpRxClk-domain logic; the Trigger Manager handles the crossing internally

  • If LANE_MON_GEN_G is false, the LaneRx monitor AXI-Lite ports still exist in the crossbar but return AXI_LITE_READ_SLAVE_EMPTY_SLVERR_C. Software register reads to those regions will get a SLVERR response

  • Pipeline the AXI-Stream output of every LaneRx if you cannot place the receiver near the GT hard blocks. This is handled with the PIPELINE_* / *_PIPE_G generics on lower-level modules; the Pix2PgpAsicStreamRx wrapper itself has no such generic (the wrapper defaults are used)