Carry Lookahead Adder in VHDL and Verilog

A Carry Lookahead (Look Ahead) Adder is made of a number of full-adders cascaded together. It is used to add together two binary numbers using only simple logic gates. The figure below shows 4 full-adders connected together to produce a 4-bit carry lookahead adder. Carry lookahead adders are similar to Ripple Carry Adders. The difference is that carry lookahead adders are able to calculate the Carry bit before the Full Adder is done with its operation. This gives it an advantage over the Ripple Carry Adder because it is able to add two numbers together faster. The drawback is that it takes more logic. You will find there is often a balance between speed of execution and resources used when designing FPGAs and ASICs.

Carry Lookahead Adder 4-bit Block Diagram

There are two examples for each VHDL and Verilog shown below. The first contains a simple carry lookahead adder made up of four full adders (it can add together any four-bit inputs). The second example uses a generic that creates a carry look ahead adder that accepts as an input parameter the WIDTH of the inputs. Therefore it is scalable for any input widths.

VHDL Implementation:

Example 1: Four-Bit Carry Lookahead Adder in VHDL

Note that the carry lookahead adder output (o_result) is one bit larger than both of the two adder inputs. This is because two N bit vectors added together can produce a result that is N+1 in size. For example, b"11" + b"11" = b"110". In decimal, 3 + 3 = 6.

The output o_result is assigned using the ampersand (&) VHDL concatenation operator. As long as inputs to the concatenation operator of the same type they can be concatenated together.

-------------------------------------------------------------------------------
-- File Downloaded from http://www.nandland.com
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;

entity carry_lookahead_adder_4_bit is
  port (
    i_add1  : in std_logic_vector(3 downto 0);
    i_add2  : in std_logic_vector(3 downto 0);
    --
    o_result   : out std_logic_vector(4 downto 0)
    );
end carry_lookahead_adder_4_bit;


architecture rtl of carry_lookahead_adder_4_bit is

  component full_adder is
    port (
      i_bit1  : in  std_logic;
      i_bit2  : in  std_logic;
      i_carry : in  std_logic;
      o_sum   : out std_logic;
      o_carry : out std_logic);
  end component full_adder;

  signal w_G : std_logic_vector(3 downto 0); -- Generate
  signal w_P : std_logic_vector(3 downto 0); -- Propagate
  signal w_C : std_logic_vector(4 downto 0); -- Carry

  signal w_SUM   : std_logic_vector(3 downto 0);

  
begin 
  
  FULL_ADDER_BIT_0 : full_adder
    port map (
      i_bit1  => i_add1(0),
      i_bit2  => i_add2(0),
      i_carry => w_C(0),
      o_sum   => w_SUM(0),
      o_carry => open
      );

  FULL_ADDER_BIT_1 : full_adder
    port map (
      i_bit1  => i_add1(1),
      i_bit2  => i_add2(1),
      i_carry => w_C(1),
      o_sum   => w_SUM(1),
      o_carry => open
      );

  FULL_ADDER_BIT_2 : full_adder
    port map (
      i_bit1  => i_add1(2),
      i_bit2  => i_add2(2),
      i_carry => w_C(2),
      o_sum   => w_SUM(2),
      o_carry => open
      );
  
  FULL_ADDER_BIT_3 : full_adder
    port map (
      i_bit1  => i_add1(3),
      i_bit2  => i_add2(3),
      i_carry => w_C(3),
      o_sum   => w_SUM(3),
      o_carry => open
      );

  -- Create the Generate (G) Terms:  Gi=Ai*Bi
  w_G(0) <= i_add1(0) and i_add2(0);
  w_G(1) <= i_add1(1) and i_add2(1);
  w_G(2) <= i_add1(2) and i_add2(2);
  w_G(3) <= i_add1(3) and i_add2(3);

  -- Create the Propagate Terms: Pi=Ai+Bi
  w_P(0) <= i_add1(0) or i_add2(0);
  w_P(1) <= i_add1(1) or i_add2(1);
  w_P(2) <= i_add1(2) or i_add2(2);
  w_P(3) <= i_add1(3) or i_add2(3);

  -- Create the Carry Terms:
  w_C(0) <= '0'; -- no carry input
  w_C(1) <= w_G(0) or (w_P(0) and w_C(0));
  w_C(2) <= w_G(1) or (w_P(1) and w_C(1));
  w_C(3) <= w_G(2) or (w_P(2) and w_C(2));
  w_C(4) <= w_G(3) or (w_P(3) and w_C(3));

  -- Final Answer
  o_result <= w_C(4) & w_SUM;  -- VHDL Concatenation
  
