Clock Domains, Synchronizers & Edge Detection
Metastability, the two-flip-flop synchronizer, edge detectors, and why you should use clock enables instead of generated clocks.
Inside one clock domain, every flip-flop samples signals that changed safely after the previous edge. Signals from outside — a push button, another clock domain, an external chip — can change at any moment, including right at a clock edge. A flip-flop sampling a changing input can go metastable: its output hovers between 0 and 1 for an unpredictable time.
Clock enables, not divided clocks
always @(posedge clk) if (button) count <= count + 1; // raw button
Synchronize (and debounce) the button, then count rising edges
The raw input is asynchronous (metastability risk) and a level, so count increases every clock the button is held. Synchronize, then use an edge detector.
reg [7:0] sync1, sync2; // 8-bit bus through 2 FFs Use Gray code, a handshake, or an asynchronous FIFO for multi-bit data
Each bit settles independently, so the captured value can mix old and new bits — a value that never existed.
What is metastability?
When a flip-flop samples an input that changes within its setup/hold window, its output can stay at an intermediate level for an unbounded (though usually short) time before resolving to 0 or 1.
Why is a two-flip-flop synchronizer not enough for a multi-bit counter?
Each bit is synchronized independently and may be captured in different cycles, producing an invalid combination. Gray-code the counter (one bit changes per step) or use a handshake or async FIFO.