Booth Multiplier Verilog Code: Signed Radix-2 Multiplier

Booth’s algorithm multiplies two signed numbers directly in two’s-complement form, without first converting the operands to sign-magnitude. The radix-2 version scans the multiplier one bit at a time, paired with the bit to its right, and on each step decides whether to add the multiplicand, subtract it, or do nothing, then shifts the running partial product one place to the right. Because it keeps everything in two’s complement and handles runs of identical bits cleanly, it is the classic way to describe a signed hardware multiplier.

In this tutorial you build a parameterized radix-2 Booth multiplier in synthesizable Verilog-2005, drive it with a self-checking testbench, and run both through Icarus Verilog. We begin with a sequential add-shift version that produces an N×N signed product in N clocks, then show a compact combinational variant and verify it exhaustively. Radix-2 keeps the datapath simple — at most one add or subtract per multiplier bit — and is the clearest form to learn before moving to higher-radix encodings that fold several bits into each step. Every example below compiles and runs with iverilog -g2005 -o sim booth_mult.v && vvp sim.

Booth multiplier Verilog code

The module keeps the textbook three-register state — an accumulator A, the multiplier Q, and a one-bit history register Q_1 — packed into a single shift register. A start pulse latches the operands and the engine raises done for one cycle when the product is ready. A synchronous rst clears the state, and an internal busy flag ignores new start pulses until the current multiply finishes, so the handshake is safe to wire straight into a larger datapath. The WIDTH parameter sets the operand size, and the result is 2*WIDTH bits wide.

