|
| 1 | +# DFT / Scan in ORFS (OpenROAD-flow-scripts) |
| 2 | + |
| 3 | +Quickstart: `doc-DFT-howto.md` |
| 4 | + |
| 5 | +This repo wires OpenROAD’s DFT scan insertion into the ORFS flow via **opt-in** hook scripts, plus utilities to measure scan-chain wirelength and validate scan stitching. |
| 6 | + |
| 7 | +## Required OpenROAD |
| 8 | + |
| 9 | +This branch pins the `tools/OpenROAD` submodule to **OpenROAD-clean-DFT**: |
| 10 | + |
| 11 | +- Base: `7bc521f36a` |
| 12 | +- +1 commit (DFT fixes): `661abebbc3c70c59b4a3991acd176a5cc785f0d4` |
| 13 | + |
| 14 | +The key point: it works with **vanilla OpenSTA** (no OpenSTA parser patch required). |
| 15 | + |
| 16 | +## ORFS Flow Integration (Where DFT Happens) |
| 17 | + |
| 18 | +Two hook scripts are provided: |
| 19 | + |
| 20 | +- `flow/scripts/dft_scan_post_floorplan.tcl` |
| 21 | + - Intended use: `POST_FLOORPLAN_TCL=$(pwd)/flow/scripts/dft_scan_post_floorplan.tcl` |
| 22 | + - Runs after floorplan, before saving `2_1_floorplan.odb`: |
| 23 | + - `set_dft_config -max_chains 1 -clock_mixing clock_mix` |
| 24 | + - `scan_replace` (functional flops → scan flops) |
| 25 | + - creates scan ports: `scan_enable_0`, `scan_in_0`, `scan_out_0` |
| 26 | + - `set_case_analysis 0 [get_ports scan_enable_0]` (functional-mode timing) |
| 27 | + |
| 28 | +- `flow/scripts/dft_scan_pre_global_route.tcl` |
| 29 | + - Intended use: `PRE_GLOBAL_ROUTE_TCL=$(pwd)/flow/scripts/dft_scan_pre_global_route.tcl` |
| 30 | + - Runs after CTS, before global routing: |
| 31 | + - `set_dft_config ...` (must match the post-floorplan config) |
| 32 | + - `set_case_analysis 0 [get_ports scan_enable_0]` |
| 33 | + - `execute_dft_plan` (stitches the scan chain using placement) |
| 34 | + |
| 35 | +Notes: |
| 36 | +- The scripts currently hardcode `-max_chains 1` to keep scan I/O stable for comparisons. |
| 37 | +- `set_case_analysis 0` ensures STA uses functional-mode arcs for scan flops. |
| 38 | + |
| 39 | +## OpenROAD-side Fixes (Summary) |
| 40 | + |
| 41 | +The OpenROAD-clean-DFT commit includes the minimum required fixes to make DFT “alive” on top of `7bc521f36a`: |
| 42 | + |
| 43 | +- Scan pin identification works in vanilla STA (`src/dbSta/src/dbSta.cc`): |
| 44 | + - removes an overly-strict `extPort()` guard |
| 45 | + - adds/uses fallback scan pin inference by common names (`SI/SE/SO`, etc.) |
| 46 | +- DFT correctness fixes and functionality (DFT subsystem): |
| 47 | + - scan stitching fixes (no dropped links) |
| 48 | + - avoids reliance on `sta::TestCell` |
| 49 | + - scan-out fallback behavior |
| 50 | + - includes a small DFT regression (`scan_architect_no_mix_nangate45`) |
| 51 | + |
| 52 | +## Scan-Ordering Benchmark (OpenROAD vs Nearest-Neighbor) |
| 53 | + |
| 54 | +`flow/util/scan_chain_cost.py` runs OpenROAD’s `report_dft_plan -verbose`, computes total Manhattan scan-chain length, and can also compute a simple nearest-neighbor (NN) heuristic for comparison. |
| 55 | + |
| 56 | +Opt/NN results (lower is better; `openroad_over_nn < 1` means OpenROAD is shorter than NN): |
| 57 | + |
| 58 | +| platform | design | flops | openroad_um | nn_um | openroad_over_nn | |
| 59 | +|---|---|---:|---:|---:|---:| |
| 60 | +| nangate45 | aes | 562 | 3571.680 | 4178.080 | 0.855 | |
| 61 | +| nangate45 | ibex | 1931 | 9197.880 | 10545.640 | 0.872 | |
| 62 | +| nangate45 | jpeg | 4390 | 17903.670 | 20815.750 | 0.860 | |
| 63 | +| asap7 | aes | 562 | 1053.810 | 1222.344 | 0.862 | |
| 64 | +| asap7 | ibex | 273 | 428.652 | 514.404 | 0.833 | |
| 65 | +| asap7 | jpeg | 4325 | 5045.058 | 5709.204 | 0.884 | |
| 66 | +| sky130hd | aes | 562 | 11050.640 | 13137.940 | 0.841 | |
| 67 | +| sky130hd | ibex | 1931 | 21754.680 | 24411.360 | 0.891 | |
| 68 | +| sky130hd | jpeg | 4390 | 50973.380 | 57692.340 | 0.884 | |
| 69 | + |
| 70 | +Avg `opt/NN` = `0.865` (~`13.5%` shorter than NN). |
| 71 | + |
| 72 | +Reproduce (single design): |
| 73 | + |
| 74 | +- `python3 flow/util/scan_chain_cost.py --scan-replace --nearest-neighbor --openroad tools/install/OpenROAD/bin/openroad --liberty flow/platforms/nangate45/lib/NangateOpenCellLibrary_typical.lib --odb flow/results/nangate45/ibex/cmp9_or0db856_rp100_20251229_022425/3_5_place_dp.odb --sdc flow/results/nangate45/ibex/cmp9_or0db856_rp100_20251229_022425/3_place.sdc` |
| 75 | + |
| 76 | +Notes: |
| 77 | +- ASAP7 needs multiple libs; pass them all, e.g. `--liberty flow/platforms/asap7/lib/NLDM/*_TT_*`. |
| 78 | + |
| 79 | +## Scan-Chain Integrity Validation (Does It Actually Shift?) |
| 80 | + |
| 81 | +QoR deltas and plan reports are necessary but not sufficient; we also want a basic structural check that the scan path is one continuous chain from `scan_in_0` to `scan_out_0`. |
| 82 | + |
| 83 | +- `flow/util/scan_chain_validate.py` validates scan stitching from a gate-level netlist (or from an ODB by writing a temporary netlist via OpenROAD). |
| 84 | +- It treats `assign` + inserted `BUF*/CLKBUF*` as transparent, so post-P&R buffering doesn’t cause false failures. |
| 85 | + |
| 86 | +Example usage: |
| 87 | + |
| 88 | +- Validate a finished netlist: |
| 89 | + - `python3 flow/util/scan_chain_validate.py --verilog flow/results/nangate45/ibex/with_dft/6_final.v` |
| 90 | +- Validate from an ODB (writes a temp netlist first): |
| 91 | + - `python3 flow/util/scan_chain_validate.py --odb flow/results/nangate45/ibex/with_dft/6_final.odb --openroad tools/install/OpenROAD/bin/openroad --liberty flow/platforms/nangate45/lib/NangateOpenCellLibrary_typical.lib --sdc flow/results/nangate45/ibex/with_dft/6_final.sdc --ensure-ports` |
| 92 | + |
0 commit comments