Carry Look-Ahead Adder Verilog Code (4-bit + N-bit)

A carry look-ahead adder (CLA) speeds up binary addition by computing every carry in parallel instead of letting it trickle from the least significant bit to the most significant one. This page gives you working, runnable carry look ahead adder Verilog code: a hand-written 4-bit adder, a parameterized version that scales to any width, and a testbench that proves the CLA matches an ordinary ripple carry adder bit for bit.

Every snippet below compiles with Icarus Verilog using iverilog -g2005 -o sim FILE.v && vvp sim, and the simulation log next to each file is the real output from that run.

Generate and propagate: the two signals that make it work

For each bit position i, a full adder produces a carry-out when both inputs are 1 (it generates a carry) or when exactly one input is 1 and a carry already arrived (it propagates the incoming carry). Those two conditions are captured as:

  • g[i] = a[i] & b[i] — the generate term.
  • p[i] = a[i] ^ b[i] — the propagate term.

Once you have g and p, the carry into bit i+1 is c[i+1] = g[i] | (p[i] & c[i]). Expand that recurrence all the way down to cin and each carry becomes a single wide gate fed only by the inputs, so no carry waits on the one below it.

4-bit carry look-ahead adder Verilog code

This first version writes each carry out in full as a flat sum-of-products. It is verbose on purpose: you can see exactly how c[2], c[3] and c[4] depend only on g, p and cin. The testbench sweeps a grid of operand values and compares the result with Verilog’s built-in +.

// cla4.v  --  4-bit carry look-ahead adder with explicit generate/propagate
module cla4 (
    input  [3:0] a,
    input  [3:0] b,
    input        cin,
    output [3:0] sum,
    output       cout
);
    wire [3:0] g;   // generate:  g[i] = a[i] & b[i]
    wire [3:0] p;   // propagate: p[i] = a[i] ^ b[i]
    wire [4:0] c;   // carries, c[0] = cin

    assign g = a & b;
    assign p = a ^ b;

    // Each carry is written as a flat sum-of-products, so every bit
    // sees its carry at the same time instead of waiting for the one below.
    assign c[0] = cin;
    assign c[1] = g[0] | (p[0] & c[0]);
    assign c[2] = g[1] | (p[1] & g[0]) | (p[1] & p[0] & c[0]);
    assign c[3] = g[2] | (p[2] & g[1]) | (p[2] & p[1] & g[0])
                       | (p[2] & p[1] & p[0] & c[0]);
    assign 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]);

    assign sum  = p ^ c[3:0];
    assign cout = c[4];
endmodule

// Testbench: sweep a grid of inputs and check against Verilog's own + operator.
module tb_cla4;
    reg  [3:0] a, b;
    reg        cin;
    wire [3:0] sum;
    wire       cout;
    reg  [4:0] expected;
    integer    i, j, errors;

    cla4 dut (.a(a), .b(b), .cin(cin), .sum(sum), .cout(cout));

    initial begin
        errors = 0;
        cin = 1'b0;
        for (i = 0; i < 16; i = i + 5) begin
            for (j = 0; j < 16; j = j + 3) begin
                a = i[3:0];
                b = j[3:0];
                #1;
                expected = a + b + cin;
                $display("a=%2d b=%2d cin=%b | sum=%2d cout=%b | expect=%2d",
                         a, b, cin, sum, cout, expected);
                if ({cout, sum} !== expected) errors = errors + 1;
            end
        end
        // one case that forces cin=1 and an output carry
        cin = 1'b1; a = 4'd9; b = 4'd7; #1;
        $display("a=%2d b=%2d cin=%b | sum=%2d cout=%b | expect=%2d",
                 a, b, cin, sum, cout, a + b + cin);
        if ({cout, sum} !== (a + b + cin)) errors = errors + 1;
        $display("TEST %s (%0d mismatches)", (errors==0)?"PASSED":"FAILED", errors);
        $finish;
    end