end rtl;

Example 2: Scalable Carry Lookahead Adder in VHDL

The second example is more complicated. The above carry lookahead adder uses a VHDL generic to allow for different implementations of the same code. This makes the code more versatile and reusable. Using the generic, the code creates a generate statement which instantiates as many full-adders as are specified by the g_WIDTH generic.

This code shows how powerful generics and generate statements can be in creating code that is compact, but very scalable. It can be used for any width of inputs. The digital designer simply needs to set the g_WIDTH appropriately for his or her particular application and the tools will generate the correct amount of logic!

-------------------------------------------------------------------------------
-- File Downloaded from http://www.nandland.com
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;

entity carry_lookahead_adder is
  generic (
    g_WIDTH : natural
    );
  port (
    i_add1  : in std_logic_vector(g_WIDTH-1 downto 0);
    i_add2  : in std_logic_vector(g_WIDTH-1 downto 0);
    --
    o_result   : out std_logic_vector(g_WIDTH downto 0)
    );
end carry_lookahead_adder;


architecture rtl of carry_lookahead_adder is

  component full_adder is
    port (
      i_bit1  : in  std_logic;
      i_bit2  : in  std_logic;
      i_carry : in  std_logic;
      o_sum   : out std_logic;
      o_carry : out std_logic);
  end component full_adder;

  signal w_G : std_logic_vector(g_WIDTH-1 downto 0); -- Generate
  signal w_P : std_logic_vector(g_WIDTH-1 downto 0); -- Propagate
  signal w_C : std_logic_vector(g_WIDTH downto 0);   -- Carry

  signal w_SUM  : std_logic_vector(g_WIDTH-1 downto 0);

begin 

  -- Create the Full Adders
  GEN_FULL_ADDERS : for ii in 0 to g_WIDTH-1 generate
    FULL_ADDER_INST : full_adder
      port map (
        i_bit1  => i_add1(ii),
        i_bit2  => i_add2(ii),
        i_carry => w_C(ii),        
        o_sum   => w_SUM(ii),
        o_carry => open
        );
  end generate GEN_FULL_ADDERS;

  -- Create the Generate (G) Terms:  Gi=Ai*Bi
  -- Create the Propagate Terms: Pi=Ai+Bi
  -- Create the Carry Terms:  
  GEN_CLA : for jj in 0 to g_WIDTH-1 generate
    w_G(jj)   <= i_add1(jj) and i_add2(jj);
    w_P(jj)   <= i_add1(jj) or i_add2(jj);
    w_C(jj+1) <= w_G(jj) or (w_P(jj) and w_C(jj));
  end generate GEN_CLA;
    
  w_C(0) <= '0'; -- no carry input

  o_result <= w_C(g_WIDTH) & w_SUM;  -- VHDL Concatenation
  
end rtl;

VHDL Testbench:

-------------------------------------------------------------------------------
-- File Downloaded from http://www.nandland.com
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;

entity carry_lookahead_adder_tb is
end carry_lookahead_adder_tb;

