[ < Prev | Up | Next > ]   Node: Timing Analysis

hexforge / timing analysis

Timing analysis

The analyser walks the routed design, adds up cell and wire delays along every register-to-register path, and tells you the worst one per clock. It is a static check against a measured delay table, and its accuracy is limited by how that table was built.

A full report

$ hxta --device T4-25K --corner slow uart_loopback.hxr

hxta 0.7.2   design uart_loopback   device T4-25K
corner slow: 85 C, 1.14 V, delay table t4.hxd rev 11 (2026-02-18)

clock groups
  name      target        period     achieved   slack      status
  clk_12m   12.00 MHz     83.333 ns  71.4 MHz   +69.333 ns PASS
  clk_tx    48.00 MHz     20.833 ns  52.1 MHz   +1.646 ns  PASS

  2 clocks, 1 asynchronous crossing NOT analysed (see warnings)

worst path, clock clk_tx, slack +1.646 ns
  start   tx_div.count[4]           FF/Q       0.000 ns   0.000
  cell    lut4 u_2871               A -> Y     0.412 ns   0.412
  route   net n_4412 (3 hops)                  1.087 ns   1.499
  cell    lut4 u_2903               B -> Y     0.398 ns   1.897
  route   net n_4418 (5 hops)                  2.241 ns   4.138
  cell    lut4 u_2911               C -> Y     0.431 ns   4.569
  route   net n_4423 (2 hops)                  0.766 ns   5.335
  cell    lut4 u_2960               A -> Y     0.407 ns   5.742
  route   net n_4431 (9 hops)                  4.912 ns  10.654
  end     tx_shift.data[7]          FF/D       0.000 ns  10.654

  setup                                        0.182 ns  10.836
  clock skew start to end                     -0.148 ns  10.688
  required (period 20.833, uncertainty 0.250)            20.583
  slack                                                  +1.646

paths 2 to 10 by slack
   +1.812 ns  tx_div.count[4]    -> tx_shift.data[6]
   +2.004 ns  tx_div.count[3]    -> tx_shift.data[7]
   +2.119 ns  rx_sync.stage[1]   -> rx_fsm.state[2]
   +2.640 ns  tx_div.count[2]    -> tx_shift.data[5]
   +3.118 ns  rx_fsm.state[0]    -> rx_fsm.state[1]
   +3.402 ns  rx_fsm.state[2]    -> tx_load
   +4.001 ns  tx_shift.data[0]   -> uart_tx_pin
   +5.277 ns  rx_sync.stage[0]   -> rx_sync.stage[1]
   +6.015 ns  rx_fsm.state[1]    -> rx_err

warnings
  W204  clk_12m -> clk_tx crossing on net rx_sync.stage[0]: no
        constraint, path excluded from analysis
  W117  one route has 9 hops; delay estimates degrade above 6

2 clocks analysed, 0 violations, 2 warnings

Reading the path listing

Each line of the path is a delay and a running total. The right-hand column is cumulative, so the last route line being 4.912 ns of a 10.654 ns path is the whole story of this design: half the critical path is one badly routed net with nine hops. The placer put those two cells far apart because it optimises wirelength globally and knows nothing about this path, which is the structural weakness described on the build flow page.

Two practical consequences. First, re-running hxsyn --seed 3 and re-checking will often move a path like this by a nanosecond or more. Second, warning W117 means the number you are reading is the least trustworthy kind: the delay table was fitted on routes of two to six hops, and beyond that the model extrapolates.

The W204 warning deserves attention rather than irritation. Those two clocks are unrelated, the analyser cannot check the crossing, and it says so instead of quietly reporting a pass. A missing clock-domain constraint is the single most common reason a design passes timing here and misbehaves on the board.

What the model contains

Those numbers come from ring oscillators of varying length built on real boards and fitted per cell type. Accuracy is about ±12% and, importantly, the error is biased: long routes come out faster in the model than in silicon. That is the opposite of the direction you want to be wrong in.

What it ignores

  1. Hold checks. Not implemented. On these devices with a single global clock network and no local skew modelling, hold violations within one clock domain are unlikely, but "unlikely" is not "checked".
  2. Clock-domain crossings. Reported as a warning and excluded. There is no synchroniser recognition and no metastability analysis.
  3. Recovery and removal on asynchronous resets.
  4. On-die variation. One delay number per cell type across the whole die.
  5. Crosstalk and supply droop. Entirely absent from the model.
  6. Input and output delays unless you declared them with set_input_delay or set_output_delay. Undeclared IO timing is assumed ideal, which it never is.
  7. Hard block internals. Block RAM is modelled with one access time; PLL jitter is not modelled at all.

How much margin to keep

Treat a slow-corner result as the truth minus 15%. If a report says 52.1 MHz, plan for 44 MHz and verify on hardware. Designs that pass with less than roughly 10% slack have failed on boards here often enough that the figure is a rule of thumb rather than caution: three of the eight examples needed a seed change to clear it.

Where the margin genuinely is not there, the options are the boring ones: add a pipeline register, split a wide combinational expression, lower the clock, or try four seeds and keep the best. The toolchain will not retime anything for you, and it will not insert a register it was not asked for.

Flags

FlagDefaultEffect
--device <part>-Required. Must match the device the design was routed for, or the run aborts.
--corner <c>slowfast, typical or slow. Only slow is a defensible basis for a decision.
--paths <n>10How many paths to list after the worst one.
--clock <name>allRestrict the report to one clock group.
--jsonoffMachine-readable output. This format is stable; the text layout is not, and realigns whenever a column grows.
--fail-on-violationoffExit code 1 when any slack is negative, for use in a build script.

Exit codes without that last flag: 0 for a completed analysis, 2 when the routed design and the device do not match, 3 when the delay table revision is older than the device file expects.

[ < Prev | Up | Next > ]   Next node: Limitations
timing analysis · report captured with 0.7.2 · next: examples