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

  • RTL Foundations36
  • Combinational Design25
    • Combinational Timing Overview
    • Muxes, Decoders and Encoders
    • Arithmetic Blocks
      • Adder Building Blocks
      • Ripple Carry and Carry Lookahead
      • Shift-Add Multiplier
      • Wallace-Tree Multiplier Intuition
    • Comparators and Shifters
    • Tri-State and Shared Buses
    • Latch Inference
    • Arithmetic Datapaths
  • Sequential Design27
  • FSM & Control27
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Arithmetic Blocks
  1. Topics
  2. RTL Design
  3. Combinational Design
  4. Arithmetic Blocks
  5. Shift-Add Multiplier

Part 2 · Combinational · Intermediate

Shift-Add Multiplier

Multiplication as shifted copies of one operand, summed: a combinational partial-product accumulator checked on all 256 pairs.

On this page

    Why this matters

    A multiplier is a stack of shifted partial products, and the simplest loop chains N carry-propagate adds one after another. That is small, but its delay grows with N.

    After this lesson you can: form the partial products of a multiply, compare array, sequential and tree styles, and explain why signed multiply is not the unsigned circuit.

    Multiplication is shifted addition

    Multiply 6 (0110) by 5 (0101) the way you did on paper in binary: for each bit of the multiplier, write the multiplicand shifted into position if the bit is 1 (a partial product), then add them.

    6 x 5 as a partial-product array. Each multiplier bit selects either a shifted copy of a or a row of zeros; the column sums give p = 0001 1110 = 30.

    Read each row as one multiplier bit. The row starts in the column of its bit, so row i is shifted left by i.

    • Rows 0 and 2: b0 and b2 are 1, so those rows copy a: 6 and 6 x 4 = 24.

    • Rows 1 and 3: b1 and b3 are 0, so those rows are zero and add nothing.

    • Sum: 6 + 24 = 30, which needs 5 of the 8 product bits.

    Hardware does exactly this. An N×N multiplier has N partial products, each an AND of one multiplier bit with the whole multiplicand, shifted. The 2N-bit product is their sum.

    The for loop below is a behavioral combinational partial-product accumulator: it unrolls into N conditional carry-propagate additions chained one after another.

    It is small and regular, but each addition waits for the previous one. That serial chain differs from carry-save array reduction, which postpones carries. Conceptual delay grows with N; actual mapped depth depends on the target, library and constraints.

    Three ways to implement the same multiply

    Style

    Area tendency

    Delay / latency contract

    When

    Sequential shift-add (one reused adder)

    Often smaller

    About N adder iterations, plus interface overhead

    Slow, rare multiplies; see the multi-cycle sequencer

    Behavioral partial-product accumulator (this lesson)

    N conditional additions before optimization

    Unclocked combinational delay through dependent additions; no cycle latency specified

    Small widths, simple designs

    Tree multiplier (Wallace/Dadda)

    Parallel compressors plus final adder; target-dependent cost

    Unclocked: logarithmic compression depth plus final carry-propagate delay; registers define cycle latency

    High clock rate, wide operands

    A sequential version reuses one adder over W cycles; see the multi-cycle sequencer for its exact cycle contract. The bare mult_array below has no registers and no clock, so it promises no cycle count: its product is valid once the logic settles.

    Common mistakes

    Common pitfall

    Signed multiplication is not just the unsigned circuit on two's complement bits. The partial product for the sign bit has negative weight, so signed multipliers use sign-extension tricks or the Baugh-Wooley form. In RTL, declare both operands signed and use *; let the tool handle it.

    Likely question: “How does a multiplier work, and how would you make it faster?”

    • Work by summing N shifted partial products, one per multiplier bit.

    • This lesson chains N serial carry-propagate additions: small, but conceptual delay grows with N.

    • Faster with a tree that sums rows in log depth, covered next lesson.

    Check yourself How wide is the product of an 8-bit by a 12-bit unsigned multiplication, and how many partial products are there?

    The product is 8 + 12 = 20 bits. The number of partial products equals the number of bits in the multiplier operand: 12 if you iterate over the 12-bit operand (8 if you swap roles). Choosing the narrower operand as the multiplier gives fewer partial products.

    Check yourself Multiplier b = 4'b0101. Predict which partial products are nonzero before checking the code.

    Bits 0 and 2 are 1, so only rows a << 0 and a << 2 contribute; the other two rows are zero.

    Check yourself A 4-bit behavioral multiplier misses timing but a sequential one would fit. Predict what changes.

    The sequential implementation reuses one adder and adds operand, accumulator and control registers. It needs four arithmetic iterations plus the specified load/report protocol; the later sequencer counts five cycles including load. It can no longer accept arbitrary operand changes while busy. Compare actual area and timing reports before claiming a saving.

    Testbench

    A behavioral partial-product accumulator checked against a * b for all 256 operand pairs.

    mult_array.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
    29
    30
    31
    32
    33
    34
    module mult_array #(parameter int N = 4) (
      input  logic [N-1:0]   a,           // multiplicand
      input  logic [N-1:0]   b,           // multiplier
      output logic [2*N-1:0] p
    );
      always_comb begin
        p = '0;
        for (int i = 0; i < N; i++)
          if (b[i]) p = p + ({{N{1'b0}}, a} << i);     // add the shifted partial product
      end
    endmodule
    
    module tb_mult_array;
      timeunit 1ns; timeprecision 1ps;
      localparam int N = 4;
      logic [N-1:0] a, b;
      logic [2*N-1:0] p;
      mult_array #(N) dut (.*);
      int errors = 0;
      logic [2*N-1:0] expected;
      initial begin
        for (int i = 0; i < (1 << (2*N)); i++) begin            // all 256 operand pairs
          {a, b} = i[2*N-1:0]; #1;
          expected = a * b;                            // full 2N-bit reference product
          if (p !== expected) begin
            errors++;
            $display("FAIL mult_array: a=%0d b=%0d expected=%h actual=%h", a, b, expected, p);
          end
        end
        if (errors != 0) $fatal(1, "FAIL mult_array: %0d mismatching pairs", errors);
        if (errors == 0) $display("PASS: combinational partial-product accumulator equals a * b for all 256 operand pairs");
        $finish;
      end
    endmodule

    Remember

    • An N x N multiply has N partial products and a 2N-bit result.

    • The bare loop is combinational and promises no cycle count. A sequential version reuses one adder over W cycles.

    • Signed operands need sign-extension tricks or Baugh-Wooley, because the sign bit has negative weight.

    Keep going

    • Practice: An iterative shift-and-add multiplier

    • Interview: run a mock interview on this topic

    Related topics

    • Wallace-tree multiplier intuition

    Previous

    46 / 350

    Next: Wallace-Tree Multiplier Intuition

    Up next

    Up nextWallace-Tree Multiplier Intuition

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Adder Building Blocks