Frame Merge 4 (frame_merge4)

Merges four msk_decode_x16 decoded-frame streams into a single output stream, so the 64-channel demod uses a single FPGA-to-CPU DMA interconnect.

Tested platforms include xsim.

Design

frame_merge4 accepts four uchar_timed_sample input streams — one per msk_decode_x16 worker — and serialises them onto a single output stream using round-robin, frame-atomic arbitration.

Each msk_decode_x16 worker emits decoded frames as pairs of WSI messages: first a metadata message (opcode metadata) whose low byte carries the abs_bin channel tag (port_index * 16 + channel), immediately followed by a sample message (opcode sample) carrying the 134-byte decoded frame. The host software demultiplexes on abs_bin to route each frame to the correct channel.

The arbiter operates as a two-state FSM:

  • ST_ARB — scans inputs in0 .. in3 in round-robin order (advancing the start pointer after each grant) and locks onto the first input that has a beat available.

  • ST_FWD — forwards all beats from the locked input verbatim — data, opcode, som, eom, and byte_enable — until (and including) the beat where opcode = sample AND eom = '1'. This is the last byte of the 134-byte frame message. Only then does the FSM return to ST_ARB and advance the round-robin pointer.

This frame-atomic policy guarantees that the metadata message and its corresponding frame message are always forwarded as a contiguous unit. Message-level interleaving would pair a metadata beat from one channel with frame bytes from another, corrupting the abs_bin tag.

Because all four inputs are low-rate (approximately 58 KB/s each at the OPV waveform data rate), no input FIFOs are required. Backpressure is handled naturally: the selected input is consumed (take asserted) only when the downstream asserts ready. The three non-selected inputs experience backpressure silently; they do not need to be stalled at the source because their producers hold data until taken.

EOF propagation is conservative: output.eof is asserted only when all four inputs have signalled EOF, and no pending beats remain (pv = "0000"), and the arbiter is idle (ST_ARB). This prevents premature EOF while any input still holds un-forwarded frames.

Interface

<?xml version='1.0' encoding='utf-8'?>
<!-- frame_merge4: merge FOUR msk_decode_x16 outputs into ONE, so the 64-channel
     demod (4x msk_decode_x16, port_index 0..3) uses a single FPGA->CPU DMA
     interconnect instead of four.

     Each input is the uchar_timed_sample decoded-frame stream: per decoded frame
     a metadata message (abs_bin in the value-low byte) followed by a 134-byte
     sample message (the frame).  abs_bin already encodes port_index*16+ch, so the
     four streams are uniquely tagged and the host can demux on abs_bin.

     Arbitration is round-robin and FRAME-ATOMIC: once an input is selected, its
     metadata message AND the following sample (frame) message are forwarded as a
     unit before re-arbitrating, so a frame's abs_bin tag always stays paired with
     its frame bytes (message-level interleaving would split them).  Output rate is
     low (~4 x 58 KB/s), so no buffering is needed. -->
<ComponentSpec>
  <port name="in0"    producer="false" protocol="uchar_timed_sample-prot"/>
  <port name="in1"    producer="false" protocol="uchar_timed_sample-prot"/>
  <port name="in2"    producer="false" protocol="uchar_timed_sample-prot"/>
  <port name="in3"    producer="false" protocol="uchar_timed_sample-prot"/>
  <port name="output" producer="true"  protocol="uchar_timed_sample-prot"/>
</ComponentSpec>

Ports

Inputs:

  • in0: Input decoded-frame stream from msk_decode_x16 port-index 0 (abs_bins 0..15).

    • Protocol: uchar_timed_sample-prot

    • Optional: False

  • in1: Input decoded-frame stream from msk_decode_x16 port-index 1 (abs_bins 16..31).

    • Protocol: uchar_timed_sample-prot

    • Optional: False

  • in2: Input decoded-frame stream from msk_decode_x16 port-index 2 (abs_bins 32..47).

    • Protocol: uchar_timed_sample-prot

    • Optional: False

  • in3: Input decoded-frame stream from msk_decode_x16 port-index 3 (abs_bins 48..63).

    • Protocol: uchar_timed_sample-prot

    • Optional: False

Outputs:

  • output: Merged output stream; frames from all four inputs serialised in round-robin order.

    • Protocol: uchar_timed_sample-prot

    • Optional: False

Opcode Handling

Both metadata and sample opcodes are forwarded unchanged. The arbiter treats the metadata opcode message as the first half of an atomic frame unit and continues forwarding until the subsequent sample opcode EOM is consumed. No opcode is dropped, modified, or re-ordered within a frame unit.

Properties

None.

Implementations

  • frame_merge4 (HDL)

    Round-robin, frame-atomic 4-to-1 merge of uchar_timed_sample decoded-frame streams.

Dependencies

The frame_merge4 HDL worker depends on:

  • ieee.std_logic_1164

  • ieee.numeric_std

  • ocpi.types (for uchar_timed_sample opcode constants)

Limitations

Limitations of frame_merge4 are:

  • The arbiter assumes each input produces strictly paired metadata + sample messages. An input that emits a metadata message without a following sample message (e.g. due to upstream truncation) will hold the arbiter in ST_FWD indefinitely, stalling all other inputs.

  • All four input ports must be connected. Leaving an input undriven will cause the arbiter to wait for a beat from that port and stall downstream.

  • Round-robin fairness is approximate: a lagging input will be skipped during ST_ARB if it has no beat available, but will be preferred at the next opportunity. Under sustained asymmetric load, faster inputs receive proportionally more grants.

Testing

The unit test drives all four input ports simultaneously with four distinct frames each (16 frames total). Each frame carries a self-identifying payload (byte[0] = abs_bin, byte[i] = abs_bin + frame_index + i) and is preceded by a metadata message whose low byte encodes the same abs_bin. The verify script checks that:

  • All 16 frames arrive at the single output, with no drops or duplicates.

  • Every frame is intact (correct length and correct payload bytes).

  • Each frame’s abs_bin in the metadata message matches payload[0], proving frame-atomic pairing was never violated.

Tested platforms: None

Component testing not completed.