Skip to content

Verilog · Chapter 10.7 · Operators & Operands

Shift Operators in Verilog — Logical vs Arithmetic Shift

The shift operators reposition the bits of a value, left or right, by some number of positions. There are four: logical left, logical right, arithmetic left, and arithmetic right. They are among the cheapest operators in Verilog. A shift by a constant amount is free wiring, no gates, just relabeled bits, and a shift is exactly multiply or divide by a power of two, the standard cheap replacement for expensive multiply and divide. Two things separate the four operators and cause most shift bugs. First, the fill that comes in behind the shifted bits: logical shifts fill with zero, while the arithmetic right shift fills with the sign bit to preserve a signed value's sign. Second, the arithmetic right shift only fills the sign bit when the operand is signed. Get the fill wrong and a signed divide-by-two turns a negative number into a large positive. This lesson drills all four operators and these rules.

Foundation18 min readVerilogShift OperatorsBarrel ShifterArithmetic ShiftRTL Design

Chapter 10 · Section 10.7 · Operators & Operands

1. The Engineering Problem

An engineer halves a signed value — divide by two — with a right shift:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
reg signed [7:0] value;          // can be negative
reg signed [7:0] half;
// ...
half = value >> 1;               // intent: half = value / 2

For a positive value it works. For value = −8 (bit pattern 8'b1111_1000), it produces +124, not −4. The `>>` operator is the logical right shift — it fills the vacated high bit with 0, which destroys the sign: 8'b1111_1000 shifted right with a 0 fill becomes 8'b0111_1100 = 124. The sign bit was overwritten, so a negative number became a large positive.

The correct signed halving uses the arithmetic right shift, which fills with the sign bit:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
half = value >>> 1;              // arithmetic right shift, value is signed → fills sign
//                               // 8'b1111_1000 → 8'b1111_1100 = -4  ✓

`>>>` replicates the sign bit into the vacated position, preserving the value's sign — provided the operand is signed (which value is). On an unsigned operand, `>>>` would still fill 0.

Logical shifts fill with zero; the arithmetic right shift fills with the sign bit — but only when the shifted operand is signed. Using the wrong shift on a signed value silently corrupts its sign.

Shifts are cheap and ubiquitous — they scale by powers of two for free — but the logical/arithmetic fill distinction is a sharp edge on signed data. This page teaches the four operators, the fill rule, and the multiply/divide relationship that makes shifts the everyday alternative to * and /.

2. Mental Model — Shifts Reposition Bits; Fill and Amount Define the Hardware

Visual A — a shift repositions bits

Shift repositions bits with a fillb3 b2 b1 b0valueleft 1: b2 b1 b0 0fill 0 low; b3 lostright 1: f b3 b2 b1fill f high (0 or sign)12
A left shift by 1 moves every bit up one position and fills the vacated LSB with 0; bits that move past the MSB of the result width are lost (overflow). A right shift moves bits down and fills the vacated MSB — with 0 (logical) or the sign bit (arithmetic). For a constant shift amount this is pure wiring; no gates are built.

3. The Hardware View — Free Wiring or a Barrel Shifter

The cost of a shift depends entirely on whether the amount is constant or variable:

  • Constant shift amount → free wiring. `x << 2` does not build any gates — it just connects x[i] to output bit i+2 and ties the low two bits to 0. The synthesizer implements it as routing. This is why shifts are the cheapest way to scale by a power of two.
  • Variable shift amount → a barrel shifter. `x << shift` where shift is a signal must handle every possible shift amount, so it builds a barrel shifter: a log-depth tree of multiplexers (shift by 1 or not, by 2 or not, by 4 or not, …). It costs real area and delay — moderate, far less than a multiplier, but not free.

The practical consequence: a constant scale (`<< 2` for ×4) is essentially free, while a runtime-variable shift is a deliberate cost. Knowing which you have written tells you whether you committed wiring or a barrel shifter.

4. The Four Operators

shift-operators.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   x << n      // LOGICAL LEFT     — shift left n, fill low bits with 0
   x >> n      // LOGICAL RIGHT    — shift right n, fill high bits with 0
   x <<< n     // ARITHMETIC LEFT  — same as <<  (fills 0; no sign issue going left)
   x >>> n     // ARITHMETIC RIGHT — shift right n, fill high bits with the SIGN bit
                                  //   (sign fill happens only if x is SIGNED)
  • Logical left (`<<`) and arithmetic left (`<<<`) are identical — both fill the vacated low bits with 0. There is no sign concern when shifting left, so the two left shifts are the same operation.
  • Logical right (`>>`) always fills 0 in the high bits.
  • Arithmetic right (`>>>`) fills the high bits with the sign bit of the operand — if the operand is signed. On an unsigned operand it fills 0, behaving exactly like `>>`.

The only operator where the logical/arithmetic distinction matters is the right shift, and it matters only for signed operands. That single combination — arithmetic right shift of a signed value — is the §1 fix and the whole subtlety of this page.

5. Logical vs Arithmetic — The Fill Rule

The fill is what separates the operators. Side by side on a negative value:

fill-rule.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   reg signed [7:0] v = 8'b1111_1000;   // = -8
 
   v >> 1     // = 8'b0111_1100 = 124   logical: fills 0 → sign DESTROYED
   v >>> 1    // = 8'b1111_1100 = -4    arithmetic: fills sign bit → sign PRESERVED
 
   // but on an UNSIGNED operand, >>> fills 0 like >>:
   reg [7:0] u = 8'b1111_1000;          // = 248 (unsigned)
   u >>> 1    // = 8'b0111_1100 = 124   unsigned operand → >>> fills 0, not sign

The rules to internalize:

  • Left shifts and logical right shifts fill 0. Simple and unconditional.
  • The arithmetic right shift fills the sign bit — but the operand's signedness decides it, not the operator alone. `>>>` on a signed value replicates the sign; `>>>` on an unsigned value fills 0. So a sign-preserving right shift requires both the `>>>` operator and a signed operand.
  • To force it when the operand isn't declared signed, use `$signed(x) >>> n` — this makes the shift see a signed operand and fill the sign.

This is why the §1 bug has two possible fixes that must go together: use `>>>` and ensure the operand is signed. Using `>>` on signed data, or `>>>` on unsigned data, both fill 0 and corrupt a signed divide.

Visual B — logical vs arithmetic right shift

Logical versus arithmetic right shift fill8'b1111_1000 (-8)shift right 1fill 0 → 0111_1100= 124 (sign lost)fill sign → 1111_1100= -4 (correct half)12
Right-shifting the negative value 8'b1111_1000 (-8) by one. The logical right shift fills the vacated MSB with 0, giving 8'b0111_1100 (+124) — the sign is destroyed. The arithmetic right shift fills with the sign bit (1), giving 8'b1111_1100 (-4) — the sign is preserved and the value is correctly halved. The arithmetic fill happens only when the operand is signed.

6. Shift as Multiply and Divide by Powers of Two

The reason shifts appear everywhere in datapaths: they are free power-of-two scaling, the cheap stand-in for * and / (10.2):

shift-as-scale.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   x << 3      // = x * 8     (multiply by 2^3)   — free wiring
   x >> 2      // = x / 4     (unsigned divide by 2^2)
   $signed(x) >>> 1   // = signed divide by 2     (sign-preserving)

Two cautions:

  • Left-shift multiply can overflow — shifting bits past the destination width loses them (§7). `x << 3` needs three more bits of result width than x to hold the full product, exactly like a multiply.
  • Arithmetic-right-shift divide rounds toward negative infinity, not toward zero — and this differs from the `/` operator. `/` truncates toward zero (−7 / 2 = −3), but `$signed(−7) >>> 1` floors toward negative infinity (= −4). For positive values they agree; for negatives they differ by one. So `>>>` is a floor divide, not the same rounding as `/`. Choose deliberately when negative values matter.

The discipline from 10.2 carries here: prefer a shift over a multiply/divide for power-of-two scaling (it is free vs a large block), but mind the overflow on left shifts and the rounding direction on signed right shifts.

7. Width and Left-Shift Overflow

A left shift moves bits toward the MSB, and any bit pushed past the result width is lost — the same overflow behaviour as arithmetic (10.2):

shift-overflow.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   reg [7:0] x = 8'h20;          // = 32
 
   reg [7:0] narrow = x << 3;    // 32 * 8 = 256, but [7:0] holds 0..255
                                 // → 8'h00 (the set bit shifted out) — overflow!
   reg [10:0] wide  = x << 3;    // context = 11 bits → 256 fits → correct

To keep the full result of a left shift, the destination must be wide enough — `x << n` can need up to n more bits than x. As with arithmetic, Verilog evaluates the shift in the destination's context width, so a too-narrow destination silently drops the high bits. Size the result, or accept the truncation deliberately. (Right shifts don't overflow the high end, but they discard the low bits shifted out — that is the divide.)

8. Worked Examples

8.1 Example 1 — multiply by a constant via left shift

scale-up.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   // y = x * 10, built from shifts and an add (10 = 8 + 2):
   assign y = (x << 3) + (x << 1);     // x*8 + x*2 = x*10  — no multiplier

A multiply by a constant decomposes into shifts and adds — `x << 3` (×8) plus `x << 1` (×2) gives ×10 — replacing an expensive multiplier with free wiring and one adder. This shift-and-add pattern is how synthesizers (and hand-optimized RTL) implement constant multiplication cheaply. (Size y to hold the product, per §7.)

8.2 Example 2 — signed divide by a power of two

signed-halve.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module halve (
    input  signed [9:0] value,
    output signed [9:0] half
);
    assign half = value >>> 1;          // arithmetic right shift, value is signed
endmodule

Because value is signed and the operator is `>>>`, the sign bit is replicated and a negative value is correctly halved (floor division). This is the §1 fix done right — both conditions met. Swap to `>>`, or make value unsigned, and negatives break.

8.3 Example 3 — a variable shift (barrel shifter)

barrel.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module shifter (
    input  [31:0] data,
    input  [4:0]  amt,                  // variable shift amount 0..31
    output [31:0] result
);
    assign result = data << amt;        // variable amount → barrel shifter
