Streaming Operator in SystemVerilog(Pack/Unpack):
In short: The streaming operator in SystemVerilog reshapes data between a single vector and a group of values. Use >> to stream left to right and << to stream right to left. “Pack” squeezes several fields into one wide vector or byte queue, and “unpack” spreads a vector back out into fields. It is the clean way to serialise a packet for a bus and rebuild it on the other side.
When you send a transaction over a real bus, the wires do not know about your class fields. They only carry a stream of bits or bytes. The streaming operator is how you turn a set of named fields into that flat stream, and how you put the fields back together after the stream arrives.
A simple way to picture it
Think of packing a suitcase for a trip. At home your clothes are sorted into separate drawers: shirts, socks, chargers. To travel you flatten them all into one bag in a set order. That is pack. When you reach the hotel you open the bag and put everything back into the right drawers, in the same order you packed. That is unpack. The order you pack in must match the order you unpack in, or the socks end up where the shirts should be.
The two directions: >> and <<
The streaming operator has two forms. Both read the source in the same logical order, but they differ in how blocks are placed into the result.
| Operator | Name | What it does |
|---|---|---|
>> | Left to right | Streams data starting from the left (first field) toward the right. This is the natural order for most packet building. |
<< | Right to left | Streams data starting from the right. Handy when a protocol sends the last field first, or for reversing byte order. |
You can also give a slice size, for example { >> 8 { data }}, which tells the tool to move the data 8 bits at a time. That is useful when a bus is byte oriented.
Example 1: pack and unpack a bus packet
Here is a small packet class with four byte fields. The pack function flattens the fields into a byte queue, and unpack rebuilds a packet from that same queue. This is the exact shape you use in a driver and monitor pair.
class eth_packet;
rand bit [7:0] src_addr;
rand bit [7:0] dst_addr;
rand bit [7:0] length;
rand bit [7:0] chksum;
// Flatten the four fields into a byte queue
function void pack(ref bit [7:0] stream[$]);
stream = { >> 8 { src_addr, dst_addr, length, chksum } };
endfunction
// Rebuild the fields from a byte queue
function void unpack(ref bit [7:0] stream[$]);
{ >> 8 { src_addr, dst_addr, length, chksum } } = stream;
endfunction
endclass
module tb;
initial begin
eth_packet tx = new();
eth_packet rx = new();
bit [7:0] bytes[$];
tx.src_addr = 8'h8C;
tx.dst_addr = 8'h00;
tx.length = 8'hA4;
tx.chksum = 8'hFF;
tx.pack(bytes);
foreach (bytes[i])
$display("PACK: bytes[%0d] = %02h", i, bytes[i]);
rx.unpack(bytes);
$display("UNPACK: src=%02h dst=%02h len=%02h crc=%02h",
rx.src_addr, rx.dst_addr, rx.length, rx.chksum);
end
endmoduleExpected output, in plain words
The pack step writes four bytes into the queue in field order, so you see 8C, 00, A4, then FF on indexes 0 to 3. The unpack step reads those same four bytes back into the fields, so the rebuilt packet prints the same values it started with.
PACK: bytes[0] = 8c
PACK: bytes[1] = 00
PACK: bytes[2] = a4
PACK: bytes[3] = ff
UNPACK: src=8c dst=00 len=a4 crc=ffNote: this output is what the code is written to produce based on a careful read of the LRM. For a true sign off, compile and run it on your own simulator or on EDA Playground.
Example 2: reverse byte order with <<
Some protocols send bytes in the opposite order to how you store them. Instead of writing a manual loop, you flip the whole vector with the left form of the operator. Here a 32 bit word is streamed 8 bits at a time from the right, which reverses its byte order.
module reverse_bytes;
initial begin
bit [31:0] word = 32'h11_22_33_44;
bit [31:0] swapped;
// Take the word 8 bits at a time, right to left
swapped = { << 8 { word } };
$display("original = %08h", word);
$display("swapped = %08h", swapped);
end
endmoduleThe original word 11223344 becomes 44332211, because the operator moves each 8 bit block in reverse order. This is a common need when a design is big endian and your model is little endian, or the other way round.
Example 3: unpack a stream into a struct
The operator is not limited to class fields. You can also spread a wide vector into the members of a packed struct in one line, which keeps monitor code short and easy to read.
typedef struct packed {
bit [7:0] opcode;
bit [7:0] addr;
bit [15:0] payload;
} cmd_t;
module unpack_struct;
initial begin
bit [31:0] raw = 32'hA5_10_BEEF;
cmd_t cmd;
{ >> { cmd.opcode, cmd.addr, cmd.payload } } = raw;
$display("opcode=%02h addr=%02h payload=%04h",
cmd.opcode, cmd.addr, cmd.payload);
end
endmoduleThe 32 bit value is split by field width: 8 bits to opcode (A5), 8 bits to addr (10), and 16 bits to payload (BEEF).
When to use the streaming operator
- You need to serialise a transaction into a byte or bit stream before sending it on a bus.
- You need to rebuild a transaction from a captured stream inside a monitor or scoreboard.
- You want to reverse byte or bit order without writing an index loop.
- You are working with SystemVerilog queues, dynamic arrays, or packed structs and want a one line conversion.
Common mistakes to avoid
- Mismatched order: the field order in pack must match the field order in unpack, or the values land in the wrong fields.
- Wrong slice size: using
>> 8on data that is not a multiple of 8 bits can drop or misalign bits. Match the slice size to the protocol. - Confusing the arrow direction:
>>keeps block order,<<reverses it. Pick based on the endianness you need. - Streaming unpacked arrays wrongly: the operator works on packed data and queues of packed elements. Check element widths before you rely on the result.
Streaming operator vs a manual loop
| Point | Streaming operator | Manual for loop |
|---|---|---|
| Lines of code | One line for pack or unpack | Several lines with an index |
| Readability | Clear once you know the syntax | Verbose, easy to introduce an off by one bug |
| Byte reversal | Built in with << | Needs careful index math |
| Best for | Packet serialise and rebuild | Custom logic that the operator cannot express |
For serialising and rebuilding packets, the streaming operator is the shorter and safer choice. Keep manual loops for cases where you need logic the operator cannot express.
If you are new to SystemVerilog data types, it helps to first read our guide on array types and queues, since the streaming operator often works with queues. You may also want our SystemVerilog tutorials and interview questions.
Frequently asked questions
What is the streaming operator in SystemVerilog?
It is an operator that packs several values into one vector or byte stream, or unpacks a vector back into several values. The >> form streams left to right and the << form streams right to left.
What is the difference between pack and unpack?
Pack takes multiple fields and streams them into a single variable such as a byte queue. Unpack does the reverse: it takes a single stream and spreads it back across multiple fields. The field order must match on both sides.
What does the slice size like { >> 8 { data } } mean?
The number after the arrow is the block size in bits. >> 8 moves the data 8 bits at a time, which is useful for byte oriented buses. Without a number, the operator uses the natural element size.
How do I reverse byte order in SystemVerilog?
Use the left streaming form with a slice size, for example swapped = { << 8 { word } };. This moves each 8 bit block in reverse order, turning 11223344 into 44332211.
Can the streaming operator work with queues and structs?
Yes. You can pack fields into a queue or dynamic array, and you can unpack a wide vector into the members of a packed struct in a single line. It works on packed data and queues of packed elements.
When should I use a manual loop instead?
Use a manual loop when you need custom logic the operator cannot express, such as conditional reordering. For plain serialise and rebuild of packets, the streaming operator is shorter and less error prone.
