Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • Reading Paths
  • Concept Map
  • How to Read the Diagrams
  • Part 0: What Is a Protocol?10
  • Part 1: Timing and Clocking11
  • Part 2: Encoding and Framing12
    • Line Codes
    • Framing Basics
    • Packet Anatomy
    • Bit Stuffing
    • DC Balance and Running Disparity
    • Block Codes
    • Scrambling
    • Alignment and Lock
    • Control Symbols and Ordered Sets
    • Flits, Phits and Packing
    • Protocols Compared: Encoding and Framing
    • Drills: Encoding and Framing
  • Part 3: Handshakes13
  • Part 4: Flow Control17
  • Part 5: Transactions19
  • Part 6: Concurrency and Performance17
  • Part 7: Ordering13
  • Part 8: Sharing and Arbitration12
  • Part 9: Deadlock and Liveness13
  • Part 10: Reliability and Recovery20
  • Part 11: Bring-Up and Link Management10
  • Part 12: Power8
  • Part 13: Shared State and Coherence9
  • Part 14: Security and Isolation7
  • Part 15: Specifying and Verifying11
  • Part 16: Protocols Dissected17
  • Part 17: Capstones5
  • Part 18: Interview Preparation6
Loading lesson

‹Part 2: Encoding and Framing
  1. Topics
  2. First Principles of Hardware Protocols
  3. Part 2: Encoding and Framing
  4. Packet Anatomy

Part 2 · Encoding and Framing · Foundation (F)

Packet Anatomy

Header, payload and trailer: what goes where and why, fixed versus variable length, alignment and padding, and DCLink's first packet format.

