In this article, we will learn to
- Describe the SR-flip flop using the three levels of abstraction – Gate level, dataflow, and behavioral modeling.
- Generate the RTL schematic for the SR flip flop.
- Write the testbench.
- Generate simulated waveforms.
What is an SR flip flop?
Flip Flops are the basic building blocks of sequential circuits. They are memory elements made by connecting logic gates. They can shift between two states (0 and 1) and hence, formally called bi-stable multivibrator.
Did you know calculators and computers use flip flops to store data? Each flip flop can store one bit of data. Thus, a combination of flip flops makes it possible to store a large amount of data.
An SR Flip Flop is short for Set-Reset Flip Flop. It has two inputs S(Set) and R(Reset) and two outputs Q(normal output) and Q'(inverted output).
As we proceed, we will see how to write Verilog code for SR Flip Flop using different levels of abstraction.
Gate Level Modeling
With the assistance of a logic diagram, we will be able to know the essential logic gates needed to build a circuit. Verilog provides us with gate primitives, which help us create a circuit by connecting basic logic gates. Gate level modeling enables us to describe the circuit using these gate primitives.
Given below is the logic diagram of an SR Flip Flop.
From the above circuit, it is clear we need to interconnect four NAND gates in a specific fashion to obtain an SR flip flop. Let’s see how we can do that using the gate-level modeling style.
Gate level Modeling of SR flip flop
First, start with the module declaration. The keyword
module informs the compiler that we are creating a functional block with some inputs and outputs.
module srff_gate(q, qbar, s, r, clk); ... endmodule
In the parenthesis, mention the terminal ports in the logical circuit. Always mention outputs first followed by input since gate primitives use the same format.
Next, declare the input and output ports.
input s,r,clk; output q, qbar;
wire is used to represent the intermediate signals in the logic circuit.
wire nand1_out; // output of nand1 wire nand2_out; // output of nand2
The wait is over!
Time for us to instantiate the gate primitives.
nand (nand1_out,clk,s); //this is the first nand gate described with its output and inputs. In that order. nand (nand2_out,clk,r); nand (q,nand1_out,qbar); nand (qbar,nand2_out,q);
module srff_gate(q, qbar, s, r, clk); input s,r,clk; output q, qbar; wire nand1_out; // output of nand1 wire nand2_out; // output of nand2 nand (nand1_out,clk,s); nand (nand2_out,clk,r); nand (q,nand1_out,qbar); nand (qbar,nand2_out,q); endmodule
Gate level modeling works for circuits having less number of logic gates. But, when the number of logic gates increases, the circuit complexity increases. Hence, it becomes challenging to instantiate a large number of gates and interconnections.
Instead of knowing the logic circuit, we can describe the circuit using its logic expression. For that, we use a higher level of abstraction, which is Dataflow modeling. This style describes how data flows from input to output using logic equations.
Before moving on to the coding part, let’s see the characteristic equation of the SR flip flop:
Q(next) = S +R’Q(previous)
Let’s see how we code in this equation using dataflow modeling.
Dataflow Modeling of SR Flip Flop
Starting with the module declaration and port declaration:
module srff_dataflow(s,r,clk,q,qbar); input s,r,clk; output q, qbar;
Then, we move on to write the continuous assignment using keyword
assign q = clk ? (s + ((~r)&q)) : q; assign qbar = ~q;
Hence, our final code will be:
module srff_dataflow(q,qbar,s,r,clk); input s,r,clk; output q, qbar; assign q = clk? (s + ((~r) & q)) : q; assign qbar = ~q; endmodule
But…there’s a problem. Kudos to you if you’ve caught it.
Flip flops are edge-triggered circuits. When we use a conditional operator, the statement is not executed at the clock edges(HIGH to LOW or LOW to HIGH) but the clock level(HIGH and LOW). Hence, the dataflow model of SR flip flop will work only as a latch. And not as an authentic flip-flop that triggers on clock edges.
Therefore, we prefer the highest level of abstraction (behavioral modeling) for describing sequential circuits.
Behavioral Modeling is the highest level of abstraction in Verilog HDL. We can describe the circuit by just knowing how it works.
Moreover, there’s additional good news! We do not need to know the logic circuit or logic equation. We just need a simple truth table.
Let’s see how we can describe SR flip flop using behavioral modeling. We need to know how SR flip flop behaves, right? Hence let’s go through the truth table.
Using the described behavior, we can now start coding.
Behavioral Modeling of SR Flip Flip
As always, we start with the
module declaration and the port declarations
module srff_behave(s, r, clk, q, qbar); input clk, s, r; output reg q, qbar;
Do you feel like we made a mistake somewhere?
It’s not a mistake. We have to mention output as
reg in behavioral modeling. Since we use procedural assignments in this style of modeling, we have to make sure the outputs retain their value until the next value is given to them.
always@(posedge clk) begin ... end
always keyword makes sure the statements between
end will be executed as soon as the sensitivity list is triggered. Here, we are designing a positive edge-triggered SR Flipflop. The
posedge clk in the sensitivity list will make sure the statements between
end will be executed as soon as the positive edge of the clock is detected.
Now, we describe how we want our flip flop to work. Depending on the values given to S and R, we assign our Q and Q’ output.
always@(posedge clk) begin if(s = 1) begin q <= 1; qbar <= 0; end else if(r = 1) begin q <= 0; qbar <= 1; end else if(s == 0 & r == 0) begin q <= q; qbar = qbar; end end
if-else statements execute the statement depending on the conditions applied. As per above code, depending on the S and R inputs, the statements for Q and Q’ output will be executed.
So our final code will be:
module srff_behave(s,r,clk, q, qbar); input s,r,clk; output reg q, qbar; always@(posedge clk) begin if(s == 1) begin q = 1; qbar = 0; end else if(r == 1) begin q = 0; qbar =1; end else if(s == 0 & r == 0) begin q <= q; qbar <= qbar end end 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.
Ler’s see how we can write the testbench for SR flip flop.
//test bench for d flip flop //1. Declare module and ports module dff_test; reg S,R, CLK; wire Q, QBAR; //2. Instantiate the module we want to test. We have instantiated the srff_behavior srff_behavior dut(.q(Q), .qbar(QBAR), .s(S), .r(R), .clk(CLK)); // instantiation by port name. //3. Monitor TB ports $monitor("simtime = %g, CLK = %b, S = %b, R = %b, Q = %b, QBAR = %b", $time, CLK, S, R, Q, QBAR); //4. apply test vectors initial begin clk=0; forever #10 clk = ~clk; end initial begin S= 1; R= 0; #100; S= 0; R= 1; #100; S= 0; R= 0; #100; S= 1; R=1; end endmodule
Here’s how the RTL schematic will look if we peek into the elaborate design of the behavioral model of SR flip flop.
We can verify the functional correctness of described SR flip-flop by simulation. The simulated waveform of SR flip flop is given below:
I hope you understood the implementation of the SR flip-flop using the various modeling styles in Verilog. For any queries, leave us a comment below.