// booth_mult.v  --  Sequential radix-2 Booth multiplier (parameterized, signed)
module booth_mult #(parameter WIDTH = 4) (
    input  wire                      clk,
    input  wire                      rst,    // synchronous, active-high
    input  wire                      start,  // pulse high to begin a multiply
    input  wire signed [WIDTH-1:0]   a,      // multiplicand
    input  wire signed [WIDTH-1:0]   b,      // multiplier
    output reg  signed [2*WIDTH-1:0] p,      // signed product (valid when done=1)
    output reg                       done    // 1-cycle completion strobe
);
    localparam CW = $clog2(WIDTH) + 1;

    reg signed [2*WIDTH+1:0] acc;    // {A[WIDTH+1], Q[WIDTH], Q_1[1]}
    reg signed [2*WIDTH+1:0] nxt;    // next-state (blocking temp)
    reg signed [WIDTH:0]     m_ext;  // multiplicand, sign-extended by 1 bit
    reg        [CW-1:0]      count;
    reg                      busy;

    always @(posedge clk) begin
        if (rst) begin
            busy <= 1'b0;
            done <= 1'b0;
            p    <= {(2*WIDTH){1'b0}};
        end else begin
            done <= 1'b0;
            if (start && !busy) begin
                acc   <= {{(WIDTH+1){1'b0}}, b, 1'b0};   // A=0, Q=b, Q_1=0
                m_ext <= {a[WIDTH-1], a};                // sign-extend multiplicand
                count <= WIDTH[CW-1:0];
                busy  <= 1'b1;
            end else if (busy) begin
                nxt = acc;                               // start from current state
                case (acc[1:0])                          // Booth bits = {Q[0], Q_1}
                    2'b01: nxt[2*WIDTH+1:WIDTH+1] = acc[2*WIDTH+1:WIDTH+1] + m_ext;
                    2'b10: nxt[2*WIDTH+1:WIDTH+1] = acc[2*WIDTH+1:WIDTH+1] - m_ext;
                    default: ;                           // 00 / 11: no add/sub
                endcase
                nxt   = nxt >>> 1;                       // arithmetic right shift
                acc   <= nxt;
                count <= count - 1'b1;
                if (count == 1) begin
                    busy <= 1'b0;
                    done <= 1'b1;
                    p    <= nxt[2*WIDTH:1];              // {A,Q} low 2*WIDTH bits
                end
            end
        end
    end
endmodule

// -------- testbench: drive signed cases through the handshake --------
module tb_booth_mult;
    localparam WIDTH = 4;
    reg clk, rst, start;
    reg  signed [WIDTH-1:0]   a, b;
    wire signed [2*WIDTH-1:0] p;
    wire done;

    booth_mult #(.WIDTH(WIDTH)) dut (
        .clk(clk), .rst(rst), .start(start),
        .a(a), .b(b), .p(p), .done(done));

    always #1 clk = ~clk;                // 2 ns period

    reg signed [2*WIDTH-1:0] exp;
    task multiply(input signed [WIDTH-1:0] ai, input signed [WIDTH-1:0] bi);
        begin
            @(negedge clk); a = ai; b = bi; start = 1'b1;
            @(negedge clk); start = 1'b0;
            wait (done == 1'b1);
            @(negedge clk);
            exp = ai * bi;                   // widen in assignment context
            $display("%0d * %0d = %0d  (expected %0d)  %s",
                     ai, bi, p, exp, (p === exp) ? "OK" : "BAD");
        end
    endtask

    initial begin
        clk = 0; rst = 1; start = 0; a = 0; b = 0;
        @(negedge clk); rst = 0;
        multiply( 3,  5);
        multiply(-3,  5);
        multiply( 7, -2);
        multiply(-4, -6);
        multiply(-8,  7);    // most-negative multiplicand
        multiply(-8, -8);    // both most-negative
        $display("done.");
        $finish;
    end
endmodule
3 * 5 = 15  (expected 15)   OK
-3 * 5 = -15  (expected -15)   OK
7 * -2 = -14  (expected -14)   OK
-4 * -6 = 24  (expected 24)   OK
-8 * 7 = -56  (expected -56)   OK
-8 * -8 = 64  (expected 64)   OK
done.
/var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmpbgq6fkad/booth_mult.v:88: $finish called at 74 (1s)

How the radix-2 Booth algorithm works

Picture the multiplier Q with an imaginary zero appended to its right; that extra bit is Q_1. On each of WIDTH steps the hardware inspects the pair {Q[0], Q_1} and takes one of three actions before an arithmetic right shift of the whole {A, Q, Q_1} register:

Q[i]Q[i-1]MeaningAction
00inside a run of 0sshift only
01end of a run of 1sA = A + M, then shift
10start of a run of 1sA = A – M, then shift
11inside a run of 1sshift only

A plain shift-and-add multiplier would need separate handling for the sign bit; Booth recoding removes that special case because subtracting at the start of a run and adding at its end reproduces the two’s-complement value automatically. The decision reduces to a single case statement on the two Booth bits:

case ({Q[i], Q[i-1]})   // current bit, bit to its right
    2'b01:  acc = acc + M;   // end of a run of 1s  -> add
    2'b10:  acc = acc - M;   // start of a run of 1s -> subtract
    default: ;               // 00 or 11            -> just shift
endcase

Two details make the result correct for all signed inputs. First, the right shift must be arithmetic (>>> on a signed value) so the sign of the partial product is preserved on every step. Second, the accumulator field A is made one bit wider than the operands, and the multiplicand is sign-extended into it with {a[WIDTH-1], a}. That extra bit matters: when the multiplicand is the most-negative value (for example -8 at WIDTH=4), the step A - M needs +8, which does not fit in four signed bits. The widened field absorbs that carry so edge cases such as -8 × -8 still come out right.

A combinational variant, checked exhaustively

The same arithmetic unrolls into a single always @(*) loop for a purely combinational multiplier. It is handy for small widths and for proving the recoding is correct. The testbench below sweeps every one of the 256 signed operand pairs at WIDTH=4 and compares against Verilog’s native signed * operator.

// booth_comb.v  --  Combinational radix-2 Booth multiplier (parameterized, signed)
module booth_comb #(parameter WIDTH = 4) (
    input  wire signed [WIDTH-1:0]   a,   // multiplicand
    input  wire signed [WIDTH-1:0]   b,   // multiplier
    output wire signed [2*WIDTH-1:0] p    // signed product
);
    integer i;
    reg signed [2*WIDTH+1:0] acc;         // {A[WIDTH+1], Q[WIDTH], Q_1[1]}
    reg signed [WIDTH:0]     m_ext;       // multiplicand, sign-extended by 1 bit

    always @(*) begin
        m_ext = {a[WIDTH-1], a};
        acc   = {{(WIDTH+1){1'b0}}, b, 1'b0};   // A=0, Q=b, Q_1=0
        for (i = 0; i < WIDTH; i = i + 1) begin
            case (acc[1:0])                      // Booth bits = {Q[0], Q_1}
                2'b01: acc[2*WIDTH+1:WIDTH+1] = acc[2*WIDTH+1:WIDTH+1] + m_ext;
                2'b10: acc[2*WIDTH+1:WIDTH+1] = acc[2*WIDTH+1:WIDTH+1] - m_ext;
                default: ;                       // 00 / 11: skip
            endcase
            acc = acc >>> 1;                     // arithmetic right shift
        end
    end

    assign p = acc[2*WIDTH:1];                   // drop Q_1 + spare sign bit
endmodule

// -------- testbench: exhaustive signed check for WIDTH=4 --------
module tb_booth_comb;
    localparam WIDTH = 4;
    reg  signed [WIDTH-1:0]   a, b;
    wire signed [2*WIDTH-1:0] p;
    reg  signed [2*WIDTH-1:0] exp;
    integer i, j, errors;

    booth_comb #(.WIDTH(WIDTH)) dut (.a(a), .b(b), .p(p));

    initial begin
        errors = 0;
        for (i = 0; i < (1<<WIDTH); i = i + 1)
            for (j = 0; j < (1<<WIDTH); j = j + 1) begin
                a = i[WIDTH-1:0];
                b = j[WIDTH-1:0];
                #1;
                exp = a * b;
                if (p !== exp) begin
                    errors = errors + 1;
                    $display("MISMATCH %0d * %0d = %0d (expected %0d)", a, b, p, exp);
                end
            end
        // spot-check a few edge cases on screen
        a = -8; b = -8; #1; $display("-8 * -8 = %0d", p);
        a = -8; b =  7; #1; $display("-8 *  7 = %0d", p);
        a =  5; b = -3; #1; $display(" 5 * -3 = %0d", p);
        if (errors == 0)
            $display("PASS: all 256 signed products correct");
        else
            $display("FAIL: %0d mismatches", errors);
        $finish;
    end
endmodule
-8 * -8 = 64
-8 *  7 = -56
 5 * -3 = -15
PASS: all 256 signed products correct
/var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmpzntjblmk/booth_comb.v:58: $finish called at 259 (1s)

Notice how the testbench widens the expected value: exp = a * b; is evaluated in the 2*WIDTH-bit assignment context, whereas writing a*b straight into $display would truncate it to WIDTH bits and print nonsense.

Common mistakes

  • Using a logical shift. >> fills with zeros and corrupts negative partial products. You need the arithmetic >>> on a signed register.
  • Forgetting the Q_1 bit. The algorithm compares each multiplier bit with the one to its right; dropping the appended zero breaks the very first step.
  • Too narrow an accumulator. Without the extra sign bit on A, the most-negative multiplicand overflows during A - M and the product is wrong only for that corner case.
  • Truncating the expected product in the testbench. A self-determined a*b is only WIDTH bits wide; assign it to a 2*WIDTH-bit signed variable before comparing.
  • Reading the product one cycle too early. Latch p on the final shift and sample it only when done is high.

Quick check

Why must the partial-product shift be arithmetic rather than logical?

An arithmetic right shift replicates the sign bit, preserving the value of a negative partial product. A logical shift inserts zeros, which would turn negative intermediate sums into large positive numbers and give a wrong signed result.

What do the two Booth bits {Q[0], Q_1} = 10 tell the hardware to do?

They mark the start of a run of 1s, so the step subtracts the multiplicand (A = A – M) and then shifts. The pattern 01 marks the end of a run and adds instead.

Why is the accumulator field one bit wider than the operands?

So that subtracting the most-negative multiplicand (whose negation overflows the operand width) still fits. The extra sign bit captures the carry and keeps corner cases like -8 × -8 correct.

How many clock cycles does the sequential version take for an N-bit operand?

N iteration cycles, one Booth step per multiplier bit, plus the cycle that latches the operands on start. The combinational variant computes the same result in a single evaluation with no clock.

Have questions about this topic?
Share your question in comments or talk to our mentor team for batch guidance.
▶ Try it in the ChipXpert Lab

Open this design in the free in-browser simulator — edit, compile and see the waveform/log instantly.

Run it in the Lab

Learn Verilog with mentors, labs and placement support

This free series is maintained by the ChipXpert training team in Hyderabad & Bengaluru. Go deeper with instructor-led courses on real EDA tools.

Explore VLSI Courses
Next batch starts 18th November 2026
Start your VLSI career with ChipXpert

Live online and classroom batches in Hyderabad & Bengaluru. Fill in your details and a counsellor will call you back.

  • Real EDA tools in your browser: industry-standard EDAReal EDA tools in your browser
  • Recorded sessions on the elearn portalRecorded sessions
  • Placement assistance: resume, mock interviewsPlacement assistance
  • Merit scholarship up to 60% · EMI optionsScholarship up to 60%
Hi! Ask me about courses, fees, batches or discounts. ×
BENGALURU
HYDERABAD