Keyboard shortcuts

Press ← or β†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Verilog Full Adder Tutorial

A comprehensive tutorial covering basic adder design and testbench concepts in Verilog.

Files

πŸ“¦ Download all files

FileDescription
full_adder.vDesign file containing 1-bit full adder and 4-bit ripple carry adder
full_adder_tb.vTestbench with exhaustive testing and detailed comments
MakefileBuild automation for compilation and simulation

Quick Start

# Compile and run
make

# Or manually:
iverilog -o full_adder_sim full_adder.v full_adder_tb.v
vvp full_adder_sim

# View waveforms (if GTKWave is installed)
make wave

Key Verilog Concepts Explained

1. Module Structure

module module_name (
    input  wire signal_in,
    output wire signal_out
);
    // Internal logic here
endmodule
  • Module: Basic building block (like a function/class)
  • Ports: Interface to outside world (inputs/outputs)
  • wire: Default type for ports, represents physical connections

2. Data Types

TypeUse Case
wireConnections, driven by assign or module outputs
regVariables assigned in procedural blocks (always, initial)
integer32-bit signed integers for loops/counters
parameterConstants, can be overridden at instantiation

3. Operators

CategoryOperatorsExample
Bitwise& ` ^ ~`
Logical&& `
Comparison== != === !==a == b
Arithmetic+ - * / %a + b
Shift<< >>a << 2
Concatenation{ }{a, b}
Replication{n{ }}{4{1'b0}}

Important: == vs ===

  • == returns X if either operand has X/Z
  • === does exact comparison including X/Z values

4. Number Representation

4'b1010    // 4-bit binary = 10
8'hFF      // 8-bit hex = 255
8'd255     // 8-bit decimal = 255
4'bxxxx    // 4-bit unknown
4'bzzzz    // 4-bit high-impedance

Format: <size>'<base><value>

5. Continuous vs Procedural Assignment

Continuous (Combinational Logic):

assign sum = a ^ b;  // Always reflects current inputs

Procedural (Sequential/Complex Logic):

always @(posedge clk) begin
    q <= d;  // Updates on clock edge
end

always @(*) begin    // Combinational in always block
    if (sel)
        y = a;
    else
        y = b;
end

6. Blocking vs Non-Blocking Assignment

TypeOperatorUse Case
Blocking=Combinational logic, testbenches
Non-blocking<=Sequential logic (flip-flops)
// WRONG - race condition
always @(posedge clk) begin
    a = b;
    b = a;  // Both get same value!
end

// CORRECT
always @(posedge clk) begin
    a <= b;
    b <= a;  // Proper swap
end

7. Module Instantiation

// Named port connection (PREFERRED)
full_adder fa0 (
    .a(input_a),
    .b(input_b),
    .cin(carry_in),
    .sum(sum_out),
    .cout(carry_out)
);

// Positional (error-prone, avoid)
full_adder fa0 (input_a, input_b, carry_in, sum_out, carry_out);

Testbench Concepts

1. Testbench Structure

`timescale 1ns / 1ps

module design_tb;         // No ports!
    reg  inputs;          // Driven by testbench
    wire outputs;         // Driven by DUT
    
    design dut (...);     // Instantiate DUT
    
    initial begin         // Test stimulus
        // Generate patterns
        // Check results
        $finish;
    end
endmodule

2. System Tasks (Non-Synthesizable)

TaskPurpose
$display()Print with newline
$write()Print without newline
$monitor()Print on any signal change
$timeCurrent simulation time
$randomGenerate random number
$finishEnd simulation
$stopPause simulation
$dumpfile()Specify VCD filename
$dumpvars()Record signals to VCD

3. Timing Control

#10;              // Delay 10 time units
#10 a = 1;        // Delay then assign
@(posedge clk);   // Wait for clock edge
wait(signal);     // Wait until signal is true

4. Test Strategy

  1. Boundary Cases: Min/max values, zero, overflow
  2. Typical Cases: Normal operation scenarios
  3. Edge Cases: Carry propagation, bit transitions
  4. Random Testing: Cover unexpected combinations

Design Best Practices

Do’s βœ“

  • Use meaningful signal names
  • Comment your code
  • Initialize all signals in testbenches
  • Use named port connections
  • Separate combinational and sequential logic
  • Use non-blocking (<=) for sequential logic

Don’ts βœ—

  • Mix blocking and non-blocking in same always block
  • Use initial blocks in synthesizable code
  • Create combinational loops
  • Leave signals undriven (floating)
  • Use delays in synthesizable code

Common Errors

1. Undriven Signal

wire result;        // Never assigned!
assign y = result;  // y will be 'x'

2. Multiple Drivers

assign a = b;
assign a = c;  // ERROR: Two drivers!

3. Sensitivity List Issues

// WRONG - incomplete sensitivity list
always @(a)
    y = a & b;  // Won't update when b changes

// CORRECT
always @(*)
    y = a & b;

4. Latch Inference

// WRONG - creates unintended latch
always @(*) begin
    if (sel)
        y = a;
    // Missing else!
end

// CORRECT
always @(*) begin
    if (sel)
        y = a;
    else
        y = b;  // Or: y = 0;
end

Running the Simulation

# Full build and run
make

# Step by step
make compile   # Compile
make run       # Simulate
make wave      # View waveforms
make clean     # Cleanup

Expected output shows:

  1. 1-bit full adder truth table verification
  2. 4-bit adder boundary tests
  3. Random pattern testing
  4. Pass/fail summary