architecture behave of carry_lookahead_adder_tb is

  constant c_WIDTH : integer := 3;
  
  signal r_ADD_1  : std_logic_vector(c_WIDTH-1 downto 0) := (others => '0');
  signal r_ADD_2  : std_logic_vector(c_WIDTH-1 downto 0) := (others => '0');
  signal w_RESULT : std_logic_vector(c_WIDTH downto 0);


  component carry_lookahead_adder is
    generic (
      g_WIDTH : natural
      );
    port (
      i_add1   : in  std_logic_vector(g_WIDTH-1 downto 0);
      i_add2   : in  std_logic_vector(g_WIDTH-1 downto 0);
      --
      o_result : out std_logic_vector(g_WIDTH downto 0)
      );
  end component carry_lookahead_adder;
  
begin 

  -- Instantiate the Unit Under Test (UUT)
  UUT : carry_lookahead_adder
    generic map (
      g_WIDTH     => c_WIDTH
      )
    port map (
      i_add1   => r_ADD_1,
      i_add2   => r_ADD_2,
      o_result => w_RESULT
      );

  
  -- Test bench is non-synthesizable
  process is
  begin
    r_ADD_1 <= "000";
    r_ADD_2 <= "001";
    wait for 10 ns;
    r_ADD_1 <= "100";
    r_ADD_2 <= "010";
    wait for 10 ns;
    r_ADD_1 <= "010";
    r_ADD_2 <= "110";
    wait for 10 ns;
    r_ADD_1 <= "111";
    r_ADD_2 <= "111";
    wait for 10 ns;
  end process;
  
end behave;


Verilog Implementation:

Example 3: 4-Bit Carry Lookahead Adder in Verilog

Note that the carry lookahead adder output (o_result) is one bit larger than both of the two adder inputs. This is because two N bit vectors added together can produce a result that is N+1 in size. For example, b"11" + b"11" = b"110". In decimal, 3 + 3 = 6.

The output o_result is assigned using the brackets {, } Verilog concatenation operator.

///////////////////////////////////////////////////////////////////////////////
// File Downloaded from http://www.nandland.com
///////////////////////////////////////////////////////////////////////////////

`include "full_adder.v"

module carry_lookahead_adder_4_bit 
  (
   input [3:0]  i_add1,
   input [3:0]  i_add2,
   output [4:0] o_result
   );
    
  wire [4:0]    w_C;
  wire [3:0]    w_G, w_P, w_SUM;
  
  full_adder full_adder_bit_0
    ( 
      .i_bit1(i_add1[0]),
      .i_bit2(i_add2[0]),
      .i_carry(w_C[0]),
      .o_sum(w_SUM[0]),
      .o_carry()
      );

  full_adder full_adder_bit_1
    ( 
      .i_bit1(i_add1[1]),
      .i_bit2(i_add2[1]),
      .i_carry(w_C[1]),
      .o_sum(w_SUM[1]),
      .o_carry()
      );

  full_adder full_adder_bit_2
    ( 
      .i_bit1(i_add1[2]),
      .i_bit2(i_add2[2]),
      .i_carry(w_C[2]),
      .o_sum(w_SUM[2]),
      .o_carry()
      );
  
  full_adder full_adder_bit_3
    ( 
      .i_bit1(i_add1[3]),
      .i_bit2(i_add2[3]),
      .i_carry(w_C[3]),
      .o_sum(w_SUM[3]),
      .o_carry()
      );
  
  // Create the Generate (G) Terms:  Gi=Ai*Bi
  assign w_G[0] = i_add1[0] & i_add2[0];
  assign w_G[1] = i_add1[1] & i_add2[1];
  assign w_G[2] = i_add1[2] & i_add2[2];
  assign w_G[3] = i_add1[3] & i_add2[3];

  // Create the Propagate Terms: Pi=Ai+Bi
  assign w_P[0] = i_add1[0] | i_add2[0];
  assign w_P[1] = i_add1[1] | i_add2[1];
  assign w_P[2] = i_add1[2] | i_add2[2];
  assign w_P[3] = i_add1[3] | i_add2[3];

  // Create the Carry Terms:
  assign w_C[0] = 1'b0; // no carry input
  assign w_C[1] = w_G[0] | (w_P[0] & w_C[0]);
  assign w_C[2] = w_G[1] | (w_P[1] & w_C[1]);
  assign w_C[3] = w_G[2] | (w_P[2] & w_C[2]);
  assign w_C[4] = w_G[3] | (w_P[3] & w_C[3]);
  
  assign o_result = {w_C[4], w_SUM};   // Verilog Concatenation

endmodule // carry_lookahead_adder_4_bit

Example 4: Parameterizable Carry Lookahead Adder in Verilog

The above carry lookahead adder uses a Verilog parameter to allow for different implementations of the same code. This makes the code more versatile and reusable. Using the parameter, the code creates a generate statement which instantiates as many full-adders as are specified by the WIDTH parameter.

This code shows how powerful parameters and generate statements can be in creating code that is compact, but very malleable. It can be used for any width of inputs. The digital designer simply needs to set the WIDTH appropriately for his or her particular application and the tools will generate the correct amount of logic!

///////////////////////////////////////////////////////////////////////////////
// File Downloaded from http://www.nandland.com
///////////////////////////////////////////////////////////////////////////////

`include "full_adder.v"