endmodule
a= 0 b= 0 cin=0 | sum= 0 cout=0 | expect= 0
a= 0 b= 3 cin=0 | sum= 3 cout=0 | expect= 3
a= 0 b= 6 cin=0 | sum= 6 cout=0 | expect= 6
a= 0 b= 9 cin=0 | sum= 9 cout=0 | expect= 9
a= 0 b=12 cin=0 | sum=12 cout=0 | expect=12
a= 0 b=15 cin=0 | sum=15 cout=0 | expect=15
a= 5 b= 0 cin=0 | sum= 5 cout=0 | expect= 5
a= 5 b= 3 cin=0 | sum= 8 cout=0 | expect= 8
a= 5 b= 6 cin=0 | sum=11 cout=0 | expect=11
a= 5 b= 9 cin=0 | sum=14 cout=0 | expect=14
a= 5 b=12 cin=0 | sum= 1 cout=1 | expect=17
a= 5 b=15 cin=0 | sum= 4 cout=1 | expect=20
a=10 b= 0 cin=0 | sum=10 cout=0 | expect=10
a=10 b= 3 cin=0 | sum=13 cout=0 | expect=13
a=10 b= 6 cin=0 | sum= 0 cout=1 | expect=16
a=10 b= 9 cin=0 | sum= 3 cout=1 | expect=19
a=10 b=12 cin=0 | sum= 6 cout=1 | expect=22
a=10 b=15 cin=0 | sum= 9 cout=1 | expect=25
a=15 b= 0 cin=0 | sum=15 cout=0 | expect=15
a=15 b= 3 cin=0 | sum= 2 cout=1 | expect=18
a=15 b= 6 cin=0 | sum= 5 cout=1 | expect=21
a=15 b= 9 cin=0 | sum= 8 cout=1 | expect=24
a=15 b=12 cin=0 | sum=11 cout=1 | expect=27
a=15 b=15 cin=0 | sum=14 cout=1 | expect=30
a= 9 b= 7 cin=1 | sum= 1 cout=1 | expect= 1
TEST PASSED (0 mismatches)
/var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmpfqn8xdnn/cla4.v:62: $finish called at 25 (1s)

Reading the 4-bit version

The sum output is p ^ c[3:0]: the propagate bits XORed with the carry coming into each position. Because the carries are already expressed as flat equations, the four sum bits settle at nearly the same time. The testbench keeps a running errors count and prints TEST PASSED only when every vector, including a case with cin=1 and an output carry, matches the expected value.

A parameterized carry look-ahead adder

Writing out every carry by hand does not scale. The parameterized module keeps g and p as vectors and uses a generate loop to unroll the look-ahead recurrence for any WIDTH. Change one parameter and you get an 8-bit, 12-bit or 32-bit adder from the same source.

// cla_param.v  --  parameterized N-bit carry look-ahead adder
module cla #(parameter WIDTH = 8) (
    input  [WIDTH-1:0] a,
    input  [WIDTH-1:0] b,
    input              cin,
    output [WIDTH-1:0] sum,
    output             cout
);
    wire [WIDTH-1:0] g = a & b;   // generate
    wire [WIDTH-1:0] p = a ^ b;   // propagate
    wire [WIDTH:0]   c;           // carry chain, c[0] = cin

    assign c[0] = cin;

    // The look-ahead recurrence c[i+1] = g[i] | (p[i] & c[i]) is unrolled
    // by the generate loop. A synthesis tool flattens this into the
    // same parallel carry logic for any WIDTH you pick.
    genvar i;
    generate
        for (i = 0; i < WIDTH; i = i + 1) begin : carry_chain
            assign c[i+1] = g[i] | (p[i] & c[i]);
        end
    endgenerate

    assign sum  = p ^ c[WIDTH-1:0];
    assign cout = c[WIDTH];
endmodule

// Testbench: instantiate a 12-bit adder and hit it with random vectors.
module tb_cla;
    localparam WIDTH = 12;
    reg  [WIDTH-1:0] a, b;
    reg              cin;
    wire [WIDTH-1:0] sum;
    wire             cout;
    reg  [WIDTH:0]   expected;
    integer          k, errors;

    cla #(.WIDTH(WIDTH)) dut (.a(a), .b(b), .cin(cin), .sum(sum), .cout(cout));

    initial begin
        errors = 0;
        for (k = 0; k < 10; k = k + 1) begin
            a   = $random;
            b   = $random;
            cin = $random;
            #1;
            expected = a + b + cin;
            $display("W=%0d a=%4d b=%4d cin=%b | {cout,sum}=%5d | expect=%5d",
                     WIDTH, a, b, cin, {cout, sum}, expected);
            if ({cout, sum} !== expected) errors = errors + 1;
        end
        $display("TEST %s (%0d mismatches)", (errors==0)?"PASSED":"FAILED", errors);
        $finish;
    end