endmodule

Because amt is a signal, this builds a 32-bit barrel shifter — a mux tree that can shift by any amount 0–31. It is real hardware (moderate area/delay), unlike the free constant shifts above. Variable shifts are common (normalizers, aligners, ALUs) but are a deliberate cost, not free wiring.

9. Industry Perspective

  • Constant shifts are the free power-of-two scaler. Address calculation (`index << 2` for word offsets), fixed-point scaling, and constant multiplies (shift-and-add) all use constant shifts — chosen precisely because they cost no gates, unlike * and /.
  • Barrel shifters are core datapath blocks. Normalizers (floating-point), data aligners, rotate units, and ALU shift instructions are variable barrel shifters — a recognized, moderately-costed structure that engineers budget for.
  • Signed arithmetic-shift discipline prevents DSP bugs. Fixed-point and DSP code relies on `>>>` with signed operands for sign-preserving scaling; using `>>` on signed data (or `>>>` on unsigned) is a classic silent defect. Teams use `$signed(...)` explicitly where signedness must be forced.
  • The floor-vs-truncate rounding difference matters in DSP. That `>>>` floors toward negative infinity while `/` truncates toward zero is a real numerical distinction in signal processing, accounted for deliberately.

10. Common Mistakes

  1. `>>` on a signed value — logical right shift fills 0 and corrupts the sign; use `>>>` (§1/§5, DebugLab 1).
  2. `>>>` on an unsigned operand — still fills 0; the sign fill needs a signed operand (§5, DebugLab 2).
  3. Left-shift overflow — bits shifted past the destination width are lost; size the result (§7, DebugLab 3).
  4. Forgetting variable shifts cost a barrel shifter — treating `x << amt` (signal amt) as free like a constant shift (§3).
  5. Assuming `>>>` divide rounds like `/``>>>` floors toward −∞; `/` truncates toward 0 (§6).

11. Debugging Lab

Three shift-operator debug post-mortems

12. Interview Q&A

13. Exercises

Exercise 1 — Predict the shifts

For x = 8'b1010_0110, give each result: (a) x << 2; (b) x >> 2; (c) x >>> 2 when x is unsigned; (d) x >>> 2 when x is signed.

Exercise 2 — Build constant scales

Using only shifts and adds (no *), write expressions for: (a) x * 4; (b) x * 5; (c) x * 16; (d) x / 8 for unsigned x.

Exercise 3 — Fix the signed divide

Each line intends a sign-preserving divide-by-two of a value that can be negative. Identify the bug and fix it.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
y = sval >> 1;                 // sval is signed
y = uval >>> 1;                // uval is unsigned but holds a signed quantity

Exercise 4 — Reason about rounding and overflow

(a) For value = -7 (signed), what is value >>> 1, and how does it differ from value / 2? (b) For x = 8'hC0 in an 8-bit destination, what is x << 2 and why? What destination width is needed to keep the full value?

14. Summary

The shift operators — logical left, logical right, arithmetic left, arithmetic right — reposition a value's bits, cheaply: a constant shift is free wiring, and a shift is multiply or divide by a power of two.

The core ideas:

  • Shifts reposition bits with a fill. Left shifts and logical right shifts fill 0; the arithmetic right shift fills the sign bitonly when the operand is signed.
  • The left shifts are identical (both fill 0); the logical/arithmetic distinction matters only for the right shift on signed operands.
  • Constant shift = free wiring; variable shift = barrel shifter (a mux tree, moderate cost).
  • Shift is power-of-two multiply/divide — the cheap stand-in for * and /; mind left-shift overflow (size the result) and the floor-toward-−∞ rounding of arithmetic right shift (differs from /'s toward-zero).

The discipline this page instils:

  • For a sign-preserving right shift, use `>>>` AND a signed operand (or `$signed(x) >>> n`); `>>` on signed data, or `>>>` on unsigned data, both corrupt the sign.
  • Size the destination of a left shift to hold the multiplied value, or truncate deliberately.
  • Use constant shifts freely for power-of-two scaling; budget variable shifts as barrel shifters.

You can now reposition and scale bits correctly. The chapter turns next from ordering and moving to sameness: Chapter 10.8 Equality Operator drills ==, !=, ===, !== — the equality comparators — including the simulation-only case-equality (===) that compares x and z bits exactly and must not appear in synthesizable RTL.

  • Arithmetic Operators — Chapter 10.2; the expensive * and / that constant shifts cheaply replace.
  • Relational Operators — Chapter 10.6; the previous operator family and the same signedness theme.
  • integer — Chapter 5.2.2; the signed type whose sign the arithmetic right shift preserves.
  • Operator Precedence — Chapter 10.1; shifts bind looser than arithmetic and tighter than relational.