In this article, we will learn to
- Describe the JK-flip flop using the three levels of abstraction – Gate level, Dataflow, and behavioral modeling.
- Generate the RTL schematic for the JK flip flop.
- Write the testbench.
- Generate simulated waveforms.
Contents
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”.
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.
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;
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
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 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.
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:
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.