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

  • Start Here6
  • SystemVerilog Language Foundations28
    • SystemVerilog Data Types
    • Arrays: Packed, Dynamic, Queues & Associative
    • Procedural Code & Scheduling
    • Operators, Expressions & Width Rules
      • Signed & Unsigned Arithmetic
      • Equality, Case Equality & Wildcards
      • unique, unique0 & priority
      • Shifts, Concatenation & Streaming
      • Expression Width & Evaluation Rules
    • Packages, Typedefs & Compilation
    • Interfaces, Modports & Clocking Blocks
  • Object-Oriented SystemVerilog for Verification30
  • Constraint Randomization — Interview-Critical Deep Dive36
  • SystemVerilog Assertions — Interview-Critical Deep Dive40
  • Functional Coverage in SystemVerilog22
  • Testbench Architecture in SystemVerilog23
  • Advanced Language & Integration25
  • Senior & Interview Preparation21
  • Principal-Level Verification28
Loading lesson

‹Operators, Expressions & Width Rules
  1. Topics
  2. SystemVerilog
  3. SystemVerilog Language Foundations
  4. Operators, Expressions & Width Rules
  5. Shifts, Concatenation & Streaming

Part 1 · Language Foundations · Intermediate

Shifts, Concatenation & Streaming

Logical vs arithmetic shifts, reduction operators, replication, and streaming operators for pack/unpack and byte reversal.

