attar 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. attar-1.0.0/LICENSE +21 -0
  2. attar-1.0.0/PKG-INFO +269 -0
  3. attar-1.0.0/README.md +227 -0
  4. attar-1.0.0/attar/__init__.py +11 -0
  5. attar-1.0.0/attar/_slow_loop.py +58 -0
  6. attar-1.0.0/attar/design.py +733 -0
  7. attar-1.0.0/attar/evaluator.py +341 -0
  8. attar-1.0.0/attar/facts.py +134 -0
  9. attar-1.0.0/attar/hub.py +104 -0
  10. attar-1.0.0/attar/io/__init__.py +1 -0
  11. attar-1.0.0/attar/io/bookshelf.py +295 -0
  12. attar-1.0.0/attar/io/deffile.py +498 -0
  13. attar-1.0.0/attar/io/distill.py +316 -0
  14. attar-1.0.0/attar/io/export.py +197 -0
  15. attar-1.0.0/attar/io/fpformats.py +256 -0
  16. attar-1.0.0/attar/io/lef.py +122 -0
  17. attar-1.0.0/attar/io/liberty.py +350 -0
  18. attar-1.0.0/attar/io/sdc.py +244 -0
  19. attar-1.0.0/attar/io/st.py +41 -0
  20. attar-1.0.0/attar/kernels.py +144 -0
  21. attar-1.0.0/attar/metrics.py +101 -0
  22. attar-1.0.0/attar/naive/__init__.py +19 -0
  23. attar-1.0.0/attar/naive/bstar.py +183 -0
  24. attar-1.0.0/attar/naive/floorplan.py +528 -0
  25. attar-1.0.0/attar/naive/flow.py +75 -0
  26. attar-1.0.0/attar/naive/gp.py +420 -0
  27. attar-1.0.0/attar/naive/lg.py +812 -0
  28. attar-1.0.0/attar/naive/macro_lp.py +222 -0
  29. attar-1.0.0/attar/naive/rowops.py +100 -0
  30. attar-1.0.0/attar/naive/space.py +182 -0
  31. attar-1.0.0/attar/netlist.py +673 -0
  32. attar-1.0.0/attar/paths.py +25 -0
  33. attar-1.0.0/attar/rules/__init__.py +1 -0
  34. attar-1.0.0/attar/rules/pdn.py +191 -0
  35. attar-1.0.0/attar/rules/rails.py +159 -0
  36. attar-1.0.0/attar/rules/routing.py +709 -0
  37. attar-1.0.0/attar/status.py +183 -0
  38. attar-1.0.0/attar/timing/__init__.py +1 -0
  39. attar-1.0.0/attar/timing/csrc/pdtree.cpp +390 -0
  40. attar-1.0.0/attar/timing/dmp.py +356 -0
  41. attar-1.0.0/attar/timing/dmp_triton.py +623 -0
  42. attar-1.0.0/attar/timing/ir.py +316 -0
  43. attar-1.0.0/attar/timing/library.py +341 -0
  44. attar-1.0.0/attar/timing/sizing.py +120 -0
  45. attar-1.0.0/attar/timing/sta.py +1425 -0
  46. attar-1.0.0/attar/timing/steiner.py +146 -0
  47. attar-1.0.0/attar/timing/steiner_big.py +69 -0
  48. attar-1.0.0/attar/timing/steiner_triton.py +350 -0
  49. attar-1.0.0/attar/viz.py +492 -0
  50. attar-1.0.0/attar.egg-info/PKG-INFO +269 -0
  51. attar-1.0.0/attar.egg-info/SOURCES.txt +62 -0
  52. attar-1.0.0/attar.egg-info/dependency_links.txt +1 -0
  53. attar-1.0.0/attar.egg-info/requires.txt +15 -0
  54. attar-1.0.0/attar.egg-info/top_level.txt +1 -0
  55. attar-1.0.0/pyproject.toml +63 -0
  56. attar-1.0.0/setup.cfg +4 -0
  57. attar-1.0.0/tests/test_core.py +372 -0
  58. attar-1.0.0/tests/test_evaluator.py +173 -0
  59. attar-1.0.0/tests/test_examples.py +44 -0
  60. attar-1.0.0/tests/test_naive.py +392 -0
  61. attar-1.0.0/tests/test_netlist.py +237 -0
  62. attar-1.0.0/tests/test_paths.py +91 -0
  63. attar-1.0.0/tests/test_readers.py +149 -0
  64. attar-1.0.0/tests/test_reports.py +178 -0
attar-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 RayChang987
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
attar-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,269 @@
1
+ Metadata-Version: 2.1
2
+ Name: attar
3
+ Version: 1.0.0
4
+ Summary: The fast loop for physical design: any benchmark as GPU tensors, place and evaluate in seconds, validate in ORFS
5
+ Author: RayChang987
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/RayChang987/Attar
8
+ Project-URL: Documentation, https://github.com/RayChang987/Attar/tree/main/docs
9
+ Project-URL: Changelog, https://github.com/RayChang987/Attar/blob/main/CHANGELOG.md
10
+ Project-URL: Dataset, https://huggingface.co/datasets/RayChang987/attar-zoo
11
+ Project-URL: Issues, https://github.com/RayChang987/Attar/issues
12
+ Keywords: eda,physical design,placement,floorplanning,static timing analysis,vlsi,pytorch,gpu
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Environment :: GPU :: NVIDIA CUDA
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.8
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)
26
+ Requires-Python: >=3.8
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Requires-Dist: torch>=2.0
30
+ Requires-Dist: numpy
31
+ Requires-Dist: scipy
32
+ Requires-Dist: matplotlib
33
+ Requires-Dist: huggingface_hub>=0.20
34
+ Requires-Dist: zstandard
35
+ Provides-Extra: docs
36
+ Requires-Dist: pillow; extra == "docs"
37
+ Requires-Dist: pygments; extra == "docs"
38
+ Provides-Extra: dev
39
+ Requires-Dist: ruff; extra == "dev"
40
+ Requires-Dist: build; extra == "dev"
41
+ Requires-Dist: twine; extra == "dev"
42
+
43
+ <div align="center">
44
+
45
+ <img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/logo.png" alt="Attar: the fast loop for physical design" width="640">
46
+
47
+ Diverse P&R benchmarks, distilled into one plug-and-play PyTorch environment on the GPU.<br>
48
+ Evolve placement and timing-optimization algorithms in minutes, not days.
49
+
50
+ [![Python](https://img.shields.io/badge/python-3.8%2B-d9622b?style=flat-square)](https://github.com/RayChang987/Attar/blob/main/pyproject.toml)
51
+ [![PyTorch](https://img.shields.io/badge/PyTorch-CUDA-d99a1e?style=flat-square)](https://pytorch.org)
52
+ [![Validated](https://img.shields.io/badge/validated%20against-OpenROAD-8f6a3f?style=flat-square)](https://github.com/RayChang987/Attar/blob/main/docs/validation/orfs_check.md)
53
+ [![Tests](https://img.shields.io/badge/tests-107%20passing-5f7f1e?style=flat-square)](https://github.com/RayChang987/Attar/tree/main/tests)
54
+ [![License](https://img.shields.io/badge/license-MIT-a8946f?style=flat-square)](https://github.com/RayChang987/Attar/blob/main/LICENSE)
55
+
56
+ [Install](#install) &nbsp;·&nbsp; [Why Attar](#why-attar) &nbsp;·&nbsp; [Roadmap](#roadmap) &nbsp;·&nbsp; [Two modes](#two-modes) &nbsp;·&nbsp;
57
+ [How it works](#how-it-works) &nbsp;·&nbsp; [Gallery](#gallery)
58
+
59
+ </div>
60
+
61
+ <br>
62
+
63
+ ## Install
64
+
65
+ ```bash
66
+ pip install attar
67
+ ```
68
+
69
+ ```python
70
+ import attar
71
+ d = attar.load('after_fp/orfs_asap7/aes', device='cuda') # downloaded from the zoo on first use
72
+ ```
73
+
74
+ Python 3.8 or newer, with PyTorch (a CUDA GPU for the speed; everything also runs on the CPU). The designs come from
75
+ the [Attar zoo](https://huggingface.co/datasets/RayChang987/attar-zoo) on the Hugging Face Hub (246 designs, 731 MB
76
+ in all); `attar.zoo(remote=True)` lists them. The latest code: `pip install git+https://github.com/RayChang987/Attar`.
77
+
78
+ - The first timing run on a GPU machine compiles the timer's Triton kernels (about two minutes, once); later runs
79
+ reuse them and take seconds.
80
+ - With `g++` on the path, nets of more than 256 pins get OpenROAD's exact Steiner parasitics (built on first use);
81
+ without it they fall back to a lumped wire model, with a warning.
82
+
83
+ ## Why Attar
84
+
85
+ 1. **Speed decides quality.** When AI agents do the research, iteration speed is more than a metric: in our view it
86
+ decides the quality of results (QoR). An agent that can propose, test and discard an idea in seconds finds what
87
+ works. When every run takes hours, even the best algorithm starves for feedback.
88
+ 2. **Data preparation is painful.** Traditional place-and-route (P&R) tools take minutes to hours per run, and every
89
+ benchmark suite comes in its own format (LEF/DEF, Bookshelf, YAL, GSRC blocks) with its own gaps. Getting a design
90
+ ready to experiment on is slow, fragmented work, repeated for every suite.
91
+ 3. **Attar is the fast loop.** Attar distills diverse P&R benchmarks into one plug-and-play PyTorch environment:
92
+ `attar.load` a name, and the design is on the GPU. Each reader hands over only the facts its source has, with
93
+ their provenance, and nothing missing is made up ([a design is a state](#a-design-is-a-state)). The fast loop
94
+ stays faithful to the full flows without their overhead: its HPWL equals OpenROAD's to 7 digits,
95
+ its legality equals `check_placement`, its placements route in OpenROAD-flow-scripts with 0 DRC, and HPWL ranks
96
+ placements as routed wirelength does in 951 routed Innovus runs, once they differ by 2% or more
97
+ ([validation](https://github.com/RayChang987/Attar/blob/main/docs/validation/orfs_check.md)).
98
+ 4. **GPU-native.** Layouts and design features are tensors on the GPU, so researchers, developers and AI agents
99
+ train, evaluate and debug in the same few lines of Python: exact HPWL of 8.9M pins in 3 ms, a 2.2M-cell design
100
+ placed and legalized in 49 s. An algorithm is a function from tensors to positions: no database
101
+ API, no TCL, no file formats.
102
+
103
+ ## Roadmap
104
+
105
+ <p align="center"><img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/roadmap.svg" alt="Roadmap mind map. Attar in the center. Left, Data, as tensors: contest benchmarks, one per suite (placement: ISPD 2005, 2015, 2018, 2019, 2024, ICCAD 2025, GSRC placement; floorplan: MCNC, GSRC blocks, IBM-HB+), ASAP7 (15 placement, 5 floorplan designs) and NS3K (99 placement designs). Right, Naive Engine: floorplan (packing, macro placement, IO placement) and placement (placer, legalizer, PDN-aware refinement), all done. Right, Evaluation: HPWL, global routing OVF and timing done; blocked pin checking not yet; detailed routing and DRV checks will not be built" width="100%"></p>
106
+
107
+ ### Evaluation
108
+
109
+ Each evaluator against OpenROAD on the same netlist and placement; full tables in
110
+ [docs/validation](https://github.com/RayChang987/Attar/blob/main/docs/validation/timing_routing.md).
111
+
112
+ | Evaluator | Call | Compared with | Accuracy |
113
+ | --- | --- | --- | --- |
114
+ | **HPWL** | `ev.hpwl` | OpenROAD's HPWL from its database; 23 ORFS designs (ASAP7, Nangate45) up to 1.05M cells | within **0.00002%** on every design ([table](https://github.com/RayChang987/Attar/blob/main/docs/validation/orfs_check.md)) |
115
+ | **Legality** | `ev.legality` | OpenROAD `check_placement` | same verdict on all **23** ORFS designs and the **62** NS3K floorplans OpenROAD can check; placements broken by half a site rejected by both |
116
+ | **Timing** | `d.timing()` | OpenSTA after `estimate_parasitics -placement`; 31 designs (ASAP7, Nangate45, NS3K) up to 1.05M cells | WNS median error **0.00%** (ORFS) and **0.11%** (NS3K), max **0.34%**; hold slack MAE at most 0.36 ps; 5-30x faster than OpenSTA |
117
+ | **Pin and net slack** | `d.timing().pin_slack()`, `.net_slack()` | OpenSTA's `slack_max` of every pin; 8 designs (ASAP7, Nangate45) up to 384k pins | Pearson at least **0.9995**; on the pins with negative slack, MAE at most **1.03 ps**; 7-32 ms after a timing run |
118
+ | **Timing after sizing** | `d.resize` + `d.timing()` | OpenROAD `replace_cell` + OpenSTA, 20% of the cells swapped at random; 16 designs | WNS error at most **0.23%**, TNS at most 0.37% |
119
+ | **Timing after netlist edits** | `d.edit()`, `d.debuffer()` + `d.timing()` | OpenSTA on the DEF Attar exports: after 1,548 buffers and 443 clones inserted (10 NS3K designs up to 163k cells), and after `d.debuffer()` removed 45,991 buffers and 83 inverters (10 ORFS designs) | setup Pearson at least **0.9997**, WNS error at most **0.04%** after debuffer and **1.18%** after the NS3K edits; hold MAE at most 0.36 ps |
120
+ | **Global routing OVF** | `d.gr_overflow()` | OpenROAD's gcell capacities and global route; 13 ORFS designs | capacities exact without macros, within **0.16%** with them; ranks designs as OpenROAD does (Spearman **0.97**); a pre-route estimate: reads mild congestion high and heavy congestion low |
121
+ | **Steiner wirelength, RUDY, density overflow** | `ev.steiner_wirelength`, `ev.rudy`, `ev.density_overflow` | | |
122
+
123
+ ### Naive Engine
124
+
125
+ | Engine | Mode | Call | What it does |
126
+ | --- | --- | --- | --- |
127
+ | **Packing** | `before_fp` | `naive.place_macros(packing=True)` | block-level designs: B*-tree packing, annealed into the core, then for HPWL |
128
+ | **Macro placement** | `before_fp` | `naive.place_macros` | mixed-size global placement, then macros legalized on their routing tracks with a halo |
129
+ | **IO placement** | `before_fp` | `naive.place_io` | IO pins on the die boundary, net-aware once cells are placed |
130
+ | **Placer** | both | `naive.global_place` | electrostatic (ePlace/DREAMPlace style, Nesterov, CUDA graphs) at the source flow's own target density; `routability=True`: DREAMPlace's cell inflation |
131
+ | **Legalizer** | `after_fp` | `naive.legalize` | multi-row-height cells, power-rail parity, signal pins clear of the PDN's via metal |
132
+ | **PDN-aware refinement** | `after_fp` | inside `naive.legalize` | row DP and repair that keep cells clear of the PDN |
133
+
134
+ `d.floorplan(utilization=...)` sizes the die (`naive.make_die`), then places the IO pins and the macros;
135
+ `d.place()` is global placement plus legalization.
136
+
137
+ <div align="center">
138
+
139
+ <img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/demo_placement.gif" alt="Timing-driven placement written in fifteen lines of Python, run on cva6 and swerv: place for wirelength, time it, weight the nets by their slack as OpenROAD's global placement does, place again, time it" width="920">
140
+
141
+ <sub><b>Your algorithm, in fifteen lines</b> (<a href="examples/timing_driven.py">examples/timing_driven.py</a>). Real
142
+ runs on an RTX 3080 Ti, the same code on two ASAP7 designs: place for wirelength, take every net's slack
143
+ (<code>net_slack()</code>, as OpenSTA's), weight the worst 10% of the nets from 1 to 5 by criticality as OpenROAD's
144
+ timing-driven global placement does, place again. <b>cva6</b> (121k cells, 8 SRAMs): WNS -195 to -75 ps, TNS
145
+ -85.7k to -5.1k ps, HPWL +6.7%, in 2.2 s. <b>swerv</b> (103k cells): WNS -205 to -117 ps, TNS -39.5k to -1.2k ps,
146
+ HPWL +1.1%, in 1.9 s. Both legal.</sub>
147
+
148
+ <img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/demo_floorplan.gif" alt="Floorplan mode: GSRC n100 at 85% block area, floorplanned twice: GP plus LP legalization leaves 5 macros outside the core (not legal), B*-tree packing fits them all (legal)" width="920">
149
+
150
+ <sub><b>Floorplan mode</b> (<code>before_fp</code>). GSRC <b>n100</b>: 100 hard blocks, no die; Attar sizes one for 85%
151
+ block area, places the IO pins and the macros. GP + LP legalization never overlaps macros, but here 5 stick out of
152
+ the core: not legal. <code>packing=True</code> (B*-tree, annealed into the core, then for HPWL) fits them all in
153
+ 5.1 s, at 8% more wire. The lines are the strongest connections between macros and IO pins.</sub>
154
+
155
+ </div>
156
+
157
+ ## Two modes
158
+
159
+ In production chip design, the power delivery network (PDN) is the dividing line: once the power grid and the macros
160
+ are locked down, the design enters a different phase. Attar splits its problems at that line. It does not synthesize
161
+ a PDN, and it should not: a `before_fp` answer goes to a flow that draws one, and an `after_fp` problem comes
162
+ with the PDN its flow drew.
163
+
164
+ | | **Before-floorplan** (`before_fp`) | **After-floorplan** (`after_fp`) |
165
+ | --- | --- | --- |
166
+ | given | the netlist (an initial die for ORFS designs) | die, IO pins, macros, rows and PDN: a fixed floorplan |
167
+ | the answer | target utilization (the die), IO pin placement, macro placement | standard-cell placement; then timing optimization and global routing on the same floorplan |
168
+ | one call | `d.floorplan(utilization=0.6)` | `d.place()` |
169
+ | goes out as | a DEF: your flow draws the PDN and places | a DEF: your flow routes and times |
170
+ | in the zoo | 55 designs, 6 suites | 191 designs, 16 suites |
171
+
172
+ Attar measures wirelength, congestion (RUDY, GROV), density, legality and timing; see the [roadmap](#roadmap).
173
+
174
+ ## How it works
175
+
176
+ <p align="center"><img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/flow.svg" alt="Sources (LEF/DEF, Bookshelf, YAL, GSRC blocks) are distilled into the Attar IR and loaded as a Design on the GPU; attar.naive moves it and adds facts, the Evaluator measures it; export writes a DEF for your own flow (OpenROAD, Innovus, ICC2, ...)" width="100%"></p>
177
+
178
+ 1. **Distill.** A reader turns a benchmark into the Attar IR: integer arrays in a safetensors file, plus a manifest
179
+ that lists which facts the source provides and where each came from. Readers exist for LEF/DEF, Bookshelf, YAL
180
+ and GSRC blocks.
181
+ 2. **Load.** `attar.load` puts the arrays on the GPU as a `Design`. `d.status()` shows each fact, each capability,
182
+ and what is left before export.
183
+ 3. **Move.** Your algorithm, or the [built-in engines](#roadmap) (`attar.naive`), changes the positions:
184
+ die, IO pins and macros for `before_fp`, cells for `after_fp`.
185
+ 4. **Measure.** `attar.Evaluator` computes HPWL (exact, batched), Steiner wirelength, RUDY, density overflow and
186
+ legality, on the current placement or on any positions you pass.
187
+ 5. **Export.** `d.export(out_def)` writes the design back into its source DEF's frame: the PDN, IO pin shapes and
188
+ fixed cells as they were, the cells and nets from the IR (a changed die, IO pins and macros included). Your own
189
+ flow (OpenROAD, Innovus, ICC2, ...) takes it from there.
190
+
191
+ More: [concepts](https://github.com/RayChang987/Attar/blob/main/docs/concepts.md) · [benchmarks](https://github.com/RayChang987/Attar/blob/main/docs/benchmarks.md) · [API](https://github.com/RayChang987/Attar/blob/main/docs/api.md) ·
192
+ [validation](https://github.com/RayChang987/Attar/blob/main/docs/validation/timing_routing.md)
193
+
194
+ ## Gallery
195
+
196
+ What the Evaluator sees: each view is `d.plot(tiles=...)` on a real run of `attar.naive`.
197
+
198
+ <table>
199
+ <tr>
200
+ <td width="50%"><img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/gallery/eval_grov.png" alt="cva6 after placement, colored by global-routing load on OpenROAD's gcells"></td>
201
+ <td width="50%"><img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/gallery/eval_pin_access.png" alt="ariane136 after global placement: cells with a signal pin on the PDN, in stripes along the power grid"></td>
202
+ </tr>
203
+ <tr>
204
+ <td><sub><b>Global-routing overflow</b> (<code>d.gr_overflow()</code>, <code>tiles='gr_overflow'</code>): cva6 (ASAP7)
205
+ placed in 2.4 s, RUDY demand against OpenROAD's gcell capacities. GROV 0.73%: the channel left of the SRAMs and
206
+ the dense logic at the lower right are where the router will struggle.</sub></td>
207
+ <td><sub><b>Pin access</b> (<code>tiles='pin_access'</code>): ariane136 (NS3K, 136 SRAMs) right after global
208
+ placement. 12,165 cells have a signal pin on the PDN's via metal, in stripes along the power grid: NS3K's via
209
+ stacks cross the M1 pin layer.</sub></td>
210
+ </tr>
211
+ <tr>
212
+ <td><img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/gallery/eval_placed.png" alt="ariane136 legalized: legal, rails and PDN included"></td>
213
+ <td><img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/gallery/fp_n300.png" alt="GSRC n300 floorplanned by B*-tree packing, with the strongest connections between blocks and IO pins"></td>
214
+ </tr>
215
+ <tr>
216
+ <td><sub><b>Legality</b> (<code>ev.legality()</code>): the same design legalized in 2.4 s. Rows, sites, overlaps,
217
+ power-rail parity and the PDN all check out: 0 cells left on the PDN.</sub></td>
218
+ <td><sub><b>Floorplan legality and connections</b> (<code>d.floorplan_legal()</code>, <code>nets</code>): GSRC n300,
219
+ 300 hard blocks and 569 IO pins, no die given. Attar sizes one for 85% block area and packs the blocks (B*-tree) in
220
+ 43 s: legal, HPWL 565k. The lines are the strongest connections between blocks and IO pins.</sub></td>
221
+ </tr>
222
+ </table>
223
+
224
+ ## A design is a state
225
+
226
+ ```text
227
+ >>> d = attar.load('after_fp/orfs_asap7/aes'); d.status()
228
+ aes_cipher_top (orfs/asap7, fidelity F1)
229
+ placement target density 0.71 (orfs 3_3 global_place (GPL-0023))
230
+ Problem facts
231
+ ✅ netlist def 12268 nets, 42885 pins
232
+ ✅ cell_geometry lef 12420 cells (12009 movable, 0 macros), 56 masters
233
+ ✅ floorplan.die def 1 die(s), 48.71 x 48.71 um
234
+ ✅ floorplan.io def 388 IO pins placed
235
+ ✅ rows def 164 rows, height 0.27 um
236
+ ✅ pdn def 1815 wire and 4785 via shapes on M1, M2, M3
237
+ ✅ def_frame def PDN, pins, fixed cells of the source DEF, kept verbatim (849 kB)
238
+ ...
239
+ Solution state
240
+ ❌ placement 12009 movable cells unplaced (snapshots: reference)
241
+ ...
242
+ -> only a placement is missing: place the design (or restore a snapshot), then d.export("out.def")
243
+ ```
244
+
245
+ Every reader states which facts it provides, and every engine and metric states which facts it needs:
246
+ - a Bookshelf design has no cell library, so it does not export to DEF;
247
+ - a design with no special nets on the pin layers has no `pdn` rule to keep;
248
+ - a block floorplan has no rows;
249
+ - a soft-block benchmark has no cell geometry.
250
+
251
+ Each can do exactly what its facts allow. Engines add facts with provenance (`placement: naive`), so it is always
252
+ clear which part of a design came from where. See [docs/concepts.md](https://github.com/RayChang987/Attar/blob/main/docs/concepts.md).
253
+
254
+ ## Acknowledgements
255
+
256
+ Attar's global placement follows ePlace, DREAMPlace and Xplace, and its routability option DREAMPlace's cell
257
+ inflation; its rail and PDN checks follow OpenROAD's detailed placer, and its PDN repair the row DP of pa_pdn.
258
+ Attar is validated against [OpenROAD-flow-scripts](https://github.com/The-OpenROAD-Project/OpenROAD-flow-scripts) on
259
+ the ASAP7 and Nangate45 platforms. Benchmarks are from the ISPD, ICCAD and GSRC contests, MCNC and ORFS.
260
+
261
+ ## License
262
+
263
+ <div align="center">
264
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-a8946f?style=for-the-badge" alt="MIT License"></a>
265
+ <br><br>
266
+ <sub>Copyright &copy; 2026 RayChang987 &nbsp;·&nbsp; free to use, modify and distribute; see <a href="LICENSE">LICENSE</a></sub>
267
+ <br><br>
268
+ <img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/logo.png" alt="Attar" width="180">
269
+ </div>
attar-1.0.0/README.md ADDED
@@ -0,0 +1,227 @@
1
+ <div align="center">
2
+
3
+ <img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/logo.png" alt="Attar: the fast loop for physical design" width="640">
4
+
5
+ Diverse P&R benchmarks, distilled into one plug-and-play PyTorch environment on the GPU.<br>
6
+ Evolve placement and timing-optimization algorithms in minutes, not days.
7
+
8
+ [![Python](https://img.shields.io/badge/python-3.8%2B-d9622b?style=flat-square)](https://github.com/RayChang987/Attar/blob/main/pyproject.toml)
9
+ [![PyTorch](https://img.shields.io/badge/PyTorch-CUDA-d99a1e?style=flat-square)](https://pytorch.org)
10
+ [![Validated](https://img.shields.io/badge/validated%20against-OpenROAD-8f6a3f?style=flat-square)](https://github.com/RayChang987/Attar/blob/main/docs/validation/orfs_check.md)
11
+ [![Tests](https://img.shields.io/badge/tests-107%20passing-5f7f1e?style=flat-square)](https://github.com/RayChang987/Attar/tree/main/tests)
12
+ [![License](https://img.shields.io/badge/license-MIT-a8946f?style=flat-square)](https://github.com/RayChang987/Attar/blob/main/LICENSE)
13
+
14
+ [Install](#install) &nbsp;·&nbsp; [Why Attar](#why-attar) &nbsp;·&nbsp; [Roadmap](#roadmap) &nbsp;·&nbsp; [Two modes](#two-modes) &nbsp;·&nbsp;
15
+ [How it works](#how-it-works) &nbsp;·&nbsp; [Gallery](#gallery)
16
+
17
+ </div>
18
+
19
+ <br>
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ pip install attar
25
+ ```
26
+
27
+ ```python
28
+ import attar
29
+ d = attar.load('after_fp/orfs_asap7/aes', device='cuda') # downloaded from the zoo on first use
30
+ ```
31
+
32
+ Python 3.8 or newer, with PyTorch (a CUDA GPU for the speed; everything also runs on the CPU). The designs come from
33
+ the [Attar zoo](https://huggingface.co/datasets/RayChang987/attar-zoo) on the Hugging Face Hub (246 designs, 731 MB
34
+ in all); `attar.zoo(remote=True)` lists them. The latest code: `pip install git+https://github.com/RayChang987/Attar`.
35
+
36
+ - The first timing run on a GPU machine compiles the timer's Triton kernels (about two minutes, once); later runs
37
+ reuse them and take seconds.
38
+ - With `g++` on the path, nets of more than 256 pins get OpenROAD's exact Steiner parasitics (built on first use);
39
+ without it they fall back to a lumped wire model, with a warning.
40
+
41
+ ## Why Attar
42
+
43
+ 1. **Speed decides quality.** When AI agents do the research, iteration speed is more than a metric: in our view it
44
+ decides the quality of results (QoR). An agent that can propose, test and discard an idea in seconds finds what
45
+ works. When every run takes hours, even the best algorithm starves for feedback.
46
+ 2. **Data preparation is painful.** Traditional place-and-route (P&R) tools take minutes to hours per run, and every
47
+ benchmark suite comes in its own format (LEF/DEF, Bookshelf, YAL, GSRC blocks) with its own gaps. Getting a design
48
+ ready to experiment on is slow, fragmented work, repeated for every suite.
49
+ 3. **Attar is the fast loop.** Attar distills diverse P&R benchmarks into one plug-and-play PyTorch environment:
50
+ `attar.load` a name, and the design is on the GPU. Each reader hands over only the facts its source has, with
51
+ their provenance, and nothing missing is made up ([a design is a state](#a-design-is-a-state)). The fast loop
52
+ stays faithful to the full flows without their overhead: its HPWL equals OpenROAD's to 7 digits,
53
+ its legality equals `check_placement`, its placements route in OpenROAD-flow-scripts with 0 DRC, and HPWL ranks
54
+ placements as routed wirelength does in 951 routed Innovus runs, once they differ by 2% or more
55
+ ([validation](https://github.com/RayChang987/Attar/blob/main/docs/validation/orfs_check.md)).
56
+ 4. **GPU-native.** Layouts and design features are tensors on the GPU, so researchers, developers and AI agents
57
+ train, evaluate and debug in the same few lines of Python: exact HPWL of 8.9M pins in 3 ms, a 2.2M-cell design
58
+ placed and legalized in 49 s. An algorithm is a function from tensors to positions: no database
59
+ API, no TCL, no file formats.
60
+
61
+ ## Roadmap
62
+
63
+ <p align="center"><img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/roadmap.svg" alt="Roadmap mind map. Attar in the center. Left, Data, as tensors: contest benchmarks, one per suite (placement: ISPD 2005, 2015, 2018, 2019, 2024, ICCAD 2025, GSRC placement; floorplan: MCNC, GSRC blocks, IBM-HB+), ASAP7 (15 placement, 5 floorplan designs) and NS3K (99 placement designs). Right, Naive Engine: floorplan (packing, macro placement, IO placement) and placement (placer, legalizer, PDN-aware refinement), all done. Right, Evaluation: HPWL, global routing OVF and timing done; blocked pin checking not yet; detailed routing and DRV checks will not be built" width="100%"></p>
64
+
65
+ ### Evaluation
66
+
67
+ Each evaluator against OpenROAD on the same netlist and placement; full tables in
68
+ [docs/validation](https://github.com/RayChang987/Attar/blob/main/docs/validation/timing_routing.md).
69
+
70
+ | Evaluator | Call | Compared with | Accuracy |
71
+ | --- | --- | --- | --- |
72
+ | **HPWL** | `ev.hpwl` | OpenROAD's HPWL from its database; 23 ORFS designs (ASAP7, Nangate45) up to 1.05M cells | within **0.00002%** on every design ([table](https://github.com/RayChang987/Attar/blob/main/docs/validation/orfs_check.md)) |
73
+ | **Legality** | `ev.legality` | OpenROAD `check_placement` | same verdict on all **23** ORFS designs and the **62** NS3K floorplans OpenROAD can check; placements broken by half a site rejected by both |
74
+ | **Timing** | `d.timing()` | OpenSTA after `estimate_parasitics -placement`; 31 designs (ASAP7, Nangate45, NS3K) up to 1.05M cells | WNS median error **0.00%** (ORFS) and **0.11%** (NS3K), max **0.34%**; hold slack MAE at most 0.36 ps; 5-30x faster than OpenSTA |
75
+ | **Pin and net slack** | `d.timing().pin_slack()`, `.net_slack()` | OpenSTA's `slack_max` of every pin; 8 designs (ASAP7, Nangate45) up to 384k pins | Pearson at least **0.9995**; on the pins with negative slack, MAE at most **1.03 ps**; 7-32 ms after a timing run |
76
+ | **Timing after sizing** | `d.resize` + `d.timing()` | OpenROAD `replace_cell` + OpenSTA, 20% of the cells swapped at random; 16 designs | WNS error at most **0.23%**, TNS at most 0.37% |
77
+ | **Timing after netlist edits** | `d.edit()`, `d.debuffer()` + `d.timing()` | OpenSTA on the DEF Attar exports: after 1,548 buffers and 443 clones inserted (10 NS3K designs up to 163k cells), and after `d.debuffer()` removed 45,991 buffers and 83 inverters (10 ORFS designs) | setup Pearson at least **0.9997**, WNS error at most **0.04%** after debuffer and **1.18%** after the NS3K edits; hold MAE at most 0.36 ps |
78
+ | **Global routing OVF** | `d.gr_overflow()` | OpenROAD's gcell capacities and global route; 13 ORFS designs | capacities exact without macros, within **0.16%** with them; ranks designs as OpenROAD does (Spearman **0.97**); a pre-route estimate: reads mild congestion high and heavy congestion low |
79
+ | **Steiner wirelength, RUDY, density overflow** | `ev.steiner_wirelength`, `ev.rudy`, `ev.density_overflow` | | |
80
+
81
+ ### Naive Engine
82
+
83
+ | Engine | Mode | Call | What it does |
84
+ | --- | --- | --- | --- |
85
+ | **Packing** | `before_fp` | `naive.place_macros(packing=True)` | block-level designs: B*-tree packing, annealed into the core, then for HPWL |
86
+ | **Macro placement** | `before_fp` | `naive.place_macros` | mixed-size global placement, then macros legalized on their routing tracks with a halo |
87
+ | **IO placement** | `before_fp` | `naive.place_io` | IO pins on the die boundary, net-aware once cells are placed |
88
+ | **Placer** | both | `naive.global_place` | electrostatic (ePlace/DREAMPlace style, Nesterov, CUDA graphs) at the source flow's own target density; `routability=True`: DREAMPlace's cell inflation |
89
+ | **Legalizer** | `after_fp` | `naive.legalize` | multi-row-height cells, power-rail parity, signal pins clear of the PDN's via metal |
90
+ | **PDN-aware refinement** | `after_fp` | inside `naive.legalize` | row DP and repair that keep cells clear of the PDN |
91
+
92
+ `d.floorplan(utilization=...)` sizes the die (`naive.make_die`), then places the IO pins and the macros;
93
+ `d.place()` is global placement plus legalization.
94
+
95
+ <div align="center">
96
+
97
+ <img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/demo_placement.gif" alt="Timing-driven placement written in fifteen lines of Python, run on cva6 and swerv: place for wirelength, time it, weight the nets by their slack as OpenROAD's global placement does, place again, time it" width="920">
98
+
99
+ <sub><b>Your algorithm, in fifteen lines</b> (<a href="examples/timing_driven.py">examples/timing_driven.py</a>). Real
100
+ runs on an RTX 3080 Ti, the same code on two ASAP7 designs: place for wirelength, take every net's slack
101
+ (<code>net_slack()</code>, as OpenSTA's), weight the worst 10% of the nets from 1 to 5 by criticality as OpenROAD's
102
+ timing-driven global placement does, place again. <b>cva6</b> (121k cells, 8 SRAMs): WNS -195 to -75 ps, TNS
103
+ -85.7k to -5.1k ps, HPWL +6.7%, in 2.2 s. <b>swerv</b> (103k cells): WNS -205 to -117 ps, TNS -39.5k to -1.2k ps,
104
+ HPWL +1.1%, in 1.9 s. Both legal.</sub>
105
+
106
+ <img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/demo_floorplan.gif" alt="Floorplan mode: GSRC n100 at 85% block area, floorplanned twice: GP plus LP legalization leaves 5 macros outside the core (not legal), B*-tree packing fits them all (legal)" width="920">
107
+
108
+ <sub><b>Floorplan mode</b> (<code>before_fp</code>). GSRC <b>n100</b>: 100 hard blocks, no die; Attar sizes one for 85%
109
+ block area, places the IO pins and the macros. GP + LP legalization never overlaps macros, but here 5 stick out of
110
+ the core: not legal. <code>packing=True</code> (B*-tree, annealed into the core, then for HPWL) fits them all in
111
+ 5.1 s, at 8% more wire. The lines are the strongest connections between macros and IO pins.</sub>
112
+
113
+ </div>
114
+
115
+ ## Two modes
116
+
117
+ In production chip design, the power delivery network (PDN) is the dividing line: once the power grid and the macros
118
+ are locked down, the design enters a different phase. Attar splits its problems at that line. It does not synthesize
119
+ a PDN, and it should not: a `before_fp` answer goes to a flow that draws one, and an `after_fp` problem comes
120
+ with the PDN its flow drew.
121
+
122
+ | | **Before-floorplan** (`before_fp`) | **After-floorplan** (`after_fp`) |
123
+ | --- | --- | --- |
124
+ | given | the netlist (an initial die for ORFS designs) | die, IO pins, macros, rows and PDN: a fixed floorplan |
125
+ | the answer | target utilization (the die), IO pin placement, macro placement | standard-cell placement; then timing optimization and global routing on the same floorplan |
126
+ | one call | `d.floorplan(utilization=0.6)` | `d.place()` |
127
+ | goes out as | a DEF: your flow draws the PDN and places | a DEF: your flow routes and times |
128
+ | in the zoo | 55 designs, 6 suites | 191 designs, 16 suites |
129
+
130
+ Attar measures wirelength, congestion (RUDY, GROV), density, legality and timing; see the [roadmap](#roadmap).
131
+
132
+ ## How it works
133
+
134
+ <p align="center"><img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/flow.svg" alt="Sources (LEF/DEF, Bookshelf, YAL, GSRC blocks) are distilled into the Attar IR and loaded as a Design on the GPU; attar.naive moves it and adds facts, the Evaluator measures it; export writes a DEF for your own flow (OpenROAD, Innovus, ICC2, ...)" width="100%"></p>
135
+
136
+ 1. **Distill.** A reader turns a benchmark into the Attar IR: integer arrays in a safetensors file, plus a manifest
137
+ that lists which facts the source provides and where each came from. Readers exist for LEF/DEF, Bookshelf, YAL
138
+ and GSRC blocks.
139
+ 2. **Load.** `attar.load` puts the arrays on the GPU as a `Design`. `d.status()` shows each fact, each capability,
140
+ and what is left before export.
141
+ 3. **Move.** Your algorithm, or the [built-in engines](#roadmap) (`attar.naive`), changes the positions:
142
+ die, IO pins and macros for `before_fp`, cells for `after_fp`.
143
+ 4. **Measure.** `attar.Evaluator` computes HPWL (exact, batched), Steiner wirelength, RUDY, density overflow and
144
+ legality, on the current placement or on any positions you pass.
145
+ 5. **Export.** `d.export(out_def)` writes the design back into its source DEF's frame: the PDN, IO pin shapes and
146
+ fixed cells as they were, the cells and nets from the IR (a changed die, IO pins and macros included). Your own
147
+ flow (OpenROAD, Innovus, ICC2, ...) takes it from there.
148
+
149
+ More: [concepts](https://github.com/RayChang987/Attar/blob/main/docs/concepts.md) · [benchmarks](https://github.com/RayChang987/Attar/blob/main/docs/benchmarks.md) · [API](https://github.com/RayChang987/Attar/blob/main/docs/api.md) ·
150
+ [validation](https://github.com/RayChang987/Attar/blob/main/docs/validation/timing_routing.md)
151
+
152
+ ## Gallery
153
+
154
+ What the Evaluator sees: each view is `d.plot(tiles=...)` on a real run of `attar.naive`.
155
+
156
+ <table>
157
+ <tr>
158
+ <td width="50%"><img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/gallery/eval_grov.png" alt="cva6 after placement, colored by global-routing load on OpenROAD's gcells"></td>
159
+ <td width="50%"><img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/gallery/eval_pin_access.png" alt="ariane136 after global placement: cells with a signal pin on the PDN, in stripes along the power grid"></td>
160
+ </tr>
161
+ <tr>
162
+ <td><sub><b>Global-routing overflow</b> (<code>d.gr_overflow()</code>, <code>tiles='gr_overflow'</code>): cva6 (ASAP7)
163
+ placed in 2.4 s, RUDY demand against OpenROAD's gcell capacities. GROV 0.73%: the channel left of the SRAMs and
164
+ the dense logic at the lower right are where the router will struggle.</sub></td>
165
+ <td><sub><b>Pin access</b> (<code>tiles='pin_access'</code>): ariane136 (NS3K, 136 SRAMs) right after global
166
+ placement. 12,165 cells have a signal pin on the PDN's via metal, in stripes along the power grid: NS3K's via
167
+ stacks cross the M1 pin layer.</sub></td>
168
+ </tr>
169
+ <tr>
170
+ <td><img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/gallery/eval_placed.png" alt="ariane136 legalized: legal, rails and PDN included"></td>
171
+ <td><img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/gallery/fp_n300.png" alt="GSRC n300 floorplanned by B*-tree packing, with the strongest connections between blocks and IO pins"></td>
172
+ </tr>
173
+ <tr>
174
+ <td><sub><b>Legality</b> (<code>ev.legality()</code>): the same design legalized in 2.4 s. Rows, sites, overlaps,
175
+ power-rail parity and the PDN all check out: 0 cells left on the PDN.</sub></td>
176
+ <td><sub><b>Floorplan legality and connections</b> (<code>d.floorplan_legal()</code>, <code>nets</code>): GSRC n300,
177
+ 300 hard blocks and 569 IO pins, no die given. Attar sizes one for 85% block area and packs the blocks (B*-tree) in
178
+ 43 s: legal, HPWL 565k. The lines are the strongest connections between blocks and IO pins.</sub></td>
179
+ </tr>
180
+ </table>
181
+
182
+ ## A design is a state
183
+
184
+ ```text
185
+ >>> d = attar.load('after_fp/orfs_asap7/aes'); d.status()
186
+ aes_cipher_top (orfs/asap7, fidelity F1)
187
+ placement target density 0.71 (orfs 3_3 global_place (GPL-0023))
188
+ Problem facts
189
+ ✅ netlist def 12268 nets, 42885 pins
190
+ ✅ cell_geometry lef 12420 cells (12009 movable, 0 macros), 56 masters
191
+ ✅ floorplan.die def 1 die(s), 48.71 x 48.71 um
192
+ ✅ floorplan.io def 388 IO pins placed
193
+ ✅ rows def 164 rows, height 0.27 um
194
+ ✅ pdn def 1815 wire and 4785 via shapes on M1, M2, M3
195
+ ✅ def_frame def PDN, pins, fixed cells of the source DEF, kept verbatim (849 kB)
196
+ ...
197
+ Solution state
198
+ ❌ placement 12009 movable cells unplaced (snapshots: reference)
199
+ ...
200
+ -> only a placement is missing: place the design (or restore a snapshot), then d.export("out.def")
201
+ ```
202
+
203
+ Every reader states which facts it provides, and every engine and metric states which facts it needs:
204
+ - a Bookshelf design has no cell library, so it does not export to DEF;
205
+ - a design with no special nets on the pin layers has no `pdn` rule to keep;
206
+ - a block floorplan has no rows;
207
+ - a soft-block benchmark has no cell geometry.
208
+
209
+ Each can do exactly what its facts allow. Engines add facts with provenance (`placement: naive`), so it is always
210
+ clear which part of a design came from where. See [docs/concepts.md](https://github.com/RayChang987/Attar/blob/main/docs/concepts.md).
211
+
212
+ ## Acknowledgements
213
+
214
+ Attar's global placement follows ePlace, DREAMPlace and Xplace, and its routability option DREAMPlace's cell
215
+ inflation; its rail and PDN checks follow OpenROAD's detailed placer, and its PDN repair the row DP of pa_pdn.
216
+ Attar is validated against [OpenROAD-flow-scripts](https://github.com/The-OpenROAD-Project/OpenROAD-flow-scripts) on
217
+ the ASAP7 and Nangate45 platforms. Benchmarks are from the ISPD, ICCAD and GSRC contests, MCNC and ORFS.
218
+
219
+ ## License
220
+
221
+ <div align="center">
222
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-a8946f?style=for-the-badge" alt="MIT License"></a>
223
+ <br><br>
224
+ <sub>Copyright &copy; 2026 RayChang987 &nbsp;·&nbsp; free to use, modify and distribute; see <a href="LICENSE">LICENSE</a></sub>
225
+ <br><br>
226
+ <img src="https://raw.githubusercontent.com/RayChang987/Attar/main/docs/images/logo.png" alt="Attar" width="180">
227
+ </div>
@@ -0,0 +1,11 @@
1
+ """Attar: a fast loop for physical design. Designs from any source become GPU tensors (Design), metrics evaluate
2
+ them (Evaluator), and a basic set of tensorized engines (attar.naive) makes them move. What a design can do follows
3
+ from the facts it has. See README.md."""
4
+ __version__ = '1.0.0'
5
+
6
+ from .design import Design, load, zoo
7
+ from .io.distill import distill
8
+ from .evaluator import Evaluator
9
+ from .hub import fetch
10
+
11
+ __all__ = ['Design', 'load', 'zoo', 'fetch', 'distill', 'Evaluator', '__version__']
@@ -0,0 +1,58 @@
1
+ """Internal: handing a design back to the slow loop it came from (ORFS), for Attar's own validation.
2
+
3
+ Not part of the user API. Users take the result out with Design.export (a DEF) into their own flow (OpenROAD,
4
+ Innovus, ICC2, ...). Attar keeps this only to check itself against ORFS: tools/orfs_roundtrip.py (a placement into an
5
+ ORFS run), tools/orfs_handoff.py (a floorplan into ORFS 2_1) and their tests use it.
6
+
7
+ The fact 'slow_loop' says that a design comes from an ORFS stage on a platform ORFS knows; an engine that changes the
8
+ floorplan after ORFS built tapcells and PDN around it drops the fact (Design._floorplan_changed).
9
+ """
10
+ import os
11
+
12
+ from .facts import MissingFacts
13
+
14
+ # what a hand-off needs, beyond what export needs
15
+ CAPABILITIES = {
16
+ 'orfs_handoff': {'cell_library', 'def_frame', 'slow_loop', 'floorplan.io', 'floorplan.macros', 'placement'},
17
+ 'orfs_floorplan_handoff': {'cell_library', 'def_frame', 'slow_loop', 'floorplan.io', 'floorplan.macros'}, # 2_1
18
+ }
19
+
20
+
21
+ def missing(d, capability='orfs_handoff'):
22
+ """The facts a hand-off still needs (sorted)."""
23
+ return sorted(CAPABILITIES[capability] - d.present)
24
+
25
+
26
+ def can(d, capability='orfs_handoff'):
27
+ return not missing(d, capability)
28
+
29
+
30
+ def tier(d):
31
+ """A: an ORFS hand-off is possible (given a placement); B: a cell library, so export onto a DEF; C: neither."""
32
+ if CAPABILITIES['orfs_handoff'] - {'placement'} <= set(d.facts):
33
+ return 'A'
34
+ return 'B' if 'cell_library' in d.facts else 'C'
35
+
36
+
37
+ def handoff_command(d, out_def, run_dir=None):
38
+ """The command that hands an exported DEF to an ORFS run of this design (run_dir: its WORK_HOME) and finishes the
39
+ flow there (spec 7.2). A floorplan (from ORFS 2_1) goes to ORFS only when it is legal (Design.floorplan_legal)."""
40
+ o = d.manifest.get('orfs')
41
+ fp = (o or {}).get('stage') == '2_1_floorplan'
42
+ cap = 'orfs_floorplan_handoff' if fp else 'orfs_handoff'
43
+ miss = missing(d, cap)
44
+ if miss:
45
+ raise MissingFacts(d.manifest.get('design', d.path), cap, miss)
46
+ if fp:
47
+ ok, issues = d.floorplan_legal()
48
+ if not ok:
49
+ raise ValueError('%s: the floorplan is not legal (%s); ORFS would not take it'
50
+ % (d.manifest.get('design'), '; '.join(issues)))
51
+ root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
52
+ key = o['design'] if o.get('platform', 'asap7') == 'asap7' else '%s/%s' % (o['platform'], o['design'])
53
+ run = run_dir or '<ORFS WORK_HOME of %s>' % key
54
+ if fp: # the floorplan goes to ORFS, which places and routes from there
55
+ return 'python3 %s %s %s %s' % (os.path.relpath(os.path.join(root, 'tools', 'orfs_handoff.py')), key, run,
56
+ out_def)
57
+ return 'python3 %s %s %s def=%s --stage %s' % (os.path.relpath(os.path.join(root, 'tools', 'orfs_roundtrip.py')),
58
+ key, run, out_def, o['stage'])