Skip to content

Lab: Sequential Logic

Overview

This hands-on lab session builds the storage elements that give a digital circuit memory. Up to now every circuit we have built was combinational: the outputs were a pure function of the current inputs, with no feedback and no notion of time. In this lab we introduce the clock and walk through the storage hierarchy SR latch -> D latch -> D flip-flop -> 1-bit register -> N-bit register -> counter, building each piece in the Digital simulator. The motivating goal is a self-incrementing counter: an 8-bit register whose output feeds an 8-bit adder, whose result feeds back into the register so the value grows by one every clock cycle. These are the exact building blocks we will reuse for the program counter and register file in the upcoming processor project.

Learning Objectives

  • Distinguish combinational logic (no memory) from sequential logic (state that persists over time)
  • Read a clock waveform and identify the period, frequency (Hz), high/low levels, and rising/falling edges
  • Build an SR latch from cross-coupled NOR gates and explain its hold, set, reset, and forbidden states
  • Construct a D latch that is transparent while the clock is high and a D flip-flop that captures data only on the rising edge
  • Add clear (CLR) and enable (EN) controls to make a robust 1-bit register
  • Compose multiple 1-bit registers (with splitters/mergers) into an N-bit register
  • Wire a register to an adder to create a counter that increments once per clock cycle
  • Recognize and avoid common pitfalls: multiple clock sources, the forbidden SR state, and uninitialized power-on state

Prerequisites

  • Combinational logic and basic gates: NOT, AND, OR, NOR, XOR (Lab 08)
  • Sum-of-products design and truth tables
  • Multiplexers (a 2-input MUX selects between two inputs based on a select line)
  • The 8-bit ripple-carry adder built in Lab 08
  • The Digital circuit simulator installed and running on your host OS
  • Comfort tracing signal values through a circuit by hand

1. Combinational vs. Sequential Logic

Every circuit we have built so far has been combinational. A combinational circuit is a directed acyclic graph (DAG) of gates: there are no feedback loops, and the output is determined entirely by the present inputs. Give it the same inputs and you always get the same outputs, instantly (ignoring gate delay).

A sequential circuit is different: it has state. Its outputs depend not only on the current inputs but also on the history of past inputs, captured in stored values. To make the timing of those updates orderly, sequential circuits are driven by a clock.

The general shape of a sequential circuit is a loop: a block of state feeds combinational logic, and the result of that logic feeds back to update the state on the next clock tick.

flowchart LR
    CLK([CLK]) --> STATE
    STATE["State<br/>(registers / latches)"] --> COMB["Combinational<br/>Logic"]
    COMB -- "next state" --> STATE

This single picture is the heart of every processor. The "state" is registers and the program counter; the "combinational logic" is the ALU, adders, multiplexers, and decoders; and the clock paces the whole machine forward one step at a time.

The Goal for Today

The concrete target of this lab is a counter: a circuit that holds a number and adds one to it on every clock cycle. It is the simplest interesting sequential circuit and it exercises every concept we need.

                    +-----------+              o-> Count (output)
        +---------->| 8-bit     |-----+--------/
        |           | Register  |     |
   CLK--+---------->|           |     |   +-----------+
        |           +-----------+     +-->| 8-bit     |
        |                                 | Adder     |---+
        |                          1 ---->|           |   |
        |                                 +-----------+   |
        +-------------------------------------------------+
                         (sum feeds back into register)
  • The register stores the current count.
  • The adder computes count + 1.
  • The result feeds back into the register input.
  • On each rising clock edge the register latches the new (incremented) value.

We cannot build this yet, because we do not have a register, and we cannot build a register until we can store a single bit. So we start at the bottom of the hierarchy and work up.

The storage hierarchy we will climb: SR latch -> D flip-flop -> 1-bit register -> N-bit register -> counter


2. The Clock

A clock is a signal that oscillates between 0 (low) and 1 (high) at a fixed rate. It is the metronome of a sequential circuit: every storage element updates in lockstep with the clock.

        cycle period
       |<----------->|
  1 ___      ____      ____      ____
       |    |    |    |    |    |    |
       |    |    |    |    |    |    |
  0    |____|    |____|    |____|    |________  -> time
            ^         ^
        rising     falling
         edge        edge

Key vocabulary:

Term Meaning
High / low The two voltage levels, interpreted as logic 1 and logic 0
Cycle period The time for one complete low-high-low cycle
Frequency Cycles per second, measured in hertz (Hz). A 1 GHz clock ticks 1,000,000,000 times per second
Rising edge The instant the signal transitions from 0 to 1
Falling edge The instant the signal transitions from 1 to 0

Frequency and period are reciprocals: frequency = 1 / period. A clock with a 1 ns period runs at 1 GHz.

Why "edges"? It turns out the most reliable way to update state is to do it at a precise instant rather than during the whole time the clock is high. The rising edge is a single, well-defined moment shared by every storage element in the circuit, so all of them update together. We will see exactly why edges matter when we get to the D flip-flop.

In hardware, the clock is generated by a crystal oscillator (a quartz crystal that vibrates at an extremely consistent frequency). The consistency of that oscillation is what lets a billion-gate chip stay synchronized.

Important design rule: a circuit should have one top-level clock source. Driving different parts of a circuit from different clocks (or accidentally feeding the clock through extra logic) is a common source of bugs. In Digital, use a single Clock input and fan it out to every component.


3. Storing One Bit: The SR Latch

Combinational logic is a DAG, with no loops. To remember something, we need a feedback loop so a value can circulate and sustain itself. The simplest such device is the SR latch (Set/Reset latch), built from two cross-coupled NOR gates.

Recall the NOR truth table: NOR(a, b) = NOT(a OR b). The output is 1 only when both inputs are 0.

a b NOR
0 0 1
0 1 0
1 0 0
1 1 0

The SR latch wires two NOR gates so that each one's output feeds back into the other's input:

   R ----+                              the top output is Q
         |     +------+
         +---->|      |
               | NOR  |----+----------- Q  (the stored "value")
        +----->|      |    |
        |      +------+    |
        |                  |   (cross-coupled feedback)
        |      +------+    |
        +------|      |<---+
               | NOR  |----+----------- Q-bar  (always the complement of Q)
   S --------->|      |
               +------+

The two outputs are Q (the stored value) and Q-bar (its complement). In normal operation they are always opposites.

How It Behaves

R S Q Q-bar Meaning
0 0 (unchanged) (unchanged) Hold the current value
0 1 1 0 Set Q to 1
1 0 0 1 Reset Q to 0
1 1 X X Forbidden / undefined

Read this table as a sequence over time (top to bottom):

   R   S  |  Q  Q-bar
   ---------------------
   0   0  |  0    1     (start: holding a 0)
   0   1  |  1    0     (set -> Q becomes 1)
   0   0  |  1    0     (hold -> stays 1, this is the memory!)
   1   0  |  0    1     (reset -> Q becomes 0)
   0   0  |  0    1     (hold -> stays 0)
   1   1  |  X    X     (forbidden -> both outputs forced to 0, undefined)

The crucial row is R=0, S=0 after a set: the latch remembers the 1. This is exactly what we wanted: a circuit that stores one bit.

Tracing the Set Operation

Suppose Q = 0, Q-bar = 1, and we assert S = 1 (with R = 0):

  1. The bottom NOR sees S = 1, so its output Q-bar becomes 0 (NOR with any 1 input is 0).
  2. The top NOR now sees R = 0 and Q-bar = 0 (both inputs 0), so its output Q becomes 1.
  3. That Q = 1 feeds back to the bottom NOR, holding Q-bar = 0 even after S returns to 0.

The value has "latched". It will now hold Q = 1 for as long as power is applied and R stays 0.

Static RAM and the "Vortex" Intuition

Because the latch holds its value through continuous, self-sustaining signal flow, it behaves like one cell of static RAM (SRAM). Unlike dynamic RAM (DRAM), which stores charge on a capacitor and must be periodically refreshed, an SR latch keeps its value indefinitely with no refresh as long as it is powered.

A useful mental image: think of the cross-coupled feedback as a small vortex that keeps spinning. Once you set the value, the loop continuously feeds itself, perpetually re-asserting the stored bit. The value just keeps circulating.

Pitfall: never assert S and R at the same time. With R = 1, S = 1, both NOR outputs are forced to 0, so Q and Q-bar are equal (not complements) and the result is undefined. Worse, if both inputs drop to 0 simultaneously, the latch can oscillate unpredictably. We will design the D latch specifically to make this state impossible.

Power-On State

When a circuit first powers up, latches come up in an undefined state: a brand-new SR latch might hold a 0 or a 1, you cannot know which. Real designs always provide a way to force a known starting value. That is the job of the clear signal we add in Section 6.


4. The D Latch: A Clocked Storage Cell

The SR latch has two annoyances:

  1. It has the forbidden S = R = 1 state.
  2. It changes whenever its inputs change. There is no notion of "update now, ignore inputs the rest of the time".

The D latch fixes both. It has a single data input D and a clock input CLK, and it derives the latch's S and R from them so that the forbidden state can never occur.

The idea: only let D affect the latch while the clock is high, and make S and R always be opposites of each other.

   D -----+----[ AND ]---- S    (S = D AND CLK)
          |       |
          |     CLK
          |       |
        [NOT]   [ AND ]---- R    (R = (NOT D) AND CLK)
          |       |
          +-------+

   S, R feed into an SR latch -> outputs Q and Q-bar
  • S = D AND CLK
  • R = (NOT D) AND CLK

Because S and R come from D and NOT D, they can never both be 1. The forbidden state is structurally impossible.

D Latch Behavior

CLK D S R Effect on Q
0 x 0 0 Hold (latch ignores D)
1 0 0 1 Reset, so Q = 0
1 1 1 0 Set, so Q = 1

In words: when the clock is high, Q follows D (the latch is "transparent"); when the clock is low, Q holds its last value.

   D    ___________     ____________
       |           |   |
   ____|           |___|

   CLK  __    __    __    __
       |  |  |  |  |  |  |  |
   ____|  |__|  |__|  |__|  |____

   Q    follows D only during the high pulses, holds otherwise

The Digital symbol for a D latch is a box with D and CLK inputs on the left and Q, Q-bar outputs on the right:

        +-----------+
   D ---| D       Q |--- Q
        | D Latch   |
  CLK --| CLK  Q-bar|--- Q-bar
        +-----------+

The Problem with Transparency

The D latch is level-sensitive: it is transparent for the entire time the clock is high, not just at one instant. If D wiggles while the clock is high, Q wiggles right along with it. For our counter, that is dangerous: the register's output feeds the adder, whose output feeds back to the register's input. If the register is transparent, the new value could race around the loop and the count could change multiple times (or unpredictably) within a single high pulse. We need to capture D at a single, well-defined instant. That is the flip-flop.


5. The D Flip-Flop: Edge-Triggered Storage

A D flip-flop captures its input only on the rising edge of the clock and holds it for the rest of the cycle. We build it from two D latches in series (a master-slave configuration) driven by opposite clock phases.

                          +---------+              +---------+
   D ---------------------| D     Q |------+-------| D     Q |------ Q
                          | Latch   |      |       | Latch   |
                  +-------| CLK     |      |   +---| CLK     |------ Q-bar
                  |       +---------+      |   |   +---------+
                  |  (master)             |   |   (slave)
   CLK ---+-------|-----------------------+---+
          |     [NOT]                         (slave gets CLK directly)
          |       |
          +-------+   (master gets inverted CLK)
  • The master latch is driven by NOT CLK. It is transparent while the clock is low, so it tracks D during the low phase.
  • The slave latch is driven by CLK. It is transparent while the clock is high.

Walk through one cycle:

  1. Clock low: master is transparent and follows D; slave is closed and holds the previous output.
  2. Rising edge (low -> high): the master closes, freezing whatever D was at that instant; the slave opens and copies the master's frozen value to Q.
  3. Clock high: master is closed (ignores D), so even if D changes nothing leaks through. The slave just passes the already-frozen value.

The net effect: Q updates to equal D exactly once per cycle, at the rising edge, and is otherwise stable. This is edge-triggered behavior.

   D    _______     ___________     _______
       |       |   |           |   |
   ____|       |___|           |___|

   CLK   /|    /|    /|    /|    /|
        / |   / |   / |   / |   / |
   ____/  |__/  |__/  |__/  |__/  |__
        ^     ^     ^     ^     ^
        sample D at each rising edge only

   Q    updates only at the marked rising edges

The little triangle (>) drawn on a clock input in a schematic is the standard symbol meaning edge-triggered.

Why Edge-Triggering Saves the Counter

With an edge-triggered flip-flop, the register reads its input, samples it at one instant, and then holds it stable for the entire next cycle while the adder computes the next value. Because the register output is frozen during the cycle, the adder sees a stable input and produces a stable count + 1. That stable result sits at the register's input until the next rising edge, when it is captured. One clean increment per cycle, no races. This is precisely the State -> Combinational Logic -> State loop from Section 1, now made safe by edge-triggering.


6. From Flip-Flop to a 1-Bit Register

A bare flip-flop captures D on every rising edge. A real register needs two more controls:

  • CLR (clear): force the stored value to 0, regardless of D. This gives us a known power-on / reset state.
  • EN (enable): only update on the clock edge when enabled; otherwise hold the current value.

Step 6a: D Latch with Clear

First we add a clear input to the D latch. We OR the clear signal into the reset path of the latch so that asserting CLR forces a reset (Q = 0) no matter what D is doing:

   D -----+----[ AND ]---------------- S   (S = D AND CLK, but...)
          |       |
        [NOT]   CLK
          |       |
          +----[ AND ]----+
                          |
                       [ OR ]---------- R   (R = ((NOT D) AND CLK) OR CLR)
                          |
   CLR --------------------+

When CLR = 1, R is forced high, the SR latch resets, and Q goes to 0. When CLR = 0, the cell behaves like an ordinary D latch. We build the D flip-flop the same way, with CLR routed into both internal latches, producing a D latch / flip-flop with CLR:

        +-------------+
   D ---| D         Q |--- Q
        | D Latch     |
  CLK --| CLK   Q-bar |--- Q-bar
        | (CLR)       |
  CLR --| CLR         |
        +-------------+

Step 6b: Adding Enable with a MUX

For enable we use a 2-input multiplexer on the data path. The MUX chooses what gets written on the next edge:

  • If EN = 1, select the external D input -> the register loads new data.
  • If EN = 0, select the flip-flop's own current output Q -> the register reloads its own value, i.e. it holds.
                 +-------+
        D ------>|0      |
                 |  MUX  |---- d_in --> [ D flip-flop with CLR ] ---+---- Q
   +--- Q ------>|1      |                      ^   ^               |
   |             +-------+                      |   |               |
   |                ^                          CLK CLR              |
   |               EN                                               |
   +----------------------------------------------------------------+
                  (Q feeds back to MUX input 1)

Putting it together, a 1-bit register has:

  • Inputs: D (data), CLK (clock), CLR (clear), EN (enable)
  • Output: Q
EN CLR Behavior on rising edge
x 1 Q <- 0 (clear wins)
1 0 Q <- D (load new data)
0 0 Q <- Q (hold current value)

The enable feedback trick, where deasserting EN routes Q back into itself, is the key to "remembering" a value across many cycles even though the flip-flop technically captures something on every edge. It captures itself, which is a no-op.

        +-----------------+
   D ---| D             Q |--- Q
        | 1-bit Register  |
  CLK --| CLK             |
  CLR --| CLR             |
   EN --| EN              |
        +-----------------+

7. Scaling Up: The N-Bit Register

A single 1-bit register stores one bit. To store an 8-bit value we use eight 1-bit registers in parallel, all sharing the same CLK, CLR, and EN. Each register handles one bit of the data.

The trick in Digital is splitters and mergers:

  • A splitter takes a multi-bit bus (e.g. a 4-bit D) and breaks it into individual 1-bit wires.
  • A merger (also a splitter, used in reverse) combines individual 1-bit outputs back into a multi-bit bus.
   4-bit register (built from four 1-bit registers)

         splitter                              merger
   D ===|4    bit0|--[1-bit Reg]--Q0--|0    |
        |     bit1|--[1-bit Reg]--Q1--|1   4|=== Q
        |     bit2|--[1-bit Reg]--Q2--|2    |
        |     bit3|--[1-bit Reg]--Q3--|3    |
         (split)                       (merge)

   CLK --+--------+--------+--------+----  (shared by all four)
   CLR --+--------+--------+--------+----
   EN  --+--------+--------+--------+----

Because all four (or eight) cells share the same clock edge, every bit updates synchronously at the same instant. There is no skew between bits.

Extending from 4 bits to 8 bits is purely mechanical: use an 8-wide splitter, eight 1-bit registers, and an 8-wide merger. The shared control signals stay the same.

