⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content

Conversation

@PrecisEDAnon
Copy link

@PrecisEDAnon PrecisEDAnon commented Jan 8, 2026

AI generated content follows.

PR: DFT scan insertion improvements (rebased)

This PR improves OpenROAD’s dft module so scan insertion works reliably with vanilla OpenSTA and supports multi-chain planning/optimization.

Summary (what changes)

  • Robust scan pin detection in dbSta when Liberty/OpenSTA does not surface scan signal_type metadata (common in real libraries).
  • Fix scan stitching correctness and add scan_opt to re-optimize/restitch using updated placement.
  • Extend multi-chain planning:
    • set_dft_config -chain_count (exact)
    • set_dft_config -max_length (bits per chain)
    • set_dft_config -max_chains (cap)
    • placement-aware partitioning across chains with swap-based reassignment.
  • Add constraint sanity warnings when the requested (max_length, max_chains) / (chain_count, max_length) is infeasible, while still producing a best-effort plan.
  • Add/extend DFT regression coverage for these cases.

Motivation (why)

OpenROAD has a DFT flow (scan_replace + report_dft_plan + execute_dft_plan), but in practice scan insertion was often blocked or degraded by:

  • Scan pins not being recognized with vanilla OpenSTA in some PDK/library combinations (even when Liberty encodes scan behavior via nextstate_type).
  • Stitching correctness issues that could skip/omit connections.
  • No command to re-run scan ordering with updated placement without re-running scan_replace.
  • Limited multi-chain controls and no explicit feedback when a user’s chain-length constraints are impossible.

User-visible behavior

1) dbSta fallback scan pin inference (vanilla OpenSTA friendly)

If a scan flop’s scan ports are not tagged with ScanSignalType from Liberty/OpenSTA, OpenROAD now falls back to common pin names and sets the scan signal type accordingly:

  • scan enable: SE, SCE, SCAN_EN, SCAN_ENABLE, SCANENABLE
  • scan in: SI, SCD, SCAN_IN, SCANIN
  • scan out: SO, SCO, SCAN_OUT, SCANOUT

This fallback is only used when scanSignalType() is none; properly tagged libraries still take priority.

2) Deterministic scan stitching + scan_opt

  • execute_dft_plan deterministically stitches:
    • scan-in → first SI
    • SO(i) → SI(i+1)
    • last SO → scan-out
  • New scan_opt command re-orders/restitches scan chains using the latest placement information and the current set_dft_config, without re-running scan_replace.

3) Multi-chain architecture improvements

  • Support for -chain_count (exact chain count) and better handling of -max_length / -max_chains inference.
  • Placement-aware partitioning across chains, including swap/move reassignment, before running the per-chain scan ordering heuristic.

4) Constraint sanity warnings (infeasible max length / chain count)

When the requested constraints are infeasible (e.g., not enough chains to hold all scan bits), the scan architect now emits warnings and relaxes the effective bound as needed to still build a plan:

  • DFT-0073: total_bits > chain_count * max_length (capacity infeasible)
  • DFT-0074: ceil(total_bits / max_length) > max_chains (would require more chains than allowed)

Documentation updates

  • DFT README updated with:
    • set_dft_config options (-max_length, -chain_count, -max_chains)
    • scan signal name pattern behavior (including / instance/pin form)
    • scan_opt command.

Tests

Run (and passing):

  • ctest -R '^dft\\.' --output-on-failure

Notable regressions added/updated:

  • dft.scan_architect_no_mix_nangate45.tcl (Nangate45 no-mix coverage)
  • dft.max_length_sweep_sky130.tcl (sweeps max_length under a max_chains cap)
  • dft.chain_count_infeasible_sky130.tcl (infeasible chain_count/max_length warning path)

Scope / non-goals

  • This PR does not implement full DFT “planning” features like automatic physical scan I/O pin placement, scan-enable buffering trees, or netlist augmentation beyond scan insertion/stitching. Those are expected to be handled at the integration layer (flow scripts) or via future work in OpenROAD.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive set of improvements for DFT scan chain operations. The new scan_opt command provides a powerful mechanism to re-order scan chains based on placement, leveraging sophisticated TSP heuristics for wirelength optimization. The robustness of scan cell identification is significantly enhanced with intelligent fallbacks for finding scan pins in liberty files that lack explicit tagging. The codebase has also seen substantial refactoring, such as decoupling from sta::TestCell and simplifying the scan chain stitching logic, which improves maintainability and clarity. My review includes one suggestion to reduce code duplication and improve performance in the new scan pin identification logic.

Comment on lines +1258 to +1271
auto equals_ignore_case = [](const char* lhs, const char* rhs) -> bool {
if (lhs == nullptr || rhs == nullptr) {
return false;
}
while (*lhs != '\0' && *rhs != '\0') {
if (std::tolower(static_cast<unsigned char>(*lhs))
!= std::tolower(static_cast<unsigned char>(*rhs))) {
return false;
}
lhs++;
rhs++;
}
return *lhs == '\0' && *rhs == '\0';
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The equals_ignore_case lambda is duplicated in getLibertyScanEnable, getLibertyScanIn, and getLibertyScanOut. To improve maintainability, consider defining this as a static helper function in an anonymous namespace at the top of the file. Since sta/StringUtil.hh is now included, it might be worth checking if it provides a case-insensitive comparison function that could be used instead.

Additionally, these three functions now iterate over all ports twice. The two loops could be combined into a single pass for better performance. You could search for a port by scanSignalType and if not found by the end of the loop, use a fallback port found by name during the same iteration.

References
  1. When adjusting font size for multiple labels, on-the-fly adjustment while iterating can be more efficient than a two-pass approach (find max length, then adjust). The single-pass method allows for early exit if minimum font size is reached, avoiding processing all labels.

Emit DFT warnings when max_length/max_chains or chain_count/max_length are infeasible, and add regression coverage for these cases.
@github-actions
Copy link
Contributor

clang-tidy review says "All clean, LGTM! 👍"

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