Timing closure is cheapest when the RTL already has the right shape. This topic turns paths, slack, skew, exceptions and gating into habits for writing code.
7 lessons, about 39 min
The parameter makes the RTL edit small, but the interface owner must approve the changed latency. Update valid/control/side-data alignment, consumer timing, scoreboards and integration checks; a local parameter change alone does not close that work.
The whole topic on one page, taken from each lesson's Remember box. Read it before an interview, or print it.
Practice
Depth budget = (period - clock-to-Q - setup - margin) / gate-plus-wire delay.
Register interfaces where appropriate, put late signals last, limit fanout, and make pipeline stages a parameter when the path is uncertain.
Gate levels are not equal delays. Check the target library, corner, load and wire before you choose an architecture.
Rule of thumb: use the budget to decide, not to chase the minimum.
Fanout
Buffer levels grow with log of the load count: 2 levels at 16 loads, 5 at 1,024.
Replicate the register, not the logic before it. Use 2 to 4 copies, only on nets the timing report shows as high fanout.
Identical registers are merged. The copies survive only with a preserve-hierarchy boundary or the tool's do-not-merge attribute.
Rule of thumb: replicate at the source, and check the synthesis report to see that the copies are still there.
Patterns
A one-hot 16:1 mux is only slightly shallower than d[s], because the tool already builds a good tree.
AND-OR selects need at most one request. Registered control and prefix structures trade latency or area for depth.
A shallow pattern is valid only with its assumption. Keep $onehot0(req) asserted at the caller boundary.
Rule of thumb: never apply a shallow pattern without writing down and checking the assumption it relies on.
RTL Hooks
Hooks cover depth, implementation choice, output registers, replication, preserve, fanout limits and don't-touch.
Valid bits, control and side data must be delayed by the same number of stages as the data, so put them in the same hook.
Attribute names are tool specific. Put them in one wrapper or macro per tool.
Rule of thumb: let the scoreboard take its latency from the same parameter as the design.
Checklist
Registered interfaces, estimated depth of the three worst paths and an identified list of high-fanout controls.
Every shallow structure has an assertion. Every exception has an RTL reason and a test.
Gating uses library ICGs with a test enable, and the unconstrained-endpoints report is empty.
Rule of thumb: keep a short, specific list in the pull-request template, because a long generic one is skipped.
Cutting Logic Depth: a Timing-Closure Story
Restructure first: a tree instead of a chain cut 119 levels to 73 with no flops and no latency.
A register only helps outside a loop. Once the loop is the longest path, extra registers add latency and change nothing, or change the function.
Shorten a loop by changing it: split it with a registered carry, use lookahead or a redundant total, and align the result.
Rule of thumb: find where the longest path starts and ends before choosing a fix; if it starts and ends at the same register, change the loop.
Mini Project: Close Timing on a FIR Filter
Yosys already merges a sum of products into one adder tree, so rewriting the sum as a tree in RTL changed nothing: 48 levels both ways.
The transposed form makes every path one multiply and one add, at the same latency: 48 levels down to 38 for 72 flops.
Every branch of a pipelined sum must cross the same number of registers; an impulse with distinct coefficients shows which taps moved.
Rule of thumb: measure where the path starts and ends before restructuring, and re-run an impulse test after every pipelining change.
Practice question: Pipelined arbiter for timing closure
Code lab: AI pooling max
Code lab: Pipeline register stage
Interview: run a mock interview on this topic