Module 5: Clock Tree Synthesis ยท 5.4 Post-CTS Timing

Why Hold Violations Appear After CTS

Section 5.4 opens with a fact worth sitting with. Every timing report this course generated before this module, synthesis-stage STA in Module 2 and pre-CTS timing in Module 4, checked setup, and only setup had anything meaningful to say. Hold checks were technically running the whole time. They just were not telling you anything real. This article explains why, and why that stops being true the instant a real clock tree exists.

Hold has no clock-period budget

Recall the structural difference from the Verilog course’s STA lesson. Setup is a long-path constraint: data has to arrive before the next edge, with up to a full period to work with. Hold is a short-path constraint: data has to stay valid past the same edge that launched it, with essentially none of the period as budget. Hold’s entire tolerance comes from clock-to-Q and combinational delay on the data path, compared against a tiny hold-time requirement.

$$\text{Hold slack} = (t_{cq} + t_{comb} + L_{\text{launch}}) - (L_{\text{capture}} + t_{hold})$$

Look at where latency appears. (L_{\text{launch}}) helps hold slack, since a later launching edge gives the data more of a head start. (L_{\text{capture}}) hurts it, since a later capturing edge pushes the moment the old data must still be steady later in time. That is the whole mechanism this article is about.

Before CTS: latency is zero everywhere

Every earlier report used an ideal clock, every flop assumed to receive the edge at the same instant with latency zero, or at best a uniform placeholder. Substitute (L_{\text{launch}} = L_{\text{capture}} = 0):

$$\text{Hold slack} = t_{cq} + t_{comb} - t_{hold}$$

For almost any real cell and almost any real path, even a very short one like a counter’s own increment feedback, (t_{cq} + t_{comb}) comfortably exceeds a typical library hold requirement. Hold passes easily almost everywhere under an ideal clock. Not because the design is safe. Because the check was never being stressed.

Hold under an ideal clock and under a real tree
Figure 1: Top, both flops see the edge at the same instant and the data's 165 ps of delay clears the 60 ps hold window with room to spare. Bottom, the capture edge arrives 111 ps later and the hold window now overlaps the moment the data changes.

After CTS: latency is real, and unequal

The moment TritonCTS builds a tree, (L_{\text{launch}}) and (L_{\text{capture}}) stop being zero and stop being equal. Every picosecond of skew between a specific launching and capturing pair now subtracts directly from that pair’s hold slack, exactly as the equation already said, just previously hidden behind an idealisation. Nothing about the logic changed. Nothing about the cells changed. The clock model became real, and hold’s true exposure, which was always there, becomes visible for the first time.

This is why hold violations have a reputation as “the CTS surprise” even among people who have run dozens of flows. CTS does not cause hold problems in any active sense. It is the first stage honest enough to expose a vulnerability that was structurally present from the moment the RTL was written, on any path whose combinational delay is small relative to the skew the tree can achieve.

Which paths are most exposed

Given the equation, the paths at risk are the ones where (t_{cq} + t_{comb}) is already small, because they have the least cushion to absorb skew working against them. Register-to-register paths with very little logic between them are the classic offenders: a counter’s bit-to-bit increment feedback, an XOR and an AND, roughly; a simple enable-gated pass-through register; or any flop feeding almost directly into another. The UART’s baud counters are exactly this shape, a counter incrementing every cycle with a small adder’s worth of logic between one bit and the next, which is why the worked violation in the next two articles comes from precisely this kind of path.

Practice Exercise

Using the hold equation with both latencies zero, a path has (t_{cq} = 0.095) ns, (t_{comb} = 0.070) ns and (t_{hold} = 0.060) ns. Confirm its hold slack under an ideal clock, then state what would have to be true about skew for this same path to fail hold once a real tree exists.

Solution

Under the ideal clock: 0.095 + 0.070 - 0.060 = 0.105 ns, comfortably positive.

For the same path to fail once real, unequal latency exists, the skew working against it, capture latency minus launch latency in the unfavourable direction, would need to exceed that 0.105 ns cushion. Any post-CTS skew on this pair above roughly 105 ps flips its hold slack negative. A design with generous (t_{comb}) everywhere would never see this. It is specifically short, low-logic paths like this one where an ordinary, within-tolerance skew value flips a comfortable margin into a real violation.

You now understand the mechanism in the abstract. The next article makes it concrete: a full post-CTS OpenSTA report on the UART, showing exactly where a hold violation appears that no pre-CTS report ever flagged.

โ† Running CTS on the UART Reading a Post-CTS Timing Report โ†’