In this article, we will learn to
- Describe the D-flip flop using the three levels of abstraction – Gate level, Dataflow, and behavioral modeling.
- Generate the RTL schematic for the D flip flop.
- Write the testbench.
- Generate simulated waveforms.
What is D flip flop?
A flip flop can store one bit of data. Hence, it is known as a memory cell. Flip-flops are synchronous circuits since they use a clock signal. Using flip flops, we build complex circuits such as RAMs, Shift Registers, etc.
A D flip-flop stands for data or delay flip-flop. The outputs of this flip-flop are equal to the inputs.
As we proceed, we will see how we can design a D flip flop using different levels of abstraction
Gate level modeling
Gate level modeling uses primitive gates available in Verilog to build circuits. Hence, we need to know the logic diagram of the circuit we want to design.
From the above circuit, we can see that we need four NAND gates and one NOT gate to construct a D-flip flop in gate-level modeling.
Gate level Modeling of D flip flop
As always, the
module is declared listing the terminal ports in the logic circuit.
Note that we declare outputs first followed by inputs since built-in gates also follow the same pattern. Now, let’s declare the input and output ports.
input d,clk; output q, qbar;
wire dbar; //output of not1 wire nand1_out; // output of nand1 wire nand2_out; // output of nand2
Time for us to write logic gates. We use the gate (<outputs>,<inputs>) format to use the in-built gates in Verilog. Using the appropriate instance name makes identifying code errors easier.
not ( dbar,d); nand (nand1_out,clk,d); nand (nand2_out,clk,dbar); nand (q,qbar,nand2_out); nand (qbar,q,nand1_out);
and thus the final code will be:
module d_ff_gate(q,qbar,d,clk); input d,clk; output q, qbar; wire dbar; //output of not1 wire nand1_out; // output of nand1 wire nand2_out; // output of nand2 not ( dbar,d); nand (nand1_out,clk,d); nand (nand2_out,clk,dbar); nand (q,qbar,nand2_out); nand (qbar,q,nand1_out); endmodule
When the number of gates increases, the complexity of the circuit also increases. It is difficult to describe such complex circuits in terms of logic gates. That is when dataflow modeling comes handy.
Dataflow modeling is a higher level of abstraction compared to the gate-level. Instead of instantiating gates, we use the logic expression explaining how the data flows from input to output. Hence, it is much easier to construct complex circuits using this level of abstraction since there is no need to know the actual physical layout.
In dataflow modeling, we use the keyword
assign to describe a design. Let’s see how it works.
Before moving on, we need to know the logic equation. Right?
The characteristic equation of a D flip flop is
Q = D and Q’ = D’
Data Flow Modeling of D flip flop
As usual, we start with declaring the
module and the terminal ports:
module dff_dataflow(d,clk,q,qbar); input d,clk; output q, qbar;
Now, we have to describe the flow of data to the outputs using
assign q = clk?d:q; assign qbar = clk?!d:qbar;
Hence, the final code will be:
module dff_dataflow(d,clk,q,qbar); input d,clk; output q, qbar; assign q = clk?d:q; assign qbar = clk?!d:qbar; endmodule
Did you try to simulate this code?
Does something fishy?
This code works more like a latch than a Flip flop. There is no provision in dataflow modeling to detect clock events like edge trigger. Also, when modeling sequential circuits with dataflow, it can sometimes result in an unpredictable output during a simulation. Hence, we prefer the highest level of abstraction (behavioral modeling) to describe sequential circuits like flip flops.
Behavioral modeling is the highest level of abstraction. Unlike gate and dataflow modeling, behavior modeling does not demand knowing logic circuits or logic equations. As a designer, we just need to know the algorithm (behavior) of how we want the system to work. This type of modeling is simple since it does not involve using complex circuitry. A simple truth table will help us describe the design.
|Positive /Negative edge||0||0||1|
We can summarize the behavior of D-flip flop as follows:
- When a triggering clock edge is detected, Q = D.
- During the rest of the clock cycle, Q holds the previous value.
Behavioral Modeling of D flip flop
Again, starting with the
module and the port declarations:
module dff_behave(d, clk, q, qbar); input d,clk; output reg q, qbar;
Did you notice we have mentioned output datatype as
reg ? It stands for a register that will retain its value till the next value is given to it. We define output as
reg because we use procedural assignments. It holds a value from one procedural assignment statement to the next, which means it holds its value over simulation data cycles.
Then we write:
always@(posedge clk) begin ..... end
What you see in the bracket is the sensitivity list. Here the positive edge of the clock provided will control the statements in between
always keyword will make sure that the statements get executed every time the sensitivity list is triggered.
end, we write the procedure for how the system works:
always@(posedge clk) begin q <= d; qbar <= !d; end
Hence, our final code be:
module dff_behavioral(d,clk,q,qbar); input d, clk; output reg q, qbar; always@(posedge clk) begin q <= d; qbar = !d; end endmodule
Clear Input in Flip flop
All hardware systems should have a pin to clear everything and have a fresh start. It applies to flip flops too. Hence, we will include a clear pin that forces the flip flop to a state where Q = 0 and Q’ = 1 despite whatever input we provide at the D input. This clear input becomes handy when we tie up multiple flip flops to build counters, shift registers, etc.
Behavioral Modeling of D flip flop with Synchronous Clear
For synchronous clear, the output will reset at the triggered edge(positive edge in this case) of the clock after the clear input is activated.
Here’s the code:
module dff_behavioral(d,clk,clear,q,qbar); input d, clk, clear; output reg q, qbar; always@(posedge clk) begin if(clear== 1) q <= 0; qbar <= 1; else q <= d; qbar = !d; end endmodule
Behavioral Modeling of D flip flop with Asynchronous Clear
For asynchronous clear, the clear signal is independent of the clock. Here, as soon as clear input is activated, the output reset.
This can be achieved by adding a clear signal to the sensitivity list. Hence we write our code as:
module dff_behavioral(d,clk,clear,q,qbar); input d, clk, clear; output reg q, qbar; always@(posedge clk or posedge clear) begin if(clear== 1) q <= 0; qbar <= 1; else q <= d; qbar = !d; end endmodule
Like in Gate level modeling, we analyze the logic design for structural modeling. We will consider the gates required to build the design. But, instead of using in-built gates, we take each gate and create separate modules that will be integrated to form the whole circuitry.
In the case of D-flip flop, we have a NOT and four NAND gates that build the circuit.
Hence, we have to structurize each gate with their respective
Structural Modeling of D flip flop
To start with code, we will first structurize the NAND gate.
We declare the
module as nand_gate. The input and output ports are then declared.
module nand_gate(c,a,b); input a,b; output c;
Then, we use
assign statement to write the logical expression for NAND.
assign c= ~(a & b);
endmodule keyword is used for representing the end of the module.
Similarly, we do for NOT gate
module not_gate(f,e); input e; output f; assign f = ~e; endmodule
Now, we have to integrate these lower modules to form our D-flip flop. In order to do that, we use module instantiation. First, start with the name of the lower hierarchy module (defined and declared above) and write the name of the instance of your choice. The port-list will contain the output signals, followed by the input ones.
- module-name :- nand_gate
- instance name:- nand1
- output port:- x(intermediate signal)
- input ports:- d and clk
Do the same for the rest of the instances
not_gate not1(dbar,d); nand_gate nand1(x,clk,d); nand_gate nand2(y,clk,dbar); nand_gate nand3(q,qbar,y); nand_gate nand4(qbar,q,x); endmodule
Hence, the final structure code will be:
module nand_gate(c,a,b); input a,b; output c; assign c = ~(a&b); endmodule module not_gate(f,e); input e; output f; assign f= ~e; endmodule module d_ff_struct(q,qbar,d,clk); input d,clk; output q, qbar; not_gate not1(dbar,d); nand_gate nand1(x,clk,d); nand_gate nand2(y,clk,dbar); nand_gate nand3(q,qbar,y); nand_gate nand4(qbar,q,x); endmodule
A testbench is an HDL module that is used to test another module, called the device under test (DUT). The test bench contains statements to apply inputs to the DUT and, ideally, to check that the correct outputs are produced. The input and desired output patterns are called test vectors.
Let’s see how we can write a test bench for D-flip flop by following step by step instruction
//test bench for d flip flop //1. Declare module and ports module dff_test; reg D, CLK,reset; wire Q, QBAR; //2. Instantiate the module we want to test. We have instantiated the dff_behavior dff_behavior dut(.q(Q), .qbar(QBAR), .clear(reset), .d(D), .clk(CLK)); // instantiation by port name. //3. Monitor TB ports $monitor("simtime = %g, CLK = %b, D = %b,reset = %b, Q = %b, QBAR = %b", $time, CLK, D, reset, Q, QBAR); //4. apply test vectors initial begin clk=0; forever #10 clk = ~clk; end initial begin reset=1; D <= 0; #100; reset=0; D <= 1; #100; D <= 0; #100; D <= 1; end endmodule
Here’s how the RTL Schematic will look if we peek into the elaborate design of the behavioral model of the D-flip flop without clear input.
With synchronous clear input,
And with asynchronous clear input,
D flip flop Without Reset
In this waveform, we can see that the Q and Q’ will be reset state at the positive cycle after clear is activated
In this waveform, we can see that the Q and Q’ will be in the reset state as soon as clear is activated.
I hope you understood the implementation of a D flip-flop using the various modeling styles in Verilog. For any queries, leave us a comment below.