# Packet diagrams

> Page: https://docs.plotwork.dev/packet-diagrams. Index of every page: https://docs.plotwork.dev/llms.txt

A packet diagram lays out the fields of a network header or a binary record bit by bit, in rows of a fixed width, the way RFCs draw them. Use it to document a protocol header, a file format, a register map, or a message on a wire. It is for anyone who writes or reads code that packs bits, and for an agent that has been asked to explain a format.

## TL;DR

| Question | Answer |
|---|---|
| What is it for? | A header or record of fixed-width fields: TCP, UDP, IPv6, a file header, the bits of a hardware register. |
| How do I start one? | Write `packet "Title"`, then one `field` line for each field with its first and last bit, such as `field 0-15 "Source port"`. |
| How are bits counted? | From 0 at the start of the packet. A row holds 32 bits unless `bits=` says 8, 16, or 64, and a field that runs past the end of a row carries on in the next. |
| What does Mermaid convert? | `packet` and `packet-beta`: every block, by range, by one bit, or by `+N`. See [From Mermaid](#from-mermaid). |
| How big can it be? | At most 400 fields and 4,096 bits. Warnings start at 64 fields or 16 rows, at bits no field holds, and at a length that is not whole bytes. |
| How is it drawn? | A band for each row with the bit numbers over the first row and each row's bit offset at its left. Each field is a cell with its name across it; a narrow field sets its name on its side, and one too narrow even for that is numbered and named in a key under the rows. |

## Ask your agent

```text
Use Plotwork to draw the TCP header as a packet diagram, 32 bits a row. Name every field, colour the SYN, ACK and RST flags, and mark the options as variable length.
```

```text
Use Plotwork to draw the 8-bit status register of our controller as a packet diagram with the most significant bit on the left. Bit 0 is Carry, bit 1 Zero, bit 7 Global interrupt enable.
```

## Example

The fixed 20 bytes of a TCP header and its options. The flags are one bit each, so their names are set on their side; the options field has a torn edge because its length varies.

**Diagram source**

```diagram
packet "TCP header" desc="The fixed 20 bytes of a TCP segment header and its options, one row per 32-bit word. The flags SYN, ACK, RST and FIN open, confirm, reset and close a connection."

field 0-15 "Source port"
field 16-31 "Destination port"
field 32-63 "Sequence number"
field 64-95 "Acknowledgment number"
field 96-99 "Data offset" sub="in 32-bit words"
field 100-103 "Reserved"
field 104 "CWR"
field 105 "ECE"
field 106 "URG"
field 107 "ACK" tone=green
field 108 "PSH"
field 109 "RST" tone=red
field 110 "SYN" tone=blue
field 111 "FIN"
field 112-127 "Window"
field 128-143 "Checksum"
field 144-159 "Urgent pointer"
field 160-191 "Options and padding" variable=on
```

*Picture: TCP header: 18 fields over 192 bits in 6 rows of 32. The fixed 20 bytes of a TCP segment header and its options, one row per 32-bit word. The flags SYN, ACK, RST and FIN open, confirm, reset and close a connection.*

**Text description**

**Rows of 32 bits, the first bit of each row on the left.**

- Source port: bits 0 to 15, 16 bits.
- Destination port: bits 16 to 31, 16 bits.
- Sequence number: bits 32 to 63, 32 bits.
- Acknowledgment number: bits 64 to 95, 32 bits.
- Data offset: bits 96 to 99, 4 bits (in 32-bit words).
- Reserved: bits 100 to 103, 4 bits.
- CWR: bit 104, 1 bit.
- ECE: bit 105, 1 bit.
- URG: bit 106, 1 bit.
- ACK: bit 107, 1 bit.
- PSH: bit 108, 1 bit.
- RST: bit 109, 1 bit.
- SYN: bit 110, 1 bit.
- FIN: bit 111, 1 bit.
- Window: bits 112 to 127, 16 bits.
- Checksum: bits 128 to 143, 16 bits.
- Urgent pointer: bits 144 to 159, 16 bits.
- Options and padding: bits 160 to 191, 32 bits (variable length).

### A UDP header with next

`next` takes the bits right after the field before it, so a format made of whole fields can be listed by width alone.

**Diagram source**

```diagram
packet "UDP header" desc="The 8-byte header of a UDP datagram, then its data."
next 16 "Source port"
next 16 "Destination port"
next 16 "Length" sub="header and data, in bytes"
next 16 "Checksum" tone=amber
next 32 "Data" variable=on
```

*Picture: UDP header: 5 fields over 96 bits in 3 rows of 32. The 8-byte header of a UDP datagram, then its data.*

**Text description**

**Rows of 32 bits, the first bit of each row on the left.**

- Source port: bits 0 to 15, 16 bits.
- Destination port: bits 16 to 31, 16 bits.
- Length: bits 32 to 47, 16 bits (header and data, in bytes).
- Checksum: bits 48 to 63, 16 bits.
- Data: bits 64 to 95, 32 bits (variable length).

### An 8-bit register

`bits=8` makes each bit wide enough for its name, and `order=descending` puts the most significant bit on the left, as a datasheet does.

**Diagram source**

```diagram
packet "Status register" bits=8 order=descending desc="The 8-bit status register of a small microcontroller, most significant bit on the left."
field 0 "Carry" tone=blue
field 1 "Zero"
field 2 "Negative"
field 3 "Overflow" tone=red
field 4 "Sign"
field 5 "Half carry"
field 6 "Bit copy storage"
field 7 "Global interrupt enable" tone=green
```

*Picture: Status register: 8 fields over 8 bits in 1 row of 8. The 8-bit status register of a small microcontroller, most significant bit on the left.*

**Text description**

**Rows of 8 bits, the first bit of each row on the right.**

- Carry: bit 0, 1 bit.
- Zero: bit 1, 1 bit.
- Negative: bit 2, 1 bit.
- Overflow: bit 3, 1 bit.
- Sign: bit 4, 1 bit.
- Half carry: bit 5, 1 bit.
- Bit copy storage: bit 6, 1 bit.
- Global interrupt enable: bit 7, 1 bit.

## The language

### The header

`packet "Title"` starts the diagram. Every option is optional.

| Option | Values | Default | Meaning |
|---|---|---|---|
| `bits=` | `8`, `16`, `32`, `64` | `32` | How many bits a row holds. |
| `numbers=` | `on`, `off` | `on` | The bit numbers over the first row and the bit offset of each row. |
| `order=` | `ascending`, `descending` | `ascending` | `descending` puts the first bit of each row on the right. |
| `desc=` | text | none | The plain-language description, for assistive technology. |

### Statements

| Statement | Meaning | Example |
|---|---|---|
| `field <first>-<last> "<Name>"` | A field from its first bit to its last. Write one number for one bit. | `field 0-15 "Source port"` |
| `next <count> "<Name>"` | A field of `count` bits right after the field before it, or from bit 0 for the first. | `next 16 "Window"` |
| `desc "<text>"` | The plain-language description, the same as `desc=`. | `desc "The UDP header."` |

`field` and `next` take the same options.

| Option | Values | Meaning |
|---|---|---|
| `sub=` | text | A short note under the name, such as the unit. |
| `tone=` | any tone | The field's colour, for a field that matters: a flag, a checksum, a length. |
| `variable=` | `on`, `off` | `on` draws a field of variable length, such as options or a payload, with a torn edge. |

### Fields and bit ranges

Bits are counted from 0 at the start of the packet, not from the start of the row, so the second 32-bit word starts at bit 32. Write the range with a hyphen and no spaces: `96-99`. Fields may be written in any order and are drawn in bit order.

Two fields cannot share a bit: the error names the field already there and the bit to start at. Bits that no field holds are drawn hatched and reported by lint, since they are usually a typo; name them `"Reserved"` when they are reserved.

### Bits per row and bit order

A row is 832 pixels shared among its bits: 104 a bit at 8 bits a row, 26 at 32, and 14 at 64. A field that runs past the end of a row is cut there and carries on in the next row, where its name is drawn again in a quieter ink. With `order=descending`, bit 0 of each row is on the right and the ruler counts down from the left.

### Narrow fields

A name is set across its field when it fits in three lines. A field too narrow for that, such as a flag of one bit, sets its name on its side, reading upward, and its row grows to hold it. A name too long even for that, or a narrow field with a note, gets a number in its cell, and the number, the name, the bits and the note are listed in a key under the rows. Text never leaves its field. Short names, such as `URG` for the urgent pointer flag, keep every name in the rows.

## Limits and warnings

| Limit | What happens |
|---|---|
| More than 400 fields, or a bit past 4095 | Refused with `E140` before any layout. Draw the payload as one variable field, or split the record. |
| More than 64 fields, or more than 16 rows | `W200`: split the record by header or part. |
| Bits no field holds | `W200` names them. |
| A length that is not a whole number of bytes | `W200`, unless the last field is of variable length. |
| A name moved to the key | `W200` names it, so you can shorten it or use fewer bits a row. |
| A name or note cut to fit | `W203`. The full text stays in the text description. |

## From Mermaid

Mermaid `packet` and `packet-beta` convert to a packet diagram. Ask your agent to convert it, or use the `convert_mermaid` tool. The [migration guide](https://docs.plotwork.dev/migrating-from-mermaid.md) covers the converter in full.

```mermaid-source
packet
title UDP Packet
0-15: "Source Port"
16-31: "Destination Port"
32-47: "Length"
48-63: "Checksum"
64-95: "Data (variable length)"
```

The converter keeps every block and reports the field it marked variable (`M204`):

```plotwork
packet "UDP Packet"
field 0-15 "Source Port"
field 16-31 "Destination Port"
field 32-47 "Length"
field 48-63 "Checksum"
field 64-95 "Data (variable length)" variable=on
```

| Mermaid | Plotwork | Report |
|---|---|---|
| `packet`, `packet-beta` | `packet "<title>"` | none |
| `title X`, front matter `title:` | The header title | none |
| `0-15: "Name"` | `field 0-15 "Name"` | none |
| `106: "Name"` | `field 106 "Name"` | none |
| `+16: "Name"` | `next 16 "Name"` | none |
| A name ending in `(variable length)` | The name, and `variable=on` | `M204` |
| A block that shares bits with an earlier one | Dropped | `M209` |
| HTML in a name | Removed | `M205` |
| A block with no name | Dropped | `M216` |
| Front matter `config:` (`bitsPerRow`, `showBits`, `bitOrder`) and `%%{init}%%` | Dropped. Set `bits=`, `numbers=` and `order=` on the header. | `M200` |
| More than 400 blocks, or a bit past 4095 | Nothing is converted. | `M102` |
| A line that cannot be read | Nothing is converted, or the line is skipped when the conversion is lenient. | `M110`, or `M218` |

## See also

| Doc | Why |
|---|---|
| [Writing diagrams](https://docs.plotwork.dev/writing-diagrams.md) | The rules every kind shares |
| [Examples to copy](https://docs.plotwork.dev/examples.md) | Finished diagrams with the prompt that gets an agent to write each one |
| [Migrating from Mermaid](https://docs.plotwork.dev/migrating-from-mermaid.md) | Convert existing Mermaid diagrams, and what is dropped |
| [Matrices](https://docs.plotwork.dev/matrices.md) | A grid of rows and columns, for a table of values rather than bits |
| [Language reference](https://docs.plotwork.dev/reference/language.md) | Every kind, option and diagnostic |
| [Diagram kinds](https://docs.plotwork.dev/reference/language/kinds.md) | The kinds Plotwork draws and the header of each |
