Friday, March 21, 2025

Entry 8: Inside a D flip-flop

Designing a D flip-flop

In entry 5 we looked at a single D flip-flop from a 74HC74 (the chip has 2). It has input pins "D" and "Clock" (as well as PR and CLR that we did not consider). 

The D flip-flop: When the clock goes high (rising edge), the value of D is "latched" into the flip-flop. It has output pins Q (the latched valued), and the complement of Q. Here is the truth-table of a positive edge-triggered D flip-flop from 74HC74 (ignoring PR and CLR for now):

This is the symbol used (again, ignoring PR and CLR for now):

Let's try to build a D flip-flop ourselves. So I asked Grok: "How is a D flip-flop designed?"

Designing a D flip-flop involves creating a circuit that captures the value of the D (data) input at a specific clock edge (e.g., rising edge) and holds it at the output (Q) until the next edge. While you can buy D flip-flops as part of ICs (like the 74LS74), understanding how to build one from scratch reveals the magic of digital design. The most common approach is the master-slave configuration using two latches, often SR or JK latches, coordinated by a clock. Here’s how it’s done, step by step, focusing on a rising-edge-triggered D flip-flop using SR latches.

-tbc-

Grok mentioned SR latches, see entry 7, as well as "JK latches", which I do not know what they are.

-cont:


Concept

A D flip-flop needs to:

  1. Sample D only when the clock transitions (edge-triggered).
  2. Store that value and ignore D changes until the next clock edge.
  3. Avoid invalid states (unlike a raw SR latch).

The master-slave design splits this into two stages:

  • Master latch: Captures D when the clock is low (or high, depending on design).
  • Slave latch: Transfers the captured value to Q when the clock switches, locking it in.

Components

  • 8 NAND gates (2 for master SR latch, 2 for slave SR latch, 4 for input/clock logic).
  • 2 Inverters
  • Inputs: D, CLK.
  • Outputs: Q, Q̅.

Step-by-Step Construction..

I removed Groks explanation and replaced it with a picture:

Note that the Master Latch as well as the Slave Latch are SR latches of NAND type, where 1,1-input is "no change" (see entry 7). 

Building a D flip-flop

Let's build this. I am not going to physically connect 8 NAND gates and two inverters, that sounds like too much tedious work (and I do not have that many NAND gates). Instead, I will design it using basic gates in ACEL. The result will be the same.

NAND latches are named Master and Slave, We need 4 NAND gates (named according to picture) and 2 inverters (named by its input pin):

  //Define chips
  auto* masterL = new NandLatch((char*)("Master"));
  auto* slaveL = new NandLatch((char*)("Slave"));

  auto* ngate1 = new NandGate((char*)("Master Upper"));
  auto* ngate2 = new NandGate((char*)("Master Lower"));
  auto* ngate3 = new NandGate((char*)("Slave Upper"));
  auto* ngate4 = new NandGate((char*)("Slave Lower"));

  auto* invD = new Inverter((char*)("Invert D"));
  auto* invCLK = new Inverter((char*)("Invert CLK"));
  • I have a button for "D", connected to Arduino pin 2.
  • I have a button for "Clk", connected to Arduino pin 3.
  • I have an LED (to display Q) connected to Arduino pin 4.

You can, of course, use real buttons, a real LED and the Arduino Mega. These are the connections we need:

  ConnectionBase* connections[] = {
      // D is on pin 2, CLK on pin 3. Final Q output is on pin 4
      //Inverters
      new Connection(ard, 2, invD->X),
      new Connection(ard, 3, invCLK->X),
      //Master
      new Connection(ard, 2, ngate1->X1),
      new Connection(invCLK->Y, ngate1->X2),
      new Connection(invD->Y, ngate2->X1),
      new Connection(invCLK->Y, ngate2->X2),
      new Connection(ngate1->Y, masterL->Reset),
      new Connection(ngate2->Y, masterL->Set),
      //Slave
      new Connection(masterL->Q, ngate3->X1),
      new Connection(ard, 3, ngate3->X2),
      new Connection(masterL->Q_Bar, ngate4->X1),
      new Connection(ard, 3, ngate4->X2),
      new Connection(ngate3->Y, slaveL->Reset),
      new Connection(ngate4->Y, slaveL->Set),

      new Connection(slaveL->Q, ard, 4),
  };

