View Course Path

# Verilog code for SR flip-flop – All modeling styles

• 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.

Contents

## 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;

```

The keyword `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);

```

Final code:

```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```

## Dataflow Modeling

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`

```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

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.

 CLOCK EDGE S R Q Q’ State Positive/Negative 0 0 Q Q’ No change Positive/Negative 0 1 0 1 Reset State Positive/Negative 1 0 1 0 Set State Positive/Negative 1 1 X X Invalid

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.

Moving on,

```[email protected](posedge clk)
begin
...
end```

The `always` keyword makes sure the statements between `begin` and `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 `begin` and `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.

```[email protected](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```

The `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;

[email protected](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

```

## Testbench

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```

## RTL Schematic

Here’s how the RTL schematic will look if we peek into the elaborate design of the behavioral model of SR flip flop.

## Simulated Waveform

We can verify the functional correctness of described SR flip-flop by simulation. The simulated waveform of SR flip flop is given below: