10.5 Down Counter
Describe the next-state rule that defines a down counter, derive its borrow-based toggle logic, and identify when explicit stop/reload logic is needed for a countdown application.
A down counter is a counter whose next-state rule is 'subtract one, wrapping to the maximum value on underflow' — it counts backward, ...→3, 2, 1, 0, and then wraps around to the highest available state rather than continuing into negative numbers, since unsigned binary has no native negative representation. It exists for the mirror-image need of an up counter: countdown timers, watchdog timers, and any loop that tracks 'how many iterations remain' rather than 'how many have happened so far.'
Core concept: next state = current state - 1 (mod 2^n), via borrow logic
Formally, a down counter's next-state function is next_state = (current_state - 1) mod 2^n. Bit by bit, this mirrors the up counter's carry-toggle logic but with a borrow condition instead of a carry condition: the LSB still toggles on every clock (subtracting 1 always flips the lowest bit), but each higher bit toggles exactly when every bit below it is currently 0 — because that is precisely the condition under which subtracting 1 must 'borrow' from that bit position, exactly as in manual binary subtraction.
Concretely, for T flip-flops: T0 = 1 (always toggles); T1 = NOT Q0 (toggles only when Q0 is currently 0, i.e., a borrow is needed); T2 = (NOT Q0) AND (NOT Q1); and generally Tk = AND of the complements of all bits below position k. This is the exact structural mirror of the up counter's excitation equations from Topic 10.3/10.4, with every lower-bit term complemented.
• Next state = (current state - 1) mod 2^n — counts strictly downward, wrapping at the bottom. • LSB always toggles every clock; each higher bit toggles exactly when all lower bits are currently 0 (the borrow condition). • Wraps from the minimum value (0) to the maximum available value (2^n - 1) on the next clock, since unsigned binary cannot represent a negative count.
Step-by-step working
To trace a down counter, subtract 1 (in binary, borrowing as needed) on each clock edge. Starting from 111 (7) on a 3-bit down counter: 111, 110, 101, 100, 011, 010, 001, 000, and then wraps back to 111 on the next clock — because subtracting 1 from 000 requires borrowing from a bit position that doesn't exist, and by convention that unsigned underflow simply wraps to the all-ones maximum value, exactly the mirror of the up counter's overflow-discard wraparound.
It's worth noting a genuinely useful hardware shortcut here: if you already have an up-counter's flip-flop outputs available, reading their complemented outputs (Q̄ instead of Q) actually does produce a valid down-counting sequence — since complementing every bit of the value v gives 2^n - 1 - v, and as v runs 0,1,2,...,2^n-1,0,... its complement runs 2^n-1, 2^n-2, ..., 0, 2^n-1, ..., which is exactly a down count. Many flip-flops expose both Q and Q̄ pins for precisely this kind of reuse.
Practical application, real-world use, and common mistake
Down counters are the natural building block for countdown timers, watchdog timers (which must trigger a recovery action if they are allowed to count all the way down to zero without being reset by normal operation), and loop counters that track remaining iterations rather than completed ones — useful whenever downstream logic needs to know 'how many are left' directly from the counter's bits, without a separate subtraction.
The common mistake is assuming a countdown application will naturally 'stop' when the down counter reaches zero. A free-running down counter has no built-in stopping behavior — on the clock edge after it reaches 0, it will simply wrap around to its maximum value and keep counting down again, exactly like an up counter's wraparound at the top. A real countdown-to-zero application (for example, a timer that must expire exactly once) needs an explicit comparator that detects the zero state and then stops the clock, holds the counter, or reloads it, rather than relying on the counter to 'run out' on its own.
Down counter next-state rule
Complementing every output bit of an equivalent up counter (reading Q_bar pins) also produces a valid down-counting sequence, since complement(v) = 2^n - 1 - v. Underflow at 0 wraps to the maximum value (2^n - 1), mirroring the up counter's overflow-at-max wraparound to 0.
Down counter, n bits:
next_state = (current_state - 1) mod 2^n
Borrow-toggle view (bit k, 0-indexed):
bit k toggles on a given clock edge iff bits 0..(k-1) are ALL currently 0
Excitation (T flip-flops):
T0 = 1
T1 = NOT Q0
T2 = (NOT Q0) . (NOT Q1)
Tk = AND of complements of all lower bits
Sequence: (2^n - 1), (2^n - 2), ..., 1, 0, (2^n - 1), ... (repeats indefinitely)Code Examples
Each row subtracts 1 from the previous, with borrows rippling through the excitation logic exactly as manual binary subtraction would. On reaching 000, the 8th clock edge wraps the counter back to 111 (the maximum unsigned value), since binary subtraction below 0 has nothing to represent a negative result with in this unsigned scheme. Expected result: Full cycle length: 8 states (111 down through 000), repeating indefinitely.
000 (0) - 1 clock edge -> 111 (7): underflow wraps to the maximum value, mirroring the up counter's overflow-to-zero wraparound.
Clock# Q2 Q1 Q0 Decimal
0 1 1 1 7 (start)
1 1 1 0 6
2 1 0 1 5
3 1 0 0 4
4 0 1 1 3
5 0 1 0 2
6 0 0 1 1
7 0 0 0 0
8 1 1 1 7 <- wraps to maximum value (7), not to a negative numberImportant Rules
A down counter's next state is always (current state - 1) mod (number of available states).
The LSB toggles on every clock edge of a down counter; every higher bit toggles exactly when all lower bits are currently 0 (the borrow-out condition), mirroring the up counter's carry-toggle rule.
A free-running down counter does not stop at 0 — it wraps to the maximum value on the next clock, so an application that must halt or reload exactly at zero needs explicit zero-detect logic on top of the base counting behavior.
Countdown and watchdog timers
Down counters are the core of countdown timers (a kitchen-timer-style circuit counting seconds remaining), retry counters (counting attempts remaining before giving up), and watchdog timers, which continuously count down and must be periodically reloaded by normal system operation — if the countdown is ever allowed to reach zero unchecked, that is treated as a fault, triggering a reset or recovery action.
Assuming a down counter will automatically stop once it reaches 0, since 'counting down to zero' sounds like a natural endpoint.
Without additional logic, a free-running down counter simply wraps from 0 to its maximum value (2^n - 1) on the next clock edge and keeps counting — a real countdown-to-zero application needs an explicit comparator/zero-detect circuit to stop, hold, or reload the counter at exactly the right moment.
Binary hardware has no inherent concept of 'this is the end' baked into the value 0 — it is just another state in the modulo cycle, so relying on the counter to 'run out' on its own produces a counter that silently wraps and continues, rather than halting as a countdown timer would need to.
[conceptual] What next-state rule defines a down counter, and what happens when it is at its minimum value (0) on the next clock edge? A. next_state = current_state + 1; it stays at 0 permanently once reached B. next_state = (current_state - 1) mod 2^n; it wraps around to the maximum value (2^n - 1) on the next clock edge C. next_state = 0 always; a down counter cannot actually decrement in hardware D. next_state = current_state XOR (2^n - 1); it produces an error flag at 0
B. next_state = (current_state - 1) mod 2^n; it wraps around to the maximum value (2^n - 1) on the next clock edge — A down counter's defining rule is next_state = (current_state - 1) mod 2^n. Since unsigned binary has no representation for a negative number, subtracting 1 from 0 underflows and wraps to the highest available value, 2^n - 1 — exactly the mirror-image of an up counter's overflow-to-zero wraparound at its maximum value.
[interview] Why is a naive assumption that 'a down counter naturally stops at zero' incorrect for a free-running hardware counter? A. Because down counters cannot actually reach zero due to a hardware limitation B. Because a free-running counter has no built-in halting behavior at any particular state — it keeps cycling through its modulo sequence, so reaching 0 is followed by wrapping to the maximum value on the very next clock unless explicit zero-detect and stop/reload logic is added C. Because down counters always count in decimal, not binary, and decimal zero behaves differently D. It is not incorrect — all down counters stop automatically at zero by design
B. Because a free-running counter has no built-in halting behavior at any particular state — it keeps cycling through its modulo sequence, so reaching 0 is followed by wrapping to the maximum value on the very next clock unless explicit zero-detect and stop/reload logic is added — A counter is fundamentally a cyclic state machine defined by its next-state rule; nothing about reaching 0 inherently halts that rule from being applied again. A real countdown application that must stop or reload precisely at zero needs a dedicated comparator watching for the all-zero state and driving separate stop/reload control logic — the counter itself has no concept of 'done.'
Design (in words) a watchdog timer using an 8-bit down counter: it should reload to 255 whenever a KICK signal pulses (indicating the system is healthy), and assert a RESET output if it is ever allowed to count all the way down to 0 without being kicked in time.
Build an 8-bit synchronous down counter with a parallel-load input tied to the constant 255 and a load-enable driven by KICK: whenever KICK pulses, the counter synchronously reloads to 255 on the next clock instead of decrementing. Add an 8-bit zero-detect comparator (a wide NOR/AND gate checking all 8 bits are 0) watching Q7..Q0; its output drives RESET. As long as KICK arrives frequently enough to reload the counter before it reaches 0, RESET never asserts; if the system stalls and KICK stops arriving, the counter eventually reaches 0, the comparator fires, and RESET is asserted to recover the system.
You need both a synchronous reload path (triggered by KICK) and a zero-detect comparator feeding the RESET output.