A flip-flop is an edge-triggered memory circuit. In this project, we will implement a flip-flop behaviorally using Verilog®, and use a bunch of flip-flops to implement a clock divider that blinks the LEDs.
Qty | Description |
---|---|
1 | Digilent® Nexys™4, Nexys™3, Nexys™2, or Basys™2 FPGA Board |
1 | Xilinx ISE Design Suite: WebPACK (14.6 Recommended) |
1 | Digilent Adept |
A D flip-flop (D-FF) is one of the most fundamental memory devices. A D-FF typically has three inputs: a data input that defines the next state, a timing control input that tells the flip-flop exactly when to “memorize” the data input, and a reset input that can cause the memory to be reset to '0' regardless of the other two inputs (usually referred as asynchronous reset). Figure 1 below displays the block diagram for a D-FF.
In this step, we are going to implement a D-FF with asynchronous reset.
module dff(
input D,
input clk,
input rst,
output Q
);
always @ (posedge(clk), posedge(rst))
begin
if (rst == 1)
Q <= 1'b0;
else
Q <= D;
end
`timescale 1ns / 1ps
module dff(
input D,
input clk,
input rst,
output Q
);
always @ (posedge(clk), posedge(rst))
begin
if (rst == 1)
Q <= 1'b0;
else
Q <= D;
end
endmodule
A clock signal is needed in order for sequential circuits to function. Usually the clock signal comes from a crystal oscillator on-board. The oscillator used on Digilent FPGA boards usually ranges from 50 MHz to 100 MHz. However, some peripheral controllers do not need such a high frequency to operate.
There is a simple circuit that can divide the clock frequency by half. The circuit is shown in Fig. 2 below.
Assume clkdiv is high initially. As din inverts the signal clkdiv, din is initially low. When the first rising edge of clock arrives, clkdiv is updated by the current din value and changes to '0'. As soon as clkdiv changes to '0', din will be pulled up to logic '1' by the inverter. When the next rising edge of clk occurs, clkdiv will change to logic '1' and din will change back to '0' after the propagation delay of the inverter. The waveform of the circuit in Fig. 2 above is shown on the right. As a result, the period of clkdiv (the time between two adjacent rising edges) doubles the period of clk (i.e., the frequency of clkdiv is half of the clk frequency).
With this circuit, we can actually divide the clock by cascading the previous circuit, as displayed in Fig. 3 below.
Each stage divided the frequency by 2. Suppose that the input clock frequency to the first stage is 100 MHz (1,000,000Hz). After the first stage, the frequency became $\frac{100MHz}{2} = 50MHz$. After the second stage, the frequency became $\frac{100MHz}{2\cdot 2} = 25MHz$. After n stage, the frequency became: \[\frac{100MHz}{\underbrace{2\cdot 2 \cdot \ldots \cdot 2}_\text{n}} = \frac{100,000,000}{2^n}Hz\]
The block diagram of the clock divider is shown in Fig. 4. We name the internal wire out of the flip-flop clkdiv and the wire connecting to the input of D-FF din. The frequency of each clkdiv is shown in red.
module clk_divider(
input clk,
input rst,
output led
);
wire [26:0] din;
wire [26:0] clkdiv;
dff dff_inst0 (
.clk(clk),
.rst(rst),
.D(din[0]),
.Q(clkdiv[0])
);
genvar i;
generate
for (i = 1; i < 27; i=i+1)
begin : dff_gen_label
dff dff_inst (
.clk(clkdiv[i-1]),
.rst(rst),
.D(din[i]),
.Q(clkdiv[i])
);
end
endgenerate;
assign din = ~clkdiv;
assign led = clkdiv[26];
`timescale 1ns / 1ps
module clk_divider(
input clk,
input rst,
output led
);
wire [26:0] din;
wire [26:0] clkdiv;
dff dff_inst0 (
.clk(clk),
.rst(rst),
.D(din[0]),
.Q(clkdiv[0])
);
genvar i;
generate
for (i = 1; i < 27; i=i+1)
begin : dff_gen_label
dff dff_inst (
.clk(clkdiv[i-1]),
.rst(rst),
.D(din[i]),
.Q(clkdiv[i])
);
end
endgenerate;
assign din = ~clkdiv;
assign led = clkdiv[26];
endmodule
As with the combinational circuit we have designed in previous projects, you can draft a test bench to test the circuit out before implementing it on-chip. However, in this test bench, we need to emulate the clock signal and the rst signal. The clock signal is actually a constantly oscillating signal. Using the Nexys3 as an example, the input clock frequency is 100 MHz, i.e., the period of the clock is 10 ns. Half of the period the clock is high, half of the period clock is low. In other words, every half of the period, 5 ns in this case, the clock will flip itself. To simulate the clock signal, instead of putting it in the initialize statement, we will use an always statement.
`timescale 1ns / 1ps
...
reg clk;
always
#5 clk = ~clk;
In the initialize block, we will initialize clk signal to 0 and hold rst high for 10ns to reset the clock divider. So, the Verilog Test Bench will look like this:
`timescale 1ns / 1ps
module tb;
// Inputs
reg clk;
reg rst;
// Outputs
wire led;
// Instantiate the Unit Under Test (UUT)
clk_divider uut (
.clk(clk),
.rst(rst),
.led(led)
);
always
#5 clk = ~clk;
initial begin
// Initialize Inputs
clk = 0;
rst = 1;
#10 rst = 0;
// Wait 100 ns for global reset to finish
#100;
end
endmodule
The simulated waveform is shown in Fig. 5 below. You can see in the waveform that clkdiv[0] is half of the frequency of clk, and that clkdiv[1] is half of the frequency of clkdiv[2].
Now you can create a UCF file that maps clk to the global clock on board, rst to a push button, and led to an on-board LED. If your board has a 100 MHz clock, you can see that the LED blinks once every 1.45 seconds.
Now that you've completed this project, try these modifications: