In a ripple-carry adder the sum bit at position i cannot be final until the carry from position i−1 arrives, which depends on position i−2, and so on. The longest path runs through every carry stage, so the delay grows linearly with N: a 64-bit ripple adder is about 16× slower than a 4-bit one.
The waveform source deliberately delays each carry assignment by 1 ns (1ns/1ps timescale). Its separate 1 ns sampling clock does not clock the adder. Inputs 15 + 1 are applied at t = 4 ns, after initialization settles; slots 1 to 5 sample at 4.5, 5.5, 6.5, 7.5 and 8.5 ns. Watch c1 to c4 rise one model unit apart (c4 is the final carry out).
Slot 1 (4.5 ns): new operands are present, but every carry is still 0.
Slot 2 (5.5 ns): stage 0 generated c1 = 1 at 5 ns.
Slot 3 (6.5 ns): c2 rose at 6 ns as the carry propagated.
Slot 4 (7.5 ns): c3 rose at 7 ns; the last stage still waits.
Slot 5 (8.5 ns): c4 rose at 8 ns, 4 ns after the operands changed.
These four combinational stages do not imply four cycles of latency. The 1 ns stage delays are chosen teaching values, not library measurements; the functional lookahead test below has no propagation delays. Mapped timing needs the target library, loads, routing and timing constraints.
This standalone simulation model checks the same carry trace halfway between updates, including the final sum. Delays belong only in this teaching model, not synthesizable arithmetic RTL.
module fa_delay_model (
input wire a, b, cin,
output wire sum, cout
);
timeunit 1ns; timeprecision 1ps;
assign sum = a ^ b ^ cin;
assign #1 cout = (a & b) | (cin & (a ^ b));
endmodule
The last carry waits for every earlier one. That wait is the delay lookahead removes.
Each bit position either generates a carry on its own or propagates an incoming one:
Substituting repeatedly removes the dependence on the previous carry, so every carry becomes a direct function of the inputs and the first carry-in:
A prefix network combines adjacent generate/propagate pairs. For a high group H and a low group L, the combined group generates when H generates, or when H propagates a carry generated by L. It propagates only when both groups propagate. Here + means OR and multiplication means AND, not integer addition.
Other prefix nodes produce c1, c2 and c3; each sum is p_i XOR c_i. The diagram separates group construction from carry evaluation, so two combine levels must not be mistaken for the whole adder's gate delay.
Read the bits from least significant to most significant; carry-in c0 = 0.
Bit i | a_i, b_i | g_i | p_i | c_i -> c_i+1 | Sum |
|---|---|---|---|---|---|
0 | 1, 1 | 1 | 0 | 0 -> 1 | 0 |
1 | 1, 0 | 0 | 1 | 1 -> 1 | 0 |
2 | 0, 1 | 0 | 1 | 1 -> 1 | 0 |
3 | 1, 0 | 0 | 1 | 1 -> 1 | 0 |
Bit 0 generates the carry and all higher bits propagate it. Group 1:0 is (G,P) = (1,0); group 3:2 is (0,1). Combining them gives (1,0), so c4 = 1 even with c0 = 0. The result is 1_0000 (11 + 5 = 16). Ripple discovers the same carries in sequence; the group network evaluates the dependencies in a tree.
g2=0 and p2=0, so bit 2 kills the incoming carry: c3=0. Propagation requires p=1; an earlier generate cannot cross a kill bit.
Width | Ripple carry (≈ levels) | Lookahead / prefix (≈ levels) |
|---|---|---|
4 | ≈ 8 | ≈ 3 |
8 | ≈ 16 | ≈ 4 |
16 | ≈ 32 | ≈ 5 |
32 | ≈ 64 | ≈ 6 |
64 | ≈ 128 | ≈ 7 |
The level counts are first-order estimates: about two gate levels per ripple stage, and roughly log₂ N plus a constant for a prefix adder. Real values depend on the library; the trend is linear versus logarithmic.
Lookahead logic grows in size quickly with width, so large adders use hierarchical lookahead or prefix structures (Kogge-Stone, Brent-Kung, Sklansky) that balance depth against area and wiring.
You almost never write these by hand. Write a + b; many tools can map it to a faster adder when the constraint rewards it, depending on the target and library. On an FPGA this can use dedicated carry resources rather than a prefix network.
Knowing the structure helps you read timing reports (long carry paths) and answer interview questions.
Two more options sit between ripple and lookahead: a carry-skip adder skips a block carry when every propagate bit in the block is 1, and a carry-select adder builds each block twice and picks with a mux when the real carry arrives.
Both use more area to shorten the worst path. Lookahead and prefix adders go further but need more wiring.
Likely questions: “Why is a ripple-carry adder slow, and how would you build a fast N-bit adder?”
Slow because the carry ripples through every stage: delay grows linearly with N.
Fast with lookahead or prefix logic: every carry from generate/propagate, depth near log N.
In practice you write a + b and constrain it; the tool picks the architecture.
g₁: position 1 generates a carry by itself. p₁g₀: position 0 generates a carry and position 1 propagates it. p₁p₀c₀: the carry-in is propagated through both positions.
g₀ = 0 (no generate without two ones), p₀ = 1, so c₁ = 0 + 1·1 = 1. The carry-in propagates through.
After checking the requirement, the constraint and the failing report, try a tighter constraint as an experiment and compare timing and area; synthesis may map a lookahead or prefix adder, or dedicated carry resources on an FPGA, but no swap is guaranteed. No RTL rewrite is needed first.
Do | Avoid |
|---|---|
Write | Hand-writing a wide flat lookahead block by hand |
Read a long carry path in a timing report as one chain | Treating each slow sum bit as its own separate problem |
A 4-bit lookahead adder proved against a + b + cin for all 512 inputs.
module cla4 (
input logic [3:0] a, b,
input logic cin,
output logic [3:0] sum,
output logic cout
);
logic [3:0] g, p;
logic [4:0] c;
always_comb begin
g = a & b;
p = a ^ b;
c[0] = cin;
c[1] = g[0] | (p[0] & c[0]);
c[2] = g[1] | (p[1] & g[0]) | (p[1] & p[0] & c[0]);
c[3] = g[2] | (p[2] & g[1]) | (p[2] & p[1] & g[0]) | (p[2] & p[1] & p[0] & c[0]);
c[4] = g[3] | (p[3] & g[2]) | (p[3] & p[2] & g[1]) | (p[3] & p[2] & p[1] & g[0])
| (p[3] & p[2] & p[1] & p[0] & c[0]);
sum = p ^ c[3:0];
cout = c[4];
end
endmodule
module tb_cla4;
timeunit 1ns; timeprecision 1ps;
logic [3:0] a, b, sum;
logic cin, cout;
cla4 dut (.*);
int errors = 0;
logic [4:0] ref_sum;
initial begin
for (int i = 0; i < 512; i++) begin // every a, b and cin
{cin, a, b} = i[8:0]; #1;
ref_sum = {1'b0, a} + {1'b0, b} + {4'b0, cin};
if ({cout, sum} !== ref_sum) begin
errors++;
$display("FAIL cla4: a=%h b=%h cin=%b expected=%b actual=%b",
a, b, cin, ref_sum, {cout, sum});
end
end
if (errors != 0) $fatal(1, "FAIL cla4: %0d mismatching cases", errors);
if (errors == 0) $display("PASS: 4-bit carry-lookahead adder equals a + b + cin for all 512 inputs");
$finish;
end
endmodule