View Course Path

Verilog code for JK flip-flop – All modeling styles

In this article, we will learn to

What is a JK flip flop?

Flip-flops are fundamental building blocks of sequential circuits. A flip flop can store one bit of data. Hence, it is known as a memory cell. Since they work on the application of a clock signal, they come under the category of synchronous circuits.

The J-K flip-flop is the most versatile of the basic flip flops. The JK flip flop is a gated SR flip-flop with the addition of a clock input circuitry that prevents the illegal or invalid output condition that can occur when both inputs S and R are equal to logic 1. Due to this additional clocked input, a JK flip-flop has four possible input combinations, “logic 1”, “logic 0”, “no change” and “toggle”.

JK flip flop logic symbol
JK flip flop logic symbol

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 help 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 a JK flip flop.

JK flip flop logic circuit
JK flip flop logic circuit

From the above logic circuit, we can see that we need four NAND gates to construct a JK flip flop.

Gate Level Modeling of JK Flip Flop

As always, the module declaration in Verilog is done by listing the terminal ports in the logic circuit.

module jkff_gate(q,qbar,clk,j,k);

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 using the syntax for IO port declaration.

input j,k,clk;
output q,qbar;

Next, we have to declare intermediate signals. These are signals that aren’t terminal ports—for example, the signals outgoing from the nand 1, nand2.
wire nand1_out; // output from nand1
wire nand2_out; // output from nand2

Time for us to write logic gates. We use the gate (<outputs>,<inputs>) format to use the in-built gates in Verilog.

nand(nand1_out, j,clk,qbar);
nand(nand2_out, k,clk,q);
nand(q,qbar,nand1_out);
nand(qbar,q,nand2_out);

and thus the final code will be:

module jkff_gate(q,qbar,clk,j,k);

input j,k,clk;
output q,qbar;

wire nand1_out; // output from nand1
wire nand2_out; // output from nand2

nand(nand1_out, j,clk,qbar);
nand(nand2_out, k,clk,q);
nand(q,qbar,nand1_out);
nand(qbar,q,nand2_out);

endmodule

Dataflow Modeling

Describing a flip flop using dataflow modeling is not applicable. Flip flops are supposed to work on edge-triggered clocks. In dataflow modeling, it is not possible to construct an edge-triggered flip flop. It works more like a latch. 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

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.

CLOCK J K Q Q’ State
Positive edge 0 0 Q Q’ No change
Positive edge 0 1 0 1 Reset
Positive edge 1 0 1 0 Set
Positive edge 1 1 (Qprev)’ Qprev Toggle

Using the described behavior, we can start coding.

Behavioral Modeling of JK Flip Flop

As always, we start with the module declaration and the port declarations

module jkff_behave(clk,j,knq,qbar);

input clk,j,k;
output reg q,qbar;

Wait! Did we mention output as reg? Yes, we did. Why? We define output using the  reg datatype because we use procedural assignments. Therefore, we have to make sure the outputs retain their value until the next value is given to them.

Then we write:

always@(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 JK 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 J and K, we assign our Q and Q’ output.

always@(posedge clk)
begin
  if(k = 0)
   begin
    q <= 0;
    qbar <= 1;
   end
  else if(j = 1)
   begin
    q <= 0;
    qbar <= 0;
   end
  else if(j = 0 & k = 0)
   begin
    q <= q;
    qbar <= qbar;
   end
  else if(j = 1 & k = 1)
   begin
    q <= ~q;
    qbar <= ~qbar;
   end
end

Depending on the conditions applied, the if-else statements execute the statement.  As per above code, depending on the J and K inputs, the statements for Q and Q’ output will be executed.

Hence, our final code be:

module jkff_behave(clk,j,knq,qbar);

input clk,j,k;
output reg q,qbar;

always@(posedge clk)
begin
if(k = 0)
begin
q <= 0;
qbar <= 1;
end
always@(posedge clk)
begin
  if(k = 0)
   begin
    q <= 0;
    qbar <= 1;
   end
  else if(j = 1)
   begin
    q <= 0;
    qbar <= 0;
   end
  else if(j = 0 & k = 0)
   begin
    q <= q;
    qbar <= qbar;
   end
  else if(j = 1 & k = 1)
   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 JK flip flop.

//test bench for JK flip flop
//1. Declare module and ports

module jkff_test;
reg J,K, CLK;
wire Q, QBAR;

//2. Instantiate the module we want to test. We have instantiated the jkff_behavior
jkff_behavior dut(.q(Q), .qbar(QBAR), .j(J), .k(K), .clk(CLK)); // instantiation by port name.

//3. Monitor TB ports
$monitor("simtime = %g, CLK = %b, J = %b, K = %b, Q = %b, QBAR = %b", $time, CLK, J, K, Q, QBAR);

//4. apply test vectors
initial begin
  clk=0;
     forever #10 clk = ~clk;  
end 
initial begin 
 J= 1; K= 0;
 #100; J= 0; K= 1; 
 #100; J= 0; K= 0; 
 #100; J= 1; K=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 the JK-flip flop.

RTL schematic of JK flip flop
RTL schematic of JK 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:

simulated wave of JK flip flop
Simulated wave of JK flip flop

I hope you understood the implementation of the JK flip-flop using the various modeling styles in Verilog. For any queries, leave us a comment below.

One thought on “Verilog code for JK flip-flop – All modeling styles

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.