Header parser – openenoc_axis_header_parser
Captures an Ethernet header and attaches it as metadata to the unchanged frame stream.
Source: openenoc_axis_header_parser.sv.
Parameters
Name |
Default value |
Allowed values |
Description |
|---|---|---|---|
|
|
0 or positive integer |
Requested data FIFO capacity in beats, rounded up to a power of two with minimum two. Zero selects twice the beat count for the first 16 bytes. |
|
|
0, 1, or 2 |
0 bypasses output registration; 1 selects a simple buffer; 2 selects a two-entry AXI-Stream register slice (skid buffer). |
Signals
Interface ports contain channels in both directions. The table identifies the selected modport or stream role; member directions follow that interface.
Name |
Type |
Direction / role |
Description |
|---|---|---|---|
|
|
input |
Clock for this component or interface domain. |
|
|
input |
Active-high synchronous reset; flushes buffered data and headers and clears capture and output-frame tracking. |
|
|
Sink |
Incoming frame bytes, KEEP, and LAST. Input user metadata is not retained. |
|
|
Source |
Unmodified frame bytes, KEEP, and LAST, with the captured 16-byte prefix in TUSER on every beat. |
Architecture and operation
The parser copies the first 16 accepted bytes of each frame into a raw 128-bit
m_axis.tuser value. The complete frame, including those bytes, remains in
m_axis.tdata; no header is stripped or inserted. Data and header records
are buffered in order. Output waits until the matching header record is ready,
so metadata accompanies the first output beat and stays the same through the
frame’s final beat.
Input and output data widths must match and be multiples of eight bits.
Use matching byte-lane geometry, with KEEP_W = DATA_W / 8 and
LAST_EN = 1. The Ethernet profile uses KEEP_EN = 1: non-final
beats have all lanes enabled, and a partial final beat uses contiguous
enabled lanes starting at lane zero. Header capture advances only on accepted
input beats and uses KEEP to identify valid bytes.
The first frame byte occupies the least significant byte lane of its data
beat, but the most significant byte of the header metadata. For example,
with a 64-bit stream, DA0[7:0] = b0 and DA0[63:56] = b7;
the next beat carries b8 through b15 in the same lane order.
The captured header is HA = {b0, b1, ..., b15}, with
HA[127:120] = b0 and HA[7:0] = b15. The data beats themselves
are not byte-swapped.
TUSER bits |
Field |
|---|---|
127:80 |
Destination MAC |
79:32 |
Source MAC |
31:16 |
EtherType |
15:8 |
Byte 14; oETP Magic when applicable |
7:0 |
Byte 15; oETP Cmd when applicable |
These field names assume an untagged Ethernet header. The parser copies fixed byte positions without validating EtherType, Magic, or Cmd, and without decoding VLAN tags. For other payload formats, bytes 14 and 15 remain raw payload bytes. Detailed oETP command parsing belongs to oETP Engine – openenoc_endpoint_oetp_engine.
Enable output user metadata with m_axis.USER_EN = 1 and
m_axis.USER_W >= 128. If the width is larger, bits above 127 are zero.
Input TUSER is replaced by the captured header; input ID and destination
metadata are not preserved, and output TID and TDEST are zero. This metadata
belongs to the internal processing stream and is not part of the Ethernet
frame bytes.
If TLAST arrives before 16 valid bytes have been accepted, it completes the header record with the received prefix and zeroes in the missing trailing positions. The short input passes through unchanged. The block does not drop it or produce a separate short-header error indication. Capture restarts from byte zero for the next frame, independently of output progress.
Let B = ceil(16 / KEEP_W) be the number of full beats needed for the
prefix. DEPTH = 0 requests 2 * B FIFO beats. A nonzero DEPTH
requests that many beats; the actual memory depth is the next power of two,
with a minimum of two beats. Provision enough memory for header capture to
finish before output can drain that frame; rounding the requested depth to
at least B beats is sufficient. Depth sets storage capacity rather than
a fixed delay in clock cycles.
The data FIFO uses streaming mode, FRAME_FIFO = 0. Once the prefix is
available, output can begin before the complete frame arrives. Input pauses
can therefore produce output gaps after buffered data runs out. The optional
output register slice also contributes to buffering and timing. Under output
backpressure, data, KEEP, LAST, and TUSER stay stable on the offered beat.
Headers captured for later frames cannot replace the current output header.
Functional scenarios
All examples use 64-bit input and output streams, KEEP_W = 8,
KEEP_EN = 1, LAST_EN = 1, DEPTH = 0, and
M_REG_TYPE = 2. The automatic data FIFO memory holds four beats.
Output TUSER is enabled and 128 bits wide. Input and output share a
10 ns clock, and reset has already been released.
Frames enter s_axis and leave m_axis with the same data labels:
FA uses DA0, DA1, and subsequent beats; FB uses
DB0, DB1, and subsequent beats; FC uses DC0,
DC1, and subsequent beats. HA, HB, and HC identify
their corresponding captured headers. The source presents each complete
input without deasserting VALID while that input is pending.
Each 66-byte Ethernet frame includes its Ethernet header and excludes
preamble, SFD, and FCS. It occupies eight full beats with KEEP 0xFF
and a final two-byte beat with KEEP 0x03 and TLAST. The nine-byte
truncated input in the second scenario is not a complete Ethernet frame;
it uses one full beat and one final beat with KEEP 0x01.
A numbered tick marks a clock interval. A beat transfers at the ending
rising edge when VALID and READY are both high. x marks irrelevant
payload values while VALID is low.
Complete prefix capture and unchanged frame delivery
Frame |
Length |
Data beats |
Output TUSER |
|---|---|---|---|
|
66 bytes |
|
|
The first two accepted beats, DA0 and DA1, contain all 16
header bytes. Output starts with DA0 in tick 5, while the input
is still sending the frame. Every output beat carries HA, including
the unchanged header bytes on DA0 and DA1. The final DA8
beat retains KEEP 0x03 and TLAST.
The complete frame retains its captured prefix on every output beat
Truncated prefix between complete frames
Frame |
Length |
Data beats |
Output TUSER |
|---|---|---|---|
|
66 bytes |
|
|
|
9 bytes, truncated |
|
|
|
66 bytes |
|
|
The source offers the three inputs consecutively. FB ends before its
16-byte prefix is complete. Its TLAST still creates one header record,
HB = {b0, ..., b8, 56'b0}. The seven missing bytes do not retain
values from HA. Both beats of the short input pass through, including
the final KEEP 0x01.
The next complete frame receives HC from its own first 16 bytes.
On the output, metadata changes from HA to HB to HC
only as the corresponding frame changes. The short input is neither dropped
nor merged with its neighbours.
A truncated input gets a zero-padded header between two complete frames
Following headers cannot replace a stalled final beat
Frame |
Length |
Data beats |
Output TUSER |
|---|---|---|---|
|
66 bytes |
|
|
|
66 bytes |
|
|
FB starts entering in tick 10, so its first 16 bytes have already
been accepted when the final output beat of FA is held by READY low
in ticks 13 through 15. That beat keeps DA8, KEEP 0x03,
TLAST, and HA throughout the wait, even though HB is already
available for the following frame.
READY returns high in tick 16 and accepts that final FA beat at the
ending edge. The first output beat of FB follows in tick 17 with
HB. Buffer pressure also holds input beat DB7 for one extra
interval; this does not change either frame’s metadata association.
A stalled final beat keeps its own header while the next frame enters
Verification
The test suite is in dv/core/openenoc_axis_header_parser/.
Testbench
This test suite validates the openenoc_axis_header_parser module, which snoops the first 16
bytes of every AXI Stream frame and presents them as a stable 128-bit header on
m_axis.tuser. The frame payload (tdata) passes through unchanged, delayed by the header
so that tuser is valid from the first output beat. No field splitting is performed — the raw
128-bit header is exposed on tuser for a later block to parse.
Header layout (byte 0 = first byte on the wire = MSB of tuser):
Field |
Bits |
|---|---|
Destination MAC |
|
Source MAC |
|
EtherType |
|
oETP Magic |
|
oETP Cmd |
|
Coverage
Functional checks (per frame):
Payload (
tdata) passes through unchanged128-bit header is correct and stable on
tuserfor the whole frame
Scenarios (TestFactory):
Multiple payload sizes, including header-only frames (0-byte payload)
Back-to-back frames with distinct headers (header alignment under overlap)
Idle insertion and backpressure combinations
Parameter sweep (pytest):
DATA_Win {8, 16, 32, 64}