librelane 2.4.0.dev7__py3-none-any.whl → 3.0.0.dev22__py3-none-any.whl
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.
Potentially problematic release.
This version of librelane might be problematic. Click here for more details.
- librelane/__main__.py +12 -15
- librelane/common/__init__.py +1 -1
- librelane/common/drc.py +88 -7
- librelane/common/misc.py +6 -6
- librelane/common/toolbox.py +1 -1
- librelane/config/config.py +5 -1
- librelane/config/flow.py +51 -66
- librelane/config/pdk_compat.py +79 -2
- librelane/config/preprocessor.py +1 -1
- librelane/config/variable.py +2 -2
- librelane/flows/classic.py +1 -0
- librelane/flows/flow.py +3 -6
- librelane/flows/sequential.py +85 -40
- librelane/plugins.py +1 -1
- librelane/scripts/magic/common/read.tcl +2 -2
- librelane/scripts/magic/gds/extras_mag.tcl +2 -2
- librelane/scripts/odbpy/diodes.py +2 -2
- librelane/scripts/openroad/common/dpl.tcl +1 -1
- librelane/scripts/openroad/common/grt.tcl +3 -3
- librelane/scripts/openroad/common/io.tcl +163 -45
- librelane/scripts/openroad/common/resizer.tcl +1 -40
- librelane/scripts/openroad/common/set_global_connections.tcl +2 -2
- librelane/scripts/openroad/common/set_power_nets.tcl +1 -1
- librelane/scripts/openroad/common/set_rc.tcl +159 -40
- librelane/scripts/openroad/cts.tcl +37 -6
- librelane/scripts/openroad/cut_rows.tcl +19 -4
- librelane/scripts/openroad/drt.tcl +59 -8
- librelane/scripts/openroad/dump_rc.tcl +105 -0
- librelane/scripts/openroad/fill.tcl +2 -2
- librelane/scripts/openroad/floorplan.tcl +5 -3
- librelane/scripts/openroad/gpl.tcl +7 -8
- librelane/scripts/openroad/gui.tcl +22 -2
- librelane/scripts/openroad/insert_buffer.tcl +2 -2
- librelane/scripts/openroad/ioplacer.tcl +1 -2
- librelane/scripts/openroad/irdrop.tcl +3 -3
- librelane/scripts/openroad/pdn.tcl +17 -18
- librelane/scripts/openroad/rcx.tcl +1 -1
- librelane/scripts/openroad/repair_design.tcl +14 -7
- librelane/scripts/openroad/repair_design_postgrt.tcl +13 -6
- librelane/scripts/openroad/rsz_timing_postcts.tcl +13 -12
- librelane/scripts/openroad/rsz_timing_postgrt.tcl +13 -12
- librelane/scripts/openroad/sta/check_macro_instances.tcl +1 -1
- librelane/scripts/openroad/tapcell.tcl +13 -6
- librelane/scripts/openroad/ungpl.tcl +23 -0
- librelane/state/__init__.py +1 -1
- librelane/state/design_format.py +194 -142
- librelane/state/state.py +20 -21
- librelane/steps/checker.py +12 -1
- librelane/steps/common_variables.py +4 -4
- librelane/steps/cvc_rv.py +1 -1
- librelane/steps/klayout.py +14 -6
- librelane/steps/magic.py +18 -2
- librelane/steps/misc.py +1 -1
- librelane/steps/odb.py +50 -31
- librelane/steps/openroad.py +455 -128
- librelane/steps/pyosys.py +20 -5
- librelane/steps/step.py +17 -20
- librelane/steps/tclstep.py +9 -7
- librelane/steps/yosys.py +1 -1
- {librelane-2.4.0.dev7.dist-info → librelane-3.0.0.dev22.dist-info}/METADATA +1 -1
- {librelane-2.4.0.dev7.dist-info → librelane-3.0.0.dev22.dist-info}/RECORD +63 -61
- {librelane-2.4.0.dev7.dist-info → librelane-3.0.0.dev22.dist-info}/WHEEL +0 -0
- {librelane-2.4.0.dev7.dist-info → librelane-3.0.0.dev22.dist-info}/entry_points.txt +0 -0
librelane/steps/openroad.py
CHANGED
|
@@ -21,66 +21,56 @@ import re
|
|
|
21
21
|
import json
|
|
22
22
|
import functools
|
|
23
23
|
import subprocess
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
from glob import glob
|
|
27
|
-
from decimal import Decimal
|
|
28
|
-
from base64 import b64encode
|
|
24
|
+
import textwrap
|
|
25
|
+
import pathlib
|
|
29
26
|
from abc import abstractmethod
|
|
30
|
-
from
|
|
27
|
+
from base64 import b64encode
|
|
31
28
|
from concurrent.futures import Future, ThreadPoolExecutor
|
|
32
|
-
from
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
Tuple,
|
|
39
|
-
Optional,
|
|
40
|
-
Union,
|
|
41
|
-
)
|
|
42
|
-
|
|
29
|
+
from dataclasses import dataclass
|
|
30
|
+
from decimal import Decimal
|
|
31
|
+
from enum import Enum
|
|
32
|
+
from glob import glob
|
|
33
|
+
from math import inf
|
|
34
|
+
from typing import Any, Dict, List, Literal, Optional, Set, Tuple, Union
|
|
43
35
|
|
|
44
|
-
import yaml
|
|
45
36
|
import rich
|
|
46
37
|
import rich.table
|
|
38
|
+
import yaml
|
|
47
39
|
|
|
40
|
+
from ..common import (
|
|
41
|
+
Path,
|
|
42
|
+
Filter,
|
|
43
|
+
TclUtils,
|
|
44
|
+
DRC as DRCObject,
|
|
45
|
+
_get_process_limit,
|
|
46
|
+
aggregate_metrics,
|
|
47
|
+
get_script_dir,
|
|
48
|
+
mkdirp,
|
|
49
|
+
process_list_file,
|
|
50
|
+
)
|
|
51
|
+
from ..config import Macro, Variable
|
|
52
|
+
from ..config.flow import option_variables
|
|
53
|
+
from ..logging import console, debug, info, options, verbose
|
|
54
|
+
from ..state import DesignFormat, State
|
|
55
|
+
from .common_variables import (
|
|
56
|
+
dpl_variables,
|
|
57
|
+
grt_variables,
|
|
58
|
+
io_layer_variables,
|
|
59
|
+
pdn_variables,
|
|
60
|
+
routing_layer_variables,
|
|
61
|
+
rsz_variables,
|
|
62
|
+
)
|
|
63
|
+
from .openroad_alerts import OpenROADAlert, OpenROADOutputProcessor
|
|
48
64
|
from .step import (
|
|
49
65
|
CompositeStep,
|
|
50
66
|
DefaultOutputProcessor,
|
|
51
|
-
StepError,
|
|
52
|
-
ViewsUpdate,
|
|
53
67
|
MetricsUpdate,
|
|
54
68
|
Step,
|
|
69
|
+
StepError,
|
|
55
70
|
StepException,
|
|
56
|
-
|
|
57
|
-
from .openroad_alerts import (
|
|
58
|
-
OpenROADAlert,
|
|
59
|
-
OpenROADOutputProcessor,
|
|
71
|
+
ViewsUpdate,
|
|
60
72
|
)
|
|
61
73
|
from .tclstep import TclStep
|
|
62
|
-
from .common_variables import (
|
|
63
|
-
io_layer_variables,
|
|
64
|
-
pdn_variables,
|
|
65
|
-
rsz_variables,
|
|
66
|
-
dpl_variables,
|
|
67
|
-
grt_variables,
|
|
68
|
-
routing_layer_variables,
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
from ..config import Variable, Macro
|
|
72
|
-
from ..config.flow import option_variables
|
|
73
|
-
from ..state import State, DesignFormat
|
|
74
|
-
from ..logging import debug, info, verbose, console, options
|
|
75
|
-
from ..common import (
|
|
76
|
-
Path,
|
|
77
|
-
TclUtils,
|
|
78
|
-
get_script_dir,
|
|
79
|
-
mkdirp,
|
|
80
|
-
aggregate_metrics,
|
|
81
|
-
process_list_file,
|
|
82
|
-
_get_process_limit,
|
|
83
|
-
)
|
|
84
74
|
|
|
85
75
|
EXAMPLE_INPUT = """
|
|
86
76
|
li1 X 0.23 0.46
|
|
@@ -130,6 +120,22 @@ def pdn_macro_migrator(x):
|
|
|
130
120
|
return [x.strip()]
|
|
131
121
|
|
|
132
122
|
|
|
123
|
+
DesignFormat(
|
|
124
|
+
"odb",
|
|
125
|
+
"odb",
|
|
126
|
+
"OpenDB Database",
|
|
127
|
+
alts=["ODB"],
|
|
128
|
+
).register()
|
|
129
|
+
|
|
130
|
+
DesignFormat(
|
|
131
|
+
"openroad_lef",
|
|
132
|
+
"openroad.lef",
|
|
133
|
+
"Library Exchange Format Generated by OpenROAD",
|
|
134
|
+
alts=["OPENROAD_LEF"],
|
|
135
|
+
folder_override="lef",
|
|
136
|
+
).register()
|
|
137
|
+
|
|
138
|
+
|
|
133
139
|
@Step.factory.register()
|
|
134
140
|
class CheckSDCFiles(Step):
|
|
135
141
|
"""
|
|
@@ -159,7 +165,7 @@ class CheckSDCFiles(Step):
|
|
|
159
165
|
|
|
160
166
|
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
161
167
|
default_sdc_file = [
|
|
162
|
-
var for var in option_variables if var.name == "
|
|
168
|
+
var for var in option_variables if var.name == "FALLBACK_SDC"
|
|
163
169
|
][0]
|
|
164
170
|
assert default_sdc_file is not None
|
|
165
171
|
|
|
@@ -191,6 +197,38 @@ class OpenROADStep(TclStep):
|
|
|
191
197
|
alerts: Optional[List[OpenROADAlert]] = None
|
|
192
198
|
|
|
193
199
|
config_vars = [
|
|
200
|
+
Variable(
|
|
201
|
+
"PNR_CORNERS",
|
|
202
|
+
Optional[List[str]],
|
|
203
|
+
"A list of fully-qualified IPVT corners to use during PnR. If unspecified, the value for `STA_CORNERS` from the PDK will be used.",
|
|
204
|
+
pdk=True,
|
|
205
|
+
),
|
|
206
|
+
Variable(
|
|
207
|
+
"SET_RC_VERBOSE",
|
|
208
|
+
bool,
|
|
209
|
+
"If set to true, set_rc commands are echoed. Quite noisy, but may be useful for debugging.",
|
|
210
|
+
default=False,
|
|
211
|
+
),
|
|
212
|
+
Variable(
|
|
213
|
+
"LAYERS_RC",
|
|
214
|
+
Optional[Dict[str, Dict[str, Dict[str, Decimal]]]],
|
|
215
|
+
"Used during PNR steps, Specific custom resistance and capacitance values for metal layers."
|
|
216
|
+
+ " For each IPVT corner, a mapping for each metal layer is provided."
|
|
217
|
+
+ " Each mapping describes custom resistance and capacitance values."
|
|
218
|
+
+ " Usage of wildcards for specifying IPVT corners is allowed."
|
|
219
|
+
+ " Units are resistance and capacitance per unit length as defined in the first lib file.",
|
|
220
|
+
pdk=True,
|
|
221
|
+
),
|
|
222
|
+
Variable(
|
|
223
|
+
"VIAS_R",
|
|
224
|
+
Optional[Dict[str, Dict[str, Dict[str, Decimal]]]],
|
|
225
|
+
"Used during PNR steps, Specific custom resistance values for via layers."
|
|
226
|
+
+ " For each IPVT corner, a mapping for each via layer is provided."
|
|
227
|
+
+ " Each mapping describes custom resistance values."
|
|
228
|
+
+ " Usage of wildcards for specifying IPVT corners is allowed."
|
|
229
|
+
+ " Via resistance is per cut/via with units asdefined in the first lib file.",
|
|
230
|
+
pdk=True,
|
|
231
|
+
),
|
|
194
232
|
Variable(
|
|
195
233
|
"PDN_CONNECT_MACROS_TO_GRID",
|
|
196
234
|
bool,
|
|
@@ -221,6 +259,12 @@ class OpenROADStep(TclStep):
|
|
|
221
259
|
Optional[Path],
|
|
222
260
|
"Points to the DEF file to be used as a template.",
|
|
223
261
|
),
|
|
262
|
+
Variable(
|
|
263
|
+
"DEDUPLICATE_CORNERS",
|
|
264
|
+
bool,
|
|
265
|
+
"Cull duplicate IPVT corners during PNR, i.e. corners that share the same set of lib files and values for LAYERS_RC and VIAS_R as another corner are not considered outside of STA.",
|
|
266
|
+
default=False,
|
|
267
|
+
),
|
|
224
268
|
]
|
|
225
269
|
|
|
226
270
|
@abstractmethod
|
|
@@ -246,7 +290,7 @@ class OpenROADStep(TclStep):
|
|
|
246
290
|
lib_list = self.toolbox.filter_views(self.config, self.config["LIB"])
|
|
247
291
|
lib_list += self.toolbox.get_macro_views(self.config, DesignFormat.LIB)
|
|
248
292
|
|
|
249
|
-
env["_SDC_IN"] = self.config["PNR_SDC_FILE"] or self.config["
|
|
293
|
+
env["_SDC_IN"] = self.config["PNR_SDC_FILE"] or self.config["FALLBACK_SDC"]
|
|
250
294
|
env["_PNR_LIBS"] = TclStep.value_to_tcl(lib_list)
|
|
251
295
|
env["_MACRO_LIBS"] = TclStep.value_to_tcl(
|
|
252
296
|
self.toolbox.get_macro_views(self.config, DesignFormat.LIB)
|
|
@@ -262,9 +306,8 @@ class OpenROADStep(TclStep):
|
|
|
262
306
|
"""
|
|
263
307
|
The `run()` override for the OpenROADStep class handles two things:
|
|
264
308
|
|
|
265
|
-
1. Before the `super()` call:
|
|
266
|
-
|
|
267
|
-
in the environment variable `_PNR_LIBS`.
|
|
309
|
+
1. Before the `super()` call: Process _LIB_CORNER_<i> for liberty/corner
|
|
310
|
+
pairs.
|
|
268
311
|
|
|
269
312
|
2. After the `super()` call: Processes the `or_metrics_out.json` file and
|
|
270
313
|
updates the State's `metrics` property with any new metrics in that object.
|
|
@@ -273,16 +316,111 @@ class OpenROADStep(TclStep):
|
|
|
273
316
|
kwargs, env = self.extract_env(kwargs)
|
|
274
317
|
env = self.prepare_env(env, state_in)
|
|
275
318
|
|
|
319
|
+
corners: List[str] = self.config["PNR_CORNERS"] or [
|
|
320
|
+
self.config["DEFAULT_CORNER"]
|
|
321
|
+
]
|
|
322
|
+
|
|
323
|
+
@dataclass
|
|
324
|
+
class IPVTCorner:
|
|
325
|
+
name: str
|
|
326
|
+
libs: List[Path]
|
|
327
|
+
layers_rc: Optional[Dict[str, Dict[str, Decimal]]]
|
|
328
|
+
vias_r: Optional[Dict[str, Dict[str, Decimal]]]
|
|
329
|
+
|
|
330
|
+
def __eq__(self, other):
|
|
331
|
+
if not isinstance(other, IPVTCorner):
|
|
332
|
+
return False
|
|
333
|
+
return (
|
|
334
|
+
self.libs == other.libs
|
|
335
|
+
and self.layers_rc == other.layers_rc
|
|
336
|
+
and self.vias_r == other.vias_r
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
def __hash__(self):
|
|
340
|
+
return hash(
|
|
341
|
+
(
|
|
342
|
+
frozenset([str(lib) for lib in self.libs]),
|
|
343
|
+
TclStep.value_to_tcl(self.layers_rc),
|
|
344
|
+
TclStep.value_to_tcl(self.vias_r),
|
|
345
|
+
)
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
if "corners" in kwargs:
|
|
349
|
+
corners = kwargs.pop("corners")
|
|
350
|
+
debug(f"Corners Override {corners}")
|
|
351
|
+
|
|
352
|
+
count = 0
|
|
353
|
+
ipvt_corners = {}
|
|
354
|
+
for corner in corners:
|
|
355
|
+
_, libs, _, _ = self.toolbox.get_timing_files_categorized(
|
|
356
|
+
self.config, corner
|
|
357
|
+
)
|
|
358
|
+
ipvt_corners[corner] = IPVTCorner(corner, libs, None, None)
|
|
359
|
+
# debug(f"Liberty files for '{corner}' added: {libs}")
|
|
360
|
+
count += 1
|
|
361
|
+
|
|
276
362
|
check = False
|
|
277
363
|
if "check" in kwargs:
|
|
278
364
|
check = kwargs.pop("check")
|
|
279
365
|
|
|
366
|
+
layers_rc = self.config["LAYERS_RC"]
|
|
367
|
+
if layers_rc is not None:
|
|
368
|
+
for corner_wildcard, metal_layers in layers_rc.items():
|
|
369
|
+
for corner in Filter([corner_wildcard]).filter(corners):
|
|
370
|
+
ipvt_corners[corner].layers_rc = metal_layers
|
|
371
|
+
|
|
372
|
+
vias_r = self.config["VIAS_R"]
|
|
373
|
+
if vias_r is not None:
|
|
374
|
+
for corner_wildcard, metal_layers in vias_r.items():
|
|
375
|
+
for corner in Filter(corner_wildcard).filter(corners):
|
|
376
|
+
ipvt_corners[corner].vias_r = metal_layers
|
|
377
|
+
|
|
378
|
+
filtered_ipvt_corners_names_sorted = corners
|
|
379
|
+
if self.config["DEDUPLICATE_CORNERS"]:
|
|
380
|
+
filtered_ipvt_corners = {
|
|
381
|
+
k: v
|
|
382
|
+
for k, v in ipvt_corners.items()
|
|
383
|
+
if k in [corner.name for corner in set(ipvt_corners.values())]
|
|
384
|
+
}
|
|
385
|
+
filtered_ipvt_corners_names_sorted = [
|
|
386
|
+
x for _, x in sorted(zip(corners, filtered_ipvt_corners.keys()))
|
|
387
|
+
]
|
|
388
|
+
count = 0
|
|
389
|
+
for corner_name in filtered_ipvt_corners_names_sorted:
|
|
390
|
+
vias_r = ipvt_corners[corner_name].vias_r
|
|
391
|
+
if vias_r is not None:
|
|
392
|
+
for via, rc in vias_r.items():
|
|
393
|
+
res = rc["res"]
|
|
394
|
+
env[f"_VIA_R_{count}"] = TclStep.value_to_tcl(
|
|
395
|
+
[corner_name, via, res]
|
|
396
|
+
)
|
|
397
|
+
count += 1
|
|
398
|
+
count = 0
|
|
399
|
+
for corner_name in filtered_ipvt_corners_names_sorted:
|
|
400
|
+
layers_rc = ipvt_corners[corner_name].layers_rc
|
|
401
|
+
if layers_rc is not None:
|
|
402
|
+
for layer, rc in layers_rc.items():
|
|
403
|
+
res = rc["res"]
|
|
404
|
+
cap = rc["cap"]
|
|
405
|
+
env[f"_LAYER_RC_{count}"] = TclStep.value_to_tcl(
|
|
406
|
+
[corner_name, layer, res, cap]
|
|
407
|
+
)
|
|
408
|
+
count += 1
|
|
409
|
+
|
|
410
|
+
count = 0
|
|
411
|
+
for corner_name in filtered_ipvt_corners_names_sorted:
|
|
412
|
+
env[f"_LIB_CORNER_{count}"] = TclStep.value_to_tcl(
|
|
413
|
+
[corner_name] + ipvt_corners[corner_name].libs
|
|
414
|
+
)
|
|
415
|
+
count += 1
|
|
416
|
+
|
|
280
417
|
command = self.get_command()
|
|
281
418
|
|
|
282
419
|
subprocess_result = self.run_subprocess(
|
|
283
420
|
command,
|
|
284
421
|
env=env,
|
|
285
422
|
check=check,
|
|
423
|
+
cwd=self.step_dir,
|
|
286
424
|
**kwargs,
|
|
287
425
|
)
|
|
288
426
|
|
|
@@ -290,10 +428,10 @@ class OpenROADStep(TclStep):
|
|
|
290
428
|
|
|
291
429
|
views_updates: ViewsUpdate = {}
|
|
292
430
|
for output in self.outputs:
|
|
293
|
-
if output.
|
|
431
|
+
if output.multiple:
|
|
294
432
|
# Too step-specific.
|
|
295
433
|
continue
|
|
296
|
-
path = Path(env[f"SAVE_{output.
|
|
434
|
+
path = Path(env[f"SAVE_{output.id.upper()}"])
|
|
297
435
|
if not path.exists():
|
|
298
436
|
continue
|
|
299
437
|
views_updates[output] = path
|
|
@@ -332,7 +470,7 @@ class OpenROADStep(TclStep):
|
|
|
332
470
|
metrics_path = os.path.join(self.step_dir, "or_metrics_out.json")
|
|
333
471
|
return [
|
|
334
472
|
"openroad",
|
|
335
|
-
"-exit",
|
|
473
|
+
("-gui" if os.getenv("_OPENROAD_GUI", "0") == "1" else "-exit"),
|
|
336
474
|
"-no_splash",
|
|
337
475
|
"-metrics",
|
|
338
476
|
metrics_path,
|
|
@@ -420,7 +558,7 @@ class OpenSTAStep(OpenROADStep):
|
|
|
420
558
|
|
|
421
559
|
name = timing_corner
|
|
422
560
|
current_corner_spef = None
|
|
423
|
-
input_spef_dict = state_in
|
|
561
|
+
input_spef_dict = state_in.get(DesignFormat.SPEF)
|
|
424
562
|
if input_spef_dict is not None:
|
|
425
563
|
if not isinstance(input_spef_dict, dict):
|
|
426
564
|
raise StepException(
|
|
@@ -737,7 +875,7 @@ class STAPrePNR(MultiCornerSTA):
|
|
|
737
875
|
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
738
876
|
views_updates, metrics_updates = super().run(state_in, **kwargs)
|
|
739
877
|
|
|
740
|
-
sdf_dict = state_in
|
|
878
|
+
sdf_dict = state_in.get(DesignFormat.SDF, {})
|
|
741
879
|
if not isinstance(sdf_dict, dict):
|
|
742
880
|
raise StepException(
|
|
743
881
|
"Malformed input state: incoming value for SDF is not a dictionary."
|
|
@@ -876,7 +1014,7 @@ class STAPostPNR(STAPrePNR):
|
|
|
876
1014
|
|
|
877
1015
|
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
878
1016
|
views_updates, metrics_updates = super().run(state_in, **kwargs)
|
|
879
|
-
lib_dict = state_in
|
|
1017
|
+
lib_dict = state_in.get(DesignFormat.LIB, {})
|
|
880
1018
|
if not isinstance(lib_dict, dict):
|
|
881
1019
|
raise StepException(
|
|
882
1020
|
"Malformed input state: value for LIB is not a dictionary."
|
|
@@ -907,6 +1045,19 @@ class Floorplan(OpenROADStep):
|
|
|
907
1045
|
inputs = [DesignFormat.NETLIST]
|
|
908
1046
|
|
|
909
1047
|
config_vars = OpenROADStep.config_vars + [
|
|
1048
|
+
Variable(
|
|
1049
|
+
"FP_FLIP_SITES",
|
|
1050
|
+
Optional[List[str]],
|
|
1051
|
+
"Flip these sites vertically. Useful in niche alignment scenarios where single-height cells have ground at the south side and double-height cells have power at the south side, causing a short. In that situation, flipping the sites for single-height cells resolves the issue.",
|
|
1052
|
+
pdk=True,
|
|
1053
|
+
),
|
|
1054
|
+
Variable(
|
|
1055
|
+
"FP_TRACKS_INFO",
|
|
1056
|
+
Path,
|
|
1057
|
+
"A path to the a classic OpenROAD `.tracks` file. Used by the floorplanner to generate tracks.",
|
|
1058
|
+
deprecated_names=["TRACKS_INFO_FILE"],
|
|
1059
|
+
pdk=True,
|
|
1060
|
+
),
|
|
910
1061
|
Variable(
|
|
911
1062
|
"FP_SIZING",
|
|
912
1063
|
Literal["absolute", "relative"],
|
|
@@ -1101,7 +1252,7 @@ class IOPlacement(OpenROADStep):
|
|
|
1101
1252
|
@Step.factory.register()
|
|
1102
1253
|
class TapEndcapInsertion(OpenROADStep):
|
|
1103
1254
|
"""
|
|
1104
|
-
Places
|
|
1255
|
+
Places welltap cells across a floorplan, as well as endcap cells at the
|
|
1105
1256
|
edges of the floorplan.
|
|
1106
1257
|
"""
|
|
1107
1258
|
|
|
@@ -1109,10 +1260,17 @@ class TapEndcapInsertion(OpenROADStep):
|
|
|
1109
1260
|
name = "Tap/Decap Insertion"
|
|
1110
1261
|
|
|
1111
1262
|
config_vars = OpenROADStep.config_vars + [
|
|
1263
|
+
Variable(
|
|
1264
|
+
"FP_TAPCELL_DIST",
|
|
1265
|
+
Optional[Decimal],
|
|
1266
|
+
"The distance between tap cell columns. Must be specified if WELLTAP_CELL is specified.",
|
|
1267
|
+
units="µm",
|
|
1268
|
+
pdk=True,
|
|
1269
|
+
),
|
|
1112
1270
|
Variable(
|
|
1113
1271
|
"FP_MACRO_HORIZONTAL_HALO",
|
|
1114
1272
|
Decimal,
|
|
1115
|
-
"Specify the horizontal halo size around macros
|
|
1273
|
+
"Specify the horizontal halo size around macros.",
|
|
1116
1274
|
default=10,
|
|
1117
1275
|
units="µm",
|
|
1118
1276
|
deprecated_names=["FP_TAP_HORIZONTAL_HALO"],
|
|
@@ -1120,7 +1278,7 @@ class TapEndcapInsertion(OpenROADStep):
|
|
|
1120
1278
|
Variable(
|
|
1121
1279
|
"FP_MACRO_VERTICAL_HALO",
|
|
1122
1280
|
Decimal,
|
|
1123
|
-
"Specify the vertical halo size around macros
|
|
1281
|
+
"Specify the vertical halo size around macros.",
|
|
1124
1282
|
default=10,
|
|
1125
1283
|
units="µm",
|
|
1126
1284
|
deprecated_names=["FP_TAP_VERTICAL_HALO"],
|
|
@@ -1130,6 +1288,30 @@ class TapEndcapInsertion(OpenROADStep):
|
|
|
1130
1288
|
def get_script_path(self):
|
|
1131
1289
|
return os.path.join(get_script_dir(), "openroad", "tapcell.tcl")
|
|
1132
1290
|
|
|
1291
|
+
def run(self, state_in, **kwargs):
|
|
1292
|
+
if (
|
|
1293
|
+
self.config["WELLTAP_CELL"] is not None
|
|
1294
|
+
and self.config["FP_TAPCELL_DIST"] is None
|
|
1295
|
+
):
|
|
1296
|
+
raise StepException("FP_TAPCELL_DIST must be set if WELLTAP_CELL is set.")
|
|
1297
|
+
return super().run(state_in, **kwargs)
|
|
1298
|
+
|
|
1299
|
+
|
|
1300
|
+
@Step.factory.register()
|
|
1301
|
+
class UnplaceAll(OpenROADStep):
|
|
1302
|
+
"""
|
|
1303
|
+
Sets placement status of *all* instances to NONE.
|
|
1304
|
+
|
|
1305
|
+
Useful in flows where a preliminary placement is needed as a pre-requisite
|
|
1306
|
+
to something else but that placement must be discarded.
|
|
1307
|
+
"""
|
|
1308
|
+
|
|
1309
|
+
id = "OpenROAD.UnplaceAll"
|
|
1310
|
+
name = "Unplace All"
|
|
1311
|
+
|
|
1312
|
+
def get_script_path(self):
|
|
1313
|
+
return os.path.join(get_script_dir(), "openroad", "ungpl.tcl")
|
|
1314
|
+
|
|
1133
1315
|
|
|
1134
1316
|
def get_psm_error_count(rpt: io.TextIOWrapper) -> int:
|
|
1135
1317
|
sio = io.StringIO()
|
|
@@ -1141,9 +1323,9 @@ def get_psm_error_count(rpt: io.TextIOWrapper) -> int:
|
|
|
1141
1323
|
vio_type = line[len(VIO_TYPE_PFX) :].strip()
|
|
1142
1324
|
sio.write(f"- type: {vio_type}\n")
|
|
1143
1325
|
elif "bbox = " in line:
|
|
1144
|
-
sio.write(line.replace(
|
|
1326
|
+
sio.write(f" {textwrap.dedent(line.replace('bbox = ', '- bbox ='))}")
|
|
1145
1327
|
else:
|
|
1146
|
-
sio.write(line)
|
|
1328
|
+
sio.write(f" {textwrap.dedent(line)}")
|
|
1147
1329
|
|
|
1148
1330
|
sio.seek(0)
|
|
1149
1331
|
violations = yaml.load(sio, Loader=yaml.SafeLoader) or []
|
|
@@ -1212,7 +1394,7 @@ class _GlobalPlacement(OpenROADStep):
|
|
|
1212
1394
|
"The desired placement density of cells. If not specified, the value will be equal to (`FP_CORE_UTIL` + 5 * `GPL_CELL_PADDING` + 10).",
|
|
1213
1395
|
units="%",
|
|
1214
1396
|
deprecated_names=[
|
|
1215
|
-
("PL_TARGET_DENSITY", lambda d: Decimal(d) * Decimal(100
|
|
1397
|
+
("PL_TARGET_DENSITY", lambda d: Decimal(d) * Decimal("100"))
|
|
1216
1398
|
],
|
|
1217
1399
|
),
|
|
1218
1400
|
Variable(
|
|
@@ -1248,11 +1430,16 @@ class _GlobalPlacement(OpenROADStep):
|
|
|
1248
1430
|
),
|
|
1249
1431
|
Variable(
|
|
1250
1432
|
"GPL_CELL_PADDING",
|
|
1251
|
-
|
|
1433
|
+
int,
|
|
1252
1434
|
"Cell padding value (in sites) for global placement. The number will be integer divided by 2 and placed on both sides.",
|
|
1253
1435
|
units="sites",
|
|
1254
1436
|
pdk=True,
|
|
1255
1437
|
),
|
|
1438
|
+
Variable(
|
|
1439
|
+
"PL_KEEP_RESIZE_BELOW_OVERFLOW",
|
|
1440
|
+
Optional[Decimal],
|
|
1441
|
+
"Only applicable when PL_TIME_DRIVEN is enabled. When the overflow is below the set value, timing-driven iterations will retain the resizer changes instead of reverting them. Allowed values are 0 to 1. If not set, a nonzero default value from OpenROAD will be used",
|
|
1442
|
+
),
|
|
1256
1443
|
]
|
|
1257
1444
|
)
|
|
1258
1445
|
|
|
@@ -1311,7 +1498,7 @@ class GlobalPlacement(_GlobalPlacement):
|
|
|
1311
1498
|
@Step.factory.register()
|
|
1312
1499
|
class GlobalPlacementSkipIO(_GlobalPlacement):
|
|
1313
1500
|
"""
|
|
1314
|
-
Performs global placement
|
|
1501
|
+
Performs preliminary global placement as a basis for pin placement.
|
|
1315
1502
|
|
|
1316
1503
|
This is useful for flows where the:
|
|
1317
1504
|
* Cells are placed
|
|
@@ -1330,6 +1517,11 @@ class GlobalPlacementSkipIO(_GlobalPlacement):
|
|
|
1330
1517
|
default="matching",
|
|
1331
1518
|
deprecated_names=[("FP_IO_MODE", _migrate_ppl_mode)],
|
|
1332
1519
|
),
|
|
1520
|
+
Variable(
|
|
1521
|
+
"FP_PIN_ORDER_CFG",
|
|
1522
|
+
Optional[Path],
|
|
1523
|
+
"Path to a custom pin configuration file.",
|
|
1524
|
+
),
|
|
1333
1525
|
Variable(
|
|
1334
1526
|
"FP_DEF_TEMPLATE",
|
|
1335
1527
|
Optional[Path],
|
|
@@ -1341,39 +1533,18 @@ class GlobalPlacementSkipIO(_GlobalPlacement):
|
|
|
1341
1533
|
kwargs, env = self.extract_env(kwargs)
|
|
1342
1534
|
if self.config["FP_DEF_TEMPLATE"] is not None:
|
|
1343
1535
|
info(
|
|
1344
|
-
f"I/O pins were loaded from {self.config['FP_DEF_TEMPLATE']}.
|
|
1536
|
+
f"I/O pins were loaded from {self.config['FP_DEF_TEMPLATE']}. Returning state unaltered…"
|
|
1537
|
+
)
|
|
1538
|
+
return {}, {}
|
|
1539
|
+
if self.config["FP_PIN_ORDER_CFG"] is not None:
|
|
1540
|
+
info(
|
|
1541
|
+
f"I/O pins to be placed from {self.config['FP_PIN_ORDER_CFG']}. Returning state unaltered…"
|
|
1345
1542
|
)
|
|
1346
1543
|
return {}, {}
|
|
1347
1544
|
env["__PL_SKIP_IO"] = "1"
|
|
1348
1545
|
return super().run(state_in, env=env, **kwargs)
|
|
1349
1546
|
|
|
1350
1547
|
|
|
1351
|
-
@Step.factory.register()
|
|
1352
|
-
class BasicMacroPlacement(OpenROADStep):
|
|
1353
|
-
id = "OpenROAD.BasicMacroPlacement"
|
|
1354
|
-
name = "Basic Macro Placement"
|
|
1355
|
-
|
|
1356
|
-
config_vars = OpenROADStep.config_vars + [
|
|
1357
|
-
Variable(
|
|
1358
|
-
"PL_MACRO_HALO",
|
|
1359
|
-
str,
|
|
1360
|
-
"Macro placement halo. Format: `{Horizontal} {Vertical}`.",
|
|
1361
|
-
default="0 0",
|
|
1362
|
-
units="µm",
|
|
1363
|
-
),
|
|
1364
|
-
Variable(
|
|
1365
|
-
"PL_MACRO_CHANNEL",
|
|
1366
|
-
str,
|
|
1367
|
-
"Channel widths between macros. Format: `{Horizontal} {Vertical}`.",
|
|
1368
|
-
default="0 0",
|
|
1369
|
-
units="µm",
|
|
1370
|
-
),
|
|
1371
|
-
]
|
|
1372
|
-
|
|
1373
|
-
def get_script_path(self):
|
|
1374
|
-
raise NotImplementedError()
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
1548
|
@Step.factory.register()
|
|
1378
1549
|
class DetailedPlacement(OpenROADStep):
|
|
1379
1550
|
"""
|
|
@@ -1584,6 +1755,13 @@ class RepairAntennas(CompositeStep):
|
|
|
1584
1755
|
|
|
1585
1756
|
Steps = [_DiodeInsertion, CheckAntennas]
|
|
1586
1757
|
|
|
1758
|
+
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
1759
|
+
if self.config["DIODE_CELL"] is None:
|
|
1760
|
+
info(f"'DIODE_CELL' not set. Skipping '{self.id}'…")
|
|
1761
|
+
return {}, {}
|
|
1762
|
+
|
|
1763
|
+
return super().run(state_in, **kwargs)
|
|
1764
|
+
|
|
1587
1765
|
|
|
1588
1766
|
@Step.factory.register()
|
|
1589
1767
|
class DetailedRouting(OpenROADStep):
|
|
@@ -1626,6 +1804,30 @@ class DetailedRouting(OpenROADStep):
|
|
|
1626
1804
|
"Specifies the maximum number of optimization iterations during Detailed Routing in TritonRoute.",
|
|
1627
1805
|
default=64,
|
|
1628
1806
|
),
|
|
1807
|
+
Variable(
|
|
1808
|
+
"DRT_SAVE_SNAPSHOTS",
|
|
1809
|
+
bool,
|
|
1810
|
+
"This is an experimental variable. Saves an odb snapshot of the layout each routing iteration. This generates multiple odb files increasing disk usage.",
|
|
1811
|
+
default=False,
|
|
1812
|
+
),
|
|
1813
|
+
Variable(
|
|
1814
|
+
"DRT_ANTENNA_REPAIR_ITERS",
|
|
1815
|
+
int,
|
|
1816
|
+
"The maximum number of iterations to run antenna repair. Set to a positive integer to attempt to repair antennas and then re-run DRT as appropriate.",
|
|
1817
|
+
default=0,
|
|
1818
|
+
),
|
|
1819
|
+
Variable(
|
|
1820
|
+
"DRT_ANTENNA_MARGIN",
|
|
1821
|
+
int,
|
|
1822
|
+
"The margin to over fix antenna violations.",
|
|
1823
|
+
default=10,
|
|
1824
|
+
units="%",
|
|
1825
|
+
),
|
|
1826
|
+
Variable(
|
|
1827
|
+
"DRT_SAVE_DRC_REPORT_ITERS",
|
|
1828
|
+
Optional[int],
|
|
1829
|
+
"Write a DRC report every N iterations. If DRT_SAVE_SNAPSHOTS is enabled, there is an implicit default value of 1.",
|
|
1830
|
+
),
|
|
1629
1831
|
]
|
|
1630
1832
|
|
|
1631
1833
|
def get_script_path(self):
|
|
@@ -1635,7 +1837,21 @@ class DetailedRouting(OpenROADStep):
|
|
|
1635
1837
|
kwargs, env = self.extract_env(kwargs)
|
|
1636
1838
|
env["DRT_THREADS"] = env.get("DRT_THREADS", str(_get_process_limit()))
|
|
1637
1839
|
info(f"Running TritonRoute with {env['DRT_THREADS']} threads…")
|
|
1638
|
-
|
|
1840
|
+
views_updates, metrics_updates = super().run(state_in, env=env, **kwargs)
|
|
1841
|
+
|
|
1842
|
+
drc_paths = list(pathlib.Path(self.step_dir).rglob("*.drc*"))
|
|
1843
|
+
for path in drc_paths:
|
|
1844
|
+
drc, _ = DRCObject.from_openroad(
|
|
1845
|
+
open(path, encoding="utf8"), self.config["DESIGN_NAME"]
|
|
1846
|
+
)
|
|
1847
|
+
|
|
1848
|
+
drc.to_klayout_xml(open(pathlib.Path(str(path) + ".xml"), "wb"))
|
|
1849
|
+
# if violation_count > 0:
|
|
1850
|
+
# self.warn(
|
|
1851
|
+
# f"DRC errors found after routing. View the report file at {report_path}.\nView KLayout xml file at {klayout_db_path}"
|
|
1852
|
+
# )
|
|
1853
|
+
|
|
1854
|
+
return views_updates, metrics_updates
|
|
1639
1855
|
|
|
1640
1856
|
|
|
1641
1857
|
@Step.factory.register()
|
|
@@ -1793,7 +2009,7 @@ class RCX(OpenROADStep):
|
|
|
1793
2009
|
views_updates: ViewsUpdate = {}
|
|
1794
2010
|
metrics_updates: MetricsUpdate = {}
|
|
1795
2011
|
|
|
1796
|
-
spef_dict = state_in
|
|
2012
|
+
spef_dict = state_in.get(DesignFormat.SPEF, {})
|
|
1797
2013
|
if not isinstance(spef_dict, dict):
|
|
1798
2014
|
raise StepException(
|
|
1799
2015
|
"Malformed input state: value for SPEF is not a dictionary."
|
|
@@ -1930,7 +2146,7 @@ class CutRows(OpenROADStep):
|
|
|
1930
2146
|
Variable(
|
|
1931
2147
|
"FP_MACRO_HORIZONTAL_HALO",
|
|
1932
2148
|
Decimal,
|
|
1933
|
-
"Specify the horizontal halo size around macros
|
|
2149
|
+
"Specify the horizontal halo size around macros.",
|
|
1934
2150
|
default=10,
|
|
1935
2151
|
units="µm",
|
|
1936
2152
|
deprecated_names=["FP_TAP_HORIZONTAL_HALO"],
|
|
@@ -1938,18 +2154,24 @@ class CutRows(OpenROADStep):
|
|
|
1938
2154
|
Variable(
|
|
1939
2155
|
"FP_MACRO_VERTICAL_HALO",
|
|
1940
2156
|
Decimal,
|
|
1941
|
-
"Specify the vertical halo size around macros
|
|
2157
|
+
"Specify the vertical halo size around macros.",
|
|
1942
2158
|
default=10,
|
|
1943
2159
|
units="µm",
|
|
1944
2160
|
deprecated_names=["FP_TAP_VERTICAL_HALO"],
|
|
1945
2161
|
),
|
|
2162
|
+
Variable(
|
|
2163
|
+
"FP_PRUNE_THRESHOLD",
|
|
2164
|
+
Optional[Decimal],
|
|
2165
|
+
'If specified, all rows smaller in width than this value will be removed. This helps avoid "islets" of cells that are hard to route and connect to PDNs.',
|
|
2166
|
+
pdk=True,
|
|
2167
|
+
units="µm",
|
|
2168
|
+
),
|
|
1946
2169
|
]
|
|
1947
2170
|
|
|
1948
2171
|
def get_script_path(self):
|
|
1949
2172
|
return os.path.join(get_script_dir(), "openroad", "cut_rows.tcl")
|
|
1950
2173
|
|
|
1951
2174
|
|
|
1952
|
-
@Step.factory.register()
|
|
1953
2175
|
class WriteViews(OpenROADStep):
|
|
1954
2176
|
"""
|
|
1955
2177
|
Write various layout views of an ODB design
|
|
@@ -1958,8 +2180,8 @@ class WriteViews(OpenROADStep):
|
|
|
1958
2180
|
id = "OpenROAD.WriteViews"
|
|
1959
2181
|
name = "OpenROAD Write Views"
|
|
1960
2182
|
outputs = OpenROADStep.outputs + [
|
|
1961
|
-
DesignFormat.
|
|
1962
|
-
DesignFormat.
|
|
2183
|
+
DesignFormat.SDF_FRIENDLY_POWERED_NETLIST,
|
|
2184
|
+
DesignFormat.LOGICAL_POWERED_NETLIST,
|
|
1963
2185
|
DesignFormat.OPENROAD_LEF,
|
|
1964
2186
|
]
|
|
1965
2187
|
|
|
@@ -1989,33 +2211,16 @@ class ResizerStep(OpenROADStep):
|
|
|
1989
2211
|
**kwargs,
|
|
1990
2212
|
) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
1991
2213
|
kwargs, env = self.extract_env(kwargs)
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
corners = self.config[corners_key] or self.config["STA_CORNERS"]
|
|
1999
|
-
lib_set_set = set()
|
|
2000
|
-
count = 0
|
|
2001
|
-
for corner in corners:
|
|
2002
|
-
_, libs, _, _ = self.toolbox.get_timing_files_categorized(
|
|
2003
|
-
self.config, corner
|
|
2004
|
-
)
|
|
2005
|
-
lib_set = frozenset(libs)
|
|
2006
|
-
if lib_set in lib_set_set:
|
|
2007
|
-
debug(f"Liberty files for '{corner}' already accounted for- skipped")
|
|
2008
|
-
continue
|
|
2009
|
-
lib_set_set.add(lib_set)
|
|
2010
|
-
env[f"RSZ_CORNER_{count}"] = TclStep.value_to_tcl([corner] + libs)
|
|
2011
|
-
debug(f"Liberty files for '{corner}' added: {libs}")
|
|
2012
|
-
count += 1
|
|
2013
|
-
|
|
2014
|
-
return super().run(state_in, env=env, **kwargs)
|
|
2214
|
+
return super().run(
|
|
2215
|
+
state_in,
|
|
2216
|
+
corners=self.config["RSZ_CORNERS"] or self.config["STA_CORNERS"],
|
|
2217
|
+
env=env,
|
|
2218
|
+
**kwargs,
|
|
2219
|
+
)
|
|
2015
2220
|
|
|
2016
2221
|
|
|
2017
2222
|
@Step.factory.register()
|
|
2018
|
-
class CTS(
|
|
2223
|
+
class CTS(OpenROADStep):
|
|
2019
2224
|
"""
|
|
2020
2225
|
Creates a `Clock tree <https://en.wikipedia.org/wiki/Clock_signal#Distribution>`_
|
|
2021
2226
|
for an ODB file with detailed-placed cells, using reasonably accurate resistance
|
|
@@ -2030,6 +2235,32 @@ class CTS(ResizerStep):
|
|
|
2030
2235
|
OpenROADStep.config_vars
|
|
2031
2236
|
+ dpl_variables
|
|
2032
2237
|
+ [
|
|
2238
|
+
# sink_buffer_max_cap_derate
|
|
2239
|
+
Variable(
|
|
2240
|
+
"CTS_BALANCE_LEVELS",
|
|
2241
|
+
Optional[bool],
|
|
2242
|
+
"Attempts to keep a similar number of levels in the clock tree across non-register cells (e.g., clock-gate or inverter).",
|
|
2243
|
+
),
|
|
2244
|
+
Variable(
|
|
2245
|
+
"CTS_SINK_BUFFER_MAX_CAP_DERATE_PCT",
|
|
2246
|
+
Optional[Decimal],
|
|
2247
|
+
"Controls automatic buffer selection. To favor strong(weak) drive strength buffers use a small(large) value."
|
|
2248
|
+
+ "The value of 100 means no derating of max cap limit",
|
|
2249
|
+
units="%",
|
|
2250
|
+
),
|
|
2251
|
+
Variable(
|
|
2252
|
+
"CTS_DELAY_BUFFER_DERATE_PCT",
|
|
2253
|
+
Optional[Decimal],
|
|
2254
|
+
"This option balances latencies between macro cells and registers by inserting delay buffers"
|
|
2255
|
+
+ "The value of 100 means all needed delay buffers are inserted",
|
|
2256
|
+
units="%",
|
|
2257
|
+
),
|
|
2258
|
+
Variable(
|
|
2259
|
+
"CTS_OBSTRUCTION_AWARE",
|
|
2260
|
+
Optional[bool],
|
|
2261
|
+
"Enables obstruction-aware buffering such that clock buffers are not placed on top of blockages or hard macros. "
|
|
2262
|
+
+ "This option may reduce legalizer displacement, leading to better latency, skew or timing QoR.",
|
|
2263
|
+
),
|
|
2033
2264
|
Variable(
|
|
2034
2265
|
"CTS_SINK_CLUSTERING_SIZE",
|
|
2035
2266
|
int,
|
|
@@ -2066,7 +2297,7 @@ class CTS(ResizerStep):
|
|
|
2066
2297
|
Variable(
|
|
2067
2298
|
"CTS_CORNERS",
|
|
2068
2299
|
Optional[List[str]],
|
|
2069
|
-
"
|
|
2300
|
+
"Clock tree synthesis step-specific override for PNR_CORNERS.",
|
|
2070
2301
|
),
|
|
2071
2302
|
Variable(
|
|
2072
2303
|
"CTS_ROOT_BUFFER",
|
|
@@ -2077,7 +2308,7 @@ class CTS(ResizerStep):
|
|
|
2077
2308
|
Variable(
|
|
2078
2309
|
"CTS_CLK_BUFFERS",
|
|
2079
2310
|
List[str],
|
|
2080
|
-
"Defines the list of clock
|
|
2311
|
+
"Defines the list of clock buffer names or buffer name wildcards to be used in CTS.",
|
|
2081
2312
|
deprecated_names=["CTS_CLK_BUFFER_LIST"],
|
|
2082
2313
|
pdk=True,
|
|
2083
2314
|
),
|
|
@@ -2114,7 +2345,10 @@ class CTS(ResizerStep):
|
|
|
2114
2345
|
return {}, {}
|
|
2115
2346
|
|
|
2116
2347
|
views_updates, metrics_updates = super().run(
|
|
2117
|
-
state_in,
|
|
2348
|
+
state_in,
|
|
2349
|
+
corners=self.config["CTS_CORNERS"] or self.config["STA_CORNERS"],
|
|
2350
|
+
env=env,
|
|
2351
|
+
**kwargs,
|
|
2118
2352
|
)
|
|
2119
2353
|
|
|
2120
2354
|
return views_updates, metrics_updates
|
|
@@ -2301,10 +2535,47 @@ class ResizerTimingPostCTS(ResizerStep):
|
|
|
2301
2535
|
default=False,
|
|
2302
2536
|
),
|
|
2303
2537
|
Variable(
|
|
2304
|
-
"
|
|
2538
|
+
"PL_RESIZER_SETUP_GATE_CLONING",
|
|
2305
2539
|
bool,
|
|
2306
2540
|
"Enables gate cloning when attempting to fix setup violations",
|
|
2307
2541
|
default=True,
|
|
2542
|
+
deprecated_names=["PL_RESIZER_GATE_CLONING"],
|
|
2543
|
+
),
|
|
2544
|
+
Variable(
|
|
2545
|
+
"PL_RESIZER_SETUP_BUFFERING",
|
|
2546
|
+
bool,
|
|
2547
|
+
"Rebuffering and load splitting during setup fixing.",
|
|
2548
|
+
default=True,
|
|
2549
|
+
),
|
|
2550
|
+
Variable(
|
|
2551
|
+
"PL_RESIZER_SETUP_BUFFER_REMOVAL",
|
|
2552
|
+
bool,
|
|
2553
|
+
"Buffer removal transform during setup fixing.",
|
|
2554
|
+
default=True,
|
|
2555
|
+
),
|
|
2556
|
+
Variable(
|
|
2557
|
+
"PL_RESIZER_SETUP_REPAIR_TNS_PCT",
|
|
2558
|
+
Optional[Decimal],
|
|
2559
|
+
"Percentage of violating endpoints to repair during setup fixing.",
|
|
2560
|
+
units="%",
|
|
2561
|
+
),
|
|
2562
|
+
Variable(
|
|
2563
|
+
"PL_RESIZER_SETUP_MAX_UTIL_PCT",
|
|
2564
|
+
Optional[Decimal],
|
|
2565
|
+
"Defines the percentage of core area used during setup fixing.",
|
|
2566
|
+
units="%",
|
|
2567
|
+
),
|
|
2568
|
+
Variable(
|
|
2569
|
+
"PL_RESIZER_HOLD_REPAIR_TNS_PCT",
|
|
2570
|
+
Optional[Decimal],
|
|
2571
|
+
"Percentage of violating endpoints to repair during hold fixing.",
|
|
2572
|
+
units="%",
|
|
2573
|
+
),
|
|
2574
|
+
Variable(
|
|
2575
|
+
"PL_RESIZER_HOLD_MAX_UTIL_PCT",
|
|
2576
|
+
Optional[Decimal],
|
|
2577
|
+
"Defines the percentage of core area used during hold fixing.",
|
|
2578
|
+
units="%",
|
|
2308
2579
|
),
|
|
2309
2580
|
Variable(
|
|
2310
2581
|
"PL_RESIZER_FIX_HOLD_FIRST",
|
|
@@ -2374,10 +2645,11 @@ class ResizerTimingPostGRT(ResizerStep):
|
|
|
2374
2645
|
deprecated_names=["GLB_RESIZER_ALLOW_SETUP_VIOS"],
|
|
2375
2646
|
),
|
|
2376
2647
|
Variable(
|
|
2377
|
-
"
|
|
2648
|
+
"GRT_RESIZER_SETUP_GATE_CLONING",
|
|
2378
2649
|
bool,
|
|
2379
2650
|
"Enables gate cloning when attempting to fix setup violations",
|
|
2380
2651
|
default=True,
|
|
2652
|
+
deprecated_names=["GRT_RESIZER_GATE_CLONING"],
|
|
2381
2653
|
),
|
|
2382
2654
|
Variable(
|
|
2383
2655
|
"GRT_RESIZER_RUN_GRT",
|
|
@@ -2385,6 +2657,42 @@ class ResizerTimingPostGRT(ResizerStep):
|
|
|
2385
2657
|
"Gates running global routing after resizer steps. May be useful to disable for designs where global routing takes non-trivial time.",
|
|
2386
2658
|
default=True,
|
|
2387
2659
|
),
|
|
2660
|
+
Variable(
|
|
2661
|
+
"GRT_RESIZER_SETUP_BUFFERING",
|
|
2662
|
+
bool,
|
|
2663
|
+
"Rebuffering and load splitting during setup fixing.",
|
|
2664
|
+
default=True,
|
|
2665
|
+
),
|
|
2666
|
+
Variable(
|
|
2667
|
+
"GRT_RESIZER_SETUP_BUFFER_REMOVAL",
|
|
2668
|
+
bool,
|
|
2669
|
+
"Buffer removal transform during setup fixing.",
|
|
2670
|
+
default=True,
|
|
2671
|
+
),
|
|
2672
|
+
Variable(
|
|
2673
|
+
"GRT_RESIZER_SETUP_REPAIR_TNS_PCT",
|
|
2674
|
+
Optional[Decimal],
|
|
2675
|
+
"Percentage of violating endpoints to repair during setup fixing.",
|
|
2676
|
+
units="%",
|
|
2677
|
+
),
|
|
2678
|
+
Variable(
|
|
2679
|
+
"GRT_RESIZER_SETUP_MAX_UTIL_PCT",
|
|
2680
|
+
Optional[Decimal],
|
|
2681
|
+
"Defines the percentage of core area used during setup fixing.",
|
|
2682
|
+
units="%",
|
|
2683
|
+
),
|
|
2684
|
+
Variable(
|
|
2685
|
+
"GRT_RESIZER_HOLD_REPAIR_TNS_PCT",
|
|
2686
|
+
Optional[Decimal],
|
|
2687
|
+
"Percentage of violating endpoints to repair during hold fixing.",
|
|
2688
|
+
units="%",
|
|
2689
|
+
),
|
|
2690
|
+
Variable(
|
|
2691
|
+
"GRT_RESIZER_HOLD_MAX_UTIL_PCT",
|
|
2692
|
+
Optional[Decimal],
|
|
2693
|
+
"Defines the percentage of core area used during hold fixing.",
|
|
2694
|
+
units="%",
|
|
2695
|
+
),
|
|
2388
2696
|
Variable(
|
|
2389
2697
|
"GRT_RESIZER_FIX_HOLD_FIRST",
|
|
2390
2698
|
bool,
|
|
@@ -2461,3 +2769,22 @@ class OpenGUI(OpenSTAStep):
|
|
|
2461
2769
|
)
|
|
2462
2770
|
|
|
2463
2771
|
return {}, {}
|
|
2772
|
+
|
|
2773
|
+
|
|
2774
|
+
@Step.factory.register()
|
|
2775
|
+
class DumpRCValues(OpenROADStep):
|
|
2776
|
+
"""
|
|
2777
|
+
Creates three reports:
|
|
2778
|
+
|
|
2779
|
+
* Initial Database Layer RC Values (from Tech LEF)
|
|
2780
|
+
* Modified Database Layer RC Values
|
|
2781
|
+
* Modified Resizer Layer RC Values
|
|
2782
|
+
"""
|
|
2783
|
+
|
|
2784
|
+
id = "OpenROAD.DumpRCValues"
|
|
2785
|
+
name = "Dump RC Values"
|
|
2786
|
+
|
|
2787
|
+
inputs = [DesignFormat.DEF]
|
|
2788
|
+
|
|
2789
|
+
def get_script_path(self) -> str:
|
|
2790
|
+
return os.path.join(get_script_dir(), "openroad", "dump_rc.tcl")
|