Module 1: TLP Headers: Every Field, Every Type
TLP Structure — Header Field Reference
Learning objectives
- Explain the core mental model behind TLP Structure — Header Field Reference
- Apply TLP Structure — Header Field Reference within TLP Headers: Every Field, Every Type
- Identify important boundaries, trade-offs, and failure modes
- Produce concrete evidence from the practice exercise
Related: Transaction Layer | Addressing and Routing | Completions | PCIE Index
Common TLP Header Fields (First DW)
Every TLP begins with the same first 32-bit double-word (DW0), regardless of type:
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
┌───┬───┬───┬────────────┬────────────────────┬───┬───┬───┬────────────┬────────────────────────────────┐
│ R │Fmt[2:0]│ Type[4:0] │ T9│ TC[2:0] │T8 │ R │ R │ TH│ R │ R │ TD│ EP│ Attr[1:0]│ AT[1:0] │ Length[9:0] │
└───┴───┴───┴────────────┴────────────────────┴───┴───┴───┴────────────┴────────────────────────────────┘(R = Reserved)
Fmt — Format Field (bits 30:29, 3 bits total including bit 28)
The Fmt field (combined with the Type field) defines the TLP type. The 3-bit Fmt encodes:
| Fmt | Meaning |
|---|---|
| 000 | 3-DW header, no data payload |
| 001 | 4-DW header, no data payload |
| 010 | 3-DW header, with data payload |
| 011 | 4-DW header, with data payload |
| 100 | TLP Prefix (special, PCIe 3.0+) |
3-DW headers are 12 bytes; 4-DW headers are 16 bytes. 3-DW headers use a 32-bit address; 4-DW headers use a 64-bit address.
Type — Transaction Type Field (bits 28:24, 5 bits)
Combined with Fmt, Type identifies the specific TLP variety. Key values:
| Fmt | Type | TLP Name |
|---|---|---|
| 000 | 00000 | Memory Read Request (MRd, 3-DW) |
| 001 | 00000 | Memory Read Request (MRd, 4-DW) |
| 010 | 00000 | Memory Write Request (MWr, 3-DW) |
| 011 | 00000 | Memory Write Request (MWr, 4-DW) |
| 000 | 00001 | Memory Read Locked (MRdLk, 3-DW) |
| 000 | 00010 | I/O Read Request (IORd) |
| 010 | 00010 | I/O Write Request (IOWr) |
| 000 | 00100 | Config Read Type 0 (CfgRd0) |
| 010 | 00100 | Config Write Type 0 (CfgWr0) |
| 000 | 00101 | Config Read Type 1 (CfgRd1) |
| 010 | 00101 | Config Write Type 1 (CfgWr1) |
| 000 | 01010 | Completion without Data (Cpl) |
| 010 | 01010 | Completion with Data (CplD) |
| 000 | 01011 | Completion for Locked Memory Read without Data |
| 010 | 01011 | Completion for Locked Memory Read with Data |
| 001 | 10000 | Message Request (no data, routed to Root Complex) |
| 011 | 10000 | Message Request with Data |
TC — Traffic Class (bits 22:20, 3 bits)
TC0–TC7. Most traffic uses TC0. Mapped to Virtual Channels by the TC/VC capability registers.
TD — TLP Digest (bit 15)
When set, the TLP includes an ECRC at the end (the last 4 bytes of the TLP, after the payload). The receiver must check and strip the ECRC before forwarding.
EP — Poisoned Data (bit 14)
When set, the data in this TLP is known to be corrupted (e.g., the source read bad data from a poisoned memory location). The receiver should not use the data and should propagate the error. An endpoint receiving a poisoned Completion should report a non-fatal error via AER.
Attr — Attributes (bits 13:12, 2 bits)
Two bits controlling ordering and snooping behavior:
- Bit 13 — Relaxed Ordering (RO): If set, this TLP may pass earlier posted transactions in the switch. Used for write-combine traffic where strict ordering is not required. See Ordering Rules.
- Bit 12 — No Snoop (NS): If set, the platform's host bridge need not snoop caches for this transaction. Software must guarantee cache coherency separately. Used for DMA to write-combining or uncached memory regions.
AT — Address Type (bits 11:10, 2 bits)
Used for Address Translation Services (ATS) and PASID extensions. For standard transactions: 00 = untranslated address, 01 = translation request, 10 = translated address.
Length — Data Payload Length (bits 9:0, 10 bits)
Number of DW (32-bit Double Words) in the data payload. Value 0 = 1024 DW (the maximum). Valid range: 1–1024 DW (4–4096 bytes). Non-data TLPs (MRd, Cpl) still carry a Length field encoding the requested or expected data amount.
Memory Read Request (MRd) Header
DW0: Fmt=000(3-DW) or 001(4-DW), Type=00000, TC, TD, EP, Attr, AT, Length
DW1: Requester ID [31:16] | Tag [15:8] | Last BE [7:4] | First BE [3:0]
DW2: Address[31:2] | PH[1:0] (3-DW: 32-bit address)
or:
DW2: Address[63:32] (4-DW: upper 32 bits of 64-bit address)
DW3: Address[31:2] | PH[1:0] (4-DW: lower 32 bits)Requester ID: 16-bit BDF (Bus[15:8] / Device[7:3] / Function[2:0]) of the requesting device. The completer uses this to route the CplD back.
Tag: 8-bit (or 10-bit with Extended Tags) unique handle for this outstanding request per Requester ID. The completer echoes this back in the CplD.
First BE / Last BE: Byte enable masks for the first and last DW of the requested data. Indicates which bytes within those DWs are significant. For a single-DW read, Last BE = 0000.
PH: Processing Hints (0=00, 1=01, etc.) for cache hint optimization (PCIe 3.0+).
Memory Write Request (MWr) Header
DW0: Fmt=010(3-DW) or 011(4-DW), Type=00000, TC, TD, EP, Attr, AT, Length
DW1: Requester ID [31:16] | Tag [15:8] | Last BE [7:4] | First BE [3:0]
DW2: Address[31:2] | PH[1:0] (3-DW)
or:
DW2: Address[63:32] (4-DW upper)
DW3: Address[31:2] | PH[1:0] (4-DW lower)
Data Payload: Length × 4 bytes of write data
[ECRC: 4 bytes if TD=1]MWr has the same header structure as MRd but with Fmt indicating a data payload follows. No Completion TLP is generated.
Configuration TLP Headers (Type 0 and Type 1)
DW0: Fmt=000(read)/010(write), Type=00100(Type0)/00101(Type1), TC=0, Length=1
DW1: Requester ID [31:16] | Tag [15:8] | Last BE [7:4] | First BE [3:0]
DW2: Completer ID [31:16] | R[15:12] | Ext Reg Num[11:8] | Reg Num[7:2] | R[1:0]Completer ID: The BDF of the target device (the one being configured).
Ext Reg Num + Reg Num: Together form a 10-bit config register address, selecting which DW of the configuration space is being accessed. Reg Num bits [7:2] select among the 64 DWs of the first 256-byte space; Ext Reg Num selects among the upper 4KB extended space blocks.
Type 0 vs Type 1:
- Type 0: The device identified by Completer ID is on the local segment — the bridge receiving this TLP is directly upstream of the target. The bridge terminates the transaction locally, accessing the target device's configuration space.
- Type 1: The target is further downstream. The bridge receiving this TLP checks if the target's bus number falls within its subordinate bus range. If so, it converts the Type 1 to a Type 0 and forwards it to the correct port. If not, it returns an Unsupported Request (UR) completion.
Completion TLP Headers (Cpl and CplD)
DW0: Fmt=000(Cpl) or 010(CplD), Type=01010, TC, TD, EP, Attr, AT, Length
DW1: Completer ID [31:16] | Cpl Status[15:13] | BCM[12] | Byte Count[11:0]
DW2: Requester ID [31:16] | Tag [15:8] | R[7] | Lower Address[6:0]
[Data Payload: Length × 4 bytes, if CplD]
[ECRC: 4 bytes if TD=1]Completer ID: BDF of the device generating the completion.
Cpl Status (3 bits): Indicates whether the request succeeded:
| Code | Status | Meaning |
|---|---|---|
| 000 | SC — Successful Completion | Transaction completed normally |
| 001 | UR — Unsupported Request | Address not decoded, type not supported |
| 010 | CRS — Config Req Retry Status | Config access not yet available (during device reset/init) |
| 100 | CA — Completer Abort | Request could not be completed (implementation error or illegal access) |
BCM — Byte Count Modified: Legacy PCI-X field, always 0 in PCIe.
Byte Count: The number of bytes of data that remain to be returned to the requester. For a single completion satisfying the entire request, Byte Count = Length × 4 (adjusted for First/Last BE). For split completions (when a large read is returned in multiple smaller CplDs), each subsequent CplD decrements Byte Count.
Lower Address: The byte address (bits 6:0) of the first byte of data in this completion. Required for byte-accurate alignment in split completions.
Tag: Echoed from the original request, used for completion matching.
Message TLP Headers
Messages are used for interrupt signaling, power management, error reporting, and vendor-specific events. They have a fixed 4-DW (16-byte) header, no data (or up to 4096 bytes for vendor-specific messages).
DW0: Fmt=001(no data) or 011(with data), Type[4:0] encodes routing subtype
DW1: Requester ID [31:16] | Tag [15:8] | Message Code [7:0]
DW2: Address[63:32] or routing info (depends on routing type)
DW3: Address[31:0] or routing info
[Data Payload: Length × 4 bytes, if applicable]Message Routing (encoded in Type field):
| Type[2:0] | Routing |
|---|---|
| 000 | Routed to Root Complex (via IDs up the hierarchy) |
| 001 | Addressed routing (by address in DW2/3) |
| 010 | ID routing (by Completer ID) |
| 011 | Broadcast from Root Complex (downstream to all) |
| 100 | Local (terminate at receiver, not forwarded) |
| 101 | Gather to Root Complex (like "to RC" but aggregated) |
Message Code: Identifies the specific message:
| Code | Message |
|---|---|
| 0x20 | Assert_INTA |
| 0x24 | Assert_INTB |
| 0x60 | PM_Active_State_Nak |
| 0x18 | PM_PME |
| 0x19 | PME_Turn_Off |
| 0x1B | PME_TO_Ack |
| 0x30 | ERR_COR |
| 0x31 | ERR_NONFATAL |
| 0x33 | ERR_FATAL |
| 0x7E | Vendor_Defined Type 0 |
| 0x7F | Vendor_Defined Type 1 |
Quick Decode Reference
To decode a TLP from a logic analyzer trace:
1. Read DW0:
- Bits [30:29]: Fmt (header size + payload present)
- Bits [28:24]: Type (transaction variety)
- Bits [9:0]: Length in DW
2. Combine Fmt + Type to look up TLP type in the table above.
3. Read DW1:
- For requests: bits [31:16] = Requester ID (Bus/Dev/Fn)
- For completions: bits [31:16] = Completer ID
- bits [15:8] = Tag (requests and completions)
4. Read DW2 (and DW3 if 4-DW):
- For Memory/IO: address
- For Config: target BDF + register number
- For Completions: Requester ID + Lower Address
5. Check TD bit in DW0 for ECRC presence at end of TLP.
6. Check EP bit in DW0 for poisoned data.Common Pitfalls
PITFALL 1: Confusing 3-DW and 4-DW Memory TLPs
3-DW headers carry a 32-bit address (Fmt=000/010) — only for addresses < 4 GB.
4-DW headers carry a 64-bit address (Fmt=001/011) — required for addresses ≥ 4 GB.
A device that receives a 3-DW request for an address it only maps at > 4 GB
will return UR. Enable 64-bit BARs to avoid this.
PITFALL 2: Misreading Length=0 as "no payload"
In the Length field, 0b0000000000 means 1024 DW (4096 bytes), not zero.
A Length=0 TLP is the maximum-length TLP, not an empty one. A TLP with
no data (MRd, Cpl) still has a non-zero Length field indicating the requested
or expected data size.
PITFALL 3: Forgetting Tag is per-Requester-ID
Two different devices can both use Tag 0x01 simultaneously — they have different
Requester IDs, so their completions don't conflict. Only within one device do Tags
need to be unique among outstanding requests.
PITFALL 4: Ignoring First BE and Last BE
A 4-byte read is not always 4 valid bytes. First BE controls which bytes of DW0
are valid; Last BE controls DW(N-1). A driver that ignores these enables can
read stale bytes from misaligned accesses. Always verify BE interpretation
for sub-DW aligned accesses.Related
- Transaction Layer — Overview of TLP types and posted/non-posted model
- Addressing and Routing — How the address/ID fields in TLP headers drive routing
- Completions — Detailed completion matching and error status
- Flow Control — Credit types that govern when TLPs can be sent
- Error Handling — What happens when EP or bad Cpl Status is received
- PCIE Index — Full vault index
Practice lab
Draw or encode one legal transaction trace for TLP Structure — Header Field Reference. Annotate fields, channel events, ordering points, and completion conditions; then construct one illegal or adversarial trace and define the checker that should catch it. Add an operational constraint such as concurrency, recovery, security, latency, or cost, and defend the resulting design trade-off.
Review questions
- What problem does TLP Structure — Header Field Reference solve, and what assumptions does it rely on?
- Which boundary or failure case is easiest to miss, and how would you expose it?
- What alternative design would you consider, and what trade-off would change the decision?
- What artifact, trace, test, or metric proves that your implementation is correct?
Completion evidence
- A working artifact, annotated trace, or reproducible experiment
- At least one normal case and one deliberately failing or boundary case
- A concise explanation of the design choice and its trade-offs
- Saved output showing how correctness was evaluated