flowchart LR
    D["D (8-bit bus)"] --> SP["Splitter<br/>8 to 1+1+...+1"]
    SP --> R0["1-bit Reg"]
    SP --> R1["1-bit Reg"]
    SP --> Rdots["..."]
    SP --> R7["1-bit Reg"]
    R0 --> MG["Merger<br/>1+1+...+1 to 8"]
    R1 --> MG
    Rdots --> MG
    R7 --> MG
    MG --> Q["Q (8-bit bus)"]
    CLK([CLK]) --> R0 & R1 & Rdots & R7
    CLR([CLR]) --> R0 & R1 & Rdots & R7
    EN([EN]) --> R0 & R1 & Rdots & R7

Initializing to Zero with Clear

When the circuit powers on, the register holds garbage. The CLR signal threads through all eight 1-bit cells; asserting it forces every bit to 0, giving a clean, known starting value. An alternative implementation seen in the lab uses a MUX with a hard-wired constant 0 selected by CLR: when clear is active, the register loads 0 instead of D. Either approach produces a deterministic reset to zero.

Note: Digital ships with a built-in Register component that already has D, Q, CLK, C (clear), and en (enable). For the lab you should understand the hand-built version, but in later projects you may use the built-in register to save time.


8. Building the Counter

Now we have everything for the goal circuit. A counter combines the 8-bit register with the 8-bit ripple-carry adder from Lab 08:

  1. The register's output Q is the current count.
  2. Q feeds one input of the adder; the constant 1 feeds the other input.
  3. The adder output Q + 1 feeds back into the register's D input.
  4. On each rising clock edge (when EN = 1), the register captures Q + 1.
flowchart LR
    CLK([CLK]) --> REG
    CLR([CLR]) --> REG
    EN([EN]) --> REG
    REG["8-bit Register<br/>(D, CLK, CLR, EN, Q)"] -->|Q = count| OUT([Count out])
    REG -->|Q| ADD["8-bit Adder"]
    ONE["constant 1"] --> ADD
    ADD -->|Q + 1| REG

Trace the first few cycles (assume CLR was pulsed once to start at 0, then EN = 1):

   Cycle   Q (before edge)   Adder = Q+1   Q (after edge)
   -----   ---------------   -----------   --------------
     0          00000000         00000001       00000001
     1          00000001         00000010       00000010
     2          00000010         00000011       00000011
     3          00000011         00000100       00000100
    ...           ...              ...            ...
   255          11111111         00000000       00000000  (wraps around)

This is the canonical sequential circuit: state (register) -> combinational logic (adder) -> state. The counter naturally wraps from 255 back to 0 because the carry out of an 8-bit adder is discarded.

The Role of Each Control

  • CLR: pulse once at start to reset the count to 0 (clean initialization).
  • EN: gate counting on and off. With EN = 0 the register holds, so the count freezes; with EN = 1 it increments each cycle.
  • CLK: each rising edge advances the count by one.

The summary connects this directly to the processor: a counter built exactly this way becomes the program counter (PC), which holds the address of the current instruction and increments to point at the next one. The next class extends these ideas to the decoder, the full counter component, and the remaining Project 5 pieces.


9. Building It in Digital: Step-by-Step

Here is the recommended order to actually build and simulate these circuits in the Digital application.

 1. SR Latch          -> two NOR gates, cross-coupled. Inputs S, R; outputs Q, Q-bar.
 2. D Latch           -> add AND gates + NOT so S = D&CLK, R = (~D)&CLK.
 3. D Latch w/ CLR    -> OR the CLR signal into the R path.
 4. D Flip-Flop       -> two D latches, master on ~CLK, slave on CLK.
 5. 1-bit Register    -> D flip-flop (with CLR) + MUX(EN) feeding D back from Q.
 6. N-bit Register    -> splitter + N copies of (5) + merger, shared CLK/CLR/EN.
 7. Counter           -> N-bit register + adder + constant 1, output fed back to D.

