Design Challenge: 4-Input Digital Lock — From Boolean Logic to Stored State
Design a 4-input digital lock that unlocks only for one predefined ABCD combination, combining a combinational decoder for the correct-code detector with a flip-flop-based state element so the unlocked output latches and persists rather than existing only for the instant the correct code is present.
The spec is deliberately spare: four inputs — A, B, C, D — and the requirement that the lock unlocks only when a predefined combination is entered, using Boolean logic, gates, a decoder, a flip-flop, and state storage. The one-line brief hides a real design problem: a purely combinational circuit (gates and a decoder alone) can only tell you the correct code is present RIGHT NOW — the instant any input changes, the 'unlocked' signal would disappear again, which is useless as a lock (you'd have to hold all four switches in position forever to keep it open). This project's real engineering content is in the second half of that requirement list — flip-flop and state storage — which turns a momentary 'code matches' pulse into a persistent UNLOCKED state that survives until a deliberate RESET, exactly like a real electronic lock or keypad entry system.
1. Requirements and Specification
Inputs: A, B, C, D (4 single-bit inputs, each set by a switch, keypad line, or push-button representing 0 or 1) and RESET (a fifth input, asynchronous, that re-locks the system). Output: UNLOCK (1 = unlocked/open, 0 = locked). Behavior: UNLOCK must go to 1 and STAY at 1 once A,B,C,D matches the one predefined code (this design uses 1011 as the example code — adapt the decoder's inverters to change it), even after the inputs stop matching that code (e.g., the switches are released or changed), and must only return to 0 when RESET is asserted.
This latching behavior is the actual design requirement hidden behind 'unlock only when a predefined combination is entered' — a lock that only reports unlocked while you're physically holding four switches in an exact pattern is not a usable lock, so persistent state storage is not optional polish, it is the core of the assignment.
2. High-Level Architecture
The design splits into two stages: a Code-Match Detector (purely combinational — a 4-input AND-based decoder built from the code bits and their complements) that produces a single momentary signal MATCH = 1 exactly when A,B,C,D equals the predefined code and 0 otherwise; and a State Latch (a single D flip-flop, or an SR latch built from cross-coupled NAND gates) that captures MATCH on a clock edge (or level, for the SR version) and holds UNLOCK = 1 until RESET forces it back to 0 — regardless of what MATCH does afterward.
This two-stage split — combinational detection feeding sequential state storage — is the general pattern behind every keypad, code lock, and security system: 'detect the event' and 'remember the event happened' are always separate circuits, because a single stage cannot do both a fast comparison and a durable memory at once.
3. Detailed Logic Design
Code-Match Detector for code 1011 (A=1, B=0, C=1, D=1): MATCH = A AND (NOT B) AND C AND D. This is a direct 4-input AND-of-literals decoder, identical in structure to a single minterm decoder line from a 4-to-16 line decoder — in fact, this circuit IS minterm m11 (binary 1011) of a full 4-variable decoder, which is exactly why the spec calls for a 'decoder': the lock is really just one selected output line of a standard decoder, wired to mean 'this specific code was entered.'
State Latch using a D flip-flop: connect MATCH to the flip-flop's D input, clock it on a rising edge from either a debounced 'Enter' button (the user presses Enter after setting A,B,C,D) or a free-running sample clock; connect RESET to the flip-flop's asynchronous clear (CLR) input; the flip-flop's Q output IS UNLOCK. Using a D flip-flop rather than a raw SR latch is the recommended, safer choice because it only samples MATCH at a controlled clock edge (avoiding spurious unlocks from switch bounce or mid-transition input glitches) rather than reacting continuously to whatever MATCH happens to be at any instant.
Alternative SR-latch version (if a discrete clock/Enter button isn't available): S = MATCH, R = RESET, using a cross-coupled NAND or NOR latch. This reacts immediately when MATCH goes high, which is simpler to build with relays or basic gates but is more exposed to bounce and glitches — call this out explicitly as a design trade-off in your write-up rather than silently picking one.
4. Testing and Verification
Test sequence: (1) apply the wrong code, confirm MATCH=0 and UNLOCK stays 0; (2) apply the correct code and clock/Enter it, confirm UNLOCK goes to 1; (3) with UNLOCK still 1, change A,B,C,D away from the correct code, confirm UNLOCK STAYS 1 (this is the critical latching test — many first designs fail exactly here by wiring UNLOCK directly to MATCH instead of through the flip-flop); (4) assert RESET, confirm UNLOCK returns to 0 regardless of what A,B,C,D currently show; (5) with the wrong code held down, pulse the clock/Enter repeatedly, confirm UNLOCK never goes to 1.
Two specific edge cases deserve dedicated test vectors. First, switch bounce: since A, B, C, D are physical switches, a debounce circuit (or a debounce delay before sampling the clock) must be included, or a single switch flip near the code's decision boundary can register as several rapid transitions and, in rare timing windows, briefly present a wrong intermediate code to a level-sensitive (SR-latch) design. Second, the 'almost right' code: explicitly test codes that differ from the correct one by exactly 1 bit (e.g., 1010 or 0011 instead of 1011) to confirm the 4-input AND decoder correctly rejects near-misses — a wiring mistake that drops one of the four literals from the AND (e.g., forgetting the NOT B term) will pass a code that should fail.
Code-Match Boolean Equation and State Table
The apostrophe (') denotes logical NOT — B' means NOT B, so MATCH is high only when A=1, B=0, C=1, D=1 simultaneously. 'Holds previous state' on no clock edge is the entire point of using a flip-flop instead of raw combinational logic — this is what makes UNLOCK persist after the code inputs change.
MATCH = A . B' . C . D (example code = 1011; B is inverted)
D flip-flop state table (clocked on rising edge, async CLR = RESET):
RESET | clk edge | D(=MATCH) | Q_next (=UNLOCK)
1 | X | X | 0 (async clear wins)
0 | rising | 0 | 0 (wrong code -> stay/return locked)
0 | rising | 1 | 1 (correct code -> latch unlocked)
0 | no edge | X | Q (unchanged, holds previous state)Code Examples
Notice t=4: because this design samples MATCH on every Enter press (not just remembers 'was ever unlocked'), entering a WRONG code and pressing Enter while unlocked will re-lock it. This is a deliberate, realistic design choice worth stating explicitly in your report — an alternative design could gate the D-input with 'D = MATCH OR (UNLOCK AND NOT explicit-relock-button)' if you want unlock to persist through stray wrong-code entries; document whichever behavior you choose. Expected result: UNLOCK: 0,0,1,1,0,0 across t=0..t=5 in this trace (with the t=4 re-lock-on-wrong-entry behavior as designed).
t=3 A B C D = 0 0 0 0 (inputs released/changed) -> MATCH=0, but UNLOCK STAYS 1
The asynchronous reset (posedge reset in the sensitivity list) models the async CLR behavior from the state table — RESET overrides everything else immediately, without waiting for a clock edge, matching how a real panic-reset button should work.
else if (enter)\n unlock <= match;
Common mistake: A common bug here is writing unlock <= match; unconditionally (outside the enter gate) — that makes UNLOCK track MATCH combinationally through the flip-flop's D-input every clock cycle, which defeats the entire purpose of latching and makes UNLOCK drop the instant the code inputs change, exactly the flaw this project is designed to catch.
t=0 A B C D = 1 1 1 1 (wrong), Enter pressed -> MATCH=0 -> UNLOCK stays 0
t=1 A B C D = 1 0 1 0 (wrong), Enter pressed -> MATCH=0 -> UNLOCK stays 0
t=2 A B C D = 1 0 1 1 (CORRECT), Enter pressed -> MATCH=1 -> UNLOCK becomes 1
t=3 A B C D = 0 0 0 0 (inputs released/changed) -> MATCH=0, but UNLOCK STAYS 1
t=4 A B C D = 1 1 1 1 (wrong code entered while unlocked), Enter pressed
-> MATCH=0, D-input=0, but Q is only SAMPLED on clock edge with D=0
-> UNLOCK correctly DROPS to 0 on this edge (this is expected: re-entering
a wrong code and pressing Enter re-locks it, matching real keypad locks)
t=5 RESET pulsed -> UNLOCK forced to 0 immediately (async), regardless of D or clockmodule digital_lock (
input clk, reset, enter,
input a, b, c, d,
output reg unlock
);
wire match = a & ~b & c & d; // code = 1011
always @(posedge clk or posedge reset) begin
if (reset)
unlock <= 1'b0;
else if (enter)
unlock <= match;
// else: hold previous value (implicit, no clause needed)
end
endmoduleDigital Lock Block Diagram
Combinational MATCH detector feeds a D flip-flop's data input; the flip-flop's stored state, not MATCH itself, drives UNLOCK — this is what makes the unlock persist.
A --+
B --+--> [4-input AND ] --MATCH--> D +---------+
C --+ decoder (1 of 16 | -->| D FLIP- |--> UNLOCK
D --+ minterm lines) | clk->| FLOP |
RESET ->| (async |
Enter/clk -----------------------------.->| CLR) |
+---------+Important Rules
UNLOCK must be driven by the flip-flop's stored output (Q), never wired directly to the combinational MATCH signal.
RESET must be an asynchronous clear on the flip-flop so it can re-lock the system immediately, independent of the clock.
The code-match detector must be a full AND-of-literals (or equivalent decoder minterm) covering all 4 inputs — omitting any one input's literal makes the lock accept multiple codes.
Physical switch inputs must be debounced (or sampled only on a controlled Enter/clock edge) before reaching the state-storage stage.
The Same Two-Stage Pattern Runs Every Keypad Entry System
This exact architecture — a combinational match/compare stage feeding a latched state-storage stage, with an explicit reset — is how real electronic door locks, car alarm keypads, and PIN-entry systems are built at the hardware level, and it's also the conceptual ancestor of software authentication: a comparison ('does this password match?') that is momentary, feeding a session/state flag ('is this user currently logged in?') that persists until an explicit logout or timeout. Recognizing that pattern — detect an event combinationally, remember it with state — is one of the most transferable ideas in this entire course.
Wiring UNLOCK = MATCH directly (a purely combinational lock with no flip-flop).
Route MATCH into a D flip-flop's D input and drive UNLOCK from the flip-flop's Q output, clocked by an Enter button or sample clock, with RESET as async clear.
A purely combinational lock only reports unlocked for the exact instant all four inputs match the code — the moment any switch is released or changed, UNLOCK drops back to 0. That is not how any real lock behaves and fails the spec's explicit requirement for flip-flop-based state storage.
Building the code detector as, e.g., MATCH = A AND C AND D (accidentally dropping the B literal).
Include all four literals explicitly, with the correct polarity for each: MATCH = A AND (NOT B) AND C AND D for code 1011.
Dropping any one input's literal from the AND means the lock ignores that input entirely, so it accepts TWO different codes (both values of the dropped bit) instead of exactly one — a serious security flaw in a real lock design, and a very easy mistake to make when hand-wiring four literals.
Why does the spec's requirement list explicitly call for a flip-flop and 'state storage' in addition to Boolean logic, gates, and a decoder? A. Flip-flops make the circuit faster B. A purely combinational circuit (gates/decoder alone) can only indicate the code matches for as long as the exact input pattern is physically held; a flip-flop is needed so UNLOCK persists after the inputs change, which is the only way the circuit functions as an actual usable lock C. Flip-flops are required by convention in all digital designs, regardless of function D. Decoders cannot be built without a flip-flop somewhere in the circuit
B. A purely combinational circuit (gates/decoder alone) can only indicate the code matches for as long as the exact input pattern is physically held; a flip-flop is needed so UNLOCK persists after the inputs change, which is the only way the circuit functions as an actual usable lock — Combinational logic (the decoder/AND gates) can only ever reflect its CURRENT inputs — there is no memory. The moment the switches are released, a purely combinational 'MATCH' signal drops back to 0. A flip-flop is the only way to capture that momentary match and hold ('remember') it as a stable UNLOCKED state until a deliberate reset, which is the actual functional requirement of a lock.
In the recommended design, why is RESET connected to the flip-flop's asynchronous clear input rather than being sampled as an ordinary D-input signal on the next clock edge? A. Asynchronous clear is easier to draw in a schematic B. A synchronous reset would require an extra clock edge to take effect, delaying the re-lock; an asynchronous clear forces UNLOCK to 0 immediately regardless of the clock, matching how a security reset/panic button should behave C. D flip-flops do not support synchronous reset inputs at all D. It has no functional difference; it's purely a stylistic choice
B. A synchronous reset would require an extra clock edge to take effect, delaying the re-lock; an asynchronous clear forces UNLOCK to 0 immediately regardless of the clock, matching how a security reset/panic button should behave — An asynchronous clear overrides the flip-flop's state the instant it's asserted, with no dependency on a clock edge arriving — critical for a reset/panic-lock function where you want the system to re-lock immediately, not wait for the next scheduled clock tick (which, depending on clock frequency, could be a meaningful and undesirable delay).
A design has MATCH = A AND C AND D (missing the B literal) for an intended code of 1011. What security flaw does this introduce? A. No flaw — B is a don't-care bit for this design B. The lock will unlock for both A,C,D=1,1,1 combinations regardless of B's value — i.e., it accepts two different 4-bit codes (1011 and 1111) as correct instead of one C. The lock will never unlock for any input combination D. The lock will unlock only when B=1, which is the opposite of the intended behavior
B. The lock will unlock for both A,C,D=1,1,1 combinations regardless of B's value — i.e., it accepts two different 4-bit codes (1011 and 1111) as correct instead of one — Because B does not appear in the AND expression at all, its value is irrelevant to MATCH — both B=0 (code 1011) and B=1 (code 1111) satisfy A AND C AND D = 1. This doubles the number of codes the lock accepts, which is exactly the kind of subtle wiring mistake a security-review test pass (checking near-miss codes) is designed to catch.
Extend the lock to a 3-strikes lockout: if 3 consecutive wrong codes are entered (via Enter presses with MATCH=0), the lock enters a LOCKED-OUT state that ignores all further code entries until RESET, regardless of whether the correct code is subsequently entered.
Add a 2-bit strike counter clocked by Enter, incrementing when MATCH=0 and clearing to 0 when MATCH=1; add a LOCKED_OUT flip-flop that sets (via its own combinational logic: strike_count == 3) and only clears on RESET; gate the original lock's D-input as D = MATCH AND (NOT LOCKED_OUT), so even a correct code entered while locked out cannot set UNLOCK. This mirrors real ATM and phone PIN lockout behavior.
You'll need a small counter (2 bits is enough to count 0-3) that increments on 'Enter pressed AND MATCH=0' and resets to 0 on 'Enter pressed AND MATCH=1' (a successful entry clears the strike count) — and a new LOCKED_OUT flip-flop that sets when the counter reaches 3 and gates the main UNLOCK flip-flop's D input.