-
Notifications
You must be signed in to change notification settings - Fork 765
Introduce DFT to OpenROAD with Scan Chain operations #9211
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Introduce DFT to OpenROAD with Scan Chain operations #9211
Conversation
Signed-off-by: PrecisEDAnon <[email protected]>
Signed-off-by: PrecisEDAnon <[email protected]>
Signed-off-by: PrecisEDAnon <[email protected]>
Signed-off-by: PrecisEDAnon <[email protected]>
Signed-off-by: PrecisEDAnon <[email protected]>
Signed-off-by: PrecisEDAnon <[email protected]>
Signed-off-by: PrecisEDAnon <[email protected]>
There was a problem hiding this 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.
| 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'; | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
- 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.
|
clang-tidy review says "All clean, LGTM! 👍" |
AI generated content follows.
PR: DFT scan insertion improvements (rebased)
This PR improves OpenROAD’s
dftmodule so scan insertion works reliably with vanilla OpenSTA and supports multi-chain planning/optimization.Summary (what changes)
dbStawhen Liberty/OpenSTA does not surface scansignal_typemetadata (common in real libraries).scan_optto re-optimize/restitch using updated placement.set_dft_config -chain_count(exact)set_dft_config -max_length(bits per chain)set_dft_config -max_chains(cap)(max_length, max_chains)/(chain_count, max_length)is infeasible, while still producing a best-effort plan.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:nextstate_type).scan_replace.User-visible behavior
1)
dbStafallback scan pin inference (vanilla OpenSTA friendly)If a scan flop’s scan ports are not tagged with
ScanSignalTypefrom Liberty/OpenSTA, OpenROAD now falls back to common pin names and sets the scan signal type accordingly:SE,SCE,SCAN_EN,SCAN_ENABLE,SCANENABLESI,SCD,SCAN_IN,SCANINSO,SCO,SCAN_OUT,SCANOUTThis fallback is only used when
scanSignalType()isnone; properly tagged libraries still take priority.2) Deterministic scan stitching +
scan_optexecute_dft_plandeterministically stitches:scan_optcommand re-orders/restitches scan chains using the latest placement information and the currentset_dft_config, without re-runningscan_replace.3) Multi-chain architecture improvements
-chain_count(exact chain count) and better handling of-max_length/-max_chainsinference.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
set_dft_configoptions (-max_length,-chain_count,-max_chains)/instance/pin form)scan_optcommand.Tests
Run (and passing):
ctest -R '^dft\\.' --output-on-failureNotable regressions added/updated:
dft.scan_architect_no_mix_nangate45.tcl(Nangate45 no-mix coverage)dft.max_length_sweep_sky130.tcl(sweepsmax_lengthunder amax_chainscap)dft.chain_count_infeasible_sky130.tcl(infeasiblechain_count/max_lengthwarning path)Scope / non-goals