> ## Content Index
> Fetch the complete content index at: https://fpgadesign.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# Reading a Timing Report: Why Your First Instinct Might Be Wrong
- URL: https://fpgadesign.io/blog/reading-a-timing-report-why-your-first-instinct-is-wrong/
- Published: 2026-05-17T04:44:25.000Z
- Updated: 2026-05-18T00:11:42.000Z
- Description: 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.
- Author: Milind Parelkar
- Tags: Advanced Concepts

*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

```tcl
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

```systemverilog
(* 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](https://fpgadesign.io/fpga-concepts/)