A JK flip-flop is an edge-triggered storage element with two control inputs: j sets the output, k resets it, both low holds it, and both high toggles it. In Verilog, you write it as a clocked always block with a case statement on {j, k}.
10 min read | Beginner Level
What You'll Learn
- The four JK operations (hold, reset, set, toggle) and the characteristic equation
- Write a JK flip-flop in Verilog using a
casestatement - What synthesis builds from it, and how JK relates to D, T and SR flip-flops
- Verify all four operations with a self-checking testbench
What is a JK Flip-Flop?
A JK flip-flop has a clock (clk), two inputs (j and k) and an output (q). At each rising edge of clk, the pair {j, k} selects one of four operations:
| j | k | q (next) | Operation |
|---|---|---|---|
| 0 | 0 | q | Hold |
| 0 | 1 | 0 | Reset |
| 1 | 0 | 1 | Set |
| 1 | 1 | ~q | Toggle |
Writing the table as a sum of products gives the characteristic equation:
q(next) = (j & ~q) | (~k & q)
Read it as two cases. When q is 0, the next value is j. When q is 1, the next value is ~k. Between clock edges, q holds its value no matter how j and k change.
A JK flip-flop is an SR flip-flop with the forbidden state removed. On an SR flip-flop, S = R = 1 is invalid; on a JK flip-flop, j = k = 1 is defined as toggle. This makes JK a general-purpose element that can act as a D or T flip-flop with simple input wiring.
Syntax
Basic Form:
always @(posedge clk)
case ({j, k}) // Concatenate j and k into a 2-bit selector
2'b00 : q <= q; // Hold
2'b01 : q <= 1'b0; // Reset
2'b10 : q <= 1'b1; // Set
2'b11 : q <= ~q; // Toggle
endcase
Components:
posedge clk- Clock edge at whichqmay change (required){j, k}- Concatenation withjas the upper bit, so2'b10means j = 1, k = 0 (required); see Verilog Concatenation2'b11 : q <= ~q- The toggle case that distinguishes JK from SR (required)
Variations:
// 1. Equation form: same hardware, written from the characteristic equation
always @(posedge clk)
q <= (j & ~q) | (~k & q);
// 2. With active-low asynchronous reset
always @(posedge clk or negedge rstn)
if (!rstn) q <= 1'b0;
else
case ({j, k})
2'b01 : q <= 1'b0;
2'b10 : q <= 1'b1;
2'b11 : q <= ~q;
default: ; // 2'b00: hold, q keeps its value
endcase
Design
The case statement maps directly to the truth table, which makes the code easy to check against the specification. See Verilog case statement for the statement itself.
module jk_ff (
input j, // Set input
input k, // Reset input
input clk, // Clock
output reg q // Flip-flop output
);
// Evaluate j and k only at the rising clock edge
always @(posedge clk)
case ({j, k})
2'b00 : q <= q; // Hold: keep the current value
2'b01 : q <= 1'b0; // Reset: force q to 0
2'b10 : q <= 1'b1; // Set: force q to 1
2'b11 : q <= ~q; // Toggle: invert the current value
endcase
endmodule
Synthesis result: Modern standard cell libraries and FPGA fabrics have no JK flip-flop cell. Synthesis builds one from a D flip-flop with a small block of logic in front of its D input that implements the characteristic equation, D = (j & ~q) | (~k & q). The output q feeds back into that logic. On an FPGA, the three-input function (j, k, q) fits in a single LUT.
Hardware Schematic

