Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 21

Creating a Clock Signal in Your Testbench

Recommended resources

Hello! Welcome to the next lesson in our journey into Verilog.

In our last session, we built our first testbench to apply a sequence of inputs, or stimulus vectors, to a combinational circuit. We used initial blocks and delays (#) to control the timing of these inputs. Today, we'll build on that by learning how to generate a periodic clock signal, which is the heartbeat of nearly all sequential digital systems. While our previous testbench was for combinational logic, generating a clock is the first step toward testing the sequential circuits we will be designing soon.

This lesson is dedicated to the learning outcome: Generate a periodic clock signal within a testbench. By the end, you will be able to write the Verilog code needed to create a stable clock for any simulation environment.

1. The Clock's Role in Simulation

In a physical system like an FPGA or an ASIC, the clock signal is typically generated by an external crystal oscillator. It's a stable, oscillating voltage that coordinates the actions of all the sequential components, like flip-flops and registers.

In a simulation, there is no physical oscillator. Instead, we must create a virtual clock within our testbench. The purpose of this testbench clock is to mimic the behavior of a real one, allowing us to test how our design behaves cycle by cycle. It's crucial to remember that the Verilog code we write to generate a clock in a testbench is for simulation only and is not synthesizable—it cannot be turned into hardware.


2. The Core Idea: An Infinitely Toggling Signal

A clock signal is simply a signal that toggles between 0 and 1 at a constant interval.

  • Period (T): The total time it takes for one full cycle (e.g., from one rising edge to the next).
  • Frequency (f): The number of cycles per second, where .
  • Duty Cycle: The percentage of the period for which the signal is high. A 50% duty cycle is standard.

To create a clock with a period T, we need to invert a signal every T/2 time units. For example, to create a 100 MHz clock, the period is . We would need to toggle the clock signal every 5 ns.

There are a couple of common ways to achieve this in Verilog. Let's explore the most standard method first.


3. Method 1: The initial and forever Combination

In the last lesson, you learned that an initial block executes its commands only once. However, we can place a forever loop inside it to create a process that repeats indefinitely throughout the simulation. This is perfect for a clock.

The following resource explains the forever loop and its direct application in creating a clock.

How to Write a Basic Verilog Testbench

This article from FPGATutorial.com clearly introduces the forever loop and shows how it's used for clock generation.

Please read the sections titled "Verilog forever loop" and "Generate the Clock and Reset". Pay attention to: How a forever loop creates a repeating sequence of actions. The simple, clean syntax for generating a clock using initial, forever, and the delay operator (#).

As detailed in the reading, the canonical structure for a clock generator is:

`timescale 1ns / 1ps

module my_testbench;
    reg clk;

    // Clock Generation Block
    initial begin
        clk = 1'b0;          // 1. Initialize the clock to a known value.
        forever #5 clk = ~clk; // 2. Continuously invert the clock every 5 ns.
    end

    // ... rest of the testbench
endmodule

Let's break this down:

  1. clk = 1'b0;: We start the simulation by setting the clock to a known state, typically 0.
  2. forever #5 clk = ~clk;: This is the engine of our clock.
    • forever: Creates an infinite loop.
    • #5: The simulation waits for 5 nanoseconds.
    • clk = ~clk;: The clock signal is inverted (0 becomes 1, 1 becomes 0).
    • The loop then repeats, waiting another 5 ns before inverting the signal again.

The result is a signal that toggles every 5 ns. The time between two rising edges is 10 ns, giving us a clock with a 10 ns period and a 100 MHz frequency.


4. Method 2: The always Block

Another way to achieve the same result is with an always block. When used in a testbench without a sensitivity list (the part in parentheses @( ... )), an always block also executes continuously for the entire simulation, much like an initial-forever construct.

This video from Digi-Key demonstrates this alternative approach.

Introduction to FPGA Part 7 - Verilog Testbenches and Simulation | Digi-Key Electronics

This video shows how to generate a clock using an always block and discusses the practical aspects of calculating delays from a target frequency.

Watch the segment from generating the clock signal. Focus on how an always block with a delay is used to create the periodic toggle.

The code structure for this method is very similar:

`timescale 1ns / 1ps

module my_testbench;
    reg clk;

    // Initialize the clock (important for the 'always' block)
    initial begin
        clk = 1'b0;
    end

    // Clock Generation using an 'always' block
    always #5 clk = ~clk;

    // ... rest of the testbench
endmodule

Both the initial forever and always #delay methods are widely used and produce the same result for clock generation in a testbench. The initial forever style is often preferred as it keeps the entire clock generation logic contained within a single initial block.


5. A Complete Testbench Example

Let's see how this clock generation block fits into the testbench structure you learned previously. The image below shows a complete testbench that generates a clock and a reset signal. The clock generation part uses the always block method.

Verilog Clock Generation in Testbench with Waveform Output
This example shows how `parameter` can be used to define the clock's half-period, making the code more readable. It uses an `initial` block to set the starting value of `clk` and an `always` block to toggle it periodically. The accompanying waveform confirms the behavior.

Here is a consolidated example using our preferred initial forever method. This testbench creates a 100 MHz clock and a simple reset pulse that is active-high for the first 20 ns of the simulation.

`timescale 1ns / 1ps

module top_tb;

    // --- Signal Declarations ---
    reg clk;
    reg reset;
    
    // Connections to the DUT would go here
    // reg  dut_input;
    // wire dut_output;

    // --- DUT Instantiation ---
    /*
    my_design dut (
        .clk(clk),
        .reset(reset),
        ...
    );
    */

    // --- Clock Generation (100 MHz) ---
    initial begin
        clk = 1'b0;
        forever #5 clk = ~clk; // 5ns half-period -> 10ns period -> 100MHz
    end

    // --- Reset Generation ---
    initial begin
        reset = 1'b1; // Assert reset at the beginning



        #20;          // Hold reset for 20 ns
        reset = 1'b0; // De-assert reset
    end

    // --- Stimulus and Simulation Control ---
    initial begin
        // Wait for reset to be over before applying stimulus



        #30; 
        
        // ... Stimulus would be applied here, synchronized to the clock
        



        #200; // Run simulation for a total of 200ns + 30ns
        $finish; // End the simulation
    end

endmodule

This structure provides a robust foundation for testing any sequential design. It establishes the clock, properly resets the DUT, and then provides a window for applying stimulus.


Conclusion

You have now added another essential skill to your Verilog toolkit. Knowing how to generate a clock is fundamental to verifying the sequential circuits that form the backbone of modern digital logic.

Here are the key takeaways from this lesson:

  • A clock signal in a testbench is a non-synthesizable model of a real-world oscillator.
  • The most common way to create a clock is with an initial block containing a forever loop that inverts a reg variable after a fixed delay.
  • The clock's period is twice the delay value used in the loop (e.g., #5 yields a 10 ns period).
  • An always block with a delay can also be used to achieve the same effect.

In our next lesson, we will dive deeper into Verilog's system tasks, such as $display and $monitor. Now that we can generate stimulus and a clock, we need more powerful tools to observe the outputs of our DUT and debug its behavior effectively.