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
Clockinput 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):
- The bottom NOR sees
S = 1, so its outputQ-barbecomes 0 (NOR with any 1 input is 0). - The top NOR now sees
R = 0andQ-bar = 0(both inputs 0), so its outputQbecomes 1. - That
Q = 1feeds back to the bottom NOR, holdingQ-bar = 0even afterSreturns 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
SandRat the same time. WithR = 1, S = 1, both NOR outputs are forced to 0, soQandQ-barare 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:
- It has the forbidden
S = R = 1state. - 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 CLKR = (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:
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 tracksDduring the low phase. - The slave latch is driven by
CLK. It is transparent while the clock is high.
Walk through one cycle:
- Clock low: master is transparent and follows
D; slave is closed and holds the previous output. - Rising edge (low -> high): the master closes, freezing whatever
Dwas at that instant; the slave opens and copies the master's frozen value toQ. - Clock high: master is closed (ignores
D), so even ifDchanges 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 externalDinput -> the register loads new data. - If
EN = 0, select the flip-flop's own current outputQ-> 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
Registercomponent that already hasD,Q,CLK,C(clear), anden(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:
- The register's output
Qis the current count. Qfeeds one input of the adder; the constant1feeds the other input.- The adder output
Q + 1feeds back into the register'sDinput. - On each rising clock edge (when
EN = 1), the register capturesQ + 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 = 0the register holds, so the count freezes; withEN = 1it 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
CLRonce 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: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:
Click to reveal solution
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.
Click to reveal solution
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
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: - 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¶
- Digital simulator (hneemann/Digital)
- Lab 08 spec, Introduction to Digital Design: "/assignments/lab08/"
- Lab 09 spec, Processor Design Part 1: "/assignments/lab09/"
- SR latch (Wikipedia)
- Flip-flop, master-slave D flip-flop (Wikipedia)
- Static vs. dynamic RAM (Wikipedia)
- Instructor handwritten notes: "/notes/CS315-01 2025-10-22 Lab Sequential Logic.pdf"
Summary¶
-
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. -
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.
-
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 forbiddenR=S=1. It behaves like a static RAM cell that never needs refreshing. -
The D latch is clocked and safe. Deriving
S = D&CLKandR = ~D&CLKremoves the forbidden state and makes the cell transparent only while the clock is high. -
The D flip-flop is edge-triggered, built from two D latches (master on
~CLK, slave onCLK). It capturesDonly at the rising edge and ignores mid-cycle changes, which is essential for safe feedback loops. -
A 1-bit register adds CLR and EN. Clear forces a known 0 for initialization; enable (via a MUX that feeds
Qback to itself) lets the cell hold its value across cycles. Clear has priority over enable. -
N-bit registers are N parallel 1-bit cells sharing CLK/CLR/EN, wired with splitters and mergers so all bits update synchronously.
-
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.