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).
Bit 31 is the most significant bit of hdr.
| Bits | Field | Width | Meaning |
|---|---|---|---|
[31:28] | version | 4 | Protocol version. The only supported version is 2. |
[27:24] | msg_type | 4 | Message type: 0 = DATA, 1 = ACK, 2 = NACK, 3 = CTRL. Values 4–15 are reserved. |
[23:16] | length | 8 | Payload length in bytes (any value 0–255 is allowed). |
[15:12] | flags | 4 | Flag bits (any value is allowed). |
[11:4] | seq | 8 | Sequence number (any value is allowed). |
[3:0] | chk | 4 | Header 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.
| Port | Dir | Width | Meaning |
|---|---|---|---|
hdr | input | 32 | The header word. |
version | output | 4 | hdr[31:28] |
msg_type | output | 4 | hdr[27:24] |
length | output | 8 | hdr[23:16] |
flags | output | 4 | hdr[15:12] |
seq | output | 8 | hdr[11:4] |
chk_ok | output | 1 | 1 iff the checksum rule holds. |
valid | output | 1 | 1 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.
hdr | version | msg_type | length | flags | seq | chk_ok | valid | Why |
|---|---|---|---|---|---|---|---|---|
32'h2010_1057 | 2 | 0 (DATA) | 8'h10 | 4'h1 | 8'h05 | 1 | 1 | 2^0^1^0^1^0^5 = 7 = chk |
32'h2300_8FF9 | 2 | 3 (CTRL) | 8'h00 | 4'h8 | 8'hFF | 1 | 1 | |
32'h2010_1056 | 2 | 0 | 8'h10 | 4'h1 | 8'h05 | 0 | 0 | checksum should be 7 |
32'h3010_1056 | 3 | 0 | 8'h10 | 4'h1 | 8'h05 | 1 | 0 | unsupported version |
32'h2500_0007 | 2 | 5 | 8'h00 | 4'h0 | 8'h00 | 1 | 0 | reserved message type |
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.