Skip to content

Hardened macros' .lib clock-tree characterization doesn't match parent CTS — root cause of #28 mask #52

Description

@npip99

Problem

When ORFS hardens a leaf macro, the write_timing_model step produces a <macro>_typ.lib describing its boundary timing — clock-to-output delays, input setup/hold, etc. These arcs are characterized with assumptions about the macro's internal clock tree latency that bake in to the .lib's reported source/target latencies.

Specifically:

  1. Internal CTS sets internal clock-tree latency. Each macro's hardening flow builds its own clock tree. The internal CTS produces some insertion delay (say X ps) from the macro's clk pin to its internal flops.
  2. write_timing_model reports arcs relative to the internal-CTS reference. The .lib treats the macro's clk input as the reference point and characterizes flop arrival as if there's an equivalent delay between clk pin and internal flop.
  3. At chip_top, parent CTS produces a DIFFERENT delay. chip_top's CTS distributes the chip clock to each macro's clk pin. The parent insertion delay to (e.g.) u_reset_seq/clk is determined by chip_top's CTS strategy — NOT by what reset_seq's internal CTS assumed.
  4. STA sees a mismatch. chip_top's STA combines parent insertion delay + macro's reported boundary arc. If the macro's .lib assumed a different internal latency than chip_top's CTS actually delivers, the combined arrival times don't match. Result: bogus skew, bogus hold violations.

This was hit in #28 first-close attempt:

  • reset_in_sync$_DFF_PP1_/CLK (chip_top's CDC sync flop): +1948 ps source latency (chip_top's parent CTS)
  • u_reset_seq/clk (macro boundary): −932 ps target latency

The negative target latency is the .lib's reporting convention: the macro's .lib was characterized with its own clock-tree latency built in, expressed as a delta from the boundary. STA can't reconcile +1948 vs −932 → 1008 ps setup skew → hold-buffer pile → DRT can't converge → masked via HOLD_SLACK_MARGIN=-2000 in chip_top.config.mk.

Existing TODO with no home

tech/asap7/orfs/compute_array_abut.sdc:65 flags this:

# TODO before tape-out: replace this constraint with proper abstract-lib
# generation that exposes the chain register's sequential arcs natively.
# Until then, the multicycle is the industry-standard workaround for
# hardened-macro shift registers. See tech/RCA_DISCIPLINE.md.
set_multicycle_path 32 -setup -through [get_pins -hierarchical *u_a/chain_w_s*]

This TODO was identified in #41 review as "load-bearing for #28" but has never had its own tracking issue. Filing here so it's not buried in a SDC comment.

Why this matters

Until the .lib faithfully represents each macro's actual boundary timing (with its internal CTS latency exposed AS A SEQUENTIAL ARC, not absorbed into reference-relative numbers), parent-level STA has no path to honest closure on any chip_top integration. Workarounds (multicycle, HOLD_SLACK_MARGIN, set_clock_uncertainty) can mask the symptom but produce LEFs that would fail foundry sign-off STA.

This is the load-bearing root cause referenced in:

Acceptance criteria

  • Hardened macros' .lib files expose their internal clock-tree latency as explicit sequential arcs (clk → q) with real delays, not absorbed into source/target latency conventions
  • chip_top STA at the macro boundary uses these arcs and computes consistent setup/hold without manual multicycle SDC patches
  • compute_array_abut.sdc's multicycle workarounds can be removed
  • chip_top.config.mk's HOLD_SLACK_MARGIN=-2000 can be removed
  • First chip_top close achieves positive setup slack AND 0 DRC without masking knobs

Implementation options

  1. Custom OpenROAD write_timing_model invocation with SDC that clocks the macro's internal flops separately from the boundary clock pin, so the tool emits real sequential arcs instead of folding them into reference latency. Was attempted during #40: pure abutment compute_array — 32×32 closes #41 (the subagent investigation); should be revisited.
  2. Hierarchical CTS at chip_top that explicitly de-skews based on each macro's published internal-latency budget (requires manual set_clock_latency -source per macro pin, OR a manifest-driven flow).
  3. Eliminate parent CTS altogether via Chip-level clock distribution: avoid fanning chip clock to all macros via parent CTS #50 traveling clock — the macro's internal latency doesn't need to match parent CTS choices if there IS no parent CTS.

Option 3 is the largest architectural lift but is the only one that fully solves the class of problem. Options 1/2 are tactical patches.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions