Altera
Block Preview

Introduction

Principle of Operation

Data Merger (ALT) concentrates 2, 4, 8, 16 or 32 independent data streams into one output stream. Each input has a data word (IN_x) and a data-valid strobe (DV_x); the block emits one word at a time on OUT with DV_OUT, and tells each source when to stop with BUSY[IN]_x.

Internally it is a binary tree of two-way merger nodes. Each node has one hold register per branch: if both branches present a word on the same clock it forwards branch A and parks branch B, releasing it on the next clock. Nothing is arbitrated centrally, so congestion is absorbed where it happens.

What “(ALT)” means

This block and the plain Data Merger are two builds of the same design. The two VHDL files in the plugin (DataMerger.vhd and DataMerger_alt.vhd) are byte-for-byte identical except for the points listed below, and the component classes declare the same properties and the same pins.

Data Merger Data Merger (ALT)
offered on Xilinx boards (_ANY_XLX) Altera / Intel boards (_ANY_ALT)
input FIFO primitive xpm_fifo_async (Xilinx XPM) dcfifo_mixed_widths (library altera_mf)
FIFO read mode first-word-fall-through (READ_MODE = "fwft") first-word-fall-through (lpm_showahead = "ON")
FIFO reset synchronous rst asynchronous aclr
device family baked into the FIFO none (XPM is generic) intended_device_family = "Cyclone V"
default clock net if CLK is left open project acquisition clock project asynchronous clock
core DV_OUT / BUSY_OUT port type std_logic_vector(0 downto 0) std_logic
tree topology, arbitration, hold registers, latency identical identical
properties and pins identical identical

In short: choose it because of the board, not because of the behaviour. If your target is an Intel FPGA, this is the merger that will compile; if it is a Xilinx FPGA, use the plain Data Merger. Everything you read about arbitration, ordering and flow control on the Data Merger page applies here unchanged.

Pin Description

IN_0 Input InputWordSize bit BIT VECTOR
Data word for channel 0 (IN0 on the canvas). Captured on the clocks where DV_0 is high. One IN_x pin exists per channel, IN_0 … IN_(N-1), where N is Number of inputs; all of them are Input Word Size bits wide.
Default: Must be connected
DV_0 Input 1 bit BIT
Data valid for channel 0. High for one clock per word. Must go low within one clock of BUSY[IN]_0 rising, otherwise the word already parked in the node’s hold register is overwritten and lost without warning.
Default: Must be connected
IN_1 Input InputWordSize bit BIT VECTOR
Data word for channel 1. See IN_0. Channel 1 loses every collision against channel 0 at the first tree node.
Default: Must be connected
DV_1 Input 1 bit BIT
Data valid for channel 1. See DV_0.
Default: Must be connected
BUSY[OUT] Input 1 bit BIT
Back-pressure from downstream (BUSY on the canvas). While high the root node stops emitting, the hold registers fill from the leaves upward and the BUSY[IN]_x outputs rise one after another. Tie it low (or leave it unconnected) if the consumer never stalls.
CLK Input 1 bit BIT
Clock. The entire tree and both FIFO ports run on it. Left unconnected, this variant binds it to the project asynchronous clock (the Xilinx Data Merger binds to the acquisition clock instead) — connect it explicitly if the sources are in the acquisition domain.
Default: Default Board Clock
RESET Input 1 bit BIT
Reset, defaults to the project global reset. It clears the merger nodes synchronously and the input FIFOs asynchronously (aclr).
Default: Default Board Reset
BUSY[IN]_0 Output 1 bit BIT
Back-pressure to the source of channel 0 (BUSY0 on the canvas). With an input FIFO it is the FIFO’s wrfull; without one it is the tree node’s own busy flag, which gives only one clock of slack. One pin per channel. See the warning above before wiring it.
BUSY[IN]_1 Output 1 bit BIT
Back-pressure to the source of channel 1. See BUSY[IN]_0.
OUT Output InputWordSize bit BIT VECTOR
Merged output word, Input Word Size bits. Carries a word from exactly one channel per clock; the block adds no channel tag, so put an identifier in the word if you need to know where it came from.
DV_OUT Output 1 bit BIT
Output data valid (DV on the canvas). High for one clock per merged word. Never asserted while BUSY[OUT] is high.

Properties

Property window

Number of inputs InputCount

Set the number of input to the virtual block

Number of input channels, which sets the depth of the merger tree and therefore the minimum latency (one clock per level).

value tree levels minimum latency
2 1 1 clock
4 2 2 clocks
8 3 3 clocks
16 4 4 clocks
32 5 5 clocks

Changing it rebuilds the symbol (the IN_x / DV_x / BUSY[IN]_x pins are created from it). See the warning about the 16- and 32-input configurations.

Default: 2

Default: 2

Options: 2 4 8 16 32

Input Fifo Size InputFifo

Set the size of the input buffer in front of each input

Depth, in words, of the per-channel input FIFO (dcfifo_mixed_widths, lpm_numwords). 0 removes the FIFOs entirely and wires the inputs straight into the tree, leaving only the one-word hold register per branch as buffering. Larger values absorb bursts at the cost of on-chip memory: the total is Input Fifo Size × Input Word Size × Number of inputs bits.

Allowed: 0, 64, 128, 512, 1024.

Default: 64

Default: 64

Options: 0 64 128 512 1024

Input Word Size InputWordSize

Set the input word size in bits

Width in bits of every input word and of OUT. Range 2 to 1024, edited in steps of 8. All channels share it — this block cannot merge streams of different widths.

Default: 32

Default: 32

Range: 2 – 1024

⚙️ Detailed Operation

