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.
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.
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.
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.
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.
Bits 0 and 2 are 1, so only rows a << 0 and a << 2 contribute; the other two rows are zero.
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.
A behavioral partial-product accumulator checked against a * b for all 256 operand pairs.
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