Your timing report shows a setup violation on a critical path. What do you do about it?
Read the slack to see how much time is missing, confirm the path is real and correctly constrained, then shorten it by restructuring or pipelining the logic and letting physical implementation close the rest. Lowering the clock frequency works but penalises the whole design, so it comes last.
What the interviewer is scoring
- Whether you interrogate the constraint before you change the design, since a large share of early violations are constraint bugs rather than logic that is too slow
- Does the candidate separate setup from hold by cause rather than reciting the two definitions
- That you can name pipelining and retiming as different fixes with different consequences for the surrounding block
- Whether reducing the clock frequency arrives as a last resort with its cost stated, or as the first idea
- Whether you know which of the two violation types a longer clock period cannot help at all
Answer
Short answer
To fix a setup timing violation, first confirm the path and constraints are real, then inspect whether the missing slack comes from logic depth, interconnect, or clock assumptions. Restructure logic, retime, pipeline, or improve placement before lowering the clock, because a slower clock penalizes the whole domain.
What the report is telling you
A setup check asks whether data launched by one flop arrives at the next flop's input, and is stable there, before the capturing clock edge minus that flop's setup time. Static timing analysis works this out for every path in the design without simulating anything, and reports the difference between the time available and the time taken as slack. Negative slack is a violation: the path needs more time than the clock period gives it.
It helps to write the two sides out, because every fix you will propose moves one term in this expression.
time available = clock period
+ capture clock arrival
- clock uncertainty
- flop setup time
time taken = launch clock arrival
+ flop clock-to-output delay
+ combinational logic delay
+ interconnect delay
slack = time available - time taken # negative means violation
Suppose the clock period is 5ns and the report shows slack of minus 0.4ns on a path running through an adder and a wide multiplexer. That is the whole content of the violation: you need to find 0.4ns somewhere, either by making the right-hand column smaller or the left-hand column larger. The report also tells you where the time went, path element by path element, and the first thing worth knowing is whether the delay is concentrated in a few logic stages or spread across a long stretch of interconnect, because those have different remedies.
Confirm the path is real before you touch the design
Early in a project, a meaningful share of reported violations are constraints rather than logic. The path might be between two clocks that are asynchronous and never intended to be compared, in which case the fix is to declare them as such rather than to redesign anything. It might be a path that takes several cycles by construction, where the receiving logic is enabled only every fourth cycle, so the correct description is a multicycle path and the tool was simply told the wrong thing. It might involve an input or output delay that nobody has characterised yet, so the tool is assuming a default that has no relationship to the board.
This is worth a genuine look because the two mistakes here are symmetrical and both are expensive. Fixing a constraint bug by adding pipeline stages leaves you carrying latency you never needed. Fixing a real violation by relaxing a constraint gets you a design that closes timing on paper and fails in silicon, and that failure is discovered late and is not fixable in software.
The fixes, roughly in order of what they cost you
Restructuring the logic is first because it costs nothing but your time. Long chains of dependent arithmetic, priority encoders written as deeply nested conditionals, and comparisons made against a value that has itself just been computed all produce more logic depth than the function requires. Rewriting the same function as a balanced tree rather than a chain, or precomputing both possible results and selecting between them at the end, shortens the path without changing the interface at all.
Retiming comes next. If two register stages sit either side of a boundary and one of them has far more logic than the other, moving logic across the register boundary balances them. Nothing about the block's external timing or latency changes, which is what makes retiming attractive: you are redistributing existing slack rather than asking for more.
Pipelining is the reliable fix when the function genuinely needs more logic depth than one cycle affords. You insert a register stage in the middle of the path, and each half now has a full clock period. It works, and it is the answer most often reached for, but it is not free in the way retiming is.
Physical implementation is the other lever, and it is the one that closes small deficits late in the flow. Two cells that logically sit next to each other can end up far apart, and the wire between them is real delay. Improving placement so that the path's cells are near each other, or allowing the tool to use larger drive strengths on the cells along it, recovers time at the cost of area and power. Below some deficit this is where closure actually happens, and above some deficit no amount of it will help, because you cannot place your way out of fifteen levels of logic.
Pipelining changes the block, not only the path
Adding a register stage adds a cycle of latency, and that consequence leaves the path immediately. Anything that expected a result one cycle after its request now gets it two cycles later, so the control logic around the block has to be adjusted, any parallel path that must stay aligned with this one needs a matching delay, and a handshake protocol may need an extra ready or valid stage. If the block sits inside a feedback loop, pipelining it changes the loop's behaviour rather than just its timing, and that is a functional change requiring re-verification rather than a timing fix.
This is why "just add a pipeline stage" is a weaker answer than it sounds. It is often the right decision, but stating it without naming the latency cost and the verification consequence reads as knowing the technique rather than having used it.
Lowering the clock is a last resort for a specific reason
Reducing the clock frequency does close a setup violation, because the clock period is the leading term on the available side. The problem is that it is a global change applied to solve a local one. Every other path in that clock domain gets slower with it, so you pay throughput across the entire design to fix one path that was 0.4ns short. If the frequency is a product requirement, it is not on the table at all; if it is negotiable, it is still the change you make after establishing that the path cannot be shortened.
Why a longer clock period cannot save a hold violation
The point most candidates miss is that the two violation types are not symmetric, and the asymmetry is the useful thing to know. A hold check asks whether data stays stable at the capturing flop's input for long enough after the clock edge, and the launch and capture in a hold check happen on the same edge. The clock period does not appear in the hold calculation. So a hold violation is completely indifferent to your clock frequency: slowing the clock down helps setup and does exactly nothing for hold.
That inverts the fixes too. A setup violation means a path is too slow, and you make it faster. A hold violation means a path is too fast, and you make it slower, typically by having the tool insert delay along it. It also explains why hold is usually the more serious discovery: a setup failure can sometimes be lived with by running the part below its intended frequency, whereas a hold failure means the part does not work at any frequency. In an interview, volunteering that distinction unprompted tells the interviewer you have read a real timing report rather than a textbook chapter on it.
A setup violation is a question about how much time the path needs; a hold violation is a question about whether the part functions at all, and only the first one cares what your clock period is.
© 2026 Preptima. Originally published at preptima.com.
Likely follow-ups
- What changes in the slack arithmetic when the launching and capturing flops run on different clocks?
- You add a pipeline stage to close the path. What must change in the block that consumes its output?
- When is declaring a path false a legitimate fix, and when is it concealing a design error?
- Why does clock uncertainty tend to grow as a design gets physically larger?
Related questions
- Why is one flip-flop not enough to bring a signal into another clock domain?hardAlso on rtl-design7 min
- A modal passed design and QA review, but keyboard users report they can tab out of it into the page behind, and once they do they cannot get back or close it. Diagnose it and tell me what a correct dialog does.hardSame kind of round: scenario4 min
- A save button calls an API, the request fails, the error appears in the console - and the UI still shows 'Saved'. Walk me through what is actually happening in that promise chain.mediumSame kind of round: concept4 min
- An asyncio call times out and you handle the TimeoutError, but the background task keeps running and mutates shared state a few seconds later. What happened, and how do you make the timeout actually stop the work?hardSame kind of round: concept4 min