JK flip-flops

JKFLIPFLOPALGO
The JK Flip-Flop, Fully Traced: Theory, Truth Tables & Code
Digital Electronics · Sequential Logic

The JK Flip-Flop, Fully Traced

A ground-up walkthrough of the most versatile 1-bit memory element in digital design — the logic behind it, its truth and excitation tables, a NAND-gate schematic, and working algorithms in pseudocode, Python, C, and Verilog.

INPUTS J, K, CLK OUTPUTS Q, Q' FAMILY Sequential / Edge-triggered READ TIME ~10 min

01 · Foundations

What a Flip-Flop Actually Does

A flip-flop is a bistable circuit — it can sit in exactly one of two stable states, 0 or 1, and it holds that state until it's told to change. That "holding" behavior is what gives digital circuits memory. Chain enough flip-flops together and you get registers, counters, and eventually entire processors.

The JK flip-flop is often introduced as the "fixed" version of the SR (Set-Reset) latch. An SR latch has one dangerous blind spot: if both S and R are driven to 1 at the same time, the output becomes undefined. The JK flip-flop closes that gap — when both its inputs J and K are 1, instead of an invalid state, the output simply toggles. That one design decision is why the JK flip-flop shows up everywhere from counters to shift registers.

02 · Schematic

Logic Symbol & NAND-Gate Implementation

Below is a classic NAND-based JK flip-flop built from a cross-coupled latch with two feedback lines — Q and Q' are routed back into the input gates. This feedback is exactly what lets the circuit "remember" its last state and is the mechanism behind the toggle behavior.

fig 1 — nand-gate jk flip-flopschematic view
J K CLK G1 G2 G3 G4 Q Q' Q' fed back into G1 Q fed back into G2
Why feedback matters: Gate G1 receives J, CLK, and Q' as inputs. Gate G2 receives K, CLK, and Q. This cross-coupling is precisely what produces the toggle behavior when J = K = 1 — the circuit's own current state decides which side switches next.

03 · Behavior

Truth Table

Qâ‚™ is the present state (before the clock edge) and Qâ‚™₊₁ is the next state (after the clock edge).

truth_table.jk — clocked behavior
JKQâ‚™Qâ‚™₊₁Action
0000HOLD
0011HOLD
0100RESET
0110RESET
1001SET
1011SET
1101TOGGLE
1110TOGGLE

Characteristic Equation

The entire table above collapses into one Boolean expression, which is what you'd actually implement in code or use for state-machine analysis:

Qn+1 = J·Q'n + K'·Qn

Excitation Table

Useful in reverse — when designing a sequential circuit, this tells you what J and K must be set to, to move from a known Qâ‚™ to a desired Qâ‚™₊₁.

excitation_table.jk — design lookup
Qâ‚™Qâ‚™₊₁JK
000X
011X
10X1
11X0

X = don't care — either 0 or 1 works for that transition.

04 · Design Caveat

The Race-Around Condition

A plain level-triggered JK flip-flop has a flaw: if J = K = 1 and the clock stays high for longer than the gate propagation delay, the output can toggle repeatedly within a single clock pulse — an unpredictable oscillation called the race-around condition.

The standard fix is the master-slave JK flip-flop: two JK stages in series, with the master driven by the clock and the slave by its complement. The master captures the input while the clock is high; the slave only updates once the clock goes low, so the output changes at most once per clock cycle. Nearly every JK flip-flop used in real designs today is a master-slave or edge-triggered variant for exactly this reason.

Rule of thumb: in modern designs, always assume "JK flip-flop" means edge-triggered (or master-slave) unless stated otherwise — pure level-triggered JK latches are a teaching tool, not something you'd tape out.

05 · Algorithm

Generalized Algorithm

Whether you're modeling this in software, HDL, or a microcontroller-driven simulation, the logic reduces to a simple decision procedure evaluated on every active clock edge:

