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 case statement
  • 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:

jkq (next)Operation
00qHold
010Reset
101Set
11~qToggle

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 which q may change (required)
  • {j, k} - Concatenation with j as the upper bit, so 2'b10 means j = 1, k = 0 (required); see Verilog Concatenation
  • 2'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

Synthesized schematic of a JK flip-flop: a D flip-flop with feedback logic computing the next value from j, k and q

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:

TargetConnectionWhy it works
T flip-flopj = t, k = tt = 0 gives hold (00), t = 1 gives toggle (11)
D flip-flopj = d, k = ~dd = 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 case on {j, k} maps the truth table directly into code, with j as the upper bit
  • Synthesis builds it from a D flip-flop with feedback logic, since there is no JK cell
  • Tying j = k = t gives a T flip-flop, and j = d, k = ~d gives a D flip-flop
  • Without a reset, q starts as x until a set or reset is applied
  • A self-checking testbench with inputs changed on the falling edge verifies all four operations
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5