endmodule
W=12 a=1316 b=3713 cin=1 | {cout,sum}= 5030 | expect= 5030
W=12 a=1635 b=2829 cin=1 | {cout,sum}= 4465 | expect= 4465
W=12 a=1125 b= 530 cin=1 | {cout,sum}= 1656 | expect= 1656
W=12 a=3341 b= 374 cin=1 | {cout,sum}= 3716 | expect= 3716
W=12 a=2029 b=1932 cin=1 | {cout,sum}= 3962 | expect= 3962
W=12 a=1222 b=1221 cin=0 | {cout,sum}= 2443 | expect= 2443
W=12 a=2021 b= 631 cin=0 | {cout,sum}= 2652 | expect= 2652
W=12 a=2959 b=2546 cin=0 | {cout,sum}= 5505 | expect= 5505
W=12 a=2792 b=3781 cin=0 | {cout,sum}= 6573 | expect= 6573
W=12 a=2237 b=2093 cin=1 | {cout,sum}= 4331 | expect= 4331
TEST PASSED (0 mismatches)
/var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmpzm9w2zl5/cla_param.v:54: $finish called at 10 (1s)

Reading the parameterized version

The loop body assign c[i+1] = g[i] | (p[i] & c[i]) looks like it chains carries one after another, and in simulation it does resolve in order. The important part is that it is pure combinational logic with no clock: a synthesis tool is free to flatten it into the same parallel look-ahead structure as the hand-written 4-bit adder. The testbench drives a 12-bit instance with random operands through $random and again self-checks against a + b + cin.

Testbench: carry look-ahead vs ripple carry

The clearest way to trust a new adder is to compare it with one you already believe. Here a ripple carry adder (rca) and the CLA (cla) receive identical stimulus, and the testbench flags any disagreement. Both are combinational and produce the same numerical answer; only their internal timing differs.

// rca_vs_cla.v  --  ripple-carry adder and CLA checked against each other
module rca #(parameter WIDTH = 8) (
    input  [WIDTH-1:0] a,
    input  [WIDTH-1:0] b,
    input              cin,
    output [WIDTH-1:0] sum,
    output             cout
);
    wire [WIDTH:0] c;
    assign c[0] = cin;
    genvar i;
    generate
        for (i = 0; i < WIDTH; i = i + 1) begin : fa
            // full adder: carry of bit i must settle before bit i+1 starts
            assign sum[i] = a[i] ^ b[i] ^ c[i];
            assign c[i+1] = (a[i] & b[i]) | (a[i] & c[i]) | (b[i] & c[i]);
        end
    endgenerate
    assign cout = c[WIDTH];
endmodule

module cla #(parameter WIDTH = 8) (
    input  [WIDTH-1:0] a,
    input  [WIDTH-1:0] b,
    input              cin,
    output [WIDTH-1:0] sum,
    output             cout
);
    wire [WIDTH-1:0] g = a & b;
    wire [WIDTH-1:0] p = a ^ b;
    wire [WIDTH:0]   c;
    assign c[0] = cin;
    genvar i;
    generate
        for (i = 0; i < WIDTH; i = i + 1) begin : carry_chain
            assign c[i+1] = g[i] | (p[i] & c[i]);
        end
    endgenerate
    assign sum  = p ^ c[WIDTH-1:0];
    assign cout = c[WIDTH];
endmodule

// Testbench: both adders see the same stimulus; their outputs must agree.
module tb_compare;
    localparam WIDTH = 8;
    reg  [WIDTH-1:0] a, b;
    reg              cin;
    wire [WIDTH-1:0] sum_r, sum_c;
    wire             cout_r, cout_c;
    integer          k, errors;

    rca #(.WIDTH(WIDTH)) u_rca (.a(a), .b(b), .cin(cin), .sum(sum_r), .cout(cout_r));
    cla #(.WIDTH(WIDTH)) u_cla (.a(a), .b(b), .cin(cin), .sum(sum_c), .cout(cout_c));

    initial begin
        errors = 0;
        for (k = 0; k < 8; k = k + 1) begin
            a   = $random;
            b   = $random;
            cin = $random;
            #1;
            $display("a=%3d b=%3d cin=%b | rca={%b,%3d} cla={%b,%3d}",
                     a, b, cin, cout_r, sum_r, cout_c, sum_c);
            if ({cout_r, sum_r} !== {cout_c, sum_c}) errors = errors + 1;
        end
        $display("RIPPLE vs CLA %s (%0d mismatches)",
                 (errors==0)?"MATCH":"DIFFER", errors);
        $finish;
    end