The merger node

Every node in the tree is one clocked process (entity merger in DataMerger_alt.vhd) with two one-word hold registers, dHa and dHb, and their occupancy flags. On each clock:

  1. Downstream busy (dObusy = '1') → assert busy on both branches; any word arriving on A or B is written into that branch’s hold register.
  2. Hold not empty → release A’s hold first, then B’s; a word arriving in the same clock is written into the hold register behind it.
  3. Hold empty, both branches valid → forward A, park B, assert busy on both.
  4. Hold empty, one branch valid → forward it, release the busy flags of any branch that is not holding.

Two consequences follow directly:

  • Branch A wins every collision, so the input with the lower index has priority at every level of the tree. Under sustained congestion the highest channel numbers are served last.
  • Order across channels is not preserved. Two words injected on the same clock on IN_0 and IN_15 travel through different numbers of nodes, so they arrive in an order that depends on the tree, not on the input timing. If order matters, put a timestamp in the word.

Back-pressure contract — one clock of slack, then silent loss

BUSY[IN]_x is registered: a node decides to assert busy on the clock it accepts a word, and the source sees it on the next clock. The single hold register is exactly the budget for that round trip:

  • A source that stops within one clock of seeing BUSY[IN]_x rise loses nothing — the in-flight word lands in the hold register.
  • A source that keeps asserting DV_x for a second clock while the node is holding and the output is busy overwrites the hold register. The old word is gone; there is no error flag, no overflow output, nothing in the stream to show it happened.

This is the single most common way to lose data with this block. With Input Fifo Size > 0 the FIFO absorbs the burst and BUSY[IN]_x is the FIFO’s full flag instead, which gives you the whole FIFO as slack — which is why the default is 64 and not 0.

Input FIFOs (Intel dcfifo_mixed_widths)

With Input Fifo Size > 0, each channel gets one dcfifo_mixed_widths instance:

generic value
lpm_numwords Input Fifo Size
lpm_width / lpm_width_r Input Word Size
lpm_showahead "ON" (first word fall through)
intended_device_family "Cyclone V"
rdsync_delaypipe / wrsync_delaypipe 4
overflow_checking / underflow_checking "ON"
use_eab "ON" (on-chip memory blocks)

wrfull drives BUSY[IN]_x directly, and a word is popped whenever the FIFO is not empty and the tree node behind it is not busy. Two details are worth knowing:

  • Both FIFO clocks are tied to the same clk, yet the instance is a dual-clock FIFO with four-stage synchroniser pipelines on each side. That costs several extra clocks of write-to-readable delay compared with the Xilinx build, and it means the empty/full flags are conservative. It does not affect correctness — only latency and the point at which BUSY[IN]_x rises.
  • aclr is tied to RESET, so the FIFOs clear asynchronously. Give the block a clean, de-asserted reset before you start streaming.

With Input Fifo Size = 0 the FIFOs disappear, IN_x/DV_x go straight into the tree and BUSY[IN]_x becomes the tree node’s own busy flag — one word of slack, as described above.

Latency

Each merger node registers both its data and its data-valid output, so an uncontended word costs exactly one clock per tree level:

Number of inputs tree levels minimum latency
2 1 (merger) 1 clock
4 2 (four_way_merger) 2 clocks
8 3 (eight_way_merger) 3 clocks
16 4 (sixteen_way_merger) 4 clocks
32 5 (two 16-way trees + one node) 5 clocks

Add the input FIFO delay when Input Fifo Size > 0, and add one clock per collision the word loses on its way down. Aggregate throughput is one word per clock at the output regardless of the number of inputs — the tree serialises, it does not widen.

:::ALERT 16 and 32 inputs: verify before you rely on channels 8–11 (and 24–27). In the final combining stage of sixteen_way_merger, the C branch takes its data from the third sub-tree but its data-valid and busy from the fourth:

  four_way_merger5 : four_way_merger
    dC    => dO3,        -- data from sub-tree 3
    dCint => dOint4,     -- but valid from sub-tree 4
    dCbusy => dOBusy4,   -- and busy from sub-tree 4
  

dOint3 and dObusy3 are consequently never used, so sub-tree 3 (inputs 8–11 of each 16-way group) is never told to stop and its words are only forwarded when sub-tree 4 happens to present one. The same wiring is present in the Xilinx DataMerger.vhd, so this is not an ALT-specific defect — but it only affects the 16- and 32-input configurations. Until it is confirmed fixed, prefer 8 inputs or fewer, or cascade two 8-input mergers into a third one. :::

Practical configuration

situation Input Fifo Size
sources that already respect BUSY within one clock 0
steady low-rate sources 64 (default)
bursty event builders, several channels firing together 512 or 1024

Input Word Size is free between 2 and 1024 bits (the editor steps it by 8), and every channel and the output share it. A common pattern is to reserve the top bits of the word for a channel id so the merged stream can be de-multiplexed in software — the merger itself adds no tag.

Resources & Timing

  • Latency: One clock per tree level (1 / 2 / 3 / 4 / 5 clocks for 2 / 4 / 8 / 16 / 32 inputs), plus the input FIFO delay when Input Fifo Size > 0, plus one clock for each collision a word loses on the way down

  • Throughput: One word per clock at OUT, shared by all channels

  • Intel/Altera only (_ANY_ALT). The FIFOs come from the altera_mf library and name "Cyclone V" as the intended device family.
  • Buffering is Input Fifo Size × Input Word Size × Number of inputs bits of on-chip memory, plus two hold registers of Input Word Size bits in every merger node.
  • No memory-mapped registers are generated: this block is pure fabric logic.