Hi there my name is Praful! Today, I’m excited to share with you a glimpse into a project I’ve been working on—a clock divider module written in Verilog. If you’re not familiar with digital design or Verilog, you might wonder what exactly that means. Well, I’m here to explain it in a way that’s easy to understand, highlighting why it’s so fascinating and important.
The Essence of Clock Signals in Digital Systems
In the digital world, a clock signal acts like the pulse for electronic systems, coordinating the operations of its components. But sometimes, different parts of a system need to operate at slower speeds than the main clock signal. That’s where a clock divider comes in—it takes the main clock signal and produces slower versions of it.
A clock signal serves as the heart of synchronous systems, orchestrating the timing of all operations. However, different parts of a system often require clock signals at lower frequencies than the main clock. This necessitates the use of clock dividers, which generate multiple clock signals, each with a frequency that is a fraction of the input clock signal.
Here is the Step by step guide through the code explaining each and every step
Let’s dive into the heart of the clock divider module I’ve developed. The module takes one input, the main clock signal, and generates six outputs, each a divided-down version of the input clock. The outputs are aptly named f2
, f4
, f8
, f16
, f32
, and f64
, indicating how much slower they are compared to the input clock.
Here’s the core part of the module:
module clock_divider(input clk, output reg f2, f4, f8, f16, f32, f64);
This line defines our module with its input and outputs. Inside, we use a special counter that keeps track of the input clock’s cycles. As this counter increases with each clock pulse, it controls when each output toggles, creating the divided clock signals. It’s like a metronome that can be set to tick at different speeds based on how we program it.
reg [5:0] count = 0;
A 6-bit register count
is defined to keep track of the clock cycles. It’s initialized to 0 and serves as the backbone for dividing the clock by toggling its bits.
always @(posedge clk) begin
This block executes on every positive edge of the input clock, ensuring that the division is synchronous with the clock’s rising edge, a critical aspect for maintaining temporal accuracy in digital circuits.
count <= count + 1;
f2 <= count[0];
f4 <= count[1];
f8 <= count[2];
f16 <= count[3];
f32 <= count[4];
f64 <= count[5];
Within the always block, the count is incremented by one on each clock’s positive edge. The least significant bit (LSB) of count
toggles every clock cycle, effectively creating a clock signal with half the frequency of the input clock (f2
). Similarly, the subsequent bits generate f4
, f8
, f16
, f32
, and f64
, each dividing the clock frequency by increasing powers of two.
end
endmodule
Finally we are ending the initial block and the module
Below is the Complete code for clock divider Design under Test
// Clock Divider Code by Praful Kharade
// Logicflick.com
module clock_divider(input clk,
output reg f2, f4, f8, f16, f32, f64);
reg [5:0] count = 0;
always @(posedge clk) begin
count <= count + 1;
f2 <= count[0];
f4 <= count[1];
f8 <= count[2];
f16 <= count[3];
f32 <= count[4];
f64 <= count[5];
end
endmodule
If you want to Directly Run the code on EDA Playground you can do that by clicking the button below
Test bench
Imagine you’ve just finished designing a sophisticated digital clock that can divide a single clock signal into multiple, slower signals. How do you make sure it works? This is where a testbench comes into play. It’s a virtual environment where we can simulate our design, feeding it inputs and examining the outputs without ever needing to build it physically. Think of it as a digital proving ground for your designs.
Module Declaration: The testbench itself is declared as a module named tb_freq
. In Verilog, both designs and testbenches are modules, but the latter is used purely for simulation purposes.
module tb_freq;
Signal Declaration: Within this module, clk
is declared as a reg
type because we need to control it manually to simulate an input clock. The divided clock outputs (f2
, f4
, f8
, f16
, f32
) are declared as wire
types since they will be driven by the clock divider module we are testing.
reg clk;
wire f2, f4, f8, f16, f32;
Clock Divider Instance: This part of the code connects our testbench to the clock divider module (clock_divider
) we aim to test. We map the clk
signal to the clock input of the divider and the f2
to f32
signals to its outputs, effectively creating a test scenario for our module.
clock_divider instance1(.clk(clk), .f2(f2), .f4(f4), .f8(f8), .f16(f16), .f32(f32), .f64(f64));
Clock Simulation: The always
block is where we simulate the ticking of the clock. By toggling clk
every 5 simulation time units, we mimic the rising and falling edges of a real clock signal.
always #5 clk = ~clk;
Initial Block: The initial
block sets the initial conditions of the simulation and defines its duration. We start by setting clk
to 0, run the simulation for 400 time units, then end the simulation. This block also includes commands to generate a waveform (dump.vcd
) that we can analyze to visually verify our clock divider’s behavior.
initial begin
$dumpfile("dump.vcd");
$dumpvars(1);
clk = 0;
#400;
$finish;
end
Here is the complete Test bench code for Clock Divider
// Code by Praful Kharade
// Logicflick.com
module tb_freq;
reg clk;
wire f2, f4, f8, f16, f32;
clock_divider instance1(.clk(clk),
.f2(f2),
.f4(f4),
.f8(f8),
.f16(f16),
.f32(f32),
.f64(f64)
);
always #5 clk = ~clk;
initial
begin
$dumpfile("dump.vcd");
$dumpvars(1);
clk =0;
#400;
$finish;
end
endmodule
Output waveform of Clock Divider circuit
The Significance of the Testbench
Why go through all this trouble? Well, in the absence of a testbench, we’d have no straightforward way to verify the functionality of our design without physically building it—a process that’s both time-consuming and potentially costly. With a testbench, we can catch errors early, iterate quickly, and gain confidence in our design before it ever makes its way into a physical device.
To sum up
Walking through this testbench has hopefully demystified some aspects of digital verification and illustrated the critical role it plays in the design process. Whether you’re a seasoned engineer or new to digital design, understanding how to effectively use testbenches is a crucial skill in the toolkit of anyone working with digital circuits.
I’m an electrical engineer and chip designer pursuing a Master’s in Electrical Engineering at The University of Texas at Dallas. Passionate about digital design, I created Logic Flick to simplify complex concepts in Verilog, SystemVerilog, and UVM. Join me on this electrifying journey as we explore the world of digital electronics together!