endmodule
a= 36 b=129 cin=1 | rca={0,166} cla={0,166}
a= 99 b= 13 cin=1 | rca={0,113} cla={0,113}
a=101 b= 18 cin=1 | rca={0,120} cla={0,120}
a= 13 b=118 cin=1 | rca={0,132} cla={0,132}
a=237 b=140 cin=1 | rca={1,122} cla={1,122}
a=198 b=197 cin=0 | rca={1,139} cla={1,139}
a=229 b=119 cin=0 | rca={1, 92} cla={1, 92}
a=143 b=242 cin=0 | rca={1,129} cla={1,129}
RIPPLE vs CLA  MATCH (0 mismatches)
/var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmpiyucteb0/rca_vs_cla.v:68: $finish called at 8 (1s)

Reading the comparison

The ripple adder builds each carry from the one below it with c[i+1] = (a[i] & b[i]) | (a[i] & c[i]) | (b[i] & c[i]), so its worst-case delay grows with the number of bits. The CLA computes carries from g, p and cin directly. Functionally they are identical, which is exactly what the MATCH line confirms — the CLA is a drop-in replacement that trades more gates for shorter delay.

Ripple carry vs carry look-ahead at a glance

PropertyRipple carryCarry look-ahead
Carry delay (N bits)Grows with NRoughly constant for small N
Gate count / areaLowHigher
Design effortTrivialModerate
Best useNarrow or non-critical addersWide or timing-critical adders

Common mistakes

  • Swapping generate and propagate. Generate is a & b (AND) and propagate is a ^ b (XOR). Using OR for propagate still passes some vectors but breaks when both inputs are 1.
  • Getting the carry index off by one. Declare the carry vector as [WIDTH:0], tie c[0]=cin, and read cout from c[WIDTH]. A [WIDTH-1:0] vector leaves no room for the final carry.
  • Driving a wire twice. Each c[i+1] must be assigned exactly once. Putting a generate carry assignment alongside a manual one creates a multi-driver conflict.
  • Forgetting the width of expected. In the testbench, size the expected value as [WIDTH:0] so the comparison {cout, sum} !== expected keeps the output carry instead of truncating it.
  • Expecting a clock. A CLA is combinational. There is no posedge; stimulus changes and outputs settle after delta delays, which is why the testbenches use #1 between vectors.

Quick check

Why is a carry look-ahead adder faster than a ripple carry adder?

It computes every carry directly from the generate and propagate signals and cin, so carries resolve in parallel instead of rippling from bit 0 upward one full-adder delay at a time.

What do the generate and propagate signals equal for bit i?

Generate is g[i] = a[i] & b[i] and propagate is p[i] = a[i] ^ b[i]. The carry recurrence is c[i+1] = g[i] | (p[i] & c[i]).

Why declare the carry wire as [WIDTH:0] instead of [WIDTH-1:0]?

You need WIDTH+1 carries: c[0] holds cin and c[WIDTH] holds the final carry-out. A [WIDTH-1:0] vector would have nowhere to store cout.

What is the trade-off a CLA makes compared with a ripple carry adder?

It uses more gates (larger area and power) to achieve a shorter, nearly constant carry delay. For wide or timing-critical adders that extra logic is worth it; for narrow adders ripple carry is simpler.

Have questions about this topic?
Share your question in comments or talk to our mentor team for batch guidance.
▶ Try it in the ChipXpert Lab

Open this design in the free in-browser simulator — edit, compile and see the waveform/log instantly.

Run it in the Lab

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
Next batch starts 18th November 2026
Start your VLSI career with ChipXpert

Live online and classroom batches in Hyderabad & Bengaluru. Fill in your details and a counsellor will call you back.

  • Real EDA tools in your browser: industry-standard EDAReal EDA tools in your browser
  • Recorded sessions on the elearn portalRecorded sessions
  • Placement assistance: resume, mock interviewsPlacement assistance
  • Merit scholarship up to 60% · EMI optionsScholarship up to 60%
Hi! Ask me about courses, fees, batches or discounts. ×
BENGALURU
HYDERABAD