Skip to article

Operators and Expressions

Shift Operators in Verilog

Logical (<<, >>) vs. arithmetic (<<<, >>>) shifts in Verilog, and why a naive >> on a signed value loses the sign bit instead of preserving it.

3 min read · Updated


<< and >> are logical shifts: they move every bit left or right by the given count and fill the vacated positions with 0, regardless of what the original value meant. <<< and >>> are arithmetic shifts: left arithmetic shift behaves identically to logical left shift, but right arithmetic shift fills the vacated high bits by replicating the original sign bit instead of filling with 0 — correct only when the operand is declared signed.

Hardware it becomes depends on the shift amount. A shift by a fixed, compile-time constant (a << 2) is mostly rewiring — each output bit is simply connected to a different input bit, with 0 wired to the vacated positions; no gates compute anything. A shift by a runtime-variable amount (a << n, where n is a signal) is a small selection network — commonly called a barrel shifter — built from a cascade of muxes, one stage per bit of the shift amount, and genuinely costs hardware.

Predict before running

neg = -8, declared signed. Before running it, predict whether neg >> 1 and neg >>> 1 produce the same bit pattern, and what each one means as a signed number.

module shift_left (
  input  wire [7:0] a,
  input  wire [2:0] n,
  output wire [7:0] y
);
  assign y = a << n;
endmodule

module tb;
  reg [7:0] a;
  reg [2:0] n;
  wire [7:0] y;
  reg signed [7:0] neg;

  shift_left u_shift (.a(a), .n(n), .y(y));

  initial begin
    a = 8'b0000_0011;
    n = 3'd2;
    #1;
    $display("a=%b << %0d = %b (logical left shift, zero-fills from the right)", a, n, y);

    neg = -8;
    $display("neg=%b (%0d)", neg, neg);
    $display("neg >>  1 = %b (%0d)  -- logical shift, zero-fills from the left", neg >> 1, $signed(neg >> 1));
    $display("neg >>> 1 = %b (%0d)  -- arithmetic shift, replicates the sign bit", neg >>> 1, neg >>> 1);

    $display("PASS");
    $finish;
  end
endmodule
Expected output — reveal after you predict
a=00000011 << 2 = 00001100 (logical left shift, zero-fills from the right)
neg=11111000 (-8)
neg >>  1 = 01111100 (124)  -- logical shift, zero-fills from the left
neg >>> 1 = 11111100 (-4)  -- arithmetic shift, replicates the sign bit
PASS

-8 >>> 1 produces -4, which is the mathematically correct result of dividing -8 by 2 and rounding toward negative infinity — the arithmetic shift preserves the value's sign by replicating the original top bit (1) into the vacated position. -8 >> 1 produces 124 — a positive number, because the logical shift fills with 0 regardless of the operand's declared signedness, corrupting the sign entirely.

Common mistakes

  • Using >> on a signed value expecting sign preservation. >> always zero-fills; only >>> replicates the sign bit, and only when the operand is genuinely signed — a plain wire/reg treated as signed only inside a $signed() cast still shifts logically unless the shift itself is >>>.
  • Assuming <<< differs from <<. Arithmetic and logical left shift are identical (both zero-fill from the right); the distinction between arithmetic and logical shifting only matters on the right shift.
  • Shifting by a variable amount without checking its range. A shift count wider than the operand (or negative, if it comes from a signed variable) is legal syntax but produces a result that is easy to reason about incorrectly — keep shift-amount widths deliberately narrow and documented.

Sources and verification

Example provenance: SkillLift Labs authored the example for this tutorial. tests/scripts/tutorial-verified-examples.test.ts extracts the complete marked example from this Markdown file, compiles it in Verilog-2005 mode with Icarus Verilog, runs it, and requires the simulator output to match the Expected output block exactly. The same test also carries an independent, code-owned semantic oracle, and exercises the article-to-runner source-splitting path. Automation verifies those stated properties; human technical review for indexing remains a separate gate.