Skip to content

liteeth_udp_stream_sgmii: work around OpenROAD ODB-1200 in CTS hold-repair#76

Merged
mguthaus merged 1 commit intomainfrom
liteeth
Apr 24, 2026
Merged

liteeth_udp_stream_sgmii: work around OpenROAD ODB-1200 in CTS hold-repair#76
mguthaus merged 1 commit intomainfrom
liteeth

Conversation

@mguthaus
Copy link
Copy Markdown
Contributor

Summary

The bug

[INFO RSZ-0100] Repair move sequence: UnbufferMove SizeUpMove SwapPinsMove BufferMove CloneMove SplitLoadMove
[INFO RSZ-0098] No setup violations found
[INFO RSZ-0046] Found 347 endpoints with hold violations.
...
[ERROR ODB-1200] InsertBufferBeforeLoads: Load pin '_34829_/SN' is not connected to net '_03825_'.
Error: cts.tcl, 82 ODB-1200

The new RSZ-0100 move sequence (UnbufferMove first) orphans a load pin, then a later InsertBufferBeforeLoads pass trips an ODB consistency check. Fires at iter ~141 of a 347-endpoint hold-violation sweep. Bit-for-bit reproducible across runs.

Workarounds I tried and ruled out (see #75 and commit message for details):

  • set_dont_touch on reset net pattern — no-op (name didn't survive Yosys flat-synth).
  • set_false_path on reset cone — RSZ-0046 dropped only 347 → 346; the 346 other violations are datapath, not reset.

SKIP_CTS_REPAIR_TIMING=1 is the only thing that works. Downstream GRT and route still run their own hold-repair passes.

Test plan

  • ./k8s/run.sh --branch liteeth --upload-artifacts asap7 liteeth_udp_stream_sgmii — full k8s flow now completes end-to-end (41% util, 14886 µm², clean 6_final.gds on asap7).
  • Post-merge: other liteeth variants continue to pass (expected; this change is scoped to one BUILD.bazel + SDC).

…epair

OpenROAD (new pin from #71, tested at 5f1bd87f) crashes deterministically
in cts.tcl's post-CTS repair_timing on this netlist:

  [ERROR ODB-1200] InsertBufferBeforeLoads: Load pin '_34829_/SN' is
  not connected to net '_03825_'.  Error: cts.tcl, 82 ODB-1200

The new RSZ-0100 move sequence puts UnbufferMove first; an unbuffer
step orphans a load pin before a subsequent InsertBufferBeforeLoads
pass tries to reference it, tripping an ODB consistency check at
iter ~141 of a 347-endpoint hold-violation sweep. The worst-slack
endpoint (the reset synchronizer's D pin) is only a spurious display
artifact — the churn is on the datapath hold-violations, not reset.

Workarounds attempted and ruled out:
- set_dont_touch on reset net pattern: doesn't shrink the STA
  endpoint set, and Yosys flat-synth renames the net anyway. No-op.
- set_false_path -from sys_reset + -through reset net candidates:
  RSZ-0046 dropped 347 -> 346 (one endpoint removed), confirming the
  346 others aren't on the reset cone. Same crash.

Only SKIP_CTS_REPAIR_TIMING=1 bypasses the bug. Downstream GRT and
route still run their own hold-repair passes, so final QoR remains
reasonable (41% util, 14886 um^2 on asap7, clean 6_final).

Also keep a principled set_false_path -from sys_reset in the SDC
(sys_reset is an async input synchronized internally by
udpcore_int_rst; the port-to-synchronizer path shouldn't be timed).

Tracking re-enable: #75
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant