Adders

Addition is the first place gate-level thinking meets arithmetic. A full adder adds three bits (a, b, carry-in) into a sum and carry-out:

sum  = a ^ b ^ cin
cout = (a & b) | (cin & (a ^ b))

Chain four of them, carry-out to carry-in, and you have a 4-bit ripple-carry adder — the design below builds it with a generate loop, worth reading as your first taste of structural repetition in Verilog.

The design also computes the same sum a second way: assign {c5, s5} = a + b + cin;. In the waveform the two results are always identical — that's the point. Synthesis tools map + onto the FPGA's dedicated fast carry chains, which are quicker than anything you can describe by hand with gates. Write +, not adder structures. The value of knowing the full adder isn't to type it; it's to understand what the tools build, why a wide adder's delay grows with its width, and what a "carry chain" is when the timing report mentions one.

One habit to take away: the sum of two N-bit numbers needs N+1 bits. The concatenation trick {cout, sum} = a + b captures the carry cleanly and appears everywhere real arithmetic is written.

Experiment: make an add/subtract unit — b ^ {4{sub}} plus sub as carry-in is two's-complement subtraction for one extra XOR per bit. (This exact trick reappears in the ALU capstone.)

Schematic

abcinsumabcincout

The design

Verilog — design.v
// A structural ripple-carry adder next to the `+` you should use.
module adders (
    input  wire [3:0] a, b,
    input  wire       cin,
    output wire [3:0] sum_ripple,
    output wire       cout_ripple,
    output wire [3:0] sum_plus,
    output wire       cout_plus
);
    // --- structural: 4 chained full adders ---
    wire [4:0] c;
    assign c[0] = cin;

    genvar i;
    generate
        for (i = 0; i < 4; i = i + 1) begin : fa
            assign sum_ripple[i] = a[i] ^ b[i] ^ c[i];
            assign c[i+1]        = (a[i] & b[i]) | (c[i] & (a[i] ^ b[i]));
        end
    endgenerate
    assign cout_ripple = c[4];

    // --- behavioral: what you should actually write ---
    assign {cout_plus, sum_plus} = a + b + cin;
endmodule
Show the VHDL version
VHDL — design.vhd
-- Ripple-carry adder next to the '+' you should use.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity adders is
    port (
        a, b        : in  std_logic_vector(3 downto 0);
        cin         : in  std_logic;
        sum_ripple  : out std_logic_vector(3 downto 0);
        cout_ripple : out std_logic;
        sum_plus    : out std_logic_vector(3 downto 0);
        cout_plus   : out std_logic
    );
end entity;

architecture rtl of adders is
    signal c : std_logic_vector(4 downto 0);
    signal r : unsigned(4 downto 0);
begin
    -- structural ripple carry
    c(0) <= cin;
    gen_fa : for i in 0 to 3 generate
        sum_ripple(i) <= a(i) xor b(i) xor c(i);
        c(i+1) <= (a(i) and b(i)) or (c(i) and (a(i) xor b(i)));
    end generate;
    cout_ripple <= c(4);

    -- behavioral
    r <= resize(unsigned(a), 5) + resize(unsigned(b), 5)
         + ("0000" & cin);
    sum_plus  <= std_logic_vector(r(3 downto 0));
    cout_plus <= r(4);
end architecture;

The testbench

Verilog — tb.v
`timescale 1ns/1ns
module tb;
    reg  [3:0] a = 0, b = 0;
    reg        cin = 0;
    wire [3:0] sum_ripple, sum_plus;
    wire       cout_ripple, cout_plus;

    adders dut (.a(a), .b(b), .cin(cin),
                .sum_ripple(sum_ripple), .cout_ripple(cout_ripple),
                .sum_plus(sum_plus), .cout_plus(cout_plus));

    initial begin
        $dumpfile("wave.vcd"); $dumpvars(0, tb);
        #10 begin a = 4'd3;  b = 4'd4;  end   // 7, no carry
        #10 begin a = 4'd9;  b = 4'd8;  end   // 17: carry out
        #10 begin a = 4'hF;  b = 4'h1;  end   // wrap: 0 + carry
        #10 cin = 1;                          // F + 1 + 1
        #10 begin a = 4'd5;  b = 4'd5; cin = 0; end
        #10 $finish;
    end
endmodule

Simulated waveform

This trace was produced by actually simulating the code above with Icarus Verilog.

6 12 18 24 30 36 42 48 54 t (ns) sum_ripple[3:0] 0 7 1 0 1 A sum_plus[3:0] 0 7 1 0 1 A cout_ripple cout_plus a[3:0] 0 3 9 F 5 b[3:0] 0 4 8 1 5 cin c[4:0] 0 10 1E 1F A

Open this lesson in the playground →