Practical tips for the simulator:

  • One clock. Place a single Clock (or manual clock) input and fan it out. Do not create multiple clock sources or send the clock through extra gates that delay it.
  • Use the manual clock while debugging so you can step one edge at a time and watch values change.
  • Add probes on Q, the adder output, and the control signals so you can see the state each cycle.
  • Clear first. Pulse CLR once before you start counting so you begin from a known 0, not power-on garbage.
  • Encapsulate. In Digital, save each finished sub-circuit (e.g. sr-latch.dig, d-flip-flop.dig, register-8.dig) and embed it as a component in the next level up. This mirrors the hierarchy and keeps each circuit readable.
  • Name your inputs/outputs exactly as the autograder expects (e.g. CLK, CLR, EN, D, Q). The autograder matches on these names.

Autograder reminder: the Digital labs run on your host OS, not the RISC-V VM. On Windows the easiest path is WSL Ubuntu, though some students get it working in PowerShell. You can also run the tests on the BeagleV machines if needed.


Key Concepts

Concept Definition Example
Combinational logic Output is a pure function of current inputs; no memory, no feedback (a DAG) An adder, a MUX, a decoder
Sequential logic Output depends on stored state plus current inputs; uses feedback and a clock A counter, a register, a CPU
Clock A signal oscillating 0/1 at a fixed frequency that paces state updates 1 GHz = one billion cycles per second
Rising edge The instant the clock goes 0 -> 1; when edge-triggered elements update Flip-flop samples D here
SR latch Cross-coupled NOR gates storing one bit; set, reset, hold, forbidden states Static RAM cell
D latch Level-sensitive cell; transparent (Q follows D) while CLK is high S = D&CLK, R = ~D&CLK
D flip-flop Edge-triggered cell; captures D only on the rising edge Two D latches, master-slave
CLR (clear) Control that forces stored value to 0 for known initialization Reset PC to 0 at startup
EN (enable) Control that allows an update; when off, the register holds via self-feedback Freeze a counter
N-bit register N parallel 1-bit registers sharing CLK/CLR/EN, updating synchronously 8-bit count register
Counter Register + adder + constant 1, output fed back to input; increments per cycle Program counter

Practice Problems

Problem 1: Period and Frequency

A clock has a period of 4 nanoseconds. (a) What is its frequency in Hz? (b) How many rising edges occur in one microsecond?

Click to reveal solution (a) `frequency = 1 / period = 1 / (4 ns) = 1 / (4 x 10^-9 s) = 2.5 x 10^8 Hz = 250 MHz`. (b) One microsecond is `1 x 10^-6 s`. Number of cycles = `(1 x 10^-6) / (4 x 10^-9) = 250` cycles. There is exactly one rising edge per cycle, so **250 rising edges**. Key relationships:
frequency = 1 / period
period    = 1 / frequency
1 cycle   = 1 rising edge + 1 falling edge

Problem 2: Trace the SR Latch

Starting from Q = 0, Q-bar = 1, apply this input sequence to an SR latch (NOR-based) and give Q after each step:

(R=0,S=1), (R=0,S=0), (R=0,S=0), (R=1,S=0), (R=0,S=0)
Click to reveal solution
   Step   R  S  | Q  Q-bar  | Action
   ------------------------------------------
   start  -  -  | 0    1    | initial
     1    0  1  | 1    0    | SET   -> Q = 1
     2    0  0  | 1    0    | HOLD  -> stays 1
     3    0  0  | 1    0    | HOLD  -> stays 1
     4    1  0  | 0    1    | RESET -> Q = 0
     5    0  0  | 0    1    | HOLD  -> stays 0
The two `HOLD` steps demonstrate the memory property: with `R = S = 0` the latch keeps whatever it last held. Note we never asserted `R = S = 1`, which is forbidden.

Problem 3: Latch vs. Flip-Flop

While the clock is high, the data input D changes from 0 to 1 to 0. Describe what the output Q does for (a) a D latch and (b) a D flip-flop, assuming D = 0 at the rising edge.

Click to reveal solution (a) **D latch (level-sensitive, transparent while CLK high):** `Q` follows `D` the whole time the clock is high. So `Q` goes `0 -> 1 -> 0`, tracking every change. The latch is "see-through" during the high phase. (b) **D flip-flop (edge-triggered):** `Q` captures the value of `D` only at the rising edge. Since `D = 0` at that instant, `Q` becomes 0 and **stays 0** for the entire cycle, ignoring the later wiggles to 1 and back. This is exactly why we use flip-flops, not latches, for registers in a counter: the flip-flop ignores mid-cycle changes, so the feedback loop cannot race.