algorithm.pseudo
BEGIN JK_FlipFlop(J, K, Q_current)
    // Executes once per active clock edge
    IF J == 0 AND K == 0 THEN
        Q_next = Q_current              // HOLD
    ELSE IF J == 0 AND K == 1 THEN
        Q_next = 0                        // RESET
    ELSE IF J == 1 AND K == 0 THEN
        Q_next = 1                        // SET
    ELSE IF J == 1 AND K == 1 THEN
        Q_next = NOT Q_current          // TOGGLE
    END IF

    RETURN Q_next, NOT Q_next   // Q, Q'
END

06 · Implementation

Python Simulation

A small class-based simulator you can drop into a notebook to step through clock pulses and print state transitions:

jk_flip_flop.py
class JKFlipFlop:
    def __init__(self, initial_state=0):
        self.Q = initial_state

    def clock_edge(self, J, K):
        """Evaluate one active clock edge and update state."""
        if J == 0 and K == 0:
            pass                       # hold
        elif J == 0 and K == 1:
            self.Q = 0                  # reset
        elif J == 1 and K == 0:
            self.Q = 1                  # set
        elif J == 1 and K == 1:
            self.Q = 1 - self.Q          # toggle
        return self.Q, 1 - self.Q

# --- demo: step through a sequence of (J, K) inputs ---
ff = JKFlipFlop()
sequence = [(0,0), (1,0), (0,0), (1,1), (1,1), (0,1)]

for i, (J, K) in enumerate(sequence):
    Q, Qn = ff.clock_edge(J, K)
    print(f"clk{i}: J={J} K={K} -> Q={Q} Q'={Qn}")
Try it yourself: feed the sequence [(1,1)] * 5 through this class and watch Q alternate on every call — that's the toggle behavior driving binary counters in hardware.

C Implementation (Embedded / Firmware Style)

For microcontroller or bit-level simulation work, here's the same logic in C using bitwise operations:

jk_flip_flop.c
#include <stdio.h>

typedef struct {
    unsigned char Q;
} JKFlipFlop;

void clock_edge(JKFlipFlop *ff, unsigned char J, unsigned char K) {
    if (!J && !K) {
        /* hold: Q unchanged */
    } else if (!J && K) {
        ff->Q = 0;               /* reset */
    } else if (J && !K) {
        ff->Q = 1;               /* set */
    } else {
        ff->Q = !ff->Q;            /* toggle */
    }
}

int main(void) {
    JKFlipFlop ff = { 0 };
    unsigned char J_in[] = {0,1,0,1,1,0};
    unsigned char K_in[] = {0,0,0,1,1,1};

    for (int i = 0; i < 6; i++) {
        clock_edge(&ff, J_in[i], K_in[i]);
        printf("clk%d: J=%d K=%d -> Q=%d\n", i, J_in[i], K_in[i], ff.Q);
    }
    return 0;
}

Verilog (Hardware Description)

And finally, the version you'd actually synthesize onto an FPGA — an edge-triggered, master-slave-equivalent JK flip-flop with asynchronous reset:

jk_flip_flop.v
module jk_flip_flop (
    input  wire clk,
    input  wire rst_n,   // active-low async reset
    input  wire J,
    input  wire K,
    output reg  Q,
    output wire Qn
);

    assign Qn = ~Q;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            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
    end

endmodule
Why posedge clk: synthesizing to a real edge-triggered flip-flop (rather than a level-sensitive latch) is exactly what eliminates the race-around problem discussed above — the output can only change once, at the rising clock edge.

07 · Where It's Used

Real Applications

  • Binary counters — tie J = K = 1 and every clock pulse toggles Q, producing a divide-by-2 frequency output; cascade stages for divide-by-N counters.
  • Shift registers — chains of JK flip-flops move data one bit per clock cycle, used in serial-to-parallel conversion.
  • Frequency dividers — the toggle mode alone is the simplest way to halve a clock frequency in hardware.
  • Finite state machines — the excitation table above is the standard tool for deriving next-state logic when designing FSMs with JK flip-flops.

Post a Comment

0 Comments