UART · Module 8
Clock Enable vs Generated Clock
Both architectures produce one event per bit interval and both simulate correctly. One adds a clock domain, a constraint and a CDC review to a design that needed none of them.
Every chapter of Modules 5, 6 and 7 consumed a timing signal it did not build. The receiver took os_tick_i, OVERSAMPLE pulses per bit interval (Chapter 5.3); the transmitter took baud_tick_i, one per bit interval (Chapter 7.3). Both were described as enables, and both chapters said the argument for that belonged here.
This is that argument, and it is worth making carefully because the alternative is not obviously wrong. A divider producing a slower clock is a completely ordinary piece of digital design. It works. It simulates correctly. A UART built on one will transmit and receive correctly.
What it does is change the design from a one-clock-domain problem into a two-clock-domain problem — and it does so silently, because nothing in RTL simulation reports the difference.
1. What a Tick Is
A precise definition, fixed here and used unchanged for the rest of the module:
baud_tick_o is a ONE-FABRIC-CLOCK-CYCLE pulse, synchronous to clk,
asserted on the clock edge that ENDS one bit interval and BEGINS the next.
It is an enable. It is not a clock, and nothing is ever clocked by it.Two parts of that need emphasis.
It is one cycle wide. Not a level that stays high for part of the interval, not a 50% duty waveform. A consumer therefore does not need to detect an edge on it — it simply tests it.
The edge carrying it is the boundary. This is the convention Chapter 7.3 §2 adopted: the tick does not precede a boundary or follow one, it is one. The alternative convention — a tick meaning "the interval will end next cycle" — is equally implementable and produces a design where every consumer must remember to act one cycle late. Either works; mixing them does not, which is why the convention is stated once and not restated.
The consumer pattern is always the same:
// Synthesizable SystemVerilog — the enable pattern, in the abstract.
// This is what every timing-dependent block in Modules 6 and 7 looks like.
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) state_q <= S_IDLE;
else if (baud_tick) state_q <= next_state; // advance one bit interval
// else: hold. The vast majority of cycles take this path.
endAt 100 MHz and 115,200 baud that else branch is taken 867 times out of every 868 cycles (Chapter 4.3 derived the divisor). The datapath is idle almost all the time, which is exactly what a UART is: a very slow protocol on a very fast clock.
2. The Alternative
The generated-clock form divides clk down and uses the result as a clock:
// Conceptual SystemVerilog — the generated-clock architecture.
// This WORKS. It is shown so the comparison in §3 is concrete.
logic baud_clk_q;
logic [9:0] cnt_q;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin cnt_q <= '0; baud_clk_q <= 1'b0; end
else if (cnt_q == 10'd433) begin
cnt_q <= '0;
baud_clk_q <= ~baud_clk_q; // toggle: half a bit interval each way
end else cnt_q <= cnt_q + 1'b1;
end
// ... and then, somewhere else in the design:
always_ff @(posedge baud_clk_q) begin // <-- a SECOND clock domain
state_q <= next_state;
endBoth architectures produce one state advance per bit interval. Both are correct as RTL. In a functional simulation they are indistinguishable at the protocol level.
One-cycle enable versus a divided clock
12 cyclesRead the two middle rows against each other. They encode the same event at the same rate. The enable is a condition evaluated inside an existing clock domain; the divided clock is a clock, and everything it clocks lives somewhere new.
3. What the Second Domain Costs
The costs are real, specific, and mostly invisible until implementation.
A clock domain crossing appears where there was none. The divider's counter runs on clk; the state machine runs on baud_clk. Any signal passing between them — a configuration register, a status flag, a reset — crosses domains. In the enable form there is no crossing because there is one domain, and the only crossing in the whole UART is the genuinely asynchronous rx_i pin that Chapter 5.1 already handles with a synchroniser.
Static timing analysis needs to be told about it. A generated clock must be declared to the tool, and paths between the two domains must be constrained or cut. Neither is difficult; both are work that has to be done correctly, reviewed, and maintained as the design changes. A design with one clock has none of it.
On an FPGA it consumes a clock resource, or skews. A signal used as a clock should be routed on the dedicated clock network. Doing that means allocating a global buffer — a limited resource on every device — and often means the divider's output must pass through a clock buffer primitive to get there. Routing it on ordinary fabric instead works, and gives the new clock a skew relative to clk that varies with placement and that timing analysis must account for.
The relationship between the two clocks becomes an assumption. baud_clk is derived from clk, so their edges are related — but only if the tool is told so. Treated as unrelated, the analysis is pessimistic or the paths are cut and real violations are hidden.
Clock gating and low-power flows treat it differently. A derived clock interacts with gating, retention and DFT insertion in ways a plain enable does not. Module 12 owns those consequences.
4. When a Generated Clock Is the Right Answer
The rule stated above is a default, not a law, and treating it as a law is its own failure mode.
Large ratios with a genuinely slow subsystem. If a substantial block runs at a rate thousands of times below clk and its power matters, running it on a real slow clock lets the tools gate it properly. An enable keeps every flip-flop clocked and toggling its clock pin at full rate.
When the divided clock leaves the chip. A clock that must appear on a pin — a serial interface's SCLK, say — is a clock, and there is no enable equivalent.
When the protocol requires a specific duty cycle on a wire. UART does not; some interfaces do.
When the ratio is enormous. A divide-by-100,000 enable is fine functionally, but the enable's fanout reaches every flip-flop in the block and toggles once per 100,000 cycles, which is a poor power profile if the block is large.
A UART baud generator is none of these. The divisor is in the hundreds or low thousands, the consumer is a handful of small state machines and counters, the timing never leaves the chip, and the duty cycle is meaningless because the protocol defines intervals rather than edges. The enable form costs one comparison per consumer and eliminates an entire category of implementation work.
So the honest statement is conditional: for ordinary UART datapath timing, a synchronous one-cycle enable is normally the cleaner architecture — and the reasoning above, not the conclusion, is what transfers to the next block.
5. The Structural Consequence
Because the tick is an enable, a useful property follows for free: the timing generator and its consumers share no state.
There is one architectural rule worth stating explicitly, because it is the way the enable form gets accidentally converted back into the clock form:
Never gate clk with the tick. Writing assign gated_clk = clk & baud_tick; looks like an optimisation and reintroduces every cost in §3 plus a glitch hazard, because the result is a clock produced by combinational logic. Enables are what synthesis and FPGA fabric are built to handle; clock gating is a distinct technique with its own cells and its own review, and Module 12 covers it.
6. Verification
Assert the pulse width. The contract says one cycle. A generator that holds the tick high for two would advance every consumer twice per interval, halving the baud rate — and the symptom would be a rate error, sending the investigation to the divisor rather than the pulse:
// Assertion — the tick is never asserted on two consecutive cycles.
property p_tick_is_one_cycle;
@(posedge clk) disable iff (!rst_n)
baud_tick_o |=> !baud_tick_o;
endproperty
assert property (p_tick_is_one_cycle);Assert that nothing is clocked by the tick. This is not an SVA property — it is a lint and review check. Searching the design for @(posedge and confirming that clk is the only expression that appears is a two-second check that catches the architecture drifting.
Count enables, not edges. A testbench measuring the baud rate should count tick pulses over a known number of fabric clocks. Measuring "the period of baud_tick" treats it as a waveform, which is the mental model this chapter is trying to displace.
Check the consumer holds. The property that makes the enable form correct is that a consumer does nothing when the tick is low. Chapter 7.2 §9 asserted exactly this for the transmit line, and the same shape applies to any enabled state.
7. What This Means on an FPGA
One clock means one clock constraint. create_clock on the input, and the design is described. No create_generated_clock, no inter-clock path exceptions, nothing for CDC analysis to report beyond the receive pin's synchroniser.
The enable is high-fanout and low-toggle. It reaches every timing-dependent register in the receiver and transmitter — a few dozen — and pulses once per 868 cycles at 115,200 baud. That fanout is unremarkable at UART scale; a tool will not replicate it and it will not appear in a timing report. The consideration only becomes real when a single enable drives thousands of endpoints, which a UART does not.
Every flip-flop still sees every clock edge. That is the enable form's genuine cost, and it is a power cost rather than a timing one. At UART scale — tens of flip-flops — it is negligible. §4's first case is where it stops being negligible.
Probe the tick, not a derived clock. On a logic analyser the tick is one cycle wide at the sample rate of clk, so a capture triggered on it shows the fabric-clock context directly. That is the first measurement Chapter 8.2 uses to check a divisor.
8. Understanding Check
9. Summary
A tick is a one-fabric-clock-cycle pulse, synchronous to clk, asserted on the edge that ends one bit interval and begins the next. It is an enable, and nothing is ever clocked by it. The convention that the edge carrying the tick is the boundary is fixed here and used unchanged for the rest of the module.
The generated-clock alternative works, simulates identically, and produces a correct UART. What it changes is that the design acquires a second clock domain: a CDC boundary between the divider and its consumers, a generated clock to declare, inter-domain paths to constrain or cut, and on an FPGA a dedicated clock resource to allocate or a skew to account for. None of that appears in RTL simulation, which is why the choice is easy to make badly and hard to notice.
The enable form leaves the UART with exactly one clock-domain crossing — the asynchronous rx_i pin, which the receiver's synchroniser already owns.
Generated clocks are not wrong. They are right for very large ratios with real power at stake, for clocks that leave the chip, and for protocols that specify duty cycle. A UART baud generator is none of those: hundreds-to-thousands divisor, a few dozen registers, on-chip only, intervals rather than edges.
And the way the enable form is accidentally undone is clk & baud_tick — which reintroduces every cost plus a glitch hazard on a clock net.
10. What Comes Next
This chapter has said what the generator must produce and nothing about how.
Chapter 8.2 builds it. It takes the divisor arithmetic Chapter 4.3 derived and turns it into a production block: the counter and its terminal count derived rather than asserted, the off-by-one that makes every bit interval one cycle too long and shifts the whole frame, counter width from the parameters, the runtime-programmable divisor that Chapter 4.3 explicitly deferred to this module, and the safe-update policy that keeps a rate change from corrupting the interval in progress.
Browse the full path on the UART tutorials index. For terminal-count counters and enable generation as a general RTL pattern, see Clock Dividers and Timers.
Continue learning
Related tutorials
- Related topic
Integer Dividers and Baud-Rate Error
The ratio is a fraction and a counter holds an integer, so rounding is a design decision with a measurable cost. Three policies, the actual rate each produces, and why the error belongs in units of a bit period rather than as a bare percentage.
- Related topic
Oversampling Strategies: 8×, 16× and the Alternatives
Oversampling is a grid of sample positions inside each bit interval. A higher factor buys placement resolution and costs tick rate, counter width and generator accuracy — and 16× became conventional for an arithmetic reason the standard crystal frequencies make obvious.
- Related topic
What a UART Actually Is
Two digital systems need to exchange a small amount of data over very few wires, and no clock travels with it. A UART is the logic that answers that problem — it converts between locally meaningful parallel data and timed activity on a single line, and the timing agreement it depends on is what the rest of the curriculum builds.
- Related topic
Synchronous vs Asynchronous Serial Links
A forwarded clock is a sampling reference generated by the same source as the data. Remove it and the receiver must assemble one from a configured rate, an observable event in the signal, and its own local clock — the responsibility shift that turns a receiver into a state machine and shapes every UART design decision that follows.
Where this fits
Part of the UART curriculum.