On this page

    Note

    Level: Foundation (F) · Answers: Where does a message start and end?

    Before this: Framing Basics

    You are asked to design the packet format for a new link between two chips. It must carry reads, writes and their responses. Someone suggests just sending the address and data. Within ten minutes of discussion the list of things the receiver needs to know has grown to: what kind of packet this is, how long it is, who it is for, which earlier request it answers, whether it arrived intact, and whether it is the next one in sequence.

    What goes in a packet besides the payload, and where does each piece belong?

    The obvious answer, and why it breaks

    The obvious packet is pure data: address and value, nothing more. It breaks the moment the receiver needs to do anything but store it. It cannot tell a read from a write, cannot find the end of a variable-length payload, cannot match a response to its request, and cannot tell whether the bits arrived intact. Each missing piece forces either a separate wire (fine on chip, expensive off chip) or a field in the packet. Packet design is deciding which pieces the receiver needs, and where they go.

    The idea: header, payload, trailer

    Part

    Holds

    Why it sits there

    Header (first)

    Type, length, destination, tags, attributes

    The receiver needs it before the payload: to route the packet, to know how long it is, and to decide what to do with it

    Payload

    The data being moved

    Opaque to the layer carrying it

    Trailer (last)

    CRC or checksum; sometimes an end marker

    It is computed over everything before it, so it can only be finished after the payload has gone out: putting it last lets the sender stream the packet without buffering it

    Field placement follows when each piece is needed: header first, trailer last.

    Two more choices shape every format:

    • Fixed or variable length. Fixed-size packets (or cells) make buffers and timing simple but waste space when messages are small. Variable-length packets fit the data but need a length field or a delimiter, and buffers sized for the largest packet.

    • Alignment and padding. Hardware reads fields fastest when they sit at fixed positions and on natural boundaries (a 32-bit field on a 32-bit boundary). Formats therefore pad fields and payloads to multiples of the bus width, trading a few wasted bits for much simpler logic.

    Build it: DCLink step 1

    DCLink, the small protocol you build through this course, starts here. Each packet is one 32-bit header flit (the unit sent per transfer) and 0 to 15 payload flits. The header's top four bits are the packet type (write, read, completion) and the next four are the number of payload flits. The receiver finds every packet boundary by reading the previous packet's length, the length-field framing of lesson 2.2. The model packs three packets into one stream, parses them back, then flips one bit in the first length field.

    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    """DCLink step 1: framing packets by a length field.
    
    A packet is one 32-bit header flit followed by 0 to 15 payload flits. The header
    carries the packet type in bits 31:28 and the number of payload flits in bits 27:24.
    The receiver finds every packet boundary by reading the length of the one before.
    """
    TYPES = {0: "WR", 1: "RD", 2: "CPL"}
    
    
    def pack(ptype, payload):
        assert 0 <= len(payload) <= 15
        return [(ptype << 28) | (len(payload) << 24)] + list(payload)
    
    
    def unpack(flits):
        packets, i = [], 0
        while i < len(flits):
            hdr = flits[i]
            ptype, n = hdr >> 28, (hdr >> 24) & 0xF
            packets.append((TYPES.get(ptype, f"?{ptype}"), flits[i + 1 : i + 1 + n]))
            i += 1 + n                                  # the next header starts right after
        return packets
    
    
    stream = pack(0, [0xAAAA0001, 0xAAAA0002]) + pack(1, []) + pack(2, [0xBBBB0001])
    print("stream:", " ".join(f"{f:08x}" for f in stream))
    good = unpack(stream)
    for t, p in good:
        print(f"  {t:3} with {len(p)} payload flits: {[f'{x:08x}' for x in p]}")
    assert good == [("WR", [0xAAAA0001, 0xAAAA0002]), ("RD", []), ("CPL", [0xBBBB0001])]
    
    bad = list(stream)
    bad[0] ^= 1 << 24                                   # one bit flip in the first length field
    print("same stream with one bit flipped in the first length field:")
    for t, p in unpack(bad):
        print(f"  {t:3} with {len(p)} payload flits")
    print("PASS: length framing recovers every packet; one bad length field misframes the rest")

    It prints:

    Diagram
    stream: 02000000 aaaa0001 aaaa0002 10000000 21000000 bbbb0001
      WR  with 2 payload flits: ['aaaa0001', 'aaaa0002']
      RD  with 0 payload flits: []
      CPL with 1 payload flits: ['bbbb0001']
    same stream with one bit flipped in the first length field:
      WR  with 3 payload flits
      CPL with 1 payload flits
    PASS: length framing recovers every packet; one bad length field misframes the rest

    The good stream parses perfectly: 02000000 is a write (type 0) with 2 payload flits, 10000000 a read with none, 21000000 a completion with one. Now look at the corrupted run. One flipped bit turned the write's length from 2 into 3, so the receiver swallowed the read's header as payload, and the read disappeared without any error being reported. That is lesson 2.2's warning in miniature, and the reason DCLink will gain a CRC and sequence numbers in Part 10.

    Tip

    DCLink's header layout is specified once, in the DCLink contract on How to Use This Course, and grows step by step: tags in Part 6, ordering in Part 7, sequence numbers and a CRC in Part 10.

    The design space

    Choice

    Option A

    Option B

    Length

    Fixed-size packets: simple buffers, wasted space for small messages

    Variable length: efficient, needs a length or delimiter

    Header size

    Small fixed header: low overhead, little room to grow

    Larger or extensible header: room for features, more overhead on small packets

    Field placement

    Natural alignment: simple, fast logic

    Tightly packed: fewer bits, more shifting and muxing

    Integrity check

    Trailer CRC over the whole packet

    Separate header CRC so a bad header is caught before the payload arrives

    Reserved bits

    None: every bit used today

    Some reserved, must be zero: room for later versions (lesson 11.8)

    How real protocols chose

    Protocol

    Packet structure

    Ethernet

    Preamble and start frame delimiter, then the frame (addresses, type or length, payload) and a CRC-32 frame check sequence at the end.

    PCI Express

    A transaction-layer packet with a header, an optional data payload and an optional end-to-end CRC; the data link layer adds a sequence number in front and a CRC (LCRC) behind. Each layer adds its own header and trailer (lesson 0.7).

    PCI Express 6.0

    Packets are carried inside fixed 256-byte flits: 236 bytes of transaction-layer data, 6 bytes of data-link payload, 8 bytes of CRC and 6 bytes of FEC.

    What breaks

    A packet format puts its CRC in the header, computed over the payload, to keep all control fields together (illustrative). The sender must now compute the CRC before sending the first word, so it has to buffer the entire payload first. Latency rises by a full packet time, and the transmit buffer must hold the largest packet. The fix moved the CRC to a trailer, so the packet could stream out while the CRC was computed alongside. Field placement is not cosmetic: it decides buffering and latency.

    Why this matters

    Senior lens. Review a packet format by walking a packet through the receiver in time order: at each word, what does the receiver know, and what must it decide? Fields needed early (type, length, destination) must come early; fields computed late (CRC) must come late; anything else should sit where the hardware can find it with the least logic. Then check headroom: reserved fields, a version, an extension mechanism. Formats live far longer than their first implementation.

    Interview

    Asked: "What fields would you put in a header for a memory read request?"

    Weak answer: The address.

    Strong answer: Type (it's a read), the address, the size or length of data requested, a tag so the response can be matched to this request, the requester's identity if responses must be routed back, and attributes such as cacheability or security. Then, depending on the link, a sequence number and a CRC at the link layer. I'd keep fields the receiver needs first at the front, naturally aligned, and leave reserved bits for growth.

    Follow-ups: (1) Why does the CRC usually go at the end? (2) Why do fixed-size flits waste space, and when is that worth it?

    Check yourself In the model's corrupted stream, why did the receiver report no error?

    Length framing has no check of its own: the receiver trusted the bad length, consumed the next header as payload, and every later boundary still looked plausible. Only a CRC or sequence number would expose it.

    Check yourself Why does the header come before the payload?

    The receiver needs the type, length and destination to route and buffer the packet, and it needs them before the payload arrives.

    Check yourself What does a reserved, must-be-zero field buy?

    Room for a later version to add a feature: old receivers ignore it, new ones use it, and old senders always send zero, so both stay compatible.

    Key takeaways

    • A packet is a header (what the receiver needs first), a payload, and a trailer (what can only be computed last, such as a CRC).

    • Fixed versus variable length and alignment versus packing trade simplicity against efficiency.

    • Length framing without a check silently misframes after one bad bit: DCLink will need a CRC.

    Keep going

    Next: Lesson 2.4, Bit Stuffing. How to keep data from looking like a delimiter, and from starving the receiver of transitions, by inserting bits.

    Related topics

    • Part 2 overview: Encoding and Framing

    • Lesson 0.7: Layering and the End-to-End Argument

    Previous

    28 / 234

    Next: Bit Stuffing

    Up next

    Up nextBit Stuffing

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Line Codes
    • DC Balance and Running Disparity
    • Block Codes