On this page

    Why this matters

    Every word arrived with its bytes backwards. The reversal used {<<{w}}, which mirrors bits, where {<<8{w}} swaps bytes; one number decided the bug.

    After this lesson you can: use logical and arithmetic shifts correctly, build values with concatenation and replication, and pack, unpack and reverse data with streaming.

    Logical and arithmetic shift

    Two right shifts exist. Logical >> always zero-fills, while arithmetic >>> replicates the sign bit, but only when the left operand is signed.

    On an unsigned operand >>> quietly becomes >>. The operator alone never gives sign-preserving division by two.

    Predict first s is a signed byte holding -16 (8'hF0) and u an unsigned byte holding 8'hF0. What are s >>> 2, s >> 2 and u >>> 2?

    -4 (8'hFC), 60 (8'h3C) and 60. Only a signed operand gets its sign bit copied by >>>; >> always fills with zeros, and >>> on an unsigned value does the same.

    Expression

    Operand

    Demo result

    s >>> 2

    signed, -16 (8'hF0)

    -4 (8'hFC, sign replicated)

    s >> 2

    signed, -16 (8'hF0)

    60 (8'h3C, zero-filled)

    u >>> 2

    unsigned, 240 (8'hF0)

    60 (acts like >>)

    << vs <<<

    any

    Identical: both zero-fill from the right

    Concatenation and replication

    Concatenation joins operands MSB-first, and replication repeats a value N times. Every operand needs a known width, so unsized literals are illegal inside.

    The result is always unsigned, which poisons signed arithmetic nearby. Concatenation also splits values on the left side of assignments.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // snippet
    logic [3:0] hi = 4'hA, lo = 4'h5;
    logic [7:0] w = {hi, lo};            // 8'hA5
    logic [31:0] rep = {4{8'hFF}};        // 32'hFFFF_FFFF
    logic [7:0] b8;
    logic [15:0] sext = {{8{b8[7]}}, b8}; // manual sign extension of byte b8
    // Left-hand-side split: one 9-bit add into carry plus sum
    logic [7:0] a8, c8, sum8;
    logic carry8, cin8;
    assign {carry8, sum8} = a8 + c8 + cin8;

    Reduction operators fold every bit of one vector into a single bit:

    • `|v` is 1 when any bit is set.

    • `&v` is 1 when every bit is set.

    • `^v` is 1 for odd parity.

    Streaming pack and byte order

    Streaming converts structs and arrays to bit streams. >> keeps slice order, while << reverses it at the chosen granularity.

    {<<8{w}} reverses byte order and keeps bit order inside each byte. {<<{w}} with the default 1-bit slice mirrors every bit.

    The slice size is the whole answer: 8 swaps bytes, 1 mirrors bits.

    Form (32'h12_34_56_78)

    Meaning

    Result

    {>>{w}}

    Stream MSB-first

    12 34 56 78 (no change)

    {<<8{w}}

    Reverse bytes

    78 56 34 12 (endianness swap)

    {<<16{w}}

    Reverse halfwords

    56 78 12 34

    {<<{w}}

    Reverse bits

    Every bit mirrored

    Packing a struct, unpacking it on the left side, and both reversals, run on Verilator:

    design.sv
    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
    typedef struct packed {
      logic [7:0]  cmd;
      logic [15:0] addr;
      logic [31:0] data;
    } pkt_t;
    
    module tb_stream;
      pkt_t pkt, back;
      logic [55:0] flat;
      logic [31:0] w, le, rb;
      int errors = 0;
      initial begin
        pkt = '{cmd: 8'h5A, addr: 16'hBEEF, data: 32'h1234_5678};
        flat = {>>{pkt}};              // pack the struct, MSB first
        if (flat !== 56'h5A_BEEF_1234_5678) errors++;
        {>>{back}} = flat;             // unpack on the left side
        if (back !== pkt) errors++;
        w = 32'h1234_5678;
        le = {<<8{w}};                 // reverse bytes
        rb = {<<{w}};                  // reverse bits
        $display("w=%h  {<<8{w}}=%h  {<<{w}}=%h", w, le, rb);
        if (le !== 32'h7856_3412) errors++;
        if (rb !== 32'h1E6A_2C48) errors++;
        if (errors == 0) $display("PASS: struct packed and unpacked, bytes and bits reversed");
        else $fatal(1, "FAIL: %0d streaming checks disagreed", errors);
        $finish;
      end
    endmodule
    Terminal
    w=12345678  {<<8{w}}=78563412  {<<{w}}=1e6a2c48
    PASS: struct packed and unpacked, bytes and bits reversed

    Streaming into a byte queue, q = {>>byte{pkt}}, is the same idea with a queue on the left; the queues lesson in Arrays shows the queue side.

    Testbench

    Shifts, reductions and replication face fixed vectors with known answers. A second block packs, splits and reverses bytes the manual way.

    design.sv
    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
    module tb_pack_manual;
      logic [7:0] cmd, cmd_back;
      logic [15:0] addr, addr_back;
      logic [31:0] data, data_back;
      logic [55:0] flat;
      logic [7:0] b0, b1, b2, b3, b4, b5, b6;
      logic [31:0] w, le, rb;
      int errors = 0;
      initial begin
        cmd = 8'h5A; addr = 16'hBEEF; data = 32'h1234_5678;
        flat = {cmd, addr, data};
        if (flat !== 56'h5ABEEF12345678) errors++;
        {b0, b1, b2, b3, b4, b5, b6} = flat;
        if (b0 !== 8'h5A || b1 !== 8'hBE || b2 !== 8'hEF) errors++;
        if (b3 !== 8'h12 || b4 !== 8'h34 || b5 !== 8'h56 || b6 !== 8'h78) errors++;
        {cmd_back, addr_back, data_back} = flat;
        if (cmd_back !== cmd || addr_back !== addr || data_back !== data) errors++;
        w = 32'h1234_5678;
        le = {w[7:0], w[15:8], w[23:16], w[31:24]};
        if (le !== 32'h7856_3412) errors++;
        rb = 32'h0;
        for (int i = 0; i < 32; i++) rb[i] = w[31-i];
        if (rb !== 32'h1E6A_2C48) errors++;
        if (errors != 0) $fatal(1, "FAIL: manual pack or reversal disagrees");
        $display("PASS: manual pack splits to 7 ordered bytes and reversals hold");
        $finish;
      end
    endmodule
    Terminal
    PASS: manual pack splits to 7 ordered bytes and reversals hold
    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    module tb_shifts;
      timeunit 1ns; timeprecision 1ps;
      logic signed [7:0] s;
      logic        [7:0] u, v;
      int errors = 0;
      initial begin
        s = -8'sd16;
        u = 8'hF0;
        v = 8'b1011_0010;
        #1;
        if (s >>> 2 !== -8'sd4) errors++;
        if (s >> 2 !== 8'd60) errors++;
        if (u >>> 2 !== 8'd60) errors++;
        if (u << 2 !== 8'hC0) errors++;
        if (|v !== 1'b1) errors++;
        if (&v !== 1'b0) errors++;
        if (^v !== 1'b0) errors++;
        if (~|v !== 1'b0) errors++;
        if ({4{2'b10}} !== 8'b1010_1010) errors++;
        if (errors != 0) $fatal(1, "FAIL: shift or reduction results disagree");
        $display("PASS: arithmetic shift keeps -4 while logical shifts give 60");
        $finish;
      end
    endmodule
    Terminal
    PASS: arithmetic shift keeps -4 while logical shifts give 60

    Common pitfall

    Applying >>> to an unsigned operand silently zero-fills, and {<<{w}} bit-reverses where {<<8{w}} byte-reverses. The slice size is the whole answer, and the operand signedness decides the shift.

    Interview

    Likely questions: the one-line endianness swap, >> versus >>>, and packing a struct into a byte queue.

    • Endianness swaps with {<<8{word}}: slices of 8 reverse, bits within bytes stay.

    • `>>>` sign-extends only for signed operands; on unsigned it equals >>.

    • Packing uses q = {>>byte{pkt}}, and the same streaming form unpacks on the left side.

    Check yourself Which reduction operator gives the parity of v, and what does it return for 8'b1011_0010?

    ^v, the XOR of all bits. It returns 0, because the vector has four ones, an even count.

    Check yourself What is the difference between {<<8{w}} and {<<{w}} for a 32-bit w?

    {<<8{w}} reverses byte order and keeps bit order inside each byte. {<<{w}} with the default 1-bit slice mirrors every bit.

    Project step

    Build the Part 0 PacketFIFO packet as bytes: compute the check byte as the XOR of the header 22 and the payload A5 3C, stream the four bytes into one 32-bit word, then stream them back out and confirm that all four XOR to zero.

    One way to write it:

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    module tb_pkt_bytes;
      logic [7:0]      hdr, chk;
      logic [7:0]      payload [0:1];
      logic [3:0][7:0] wire_bytes;       // four bytes as one 32-bit vector, first byte at the top
      logic [7:0]      h2, p0, p1, c2;
      int errors = 0;
      initial begin
        hdr = 8'h22;                     // DATA, dest 2, len 2
        payload[0] = 8'hA5;
        payload[1] = 8'h3C;
        chk = hdr ^ payload[0] ^ payload[1];          // check byte: XOR of everything before it
        wire_bytes = {>>{hdr, payload[0], payload[1], chk}};
        $display("check byte %h, packet on the wire %h", chk, wire_bytes);
        if (chk !== 8'hBB || wire_bytes !== 32'h22A5_3CBB) errors++;
        {>>{h2, p0, p1, c2}} = wire_bytes;            // and back
        if (h2 !== hdr || p0 !== 8'hA5 || p1 !== 8'h3C || c2 !== chk) errors++;
        if ((h2 ^ p0 ^ p1 ^ c2) !== 8'h00) errors++;  // a good packet XORs to zero
        if (errors == 0) $display("PASS: check byte BB, packet 22 A5 3C BB packed and unpacked, XOR of all four is 0");
        else $fatal(1, "FAIL: %0d packet byte checks disagreed", errors);
        $finish;
      end
    endmodule
    Terminal
    check byte bb, packet on the wire 22a53cbb
    PASS: check byte BB, packet 22 A5 3C BB packed and unpacked, XOR of all four is 0

    Remember

    • >>> copies the sign bit only for signed operands; >> always fills with zeros.

    • Concatenations are unsigned and need sized operands.

    • {<<N{w}} reverses slices of N bits: 8 swaps bytes, 1 mirrors bits.

    Rule of thumb: the slice size decides what a reversal reverses.

    How this was checked

    Run with Verilator 5.048 (--binary --timing) on 2026-10-18; every bench printed the PASS line shown, with no warnings.

    Icarus 13 runs the manual-pack and shift benches too, but has no streaming operators, so the streaming and PacketFIFO byte benches need Verilator.

    Related topics

    • Next: Expression Width & Evaluation Rules

    Previous

    24 / 259

    Next: Expression Width & Evaluation Rules

    Up next

    Up nextExpression Width & Evaluation Rules

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Signed & Unsigned Arithmetic
    • Equality, Case Equality & Wildcards