2026-07-14
You've seen how self-timed logic computes without a clock. But how does an async circuit know when both of its inputs have arrived? The answer is a strange little gate that most textbooks skip: the Muller C-element, invented by David Muller in 1955. It's the async equivalent of the flip-flop — the state-holding primitive that makes clockless design possible.
A C-element has two inputs and one output with this rule: the output changes only when both inputs agree. If A=B=1, output goes to 1. If A=B=0, output goes to 0. If A≠B, the output holds its previous value. That last property is what makes it stateful — it's a memory element built from a rendezvous condition rather than a clock edge.
The transistor-level implementation is elegant: a pull-up network that pulls high only when both inputs are 1, a pull-down network that pulls low only when both are 0, and a keeper (weak cross-coupled inverter pair) that holds the output when neither network is active. A standard static C-element uses 8 transistors — roughly the same as a NAND gate plus a latch.
Where you actually find them: four-phase handshake protocols. When a sender says "data valid" (req=1) and a receiver says "ready" (ack=0), a C-element combines these into a single "transaction complete" signal that only fires when both parties agree. Intel's RAPPID async instruction decoder used thousands of them. IBM's asynchronous shifter in the PowerPC 8xx series used C-elements for pipeline handshaking. Modern GALS (Globally Asynchronous, Locally Synchronous) NoCs use them at every clock boundary crossing.
The critical property — indication: a C-element's output transition indicates that both inputs have completed their transitions. This is called being "input-complete," and it's what lets you build delay-insensitive circuits — logic that works correctly regardless of wire delays. Synchronous logic assumes wires are fast enough; async logic with C-elements proves the wire arrived.
Rule of thumb for sizing the keeper: the keeper's drive strength should be roughly 1/4 the strength of the pull-up/pull-down networks. Too strong and your inputs can't flip the output; too weak and leakage or noise corrupts the held state. In a 7nm process, a typical C-element keeper uses minimum-width devices while the main networks use 2–3× width transistors.
The tradeoff: async design with C-elements eliminates clock distribution power and adapts naturally to voltage/temperature variation, but you pay in area (8T vs a 6T static gate) and in EDA tooling — most synthesizers don't understand C-elements natively, so you drop them in as hard macros.
