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] | Meaning | Action |
|---|---|---|---|
| 0 | 0 | inside a run of 0s | shift only |
| 0 | 1 | end of a run of 1s | A = A + M, then shift |
| 1 | 0 | start of a run of 1s | A = A – M, then shift |
| 1 | 1 | inside a run of 1s | shift 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
endcaseTwo 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 asignedregister. - Forgetting the
Q_1bit. 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 duringA - Mand the product is wrong only for that corner case. - Truncating the expected product in the testbench. A self-determined
a*bis onlyWIDTHbits wide; assign it to a2*WIDTH-bit signed variable before comparing. - Reading the product one cycle too early. Latch
pon the final shift and sample it only whendoneis 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.
Share your question in comments or talk to our mentor team for batch guidance.
Open this design in the free in-browser simulator — edit, compile and see the waveform/log instantly.
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