All of this works exactly as the D flip-flop from the 74HC74:

You can play with this yourself on Wokwi. The name of the project is "D flip-flop".

Understanding the D flip-flop

One way to understand the D flip-flop is to play around with it, printing the state of all gates / latches. This is the basic analysis of the D flip-flop:

  • When Clk = 0, NAND gates 3 and 4 outputs 1 (NAND gate outputs 0 only if both inputs are 1) and there can be no change in the Slave SR latch. The Slave latch is "frozen".
  • Similarly, when Clk = 1, there can be no change in the Master SR latch and it is "frozen".
  • When Clk = 0, the Master Q is equal to D. Confirm this by a print when Clk = 0, D = 0, and Clk = 0, D = 1.
  • When Clk goes high, the Slave Q is equal to Master Q. Confirm this by a print.

All in all, the result is this:

Here is a more detailed explanation from Grok, which may be more useful:

How It Works (Rising-Edge Triggered)

  • CLK = 0:
    • NOT CLK = 1.
    • Master S̅ = NAND(D, 1) = NOT D, R̅ = NAND(NOT D, 1) = D.
    • Master is transparent: Q (master) follows D (if D = 1, Q = 1; if D = 0, Q = 0).
    • Slave S̅ = NAND(Q (master), 0) = 1, R̅ = NAND(Q̅ (master), 0) = 1.
    • Slave holds its previous state (no change).
  • CLK rises to 1 (Rising Edge):
    • NOT CLK = 0.
    • Master S̅ = NAND(D, 0) = 1, R̅ = NAND(NOT D, 0) = 1.
    • Master locks its state (holds the D value it had when CLK was 0).
    • Slave S̅ = NAND(Q (master), 1) = NOT Q (master), R̅ = NAND(Q̅ (master), 1) = NOT Q̅ (master).
    • Slave updates: Q (slave) takes the master’s Q (the D value from just before the edge).
  • CLK = 1:
    • Master stays locked (S̅ = 1, R̅ = 1).
    • Slave stays stable (Q reflects the captured D).
  • CLK falls to 0:
    • Master becomes transparent again, tracking D.
    • Slave holds its value (CLK = 0 forces S̅ = 1, R̅ = 1).

Key Result: Q updates only when CLK goes from 0 to 1, making it rising-edge-triggered.


Verification

  • D = 1, CLK = 0: Master Q = 1, Slave Q holds old value.
  • CLK → 1: Master locks Q = 1, Slave Q becomes 1.
  • D changes to 0, CLK = 1: Master stays locked, Slave Q stays 1.
  • CLK → 0: Master Q = 0, Slave Q still 1 (no change until next rising edge).

Preset and Clear

In addition to D, Clock, Q and Q-bar, the 74HC74 has two additional input pins Preset and Clear. Clear will set the Q value to 0 while Preset will set it to 1. Preset and Clear are both "active low" meaning that you need to make the Preset pin low / Clear pin low to set Q = 1 / Q = 0:

This is the symbol for D flip-flop from the 74HC74:

The "circles" in Preset and Clear indicate that they are active low. Adding Preset and Clear to the D flip flop we considered above is simple, no need to ask Grok. We replace the Slave section with the following:

Note that when the clock is low, the output of 3 and 4 is 1. If Clear is low and Preset high, then the Slave latch will reset and Q = 0. I did not build this, but you are welcome to do so.

ACEL D flip-flop

I built an ACEL component based on the schedules above called DFlipFlop. Since I am not a fan of "Active low", I designed DFlipFlop with Preset and Clear "Active high":

This is the symbol I will use for the ACEL D flip-flop:

PR and CLR are by default 0, so if they are not needed, then no connection is required. These are the names of the pins:

  • Input pin: D
  • Input pin: Clock
  • Input pin: Clear
  • Input pin: Preset
  • Output pin: Q
  • Output pin: Q_Bar
The Wokwi project "D flip-flop" also has the DFlipFlop chip allowing us to confirm that component works as expected. In this project, Preset and Clear are not hooked up, but you can easily add two buttons to test that they also work as expected (I hope they do!)