Reading a Timing Report: Why Your First Instinct Might Be Wrong
Most engineers see a timing violation and immediately reach for pipelining. But the timing report is telling you exactly what the problem is — if you know how to read it.
Most engineers see a timing violation and immediately reach for pipelining. Sometimes that's exactly right. Sometimes the report is telling you something completely different — and if you don't read it carefully, you'll spend hours fixing the wrong thing.
The Scenario
You're in a design review — or a real interview. The interviewer shows you a timing report snippet from a 250 MHz design:
─────────────────────────────────────
Slack (VIOLATED) : -0.482ns
─────────────────────────────────────
Source : tx_data_reg[7]/C (FDRE)
Destination : rx_proc_reg[7]/D (FDRE)
Data Path Delay : 3.847ns
Logic Delay : 0.461ns (12%)
Route Delay : 3.386ns (88%)
Clock Path Skew : -0.142ns
Clock Uncertainty : 0.035ns
Required Time : 3.823ns
Arrival Time : 4.305ns
─────────────────────────────────────
"Where do you start?"
Most candidates say: add pipelining. Reduce LUT depth. Restructure the RTL.
Hold on.
How to Read This Report
Before reaching for a fix, understand what the report is actually telling you.
Slack is the timing margin — the difference between when a signal arrives and when it needs to arrive at the destination flip-flop. Negative slack means the path is failing: the signal is arriving 0.482ns too late.
Data Path Delay is the total time for the signal to travel from the source flip-flop to the destination. It has two components:
- Logic Delay — time spent propagating through LUTs, carry chains, DSP slices, and other combinatorial elements between registers.
- Route Delay — time spent traveling through the physical routing fabric. This is pure wire delay — it has nothing to do with your RTL.
Clock Path Skew is the difference in clock arrival time between source and destination registers. A negative value means the clock reaches the destination earlier than the source — that tightens your setup window.
The setup check the tool performs is essentially:
Slack = (Clock Period) - (Data Path Delay) - (Clock Uncertainty) + (Clock Skew)
= 4.000ns - 3.847ns - 0.035ns + (-0.142ns)
= -0.024ns [simplified]
The violation is real, and the path is telling you exactly where it comes from.
The Split That Changes Everything
Look at the logic/route breakdown:
Logic Delay : 0.461ns (12%)
Route Delay : 3.386ns (88%)
This is not a logic problem. There is almost nothing to optimize in the RTL.
If you add a pipeline stage, you split the data path — but the new shorter path is still 88% routing-dominated. The pipeline register moves the problem; it doesn't fix it.
If you reduce LUT depth, you shave fractions of a nanosecond off a budget that's already only 0.461ns. The 3.386ns routing delay doesn't move at all.
The signal is traveling a long distance across the FPGA fabric. That's a placement problem, not a logic problem.
The Clock Skew Makes It Worse
The clock path skew of −0.142ns works directly against setup timing. Positive skew helps setup — the destination clock arrives later, giving data more time to propagate. Negative skew does the opposite: the destination clock arrives earlier, shrinking the window.
In this case, the placer has already put the registers far apart — and the clock tree has compounded it with unfavorable skew. The routing was already marginal; the clock distribution made it worse.
The 60% Rule of Thumb
Routing delay should not consume more than 60% of your clock period.
At 250 MHz, the clock period is 4.000ns. 60% of that is 2.4ns.
The route delay here is 3.386ns — 85% of the clock period. That's nearly 1ns beyond the threshold.
When you see a number like this, stop looking at the RTL. The problem is physical.
The twelve common causes of FPGA timing failures are covered in detail in Chapter 4, Section 4.6.6 of Demystifying the Digital Design Interview.
The Fix: Guide the Placer
The solution is to help the placer co-locate the communicating registers.
Option 1: Pblock Constraint
create_pblock pblock_tx_rx_pipe
add_cells_to_pblock [get_pblocks pblock_tx_rx_pipe] \
[get_cells -hierarchical -filter {NAME =~ u_tx_pipeline/*}]
add_cells_to_pblock [get_pblocks pblock_tx_rx_pipe] \
[get_cells -hierarchical -filter {NAME =~ u_rx_pipeline/*}]
resize_pblock [get_pblocks pblock_tx_rx_pipe] \
-add {SLICE_X10Y100:SLICE_X30Y150}
Note: Pblocks are a scalpel, not a paintbrush. Constrain only what you understand. Over-constraining removes escape routes and can make other paths worse.
Option 2: KEEP_HIERARCHY
(* keep_hierarchy = "yes" *) module tx_pipeline (
input logic clk,
input logic [7:0] data_in,
output logic [7:0] data_out
);
always_ff @(posedge clk) begin
data_out <= data_in;
end
endmodule
Or via XDC: set_property KEEP_HIERARCHY TRUE [get_cells u_tx_pipeline]
Option 3: Structural RTL Refactor (Last Resort)
If the two registers belong to modules architecturally far apart, consider whether the interface between them can be redesigned to be more local. Sometimes a long routing path is a symptom of an interface that shouldn't exist at that level of the hierarchy.
What You Are Not Doing
To be explicit about what doesn't fix this:
- Adding pipeline stages — you're cutting an already logic-light path. Routing delay still dominates.
- Changing clock constraints — relaxing by 200ps hides the violation but doesn't change physics.
- Restructuring RTL to reduce LUT count — logic is 12% of the problem. Even eliminating it entirely only recovers 0.461ns. The violation is 0.482ns.
"A clock constraint is a declaration of intent — not a fix."
— Chapter 4, Page 118, Section 4.2 · Demystifying the Digital Design Interview
The Broader Lesson
Timing failures have different root causes, and the report tells you which category you're in:
| Dominant delay | Root cause | Fix direction |
|---|---|---|
| Logic-dominated (>60%) | Too many logic levels | Pipeline, retime, restructure RTL |
| Route-dominated (>60%) | Poor placement | Pblocks, KEEP_HIERARCHY, floorplan review |
| Skew-dominated | Clock tree or CDC issue | Review clock buffers, synchronizers, constraints |
| Combined | Marginal design | Combination of above; check SLR crossings |
Read before you react. There is no one-size-fits-all fix for a timing violation — the path tells you what it needs.
This post is based on content from Chapter 4: Static Timing Analysis & Timing Closure in Demystifying the Digital Design Interview: The Missing Guide for Practical RTL and FPGA Interview Preparation by Milind Parelkar.
Practice interview questions on this topic → FPGA Architecture Questions