Conditional-Sum Adder in Verilog: Speculate-Both-Carries with Code
A conditional-sum adder speeds up addition by refusing to wait for the carry. Every block computes its sum twice in parallel, once assuming an incoming carry of 0 and once assuming 1, then a multiplexer picks the correct answer the instant the real carry arrives from the block below. Because both candidates are already sitting at the mux inputs, the critical path through the high bits collapses to a chain of 2:1 selects instead of a long ripple.
This page gives you working, simulator-verified conditional-sum adder Verilog code: a clear 8-bit design and a parameterized 16-bit hierarchy, each self-checked against a golden a + b + cin reference so you can trust every reported result. It is the direct conceptual ancestor of the carry-select adder.
Two 4-bit blocks each produce a (sum, carry-out) pair for carry-in 0 and for carry-in 1. The real cin selects the low block; the low block’s resolved carry selects the high block. The testbench sweeps all 131,072 operand/carry combinations against a golden model.
// 4-bit conditional-sum building block:
// precompute the sum for carry-in = 0 and carry-in = 1 in parallel.
module csum_block4(a, b, sum0, cout0, sum1, cout1);
input [3:0] a, b;
output [3:0] sum0, sum1;
output cout0, cout1;
assign {cout0, sum0} = a + b + 1'b0; // speculate cin = 0
assign {cout1, sum1} = a + b + 1'b1; // speculate cin = 1
endmodule
// 8-bit conditional-sum adder: two 4-bit blocks, each speculating both
// carries. The real cin selects the low block; the low block's resolved
// carry selects the high block.
module csum_add8(a, b, cin, sum, cout);
input [7:0] a, b;
input cin;
output [7:0] sum;
output cout;
wire [3:0] s0l, s1l, s0h, s1h;
wire c0l, c1l, c0h, c1h;
csum_block4 lo(.a(a[3:0]), .b(b[3:0]),
.sum0(s0l), .cout0(c0l), .sum1(s1l), .cout1(c1l));
csum_block4 hi(.a(a[7:4]), .b(b[7:4]),
.sum0(s0h), .cout0(c0h), .sum1(s1h), .cout1(c1h));
wire [3:0] suml = cin ? s1l : s0l; // select low block by real cin
wire cl = cin ? c1l : c0l; // low block's resolved carry-out
wire [3:0] sumh = cl ? s1h : s0h; // select high block by that carry
wire ch = cl ? c1h : c0h;
assign sum = {sumh, suml};
assign cout = ch;
endmodule
module tb;
reg [7:0] a, b;
reg cin;
wire [7:0] sum;
wire cout;
integer i, j, k;
reg [8:0] ref9;
integer fails;
csum_add8 dut(.a(a), .b(b), .cin(cin), .sum(sum), .cout(cout));
initial begin
fails = 0;
// Exhaustive sweep over all 8-bit operands and both carry-in values.
for (i = 0; i < 256; i = i + 1) begin
for (j = 0; j < 256; j = j + 1) begin
for (k = 0; k < 2; k = k + 1) begin
a = i[7:0]; b = j[7:0]; cin = k[0];
#1;
ref9 = a + b + cin; // golden model
if ({cout, sum} !== ref9) begin
fails = fails + 1;
if (fails <= 5)
$display("FAIL a=%0d b=%0d cin=%0d got {cout,sum}=%0d exp=%0d",
a, b, cin, {cout, sum}, ref9);
end
end
end
end
// A few named spot checks the reader can map to the output.
a = 8'd0; b = 8'd0; cin = 1'b0; #1;
if ({cout,sum} === 9'd0) $display("PASS 0+0+0 = %0d", {cout,sum});
else $display("FAIL 0+0+0");
a = 8'd255; b = 8'd1; cin = 1'b0; #1;
if ({cout,sum} === 9'd256) $display("PASS 255+1+0 = %0d (carry out)", {cout,sum});
else $display("FAIL 255+1+0");
a = 8'd200; b = 8'd99; cin = 1'b1; #1;
if ({cout,sum} === 9'd300) $display("PASS 200+99+1 = %0d", {cout,sum});
else $display("FAIL 200+99+1");
if (fails == 0)
$display("ALL TESTS PASSED (131072 exhaustive vectors)");
else
$display("TOTAL FAILS = %0d", fails);
$finish;
end
endmodule
PASS 0+0+0 = 0 PASS 255+1+0 = 256 (carry out) PASS 200+99+1 = 300 ALL TESTS PASSED (131072 exhaustive vectors)The log shows the exhaustive sweep passing: every one of the 2^8 x 2^8 x 2 input combinations matched
a + b + cin, and the three named spot checks (0+0+0, the 255+1 carry-out case, and 200+99+1) print their decimal results. A single mismatch anywhere would have printed aFAILline, soALL TESTS PASSEDproves the speculate-and-select logic is functionally identical to a plain adder.This variant uses a parameterized
csum_blockinstantiated four times with agenerateloop, forming a 16-bit adder. The resolved carry ripples through a chain of select muxes from block 0 up to block 3, which is exactly how a conditional-sum hierarchy propagates its decision.// Parameterized conditional-sum block of WIDTH bits. // Produces both candidate results: (sum0,cout0) for cin=0 and // (sum1,cout1) for cin=1. This is the pair that gets doubled at // every level of a conditional-sum hierarchy. module csum_block #(parameter WIDTH = 4) (a, b, sum0, cout0, sum1, cout1); input [WIDTH-1:0] a, b; output [WIDTH-1:0] sum0, sum1; output cout0, cout1; assign {cout0, sum0} = a + b + 1'b0; assign {cout1, sum1} = a + b + 1'b1; endmodule // 16-bit conditional-sum adder built as four 4-bit blocks. // Each block speculates both carries; a mux chain selects the right // candidate as the carry resolves from block 0 up to block 3. module csum_add16(a, b, cin, sum, cout); input [15:0] a, b; input cin; output [15:0] sum; output cout; wire [3:0] s0 [0:3]; // sum assuming cin=0 for each block wire [3:0] s1 [0:3]; // sum assuming cin=1 for each block wire c0 [0:3]; // cout assuming cin=0 wire c1 [0:3]; // cout assuming cin=1 genvar g; generate for (g = 0; g < 4; g = g + 1) begin : blk csum_block #(.WIDTH(4)) u ( .a(a[g*4 +: 4]), .b(b[g*4 +: 4]), .sum0(s0[g]), .cout0(c0[g]), .sum1(s1[g]), .cout1(c1[g])); end endgenerate // Ripple the resolved carry through the select muxes. wire [3:0] y0 = cin ? s1[0] : s0[0]; wire k0 = cin ? c1[0] : c0[0]; wire [3:0] y1 = k0 ? s1[1] : s0[1]; wire k1 = k0 ? c1[1] : c0[1]; wire [3:0] y2 = k1 ? s1[2] : s0[2]; wire k2 = k1 ? c1[2] : c0[2]; wire [3:0] y3 = k2 ? s1[3] : s0[3]; wire k3 = k2 ? c1[3] : c0[3]; assign sum = {y3, y2, y1, y0}; assign cout = k3; endmodule module tb; reg [15:0] a, b; reg cin; wire [15:0] sum; wire cout; integer i, j, k; reg [16:0] ref17; integer fails; csum_add16 dut(.a(a), .b(b), .cin(cin), .sum(sum), .cout(cout)); initial begin fails = 0; // Wide pseudo-sweep with FIXED (deterministic) stride vectors. // Steps of 777/1103 are coprime-ish to 65536 so they visit a broad, // reproducible spread of operands including boundary values. for (i = 0; i < 65536; i = i + 777) begin for (j = 0; j < 65536; j = j + 1103) begin for (k = 0; k < 2; k = k + 1) begin a = i[15:0]; b = j[15:0]; cin = k[0]; #1; ref17 = a + b + cin; if ({cout, sum} !== ref17) begin fails = fails + 1; if (fails <= 5) $display("FAIL a=%0d b=%0d cin=%0d got=%0d exp=%0d", a, b, cin, {cout, sum}, ref17); end end end end // Explicit boundary spot checks. a = 16'h0000; b = 16'h0000; cin = 1'b0; #1; if ({cout,sum} === 17'd0) $display("PASS 0+0+0 = %0d", {cout,sum}); else $display("FAIL 0+0+0"); a = 16'hFFFF; b = 16'h0001; cin = 1'b0; #1; if ({cout,sum} === 17'd65536) $display("PASS 65535+1+0 = %0d (carry out)", {cout,sum}); else $display("FAIL 65535+1+0"); a = 16'hFFFF; b = 16'hFFFF; cin = 1'b1; #1; if ({cout,sum} === 17'd131071) $display("PASS 65535+65535+1 = %0d", {cout,sum}); else $display("FAIL max+max+1"); a = 16'h0F0F; b = 16'h00F1; cin = 1'b0; #1; // carry crosses block boundaries if ({cout,sum} === (16'h0F0F + 16'h00F1)) $display("PASS 0x0F0F+0x00F1 = %0d", {cout,sum}); else $display("FAIL cross-block"); if (fails == 0) $display("ALL TESTS PASSED (wide deterministic sweep + boundary checks)"); else $display("TOTAL FAILS = %0d", fails); $finish; end endmodulePASS 0+0+0 = 0
PASS 65535+1+0 = 65536 (carry out)
PASS 65535+65535+1 = 131071
PASS 0x0F0F+0x00F1 = 4096
ALL TESTS PASSED (wide deterministic sweep + boundary checks)The log confirms a wide, deterministic stride sweep (fixed steps, no random stimulus) plus explicit boundary cases: all-zero, the 65535+1 carry-out, the maximum 65535+65535+1, and a vector whose carry crosses every 4-bit block boundary. Each prints a
PASSwith its decimal sum, and the finalALL TESTS PASSEDline only appears because zero vectors disagreed with thea + b + cingolden model.How the conditional-sum adder works
The core idea is speculation. Addition is slow because bit i cannot finish until it knows the carry coming into it, and that carry depends on every bit below it. A conditional-sum adder breaks the dependency by computing both possible answers up front. For each block it evaluates:
{cout0, sum0} = a + b + 0— the result if the incoming carry turns out to be 0;{cout1, sum1} = a + b + 1— the result if the incoming carry turns out to be 1.Both computations run in parallel and do not depend on anything outside the block. When the true carry finally arrives from the block below, a 2:1 multiplexer selects the matching
sumand the matchingcoutin one gate delay. That selectedcoutis then the true carry into the next block up, so the carry decision ripples through a short chain of muxes rather than through full adder logic.Timing intuition
In a ripple-carry adder the worst-case path runs through every full adder in series. In the conditional-sum structure, once the block sums are ready, the remaining delay is one mux per block boundary. Trading a longer carry path for parallel speculation plus a mux chain is the whole point: you spend area to buy time.
Relationship to the carry-select adder
The conditional-sum adder is the direct precursor of the carry-select adder, and the two are easy to confuse. Both compute each block twice (for carry-in 0 and 1) and select with a mux. The distinction is how far the idea is pushed:
- Carry-select adder: the block adders themselves are ordinary ripple-carry (or other) adders. Only the final carry-out of each block and its sum are muxed. It is a practical, widely used structure.
- Conditional-sum adder: the speculate-both-carries idea is applied recursively, down to very small blocks (classically single bits), so the entire adder is a tree of muxes selecting precomputed candidate sums.
The doubling of candidate sums
Every level of a fully recursive conditional-sum adder keeps two candidate results per sub-block — one for each assumed carry-in. When two sub-blocks merge into a larger block, each of the parent's two required outputs (for carry-in 0 and 1) is formed by selecting among the children's candidates. This is why the structure is sometimes described as having its candidate count double as you go: at each bit position you must keep the carry-in-0 and carry-in-1 versions alive until the real carry resolves them. The cost is extra muxes and duplicated adder logic (area roughly doubles for the speculation), bought in exchange for a logarithmic-style carry-resolution path instead of a linear ripple. The parameterized 16-bit example above shows the small-block version of exactly this: four blocks, each holding both candidates, selected by a rippling carry.
Common mistakes
- Dropping the block carry-out from speculation. You must precompute both
cout0andcout1. The selected carry-out is what drives the next block's mux; using only one of them breaks the chain for half the inputs.- Selecting sum and carry with different controls. Within a block, the same resolved carry must select the sum bits and the carry-out. Mixing
c0/c1selection for the sum but forgetting it for the carry produces results that pass on some vectors and fail on others — exactly the kind of bug an exhaustive self-check catches.- Width overflow on the concatenation. Each block's
{cout, sum}must be one bit wider than the operands, or the carry is silently lost. In the code the left-hand side isWIDTH+1bits via concatenation.- Assuming it is automatically faster in synthesis. For small widths a synthesis tool may map a behavioral
+to something just as good or better. The conditional-sum structure earns its keep at wide widths where ripple delay dominates.Synthesis notes
The Verilog here is fully synthesizable: every block is combinational, built from
assignstatements and continuous-assignment muxes, with no latches and no clock. A few practical points:
- The
a + b + 1'b0anda + b + 1'b1expressions synthesize to two adders per block. That duplication is intentional — it is the area cost of speculation.- The ternary selects (
cl ? s1 : s0) map to 2:1 multiplexers. The resolved-carry chain (k0, k1, k2, k3in the 16-bit version) is the structure's carry path; keeping blocks small shortens the sum computation but lengthens this mux chain, so block size is a real design knob.- Use
generate(as in the 16-bit example) to scale the design to arbitrary widths without copy-paste, parameterizing both block width and block count.- Because the design is purely combinational, timing closure depends on the surrounding register-to-register path; pipeline the adder if the combined speculate-plus-select delay exceeds your clock period.
FAQ
Is a conditional-sum adder the same as a carry-select adder?
No, but they are closely related. Carry-select is the practical, single-level application of the speculate-both-carries idea; conditional-sum applies it recursively down to tiny blocks. The examples on this page use small fixed blocks, which sit between the two in spirit.
Why compute the sum twice instead of waiting for the carry?
Waiting serializes the whole adder. Computing both candidate sums in parallel means the only post-carry delay is a multiplexer, which is what makes wide conditional-sum adders fast.
Does the self-check really prove correctness?
The 8-bit example is exhaustive — it checks all 131,072 input combinations against
a + b + cin, so it is a complete functional proof for that width. The 16-bit example cannot be fully exhaustive in reasonable time, so it uses a wide deterministic stride sweep plus explicit boundary vectors; it is strong evidence, though not a full proof, for the parameterized structure.How do I make it wider than 16 bits?
Increase the block count in the
generateloop and extend the resolved-carry mux chain, or restructure the chain as a balanced tree to shorten the carry-resolution path at very large widths.Have questions about this topic?
Share your question in comments or talk to our mentor team for batch guidance.▶ Try it in the ChipXpert LabRun it in the LabOpen 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 Hi! Ask me about courses, fees, batches or discounts. ×ChipXpert AssistantAsk about courses, fees, batches and centres