module carry_lookahead_adder
  #(parameter WIDTH)
  (
   input [WIDTH-1:0] i_add1,
   input [WIDTH-1:0] i_add2,
   output [WIDTH:0]  o_result
   );
    
  wire [WIDTH:0]     w_C;
  wire [WIDTH-1:0]   w_G, w_P, w_SUM;

  // Create the Full Adders
  genvar             ii;
  generate
    for (ii=0; ii<WIDTH; ii=ii+1) 
      begin
        full_adder full_adder_inst
            ( 
              .i_bit1(i_add1[ii]),
              .i_bit2(i_add2[ii]),
              .i_carry(w_C[ii]),
              .o_sum(w_SUM[ii]),
              .o_carry()
              );
      end
  endgenerate

  // Create the Generate (G) Terms:  Gi=Ai*Bi
  // Create the Propagate Terms: Pi=Ai+Bi
  // Create the Carry Terms:
  genvar             jj;
  generate
    for (jj=0; jj<WIDTH; jj=jj+1) 
      begin
        assign w_G[jj]   = i_add1[jj] & i_add2[jj];
        assign w_P[jj]   = i_add1[jj] | i_add2[jj];
        assign w_C[jj+1] = w_G[jj] | (w_P[jj] & w_C[jj]);
      end
  endgenerate
  
  assign w_C[0] = 1'b0; // no carry input on first adder

  assign o_result = {w_C[WIDTH], w_SUM};   // Verilog Concatenation

endmodule // carry_lookahead_adder

Testbench:

///////////////////////////////////////////////////////////////////////////////
// File Downloaded from http://www.nandland.com
///////////////////////////////////////////////////////////////////////////////

`include "carry_lookahead_adder.v"

module carry_lookahead_adder_tb ();

  parameter WIDTH = 3;

  reg [WIDTH-1:0] r_ADD_1 = 0;
  reg [WIDTH-1:0] r_ADD_2 = 0;
  wire [WIDTH:0]  w_RESULT;
  
  carry_lookahead_adder #(.WIDTH(WIDTH)) carry_lookahead_inst
    (
     .i_add1(r_ADD_1),
     .i_add2(r_ADD_2),
     .o_result(w_RESULT)
     );

  initial
    begin
      #10;
      r_ADD_1 = 3'b000;
      r_ADD_2 = 3'b001;
      #10;
      r_ADD_1 = 3'b010;
      r_ADD_2 = 3'b010;
      #10;
      r_ADD_1 = 3'b101;
      r_ADD_2 = 3'b110;
      #10;
      r_ADD_1 = 3'b111;
      r_ADD_2 = 3'b111;
      #10;
    end

endmodule // carry_lookahead_adder_tb

Modelsim Results of Carry Lookahead Adder


Help Me Make Great Content!     Support me on Patreon!     Buy a Go Board!