Problem 4: Register Control Truth Table

Given a 1-bit register with EN and CLR, fill in the value of Q after the next rising edge for each case. Current value is Q = 1, and D = 0.

   EN  CLR | Q after edge
   --------|-------------
    0   0  |   ?
    1   0  |   ?
    0   1  |   ?
    1   1  |   ?
Click to reveal solution
   EN  CLR | Q after edge | Reason
   --------|--------------|---------------------------------
    0   0  |     1        | HOLD: EN off, Q feeds back to itself
    1   0  |     0        | LOAD: capture D (which is 0)
    0   1  |     0        | CLEAR wins regardless of EN
    1   1  |     0        | CLEAR wins regardless of EN/D
Clear has the highest priority: whenever `CLR = 1`, the register goes to 0 no matter what `EN` or `D` say. When `CLR = 0`, `EN` decides between loading `D` (`EN = 1`) and holding (`EN = 0`).

Problem 5: Counter Sequence

An 8-bit counter starts at Q = 11111110 (254) with EN = 1 and CLR = 0. What are the next three values of Q after three rising edges? What happens at 255?

Click to reveal solution
   Edge   Q before    Adder Q+1   Q after
   ----   ---------   ---------   ---------
    1     11111110    11111111    11111111   (254 -> 255)
    2     11111111    00000000    00000000   (255 -> 0, wraps!)
    3     00000000    00000001    00000001   (0 -> 1)
At 255, `Q + 1 = 256`, which is `1 00000000` in 9 bits. The 8-bit adder keeps only the low 8 bits and discards the carry out, so the result is `00000000`. The counter **wraps around** to 0. An 8-bit counter therefore counts `0, 1, ..., 255, 0, 1, ...` modulo 256.

Problem 6: Why Two Latches?

Explain why a D flip-flop is built from two D latches with opposite clock phases instead of just one D latch.

Click to reveal solution A single D latch is **transparent** while the clock is high: any change on `D` during that whole window passes straight through to `Q`. In a feedback circuit like a counter, that transparency lets the new value race around the `register -> adder -> register` loop and corrupt the count within one clock pulse. The two-latch (master-slave) design eliminates this:
   master latch -> driven by ~CLK -> open while clock is LOW
   slave  latch -> driven by  CLK -> open while clock is HIGH
- While the clock is low, the master tracks `D` but the slave is closed (output frozen). - At the rising edge, the master **closes** (freezing the sampled `D`) and the slave **opens**, copying that single frozen value to `Q`. - While the clock is high, the master is closed, so further changes on `D` cannot get through. The result is that `Q` changes at exactly one instant per cycle, the rising edge. There is never a moment when input and output are both "live", so no race can occur. That single, well-defined update instant is what makes synchronous sequential logic reliable.

Further Reading


Summary

  1. Sequential logic adds memory. Unlike combinational circuits (a DAG with no feedback), sequential circuits have state and use feedback, paced by a clock, in the loop state -> combinational logic -> state.

  2. The clock paces everything. It oscillates 0/1 at a fixed frequency (Hz); the rising edge is the shared instant when edge-triggered elements update. Use a single top-level clock source.

  3. The SR latch stores one bit using cross-coupled NOR gates. Its states are hold (R=S=0), set (S=1), reset (R=1), and the forbidden R=S=1. It behaves like a static RAM cell that never needs refreshing.

  4. The D latch is clocked and safe. Deriving S = D&CLK and R = ~D&CLK removes the forbidden state and makes the cell transparent only while the clock is high.

  5. The D flip-flop is edge-triggered, built from two D latches (master on ~CLK, slave on CLK). It captures D only at the rising edge and ignores mid-cycle changes, which is essential for safe feedback loops.

  6. A 1-bit register adds CLR and EN. Clear forces a known 0 for initialization; enable (via a MUX that feeds Q back to itself) lets the cell hold its value across cycles. Clear has priority over enable.

  7. N-bit registers are N parallel 1-bit cells sharing CLK/CLR/EN, wired with splitters and mergers so all bits update synchronously.

  8. A counter is a register plus an adder. The register output plus the constant 1 feeds back into the register input, so the count increments by one per cycle (wrapping at 2^N - 1). This same pattern becomes the processor's program counter in the next project.