The short answer: a half adder adds two bits and gives a sum (A XOR B) and a carry (A AND B). A full adder adds three bits, including a carry in, giving S = A XOR B XOR Cin and Cout = A·B + Cin·(A XOR B). Chain N full adders and you get a ripple-carry adder; compute the carries in parallel and you get a much faster carry-lookahead adder. Subtraction is just addition of the two’s complement: A − B = A + B’ + 1.
Adders are the most important arithmetic block in any processor, and a favourite interview topic. This post combines my older posts on adders and subtractors.
- From half adder to fast adders
- Half and full adder truth tables
- Ripple-carry vs carry-lookahead
- Subtractors and two’s complement
- Adders in Verilog
Table of Contents
Part 1: From half adder to fast adders

Part 2: Half and full adder truth tables
| A | B | Cin | Sum | Cout |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 1 | 0 |
| 0 | 1 | 0 | 1 | 0 |
| 0 | 1 | 1 | 0 | 1 |
| 1 | 0 | 0 | 1 | 0 |
| 1 | 0 | 1 | 0 | 1 |
| 1 | 1 | 0 | 0 | 1 |
| 1 | 1 | 1 | 1 | 1 |
A half adder is the top half of this table with Cin = 0.
Part 3: Ripple-carry vs carry-lookahead
A ripple-carry adder chains full adders, so each carry waits for the one before it. Delay grows linearly with the width, which is too slow for wide adders at high clock speeds.
A carry-lookahead adder computes, for each bit, generate G = A·B and propagate P = A XOR B, then calculates carries directly: C1 = G0 + P0·C0, C2 = G1 + P1·G0 + P1·P0·C0, and so on. Grouped into blocks, this makes the delay grow roughly logarithmically. Other fast designs include carry-select and parallel-prefix adders such as Kogge-Stone.
Part 4: Subtractors and two’s complement
A half subtractor gives difference A XOR B and borrow A’·B; a full subtractor adds a borrow in. In practice, chips subtract with an adder: invert B, set the carry in to 1, and add. That is why an ALU can add and subtract with the same hardware.
Part 5: Adders in Verilog
// Full adder
module full_adder (
input wire a, b, cin,
output wire sum, cout
);
assign sum = a ^ b ^ cin;
assign cout = (a & b) | (cin & (a ^ b));
endmodule
// N-bit adder/subtractor: let synthesis choose the architecture
module addsub #(parameter N = 8) (
input wire [N-1:0] a, b,
input wire sub, // 0 = add, 1 = subtract
output wire [N-1:0] y,
output wire cout
);
assign {cout, y} = a + (sub ? ~b : b) + sub;
endmodule
In real RTL, write the behaviour with + and -. Synthesis picks a ripple, lookahead or prefix adder depending on your timing constraints.
Practise this on VLSI Forge
I built VLSI Forge so you can write RTL in your browser, run it on a real simulator and check every signal in the waveform. Free, nothing to install.
FAQ
Why is it called a half adder?
Because it cannot accept a carry in, so two half adders (plus an OR gate) are needed to make a full adder.
Which adder is fastest?
Parallel-prefix adders like Kogge-Stone are among the fastest, at the cost of more area and wiring.
How is overflow detected in signed addition?
Overflow occurs when the carry into the sign bit differs from the carry out of it.
Should I write adders gate by gate in RTL?
No. Use + and -, and let synthesis choose the best architecture for your timing.