Quick Check
Q: q is 1, and j = k = 1 for three rising clock edges. What is q after each edge?
Show Answer
0, 1, 0. With both inputs high, the flip-flop toggles on every edge.
JK as a Universal Flip-Flop
Because the JK flip-flop has all four operations, other flip-flop types can be built from it by wiring its inputs:
| Target | Connection | Why it works |
|---|---|---|
| T flip-flop | j = t, k = t | t = 0 gives hold (00), t = 1 gives toggle (11) |
| D flip-flop | j = d, k = ~d | d = 0 gives reset (01), d = 1 gives set (10) |
See Verilog T Flip Flop for the toggle-only version.
Where is JK Behavior Used?
Set, clear and hold is the behavior of a status flag in a control block. An interrupt-pending bit is a typical example: a hardware event sets it, a software acknowledge clears it, and it holds in between. In RTL this is written directly as if (event) flag <= 1; else if (ack) flag <= 0;, and synthesis builds a D flip-flop with the same kind of feedback logic a JK flip-flop needs.
JK Flip-Flops in Discrete Logic
JK flip-flops were the standard building block of counters and sequencers in discrete 74-series TTL and CMOS logic, where each package held one or two flip-flops. The toggle mode with j = k = 1 made binary counters and frequency dividers easy to wire by hand. Engineers still meet them when reading legacy schematics or converting board-level designs into HDL.
Testbench
This testbench is self-checking. It applies a sequence of {j, k} pairs that covers all four operations, and after each rising edge it compares q with a simple reference model. Inputs change on the falling edge, so they are stable well before the rising edge that samples them. See Verilog Testbench for testbench structure.
module tb_jk;
reg clk;
reg j, k;
wire q;
reg exp_q; // Expected q from the reference model
reg [1:0] jk_seq [0:7]; // {j, k} pairs to apply, in order
integer i, errors;
jk_ff u0 (.j(j), .k(k), .clk(clk), .q(q));
// Clock: period of 10, rising edges at 5, 15, 25, ...
always #5 clk = ~clk;
initial begin
// Stimulus sequence: start with reset, since q is x until set or reset
jk_seq[0] = 2'b01; // Reset: q -> 0
jk_seq[1] = 2'b00; // Hold: q stays 0
jk_seq[2] = 2'b10; // Set: q -> 1
jk_seq[3] = 2'b00; // Hold: q stays 1
jk_seq[4] = 2'b11; // Toggle: q -> 0
jk_seq[5] = 2'b11; // Toggle: q -> 1
jk_seq[6] = 2'b01; // Reset: q -> 0
jk_seq[7] = 2'b11; // Toggle: q -> 1
clk = 0; // Initialize clk, or ~x stays x and no edge ever occurs
{j, k} = 2'b00;
errors = 0;
exp_q = 1'bx;
for (i = 0; i < 8; i = i + 1) begin
@(negedge clk); // Change inputs away from the rising edge
{j, k} = jk_seq[i];
@(posedge clk); // Flip-flop samples j and k here
#1; // Let q update before checking
// Reference model, written as a lookup instead of the equation
case ({j, k})
2'b00 : exp_q = exp_q;
2'b01 : exp_q = 1'b0;
2'b10 : exp_q = 1'b1;
2'b11 : exp_q = ~exp_q;
endcase
$display("[%0t] j=%b k=%b q=%b", $time, j, k, q);
if (q !== exp_q) begin
$display(" ERROR: expected q=%b", exp_q);
errors = errors + 1;
end
end
if (errors == 0) $display("PASS: all JK operations correct");
else $display("FAIL: %0d mismatches", errors);
$finish;
end
endmodule
Each line of output is printed 1 time unit after a rising edge: at 16, 26, 36, and so on. With a correct design, q follows the sequence 0, 0, 1, 1, 0, 1, 0, 1, and the run ends with a PASS line.
Quick Check
Q: Why does the testbench start with {j, k} = 2'b01 instead of hold or toggle?
Show Answer
The design has no reset, so q starts as x. Hold keeps x, and toggle inverts x into x. Only set or reset drives a known value, so the first operation must be one of them.
Common Beginner Mistakes
Mistake #1: Swapping the order of j and k in the concatenation
Wrong: case ({k, j}) with the same case items
Right: case ({j, k})
Why? The leftmost signal in a concatenation is the most significant bit. With {k, j}, the item 2'b10 means k = 1, j = 0, so set and reset are swapped. The code compiles cleanly and hold and toggle still work, so the bug appears only when you test set and reset.
Mistake #2: Treating j = k = 1 as invalid
Wrong: A case with only 2'b00, 2'b01 and 2'b10 items
Right: Include 2'b11 : q <= ~q;
Why? In a clocked block, an unassigned q holds its value, so j = k = 1 behaves like hold. That is SR-style behavior with the invalid input ignored, not a JK flip-flop. The toggle case is what defines JK.
Mistake #3: Expecting q to start at 0
Wrong: Applying hold or toggle first and expecting a known output
Right: Add a reset input, or apply set or reset before anything else
Why? A reg starts as x in simulation. Hold keeps it x and toggle turns x into x. Only set (10) or reset (01) assigns a known constant. Real designs add a reset input, as shown in the Syntax variations, so the flip-flop always starts in a known state.
Mistake #4: Driving j and k on the rising clock edge
Wrong: @(posedge clk) j = 1; in the testbench
Right: @(negedge clk) j = 1;, or use non-blocking assignments for testbench inputs
Why? If the testbench changes j with a blocking assignment in the same time step as the rising edge, the flip-flop may see either the old or the new value, depending on the order in which the simulator runs the two blocks. Changing inputs on the falling edge keeps them clear of the sampling edge.
Practice Exercise
Challenge: Add an Asynchronous Reset
Write a module jk_ff_rst with the same ports as jk_ff plus an active-low asynchronous reset rstn. When rstn is 0, q must clear immediately. Otherwise, it behaves as a JK flip-flop.
Hint
Add negedge rstn to the sensitivity list, check !rstn first, and put the existing case in the else branch. See D Flip-Flop Async Reset for the reset template.
Solution
module jk_ff_rst (
input j,
input k,
input clk,
input rstn, // Active-low asynchronous reset
output reg q
);
always @(posedge clk or negedge rstn)
if (!rstn) // Reset first, without waiting for clk
q <= 1'b0;
else
case ({j, k})
2'b00 : q <= q; // Hold
2'b01 : q <= 1'b0; // Reset
2'b10 : q <= 1'b1; // Set
2'b11 : q <= ~q; // Toggle
endcase
endmodule
Synthesis builds a D flip-flop with an asynchronous clear pin driven by rstn, plus the same JK feedback logic in front of D. With a reset, the testbench no longer needs to start with {j, k} = 2'b01.
Summary
In this tutorial, you learned:
- A JK flip-flop holds (00), resets (01), sets (10) or toggles (11) at each rising clock edge
- Its characteristic equation is
q(next) = (j & ~q) | (~k & q) - A
caseon{j, k}maps the truth table directly into code, withjas the upper bit - Synthesis builds it from a D flip-flop with feedback logic, since there is no JK cell
- Tying
j = k = tgives a T flip-flop, andj = d, k = ~dgives a D flip-flop - Without a reset,
qstarts as x until a set or reset is applied - A self-checking testbench with inputs changed on the falling edge verifies all four operations