Packet Header Parser

Medium · Combinational Logic · SystemVerilog Constructs

A small network protocol sends a 32-bit header word in front of every packet. Write a combinational parser that splits the header into its fields and checks whether it is valid.

This problem is about two SystemVerilog features that make such code readable: typedef struct packed (name the bit fields of a vector) and package (share types and constants between modules).

Header format

Bit 31 is the most significant bit of hdr.

BitsFieldWidthMeaning
[31:28]version4Protocol version. The only supported version is 2.
[27:24]msg_type4Message type: 0 = DATA, 1 = ACK, 2 = NACK, 3 = CTRL. Values 4–15 are reserved.
[23:16]length8Payload length in bytes (any value 0–255 is allowed).
[15:12]flags4Flag bits (any value is allowed).
[11:4]seq8Sequence number (any value is allowed).
[3:0]chk4Header checksum.

Checksum rule. chk must equal the XOR of the other seven 4-bit nibbles of the header:

chk == hdr[31:28] ^ hdr[27:24] ^ hdr[23:20] ^ hdr[19:16] ^ hdr[15:12] ^ hdr[11:8] ^ hdr[7:4]

Equivalently, the XOR of all eight nibbles (including chk) is 4'h0. Note that the 8-bit fields length and seq each contribute two nibbles.

Ports

PortDirWidthMeaning
hdrinput32The header word.
versionoutput4hdr[31:28]
msg_typeoutput4hdr[27:24]
lengthoutput8hdr[23:16]
flagsoutput4hdr[15:12]
seqoutput8hdr[11:4]
chk_okoutput11 iff the checksum rule holds.
validoutput11 iff all three hold: version == 2, msg_type is 0–3 (not reserved), and chk_ok == 1.

The field outputs always show the decoded fields, even when the header is not valid. Everything is purely combinational.

Examples

hdrversionmsg_typelengthflagsseqchk_okvalidWhy
32'h2010_105720 (DATA)8'h104'h18'h05112^0^1^0^1^0^5 = 7 = chk
32'h2300_8FF923 (CTRL)8'h004'h88'hFF11
32'h2010_1056208'h104'h18'h0500checksum should be 7
32'h3010_1056308'h104'h18'h0510unsupported version
32'h2500_0007258'h004'h08'h0010reserved message type

Suggested structure

Your single source file may contain a package followed by the module:

package pkt_pkg;
    localparam logic [3:0] PKT_VERSION = 4'd2;

    typedef enum logic [3:0] { MSG_DATA = 4'd0, MSG_ACK, MSG_NACK, MSG_CTRL } msg_type_e;

    typedef struct packed {
        logic [3:0] version;   // first member = most significant bits
        // ... the remaining fields, in order ...
    } pkt_hdr_t;
endpackage

module packet_header_parser
    import pkt_pkg::*;
(
    input  logic [31:0] hdr,
    ...
);
    pkt_hdr_t h;
    assign h = hdr;            // a packed struct is just a named view of a bit vector
    assign version = h.version;
    ...
endmodule

In a packed struct the first member occupies the most significant bits. Getting that order backwards is the most common bug with packed structs.

Keep the top-level ports as plain logic vectors (as given in the starter code): the testbench drives them as numbers.

Sign up free to solve Packet Header Parser in your browser.

More Combinational Logic problems