Real chips use several clocks and resets. This section builds reset trees, synchronisers, Gray-coded FIFOs and handshakes, then proves them with window-counted simulation, assertions and checklists.
Topic | Lessons | After it you can… | Study time |
|---|---|---|---|
5 | Build a reset tree with a synchroniser per domain and an ordered release. | 2 h | |
5 | Use 2FF/3FF synchronisers and avoid bus-bit mistakes. | 2–3 h | |
7 | Design and test a Gray-coded async FIFO. | 3–4 h | |
5 | Choose and build handshake, pulse and load-pulse crossings. | 2–3 h | |
5 | Make crossings robust to one-sided resets. | 2–3 h | |
7 | Verify crossings with hostile simulation, assertions, scoreboards and mutations. | 2–3 h |
Study time covers reading each lesson and running its examples. The section's hands-on project takes extra hours on top.
Simulations use a metastability-aware flip-flop model: a data change inside the setup/hold window gives a random old/new output. Window hits are counted, so a test that never hit the window is visibly inconclusive.
Several lessons include a mutation: the design was deliberately broken (binary pointers instead of Gray, unstable data, a too-short hold time, resets on one side only) and the test was shown to fail. Those results are quoted in the lessons.
SVA properties run in Verilator and were each shown to fire on their own violation.
Reliability (MTBF) tables use stated illustrative parameters; real work needs library values.
Because the bits can be sampled at different times, so the destination sees values that never existed on the counter. The bus lesson measures this and shows the Gray-code fix.
Use these four questions to decide whether you are ready to move on: explain, predict, implement and debug. If one is shaky, each answer names the lesson to revisit. New readers can skip this until they finish the section.
Asynchronous assertion puts the logic in a known state immediately, even with no clock running. Synchronous release, through a small reset synchronizer, makes every flop leave reset on the same clock edge and away from it, which avoids recovery and removal violations and flops that leave reset in different cycles. Revisit The async-assert, sync-deassert template.
Any mix of old and new bits, because each bit resolves independently: 0x7F, 0x80, but also values such as 0xFF or 0x00 that the counter never held. Multi-bit values need Gray code (one bit changes per step), a handshake, or an async FIFO. Revisit Do not synchronize buses bit by bit.
Empty, in the read domain: the read pointer equals the synchronized write pointer. Full, in the write domain: the write pointer equals the synchronized read pointer with its two most significant bits inverted. Each flag is computed in its own domain, so it can only be late, never early. Revisit Full, empty and almost flags.
The slow clock can take no edge while the pulse is high, so the pulse never gets sampled. Convert the event to a level first: toggle a flop on each event in the source domain, synchronize the toggle, and detect its edges in the destination; or use a request/acknowledge handshake when events can come close together. Revisit Pulse synchronizers and event toggles.