This document records the bit-level formats OpenURMA uses, with citations to
UB-Base-Specification 2.0.1. The artifact must not drift from the spec at
the wire — the wire format is fully spec-faithful. The internal pipeline
uses a denser representation for FPGA pipelining; the conversion is done at
the UB_Eth_Decap / UB_Eth_Encap boundary.
OpenURMA encapsulates UB packets in standard Ethernet frames. We do not implement the UB physical/link layer. The wire layout per packet is:
+-----------------+-----------------+-----------------+----------------+
| Ethernet hdr | NTH (24-bit CNA)| TPH (RTPH/UTPH) | TAH (BTAH/...) |
| 14 B | 12 B | 16 B / 16 B | 16 B (full) |
+-----------------+-----------------+-----------------+----------------+
| ext TAHs (MAETAH/MTETAH/TVETAH/...) | Payload | ICRC? |
+-------------------------------------+---------+--------------------+
We use UB Ethertype 0xCAFE (placeholder; final value TBD via IANA). ICRC
is omitted in the MVP — Ethernet FCS is sufficient for back-to-back testing.
Standard dst_mac (6) | src_mac (6) | ethertype (2). Ethertype = 0xCAFE.
NTH carries network-layer addressing. We use the 24-bit CNA format because
it is the format whose NLP=0x010 indicates RTPH (16-bit CNA's NLP cannot
indicate RTPH; spec §5.2.1).
byte 0 [b7..b0]: RT[1:0] | reserved[5:0] // we do not carry LPH inside
byte 1..3 : SCNA[23:0] // big-endian on the wire
byte 4..6 : DCNA[23:0]
byte 7..8 : CCI[15:0]
byte 9 : LBF[7:0]
byte 10 [b7..b0]: SL[3:0] | NLP[2:0] | mgmt[1]
byte 11 : reserved
NLP values relevant to OpenURMA:
0x010= RTPH follows (per spec §5.2.2 table)- (We assign internally
0x011= UTPH for the MVP — UTP over 24-bit CNA NTH is not explicitly specified at the network layer; we document this as an Open UMA-only convention pending UB clarification.)
byte 0 : TPOpcode[7:0] // see TPOpcode encoding below
byte 1 : TPVer[1:0] | Padding[1:0] | NLP[3:0]
byte 2..4 : SrcTPN[23:0]
byte 5..7 : DstTPN[23:0]
byte 8 : A[1] | F[1] | reserved[5:0]
byte 9..11: PSN[23:0]
byte 12 : RSPST[2:0] | RSPINFO[4:0]
byte 13..15: TPMSN[23:0]
TPOpcode[6:0]:
0x00UTP packet (UTP only — OpenURMA wires UTPH instead, see below)0x01Reliable TP Packet (RTP)0x02TPACK / TPNAK0x03TPACK-CC / TPNAK-CC (CETPH attached)0x05TPSACK0x06TPSACK-CC0x08CNP (CETPH-only)
TPOpcode[7] (the last bit) marks last packet of a transaction.
RTPH.NLP:
0x0: ATAH or BTAH follows (transaction layer)0x1: 32-bit UPIH + 256-bit EIDH follows0x3: CIPH (security)
OpenURMA MVP only uses RTPH.NLP=0x0.
byte 0 : TPOpcode[7:0] // bit 0 = 0 means UTP
byte 1 : TPVer[1:0] | Padding[1:0] | NLP[3:0]
byte 2..15: reserved
UTPH.NLP semantics same as RTPH.NLP; OpenURMA uses 0x0.
byte 0 : TAOpcode[7:0]
byte 1 : TAver[1:0] | EE_bits[1:0] | TV_EN[1] | Poison[1] | Target_Hint[1] | UD_Flag[1]
byte 2..3 : INI_TASSN[15:0]
byte 4 : No_TAACK[1] | ODR[2:0] | MT_EN[1] | FCE[1] | Retry[1] | Alloc[1]
byte 5 : E_bit[1] | INI_RC_Type[1:0] | reserved[4:0]
byte 6..7 : reserved
byte 8..10: INI_RC_ID[19:0] (20 bits, byte-aligned padded to 24)
byte 11..15: reserved
TAOpcode (full list, spec §7.2.1):
0x00Send0x01Send_with_immediate0x03Write0x04Write_with_immediate0x05Write_with_notify0x06Read0x07Atomic_compare_swap0x08Atomic_swap0x09Atomic_store0x0AAtomic_load0x0BAtomic_fetch_add0x0CAtomic_fetch_sub0x0DAtomic_fetch_and0x0EAtomic_fetch_or0x0FAtomic_fetch_xor0x10Management0x11TAACK (response)0x12Read_response (response)0x13Atomic_response (response)0x14Write_with_be0x15Prefetch_tgt0x17Writeback0x18Writeback_with_be
ODR (3 bits — spec §7.2 Table 7-1):
ODR[1:0]execution-order tag: 00=NO, 01=RO, 10=SOODR[2]completion-order: 0=no completion-order, 1=in-order completion
byte 0 : TAOpcode[7:0] // 0x11=TAACK, 0x12=Read_resp, 0x13=Atom_resp
byte 1 : TAver[1:0] | reserved | Poison | reserved | SV
byte 2..3 : INI_TASSN[15:0]
byte 4 : RSPST[2:0] | RSPINFO[4:0]
byte 5 : reserved | INI_RC_Type[1:0] | reserved
byte 6..7 : reserved
byte 8..10: INI_RC_ID[19:0]
byte 11..15: reserved
byte 0..7 : Address[63:0]
byte 8 : reserved[7:0]
byte 9..11: TokenID[19:0] (byte-aligned padded)
byte 12..15: Length[31:0]
byte 0..3 : TokenValue[31:0]
byte 0 : Hint[7:0]
byte 1..3 : TGT_TC_Type[1:0] | TGT_TC_ID[19:0] (byte-aligned)
Inside the OpenURMA element pipeline, each UB packet is represented as a
single 64-byte metadata flit (or two flits if MAETAH-bearing). Header
fields are packed into the four 64-bit lanes of flit_t. This is denser
and faster than streaming raw bytes; spec fidelity is restored at the
UB_Eth_Encap boundary.
For packets with MAETAH/MTETAH/payload, a second flit follows with
sop=0, carrying address + length + tokens (and atomic operands inline).
Subsequent payload flits stream the data section if any.
Lane 0 — NTH summary
bits [23:0] DCNA
bits [47:24] SCNA
bits [55:48] LBF
bits [59:56] SL
bits [62:60] NTH_NLP // 010 = RTPH, 011 = UTPH (OpenURMA conv.)
bits [63] valid (1 = packet present)
Lane 1 — RTPH
bits [7:0] TPOpcode
bits [9:8] TPVer
bits [11:10] Padding
bits [15:12] RTPH_NLP // 0 = ATAH/BTAH follows
bits [39:16] SrcTPN
bits [63:40] DstTPN
Lane 2 — RTPH cont. + service mode
bits [23:0] PSN
bits [47:24] TPMSN
bits [50:48] RSPST
bits [55:51] RSPINFO
bits [56] A_flag
bits [57] F_flag (Fake)
bits [59:58] service_mode // 00=ROI, 01=ROT, 10=ROL, 11=UNO
bits [60] is_response // 0 = request, 1 = response/ACK
bits [61] last_pkt // RTPH TPOpcode[7]
bits [63:62] reserved
Lane 3 — BTAH
bits [7:0] TAOpcode
bits [9:8] TAver
bits [11:10] EE_bits
bits [12] TV_EN
bits [13] Poison
bits [14] Target_Hint
bits [15] UD_Flag
bits [31:16] INI_TASSN
bits [34:32] ODR // [1:0] exec, [2] completion
bits [35] Fence // OpenURMA-only flag, set by Jetty_Sched
bits [36] MT_EN
bits [37] FCE
bits [38] Retry
bits [39] Alloc
bits [41:40] INI_RC_Type
bits [42] E_bit
bits [62:43] INI_RC_ID (20 bits)
bits [63] reserved
Lane 0 — MAETAH.Address
bits [63:0] Address[63:0]
Lane 1 — MAETAH cont.
bits [19:0] TokenID
bits [31:20] reserved
bits [63:32] Length
Lane 2 — TokenValue + MTETAH (when applicable)
bits [31:0] TokenValue (TVETAH)
bits [39:32] MTETAH.Hint
bits [41:40] MTETAH.TGT_TC_Type
bits [61:42] MTETAH.TGT_TC_ID
bits [63:62] reserved
Lane 3 — Atomic operands (compare/swap/operand) OR Immediate/notify scratch
bits [63:0] operand1 (8 bytes; for CAS this is the swap/compare value)
For immediate or notify, this carries the 8 B inline value.
Each carries up to 32 bytes of payload data. sop=0; only the last has
eop=1. For Read responses, payload is filled by UB_HBM_Read. For Write,
filled by the upstream Doorbell or RX path.
Packet size / MTU. The pipeline's per-packet wire buffer is
WIRE_MAX = 384bytes (UB_Eth_Encap/UB_Eth_Decap), i.e. an MTU of ~306 payload bytes after the headers. A transfer larger than that is segmented into multiple MTU-sized packets — e.g. the gem5 in-guest pipeline-data path (OPENURMA_PIPE_DATA) sends a large WRITE as a sequence of 256-byte-payload packets.
The wire format is the contract with peer NICs and any external observer (packet capture, future interop with HiSilicon UB silicon). It must match spec bit-for-bit.
The internal format is a private optimization. Decoupling them lets us avoid byte-shuffling at every element boundary (which would dominate the HLS pipeline) while still emitting a correct UB packet on the wire.
The conversion is done in two elements only: UB_Eth_Decap (RX, wire →
internal) and UB_Eth_Encap (TX, internal → wire). All ordering, PSN,
state-table logic operates on the internal format.