librelane 2.4.0.dev9__py3-none-any.whl → 3.0.0.dev23__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/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.dev9.dist-info → librelane-3.0.0.dev23.dist-info}/METADATA +1 -1
- {librelane-2.4.0.dev9.dist-info → librelane-3.0.0.dev23.dist-info}/RECORD +62 -60
- {librelane-2.4.0.dev9.dist-info → librelane-3.0.0.dev23.dist-info}/WHEEL +0 -0
- {librelane-2.4.0.dev9.dist-info → librelane-3.0.0.dev23.dist-info}/entry_points.txt +0 -0
librelane/state/state.py
CHANGED
|
@@ -22,7 +22,6 @@ from typing import Callable, List, Mapping, Tuple, Union, Optional, Dict, Any
|
|
|
22
22
|
|
|
23
23
|
from .design_format import (
|
|
24
24
|
DesignFormat,
|
|
25
|
-
DesignFormatObject,
|
|
26
25
|
)
|
|
27
26
|
|
|
28
27
|
from ..common import (
|
|
@@ -91,26 +90,21 @@ class State(GenericImmutableDict[str, StateElement]):
|
|
|
91
90
|
if c_mapping := copying:
|
|
92
91
|
for key, value in c_mapping.items():
|
|
93
92
|
if isinstance(key, DesignFormat):
|
|
94
|
-
copying_resolved[key.
|
|
93
|
+
copying_resolved[key.id] = value
|
|
95
94
|
else:
|
|
96
95
|
copying_resolved[key] = value
|
|
97
96
|
|
|
98
|
-
for format in DesignFormat:
|
|
99
|
-
assert isinstance(format.value, DesignFormatObject) # type checker shut up
|
|
100
|
-
if format.value.id not in copying_resolved:
|
|
101
|
-
copying_resolved[format.value.id] = None
|
|
102
|
-
|
|
103
97
|
overrides_resolved = {}
|
|
104
98
|
if o_mapping := overrides:
|
|
105
99
|
for k, value in o_mapping.items():
|
|
106
100
|
if isinstance(k, DesignFormat):
|
|
107
|
-
|
|
108
|
-
k.value, DesignFormatObject
|
|
109
|
-
) # type checker shut up
|
|
110
|
-
k = k.value.id
|
|
101
|
+
k = k.id
|
|
111
102
|
overrides_resolved[k] = value
|
|
112
103
|
|
|
113
104
|
self.metrics = GenericImmutableDict(metrics or {})
|
|
105
|
+
for key in list(copying_resolved.keys()):
|
|
106
|
+
if copying_resolved[key] is None:
|
|
107
|
+
del copying_resolved[key]
|
|
114
108
|
|
|
115
109
|
super().__init__(
|
|
116
110
|
copying_resolved,
|
|
@@ -119,21 +113,24 @@ class State(GenericImmutableDict[str, StateElement]):
|
|
|
119
113
|
**kwargs,
|
|
120
114
|
)
|
|
121
115
|
|
|
116
|
+
def get_by_df(self, key: DesignFormat) -> StateElement:
|
|
117
|
+
return self.get(key.id)
|
|
118
|
+
|
|
122
119
|
def __getitem__(self, key: Union[DesignFormat, str]) -> StateElement:
|
|
123
120
|
if isinstance(key, DesignFormat):
|
|
124
|
-
id: str = key.
|
|
121
|
+
id: str = key.id
|
|
125
122
|
key = id
|
|
126
123
|
return super().__getitem__(key)
|
|
127
124
|
|
|
128
125
|
def __setitem__(self, key: Union[DesignFormat, str], item: StateElement):
|
|
129
126
|
if isinstance(key, DesignFormat):
|
|
130
|
-
id: str = key.
|
|
127
|
+
id: str = key.id
|
|
131
128
|
key = id
|
|
132
129
|
return super().__setitem__(key, item)
|
|
133
130
|
|
|
134
131
|
def __delitem__(self, key: Union[DesignFormat, str]):
|
|
135
132
|
if isinstance(key, DesignFormat):
|
|
136
|
-
id: str = key.
|
|
133
|
+
id: str = key.id
|
|
137
134
|
key = id
|
|
138
135
|
return super().__delitem__(key)
|
|
139
136
|
|
|
@@ -164,10 +161,8 @@ class State(GenericImmutableDict[str, StateElement]):
|
|
|
164
161
|
if current_top_key is None:
|
|
165
162
|
current_top_key = key
|
|
166
163
|
current_folder = key.strip("_*")
|
|
167
|
-
if df := DesignFormat.
|
|
168
|
-
|
|
169
|
-
assert isinstance(df.value, DesignFormatObject)
|
|
170
|
-
current_folder = df.value.folder
|
|
164
|
+
if df := DesignFormat.factory.get(key):
|
|
165
|
+
current_folder = df.folder
|
|
171
166
|
|
|
172
167
|
target_dir = os.path.join(save_directory, current_folder)
|
|
173
168
|
|
|
@@ -228,7 +223,11 @@ class State(GenericImmutableDict[str, StateElement]):
|
|
|
228
223
|
"""
|
|
229
224
|
|
|
230
225
|
def visitor(key, value, top_key, _, depth):
|
|
231
|
-
if
|
|
226
|
+
if (
|
|
227
|
+
depth == 0
|
|
228
|
+
and DesignFormat.factory.get(top_key) is None
|
|
229
|
+
and value is not None
|
|
230
|
+
):
|
|
232
231
|
raise InvalidState(
|
|
233
232
|
f"Key '{top_key}' does not match a known design format."
|
|
234
233
|
)
|
|
@@ -314,8 +313,8 @@ class State(GenericImmutableDict[str, StateElement]):
|
|
|
314
313
|
continue
|
|
315
314
|
|
|
316
315
|
key_content = id
|
|
317
|
-
if format := DesignFormat.
|
|
318
|
-
key_content = format.
|
|
316
|
+
if format := DesignFormat.factory.get(id):
|
|
317
|
+
key_content = format.id
|
|
319
318
|
|
|
320
319
|
value_content = str(value)
|
|
321
320
|
if isinstance(value, Mapping):
|
librelane/steps/checker.py
CHANGED
|
@@ -266,7 +266,16 @@ class WireLength(MetricChecker):
|
|
|
266
266
|
default=True,
|
|
267
267
|
deprecated_names=["QUIT_ON_LONG_WIRE"],
|
|
268
268
|
)
|
|
269
|
-
config_vars = [
|
|
269
|
+
config_vars = [
|
|
270
|
+
error_on_var,
|
|
271
|
+
Variable(
|
|
272
|
+
"WIRE_LENGTH_THRESHOLD",
|
|
273
|
+
Optional[Decimal],
|
|
274
|
+
"A value above which wire lengths generate warnings.",
|
|
275
|
+
units="µm",
|
|
276
|
+
pdk=True,
|
|
277
|
+
),
|
|
278
|
+
]
|
|
270
279
|
|
|
271
280
|
def get_threshold(self) -> Optional[Decimal]:
|
|
272
281
|
threshold = self.config["WIRE_LENGTH_THRESHOLD"]
|
|
@@ -477,6 +486,7 @@ class TimingViolations(MetricChecker):
|
|
|
477
486
|
cls.base_corner_var_name.replace("TIMING", replace_by),
|
|
478
487
|
Optional[List[str]],
|
|
479
488
|
f"A list of wildcards matching IPVT corners to use during checking for {cls.violation_type} violations.",
|
|
489
|
+
pdk=True,
|
|
480
490
|
)
|
|
481
491
|
if cls.corner_override:
|
|
482
492
|
variable.default = cls.corner_override
|
|
@@ -635,3 +645,4 @@ class HoldViolations(TimingViolations):
|
|
|
635
645
|
violation_type = "hold"
|
|
636
646
|
|
|
637
647
|
metric_name = "timing__hold_vio__count"
|
|
648
|
+
corner_override = ["*"]
|
|
@@ -261,21 +261,21 @@ dpl_variables = [
|
|
|
261
261
|
),
|
|
262
262
|
Variable(
|
|
263
263
|
"PL_MAX_DISPLACEMENT_X",
|
|
264
|
-
|
|
264
|
+
int,
|
|
265
265
|
"Specifies how far an instance can be moved along the X-axis when finding a site where it can be placed during detailed placement.",
|
|
266
266
|
default=500,
|
|
267
267
|
units="µm",
|
|
268
268
|
),
|
|
269
269
|
Variable(
|
|
270
270
|
"PL_MAX_DISPLACEMENT_Y",
|
|
271
|
-
|
|
271
|
+
int,
|
|
272
272
|
"Specifies how far an instance can be moved along the Y-axis when finding a site where it can be placed during detailed placement.",
|
|
273
273
|
default=100,
|
|
274
274
|
units="µm",
|
|
275
275
|
),
|
|
276
276
|
Variable(
|
|
277
277
|
"DPL_CELL_PADDING",
|
|
278
|
-
|
|
278
|
+
int,
|
|
279
279
|
"Cell padding value (in sites) for detailed placement. The number will be integer divided by 2 and placed on both sides. Should be <= global placement.",
|
|
280
280
|
units="sites",
|
|
281
281
|
pdk=True,
|
|
@@ -335,6 +335,6 @@ rsz_variables = dpl_variables + [
|
|
|
335
335
|
Variable(
|
|
336
336
|
"RSZ_CORNERS",
|
|
337
337
|
Optional[List[str]],
|
|
338
|
-
"
|
|
338
|
+
"Resizer step-specific override for PNR_CORNERS.",
|
|
339
339
|
),
|
|
340
340
|
]
|
librelane/steps/cvc_rv.py
CHANGED
librelane/steps/klayout.py
CHANGED
|
@@ -29,6 +29,14 @@ from ..state import DesignFormat, State
|
|
|
29
29
|
from ..common import Path, get_script_dir, mkdirp, _get_process_limit
|
|
30
30
|
|
|
31
31
|
|
|
32
|
+
DesignFormat(
|
|
33
|
+
"klayout_gds",
|
|
34
|
+
"klayout.gds",
|
|
35
|
+
"GDSII Stream (KLayout)",
|
|
36
|
+
alts=["KLAYOUT_GDS"],
|
|
37
|
+
).register()
|
|
38
|
+
|
|
39
|
+
|
|
32
40
|
class KLayoutStep(Step):
|
|
33
41
|
config_vars = [
|
|
34
42
|
Variable(
|
|
@@ -116,14 +124,14 @@ class KLayoutStep(Step):
|
|
|
116
124
|
result += lef_args
|
|
117
125
|
|
|
118
126
|
if include_gds:
|
|
119
|
-
gds_args = []
|
|
127
|
+
gds_args: List[str] = []
|
|
120
128
|
for gds in self.config["CELL_GDS"]:
|
|
121
129
|
gds_args.append("--with-gds-file")
|
|
122
130
|
gds_args.append(gds)
|
|
123
131
|
for gds in self.toolbox.get_macro_views(self.config, DesignFormat.GDS):
|
|
124
132
|
gds_args.append("--with-gds-file")
|
|
125
|
-
gds_args.append(gds)
|
|
126
|
-
if extra_gds := self.config["
|
|
133
|
+
gds_args.append(str(gds))
|
|
134
|
+
if extra_gds := self.config["EXTRA_GDS"]:
|
|
127
135
|
for gds in extra_gds:
|
|
128
136
|
gds_args.append("--with-gds-file")
|
|
129
137
|
gds_args.append(gds)
|
|
@@ -149,7 +157,7 @@ class Render(KLayoutStep):
|
|
|
149
157
|
|
|
150
158
|
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
151
159
|
input_view = state_in[DesignFormat.DEF]
|
|
152
|
-
if gds := state_in
|
|
160
|
+
if gds := state_in.get(DesignFormat.GDS):
|
|
153
161
|
input_view = gds
|
|
154
162
|
|
|
155
163
|
assert isinstance(input_view, Path)
|
|
@@ -193,7 +201,7 @@ class StreamOut(KLayoutStep):
|
|
|
193
201
|
|
|
194
202
|
klayout_gds_out = os.path.join(
|
|
195
203
|
self.step_dir,
|
|
196
|
-
f"{self.config['DESIGN_NAME']}.{DesignFormat.KLAYOUT_GDS.
|
|
204
|
+
f"{self.config['DESIGN_NAME']}.{DesignFormat.KLAYOUT_GDS.extension}",
|
|
197
205
|
)
|
|
198
206
|
kwargs, env = self.extract_env(kwargs)
|
|
199
207
|
|
|
@@ -205,7 +213,7 @@ class StreamOut(KLayoutStep):
|
|
|
205
213
|
"klayout",
|
|
206
214
|
"stream_out.py",
|
|
207
215
|
),
|
|
208
|
-
state_in[DesignFormat.DEF.
|
|
216
|
+
state_in[DesignFormat.DEF.id],
|
|
209
217
|
"--output",
|
|
210
218
|
abspath(klayout_gds_out),
|
|
211
219
|
"--top",
|
librelane/steps/magic.py
CHANGED
|
@@ -37,6 +37,22 @@ from ..config import Variable
|
|
|
37
37
|
from ..common import get_script_dir, DRC as DRCObject, Path, mkdirp
|
|
38
38
|
|
|
39
39
|
|
|
40
|
+
DesignFormat(
|
|
41
|
+
"mag",
|
|
42
|
+
"mag",
|
|
43
|
+
"Magic VLSI View",
|
|
44
|
+
alts=["MAG"],
|
|
45
|
+
).register()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
DesignFormat(
|
|
49
|
+
"mag_gds",
|
|
50
|
+
"magic.gds",
|
|
51
|
+
"GDSII Stream (Magic)",
|
|
52
|
+
alts=["MAG_GDS"],
|
|
53
|
+
).register()
|
|
54
|
+
|
|
55
|
+
|
|
40
56
|
class MagicOutputProcessor(OutputProcessor):
|
|
41
57
|
_error_patterns = [
|
|
42
58
|
re.compile(rx)
|
|
@@ -192,10 +208,10 @@ class MagicStep(TclStep):
|
|
|
192
208
|
|
|
193
209
|
views_updates: ViewsUpdate = {}
|
|
194
210
|
for output in self.outputs:
|
|
195
|
-
if output.
|
|
211
|
+
if output.multiple:
|
|
196
212
|
# Too step-specific.
|
|
197
213
|
continue
|
|
198
|
-
path = Path(env[f"SAVE_{output.
|
|
214
|
+
path = Path(env[f"SAVE_{output.id.upper()}"])
|
|
199
215
|
if not path.exists():
|
|
200
216
|
continue
|
|
201
217
|
views_updates[output] = path
|
librelane/steps/misc.py
CHANGED
|
@@ -39,7 +39,7 @@ class LoadBaseSDC(Step):
|
|
|
39
39
|
outputs = [DesignFormat.SDC]
|
|
40
40
|
|
|
41
41
|
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
42
|
-
path = self.config["
|
|
42
|
+
path = self.config["FALLBACK_SDC"]
|
|
43
43
|
|
|
44
44
|
target = os.path.join(self.step_dir, f"{self.config['DESIGN_NAME']}.sdc")
|
|
45
45
|
|
librelane/steps/odb.py
CHANGED
|
@@ -76,9 +76,9 @@ class OdbpyStep(Step):
|
|
|
76
76
|
views_updates: ViewsUpdate = {}
|
|
77
77
|
command = self.get_command()
|
|
78
78
|
for output in automatic_outputs:
|
|
79
|
-
filename = f"{self.config['DESIGN_NAME']}.{output.
|
|
79
|
+
filename = f"{self.config['DESIGN_NAME']}.{output.extension}"
|
|
80
80
|
file_path = os.path.join(self.step_dir, filename)
|
|
81
|
-
command.append(f"--output-{output.
|
|
81
|
+
command.append(f"--output-{output.id}")
|
|
82
82
|
command.append(file_path)
|
|
83
83
|
views_updates[output] = Path(file_path)
|
|
84
84
|
|
|
@@ -148,7 +148,7 @@ class OdbpyStep(Step):
|
|
|
148
148
|
for lef in extra_lefs:
|
|
149
149
|
lefs.append("--input-lef")
|
|
150
150
|
lefs.append(lef)
|
|
151
|
-
if (design_lef := self.state_in.result()
|
|
151
|
+
if (design_lef := self.state_in.result().get(DesignFormat.LEF)) and (
|
|
152
152
|
DesignFormat.LEF in self.inputs
|
|
153
153
|
):
|
|
154
154
|
lefs.append("--design-lef")
|
|
@@ -207,7 +207,7 @@ class CheckMacroAntennaProperties(OdbpyStep):
|
|
|
207
207
|
|
|
208
208
|
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
209
209
|
if not self.get_cells():
|
|
210
|
-
info("No cells provided, skipping…")
|
|
210
|
+
info(f"No cells provided, skipping '{self.id}'…")
|
|
211
211
|
return {}, {}
|
|
212
212
|
return super().run(state_in, **kwargs)
|
|
213
213
|
|
|
@@ -271,7 +271,7 @@ class ApplyDEFTemplate(OdbpyStep):
|
|
|
271
271
|
|
|
272
272
|
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
273
273
|
if self.config["FP_DEF_TEMPLATE"] is None:
|
|
274
|
-
info("No DEF template provided, skipping…")
|
|
274
|
+
info(f"No DEF template provided, skipping '{self.id}'…")
|
|
275
275
|
return {}, {}
|
|
276
276
|
|
|
277
277
|
views_updates, metrics_updates = super().run(state_in, **kwargs)
|
|
@@ -527,9 +527,9 @@ class AddRoutingObstructions(OdbpyStep):
|
|
|
527
527
|
config_vars = [
|
|
528
528
|
Variable(
|
|
529
529
|
"ROUTING_OBSTRUCTIONS",
|
|
530
|
-
Optional[List[str]],
|
|
530
|
+
Optional[List[Tuple[str, Decimal, Decimal, Decimal, Decimal]]],
|
|
531
531
|
"Add routing obstructions to the design. If set to `None`, this step is skipped."
|
|
532
|
-
+ " Format of each obstruction item is: layer llx lly urx ury.",
|
|
532
|
+
+ " Format of each obstruction item is a tuple of: layer name, llx, lly, urx, ury.",
|
|
533
533
|
units="µm",
|
|
534
534
|
default=None,
|
|
535
535
|
deprecated_names=["GRT_OBS"],
|
|
@@ -550,7 +550,7 @@ class AddRoutingObstructions(OdbpyStep):
|
|
|
550
550
|
if obstructions := self.config[self.config_vars[0].name]:
|
|
551
551
|
for obstruction in obstructions:
|
|
552
552
|
command.append("--obstructions")
|
|
553
|
-
command.append(obstruction)
|
|
553
|
+
command.append(" ".join([str(o) for o in obstruction]))
|
|
554
554
|
return command
|
|
555
555
|
|
|
556
556
|
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
@@ -579,9 +579,9 @@ class AddPDNObstructions(AddRoutingObstructions):
|
|
|
579
579
|
config_vars = [
|
|
580
580
|
Variable(
|
|
581
581
|
"PDN_OBSTRUCTIONS",
|
|
582
|
-
Optional[List[str]],
|
|
582
|
+
Optional[List[Tuple[str, Decimal, Decimal, Decimal, Decimal]]],
|
|
583
583
|
"Add routing obstructions to the design before PDN stage. If set to `None`, this step is skipped."
|
|
584
|
-
+ " Format of each obstruction item is: layer llx lly urx ury
|
|
584
|
+
+ " Format of each obstruction item is a tuple of: layer name, llx, lly, urx, ury,.",
|
|
585
585
|
units="µm",
|
|
586
586
|
default=None,
|
|
587
587
|
),
|
|
@@ -686,7 +686,7 @@ class CustomIOPlacement(OdbpyStep):
|
|
|
686
686
|
|
|
687
687
|
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
688
688
|
if self.config["FP_PIN_ORDER_CFG"] is None:
|
|
689
|
-
info("No custom floorplan file configured, skipping…")
|
|
689
|
+
info(f"No custom floorplan file configured, skipping '{self.id}'…")
|
|
690
690
|
return {}, {}
|
|
691
691
|
return super().run(state_in, **kwargs)
|
|
692
692
|
|
|
@@ -715,7 +715,7 @@ class PortDiodePlacement(OdbpyStep):
|
|
|
715
715
|
),
|
|
716
716
|
Variable(
|
|
717
717
|
"GPL_CELL_PADDING",
|
|
718
|
-
|
|
718
|
+
int,
|
|
719
719
|
"Cell padding value (in sites) for global placement. Used by this step only to emit a warning if it's 0.",
|
|
720
720
|
units="sites",
|
|
721
721
|
pdk=True,
|
|
@@ -744,7 +744,11 @@ class PortDiodePlacement(OdbpyStep):
|
|
|
744
744
|
|
|
745
745
|
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
746
746
|
if self.config["DIODE_ON_PORTS"] == "none":
|
|
747
|
-
info("'DIODE_ON_PORTS' is set to 'none': skipping…")
|
|
747
|
+
info(f"'DIODE_ON_PORTS' is set to 'none': skipping '{self.id}'…")
|
|
748
|
+
return {}, {}
|
|
749
|
+
|
|
750
|
+
if self.config["DIODE_CELL"] is None:
|
|
751
|
+
info(f"'DIODE_CELL' not set. Skipping '{self.id}'…")
|
|
748
752
|
return {}, {}
|
|
749
753
|
|
|
750
754
|
if self.config["GPL_CELL_PADDING"] == 0:
|
|
@@ -784,7 +788,10 @@ class DiodesOnPorts(CompositeStep):
|
|
|
784
788
|
|
|
785
789
|
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
786
790
|
if self.config["DIODE_ON_PORTS"] == "none":
|
|
787
|
-
info("'DIODE_ON_PORTS' is set to 'none': skipping…")
|
|
791
|
+
info(f"'DIODE_ON_PORTS' is set to 'none': skipping '{self.id}'…")
|
|
792
|
+
return {}, {}
|
|
793
|
+
if self.config["DIODE_CELL"] is None:
|
|
794
|
+
info(f"'DIODE_CELL' not set. Skipping '{self.id}'…")
|
|
788
795
|
return {}, {}
|
|
789
796
|
return super().run(state_in, **kwargs)
|
|
790
797
|
|
|
@@ -811,14 +818,14 @@ class FuzzyDiodePlacement(OdbpyStep):
|
|
|
811
818
|
config_vars = [
|
|
812
819
|
Variable(
|
|
813
820
|
"HEURISTIC_ANTENNA_THRESHOLD",
|
|
814
|
-
Decimal,
|
|
821
|
+
Optional[Decimal],
|
|
815
822
|
"A Manhattan distance above which a diode is recommended to be inserted by the heuristic inserter. If not specified, the heuristic algorithm.",
|
|
816
823
|
units="µm",
|
|
817
824
|
pdk=True,
|
|
818
825
|
),
|
|
819
826
|
Variable(
|
|
820
827
|
"GPL_CELL_PADDING",
|
|
821
|
-
|
|
828
|
+
int,
|
|
822
829
|
"Cell padding value (in sites) for global placement. Used by this step only to emit a warning if it's 0.",
|
|
823
830
|
units="sites",
|
|
824
831
|
pdk=True,
|
|
@@ -834,20 +841,14 @@ class FuzzyDiodePlacement(OdbpyStep):
|
|
|
834
841
|
def get_command(self) -> List[str]:
|
|
835
842
|
cell, pin = self.config["DIODE_CELL"].split("/")
|
|
836
843
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
cell,
|
|
846
|
-
"--diode-pin",
|
|
847
|
-
pin,
|
|
848
|
-
]
|
|
849
|
-
+ threshold_opts
|
|
850
|
-
)
|
|
844
|
+
return super().get_command() + [
|
|
845
|
+
"--diode-cell",
|
|
846
|
+
cell,
|
|
847
|
+
"--diode-pin",
|
|
848
|
+
pin,
|
|
849
|
+
"--threshold",
|
|
850
|
+
str(self.config["HEURISTIC_ANTENNA_THRESHOLD"]),
|
|
851
|
+
]
|
|
851
852
|
|
|
852
853
|
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
853
854
|
if self.config["GPL_CELL_PADDING"] == 0:
|
|
@@ -855,6 +856,14 @@ class FuzzyDiodePlacement(OdbpyStep):
|
|
|
855
856
|
"'GPL_CELL_PADDING' is set to 0. This step may cause overlap failures."
|
|
856
857
|
)
|
|
857
858
|
|
|
859
|
+
if self.config["DIODE_CELL"] is None:
|
|
860
|
+
info(f"'DIODE_CELL' not set. Skipping '{self.id}'…")
|
|
861
|
+
return {}, {}
|
|
862
|
+
|
|
863
|
+
if self.config["HEURISTIC_ANTENNA_THRESHOLD"] is None:
|
|
864
|
+
info(f"'HEURISTIC_ANTENNA_THRESHOLD' not set. Skipping '{self.id}'…")
|
|
865
|
+
return {}, {}
|
|
866
|
+
|
|
858
867
|
return super().run(state_in, **kwargs)
|
|
859
868
|
|
|
860
869
|
|
|
@@ -889,6 +898,16 @@ class HeuristicDiodeInsertion(CompositeStep):
|
|
|
889
898
|
GlobalRouting,
|
|
890
899
|
]
|
|
891
900
|
|
|
901
|
+
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
902
|
+
if self.config["DIODE_CELL"] is None:
|
|
903
|
+
info(f"'DIODE_CELL' not set. Skipping '{self.id}'…")
|
|
904
|
+
return {}, {}
|
|
905
|
+
if self.config["HEURISTIC_ANTENNA_THRESHOLD"] is None:
|
|
906
|
+
info(f"'HEURISTIC_ANTENNA_THRESHOLD' not set. Skipping '{self.id}'…")
|
|
907
|
+
return {}, {}
|
|
908
|
+
|
|
909
|
+
return super().run(state_in, **kwargs)
|
|
910
|
+
|
|
892
911
|
|
|
893
912
|
@Step.factory.register()
|
|
894
913
|
class CellFrequencyTables(OdbpyStep):
|
|
@@ -975,7 +994,7 @@ class ManualGlobalPlacement(OdbpyStep):
|
|
|
975
994
|
|
|
976
995
|
def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
|
|
977
996
|
if self.config["MANUAL_GLOBAL_PLACEMENTS"] is None:
|
|
978
|
-
info("'MANUAL_GLOBAL_PLACEMENTS' not set, skipping…")
|
|
997
|
+
info(f"'MANUAL_GLOBAL_PLACEMENTS' not set, skipping '{self.id}'…")
|
|
979
998
|
return {}, {}
|
|
980
999
|
return super().run(state_in, **kwargs)
|
|
981
1000
|
|