librelane 3.0.0.dev24__py3-none-any.whl → 3.0.0.dev26__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.

Files changed (34) hide show
  1. librelane/common/__init__.py +1 -0
  2. librelane/common/drc.py +1 -0
  3. librelane/common/misc.py +27 -5
  4. librelane/common/types.py +2 -3
  5. librelane/config/__main__.py +1 -1
  6. librelane/config/variable.py +16 -0
  7. librelane/examples/spm/config.yaml +8 -8
  8. librelane/examples/spm-user_project_wrapper/config.json +17 -5
  9. librelane/flows/flow.py +89 -21
  10. librelane/scripts/magic/def/mag_gds.tcl +1 -2
  11. librelane/scripts/magic/drc.tcl +0 -1
  12. librelane/scripts/magic/gds/extras_mag.tcl +0 -2
  13. librelane/scripts/magic/gds/mag_with_pointers.tcl +0 -1
  14. librelane/scripts/magic/lef/extras_maglef.tcl +0 -2
  15. librelane/scripts/magic/lef/maglef.tcl +0 -1
  16. librelane/scripts/magic/wrapper.tcl +2 -0
  17. librelane/scripts/odbpy/power_utils.py +8 -6
  18. librelane/scripts/odbpy/reader.py +2 -2
  19. librelane/scripts/openroad/common/io.tcl +23 -11
  20. librelane/scripts/openroad/common/pdn_cfg.tcl +36 -36
  21. librelane/scripts/openroad/ioplacer.tcl +22 -21
  22. librelane/scripts/openroad/pdn.tcl +1 -1
  23. librelane/state/state.py +11 -3
  24. librelane/steps/__main__.py +1 -2
  25. librelane/steps/common_variables.py +82 -33
  26. librelane/steps/magic.py +24 -14
  27. librelane/steps/odb.py +15 -39
  28. librelane/steps/openroad.py +22 -44
  29. librelane/steps/step.py +22 -7
  30. librelane/steps/tclstep.py +1 -1
  31. {librelane-3.0.0.dev24.dist-info → librelane-3.0.0.dev26.dist-info}/METADATA +1 -1
  32. {librelane-3.0.0.dev24.dist-info → librelane-3.0.0.dev26.dist-info}/RECORD +34 -34
  33. {librelane-3.0.0.dev24.dist-info → librelane-3.0.0.dev26.dist-info}/WHEEL +0 -0
  34. {librelane-3.0.0.dev24.dist-info → librelane-3.0.0.dev26.dist-info}/entry_points.txt +0 -0
@@ -15,50 +15,51 @@ source $::env(SCRIPTS_DIR)/openroad/common/io.tcl
15
15
  read_current_odb
16
16
 
17
17
  if { [info exists ::env(CONTEXTUAL_IO_FLAG)] } {
18
- read_lef $::env(placement_tmpfiles)/top_level.lef
18
+ read_lef $::env(placement_tmpfiles)/top_level.lef
19
19
  }
20
20
 
21
- if { [info exists ::env(FP_IO_HLENGTH)] } {
22
- set_pin_length -hor_length $::env(FP_IO_HLENGTH)
21
+ if { [info exists ::env(IO_PIN_H_LENGTH)] } {
22
+ set_pin_length -hor_length $::env(IO_PIN_H_LENGTH)
23
23
  }
24
24
 
25
- if { [info exists ::env(FP_IO_VLENGTH)] } {
26
- set_pin_length -ver_length $::env(FP_IO_VLENGTH)
25
+ if { [info exists ::env(IO_PIN_V_LENGTH)] } {
26
+ set_pin_length -ver_length $::env(IO_PIN_V_LENGTH)
27
27
  }
28
28
 
29
- if { $::env(FP_IO_HEXTEND) != "0"} {
30
- set_pin_length_extension -hor_extension $::env(FP_IO_HEXTEND)
29
+ if { $::env(IO_PIN_H_EXTENSION) != "0"} {
30
+ set_pin_length_extension -hor_extension $::env(IO_PIN_H_EXTENSION)
31
31
  }
32
32
 
33
- if { $::env(FP_IO_VEXTEND) != "0"} {
34
- set_pin_length_extension -ver_extension $::env(FP_IO_VEXTEND)
33
+ if { $::env(IO_PIN_V_EXTENSION) != "0"} {
34
+ set_pin_length_extension -ver_extension $::env(IO_PIN_V_EXTENSION)
35
35
  }
36
36
 
37
- if {$::env(FP_IO_VTHICKNESS_MULT) != "" && $::env(FP_IO_HTHICKNESS_MULT) != ""} {
38
- set_pin_thick_multiplier -hor_multiplier $::env(FP_IO_HTHICKNESS_MULT) \
39
- -ver_multiplier $::env(FP_IO_VTHICKNESS_MULT)
37
+ if {$::env(IO_PIN_V_THICKNESS_MULT) != "" && $::env(IO_PIN_H_THICKNESS_MULT) != ""} {
38
+ set_pin_thick_multiplier\
39
+ -hor_multiplier $::env(IO_PIN_H_THICKNESS_MULT) \
40
+ -ver_multiplier $::env(IO_PIN_V_THICKNESS_MULT)
40
41
  }
41
42
 
42
43
  set arg_list [list]
43
- if { $::env(FP_PPL_MODE) == "random_equidistant" } {
44
- lappend arg_list -random
44
+ if { $::env(IO_PIN_PLACEMENT_MODE) == "random_equidistant" } {
45
+ lappend arg_list -random
45
46
  }
46
47
 
47
- if { [info exists ::env(FP_IO_MIN_DISTANCE)] } {
48
- lappend arg_list -min_distance $::env(FP_IO_MIN_DISTANCE)
48
+ if { [info exists ::env(IO_PIN_MIN_DISTANCE)] } {
49
+ lappend arg_list -min_distance $::env(IO_PIN_MIN_DISTANCE)
49
50
  }
50
51
 
51
- if { $::env(FP_PPL_MODE) == "annealing" } {
52
- lappend arg_list -annealing
52
+ if { $::env(IO_PIN_PLACEMENT_MODE) == "annealing" } {
53
+ lappend arg_list -annealing
53
54
  }
54
55
 
55
56
  set HMETAL $::env(FP_IO_HLAYER)
56
57
  set VMETAL $::env(FP_IO_VLAYER)
57
58
 
58
59
  log_cmd place_pins {*}$arg_list \
59
- -random_seed 42 \
60
- -hor_layers $HMETAL \
61
- -ver_layers $VMETAL
60
+ -random_seed 42 \
61
+ -hor_layers $HMETAL \
62
+ -ver_layers $VMETAL
62
63
 
63
64
  write_views
64
65
 
@@ -21,7 +21,7 @@ source $::env(SCRIPTS_DIR)/openroad/common/set_power_nets.tcl
21
21
  read_pdn_cfg
22
22
 
23
23
  set arg_list [list]
24
- if { $::env(FP_PDN_SKIPTRIM) } {
24
+ if { $::env(PDN_SKIPTRIM) } {
25
25
  lappend arg_list -skip_trim
26
26
  }
27
27
  # run PDNGEN
librelane/state/state.py CHANGED
@@ -13,7 +13,9 @@
13
13
  # limitations under the License.
14
14
  from __future__ import annotations
15
15
 
16
+ import io
16
17
  import os
18
+ import csv
17
19
  import sys
18
20
  import json
19
21
  import shutil
@@ -209,14 +211,20 @@ class State(GenericImmutableDict[str, StateElement]):
209
211
  self._walk(self, path, visitor)
210
212
  metrics_csv_path = os.path.join(path, "metrics.csv")
211
213
  with open(metrics_csv_path, "w", encoding="utf8") as f:
212
- f.write("Metric,Value\n")
213
- for metric in self.metrics:
214
- f.write(f"{metric},{self.metrics[metric]}\n")
214
+ self.metrics_to_csv(f)
215
215
 
216
216
  metrics_json_path = os.path.join(path, "metrics.json")
217
217
  with open(metrics_json_path, "w", encoding="utf8") as f:
218
218
  f.write(self.metrics.dumps())
219
219
 
220
+ def metrics_to_csv(
221
+ self, fp: io.TextIOWrapper, metrics_object: Optional[Dict[str, Any]] = None
222
+ ):
223
+ w = csv.writer(fp)
224
+ w.writerow(("Metric", "Value"))
225
+ for entry in (metrics_object or self.metrics).items():
226
+ w.writerow(entry)
227
+
220
228
  def validate(self):
221
229
  """
222
230
  Ensures that all paths exist in a State.
@@ -15,7 +15,6 @@ import os
15
15
  import shlex
16
16
  import shutil
17
17
  import datetime
18
- import functools
19
18
  import subprocess
20
19
  from functools import partial
21
20
  from typing import IO, Any, Dict, Optional, Sequence, Union
@@ -239,7 +238,7 @@ def eject(ctx, output, state_in, config, id):
239
238
  found_stdin_data = found_stdin.read()
240
239
  raise Stop()
241
240
 
242
- step.run_subprocess = functools.partial(
241
+ step.run_subprocess = partial(
243
242
  step.run_subprocess,
244
243
  _popen_callable=popen_substitute,
245
244
  )
@@ -18,204 +18,253 @@ from ..config import Variable
18
18
 
19
19
  io_layer_variables = [
20
20
  Variable(
21
- "FP_IO_VEXTEND",
21
+ "IO_PIN_V_EXTENSION",
22
22
  Decimal,
23
23
  "Extends the vertical io pins outside of the die by the specified units.",
24
24
  default=0,
25
25
  units="µm",
26
+ deprecated_names=["FP_IO_VEXTEND"],
26
27
  ),
27
28
  Variable(
28
- "FP_IO_HEXTEND",
29
+ "IO_PIN_H_EXTENSION",
29
30
  Decimal,
30
31
  "Extends the horizontal io pins outside of the die by the specified units.",
31
32
  default=0,
32
33
  units="µm",
34
+ deprecated_names=["FP_IO_HEXTEND"],
33
35
  ),
34
36
  Variable(
35
- "FP_IO_VTHICKNESS_MULT",
37
+ "IO_PIN_V_THICKNESS_MULT",
36
38
  Decimal,
37
39
  "A multiplier for vertical pin thickness. Base thickness is the pins layer min width.",
38
40
  default=2,
41
+ deprecated_names=["FP_IO_VTHICKNESS_MULT"],
39
42
  ),
40
43
  Variable(
41
- "FP_IO_HTHICKNESS_MULT",
44
+ "IO_PIN_H_THICKNESS_MULT",
42
45
  Decimal,
43
46
  "A multiplier for horizontal pin thickness. Base thickness is the pins layer min width.",
44
47
  default=2,
48
+ deprecated_names=["FP_IO_HTHICKNESS_MULT"],
49
+ ),
50
+ Variable(
51
+ "IO_PIN_V_LENGTH",
52
+ Optional[Decimal],
53
+ """
54
+ The length of the pins with a north or south orientation. If unspecified by a PDK, OpenROAD will use whichever is higher of the following two values:
55
+ * The pin width
56
+ * The minimum value satisfying the minimum area constraint given the pin width
57
+ """,
58
+ units="µm",
59
+ pdk=True,
60
+ deprecated_names=["FP_IO_VLENGTH"],
61
+ ),
62
+ Variable(
63
+ "IO_PIN_H_LENGTH",
64
+ Optional[Decimal],
65
+ """
66
+ The length of the pins with an east or west orientation. If unspecified by a PDK, OpenROAD will use whichever is higher of the following two values:
67
+ * The pin width
68
+ * The minimum value satisfying the minimum area constraint given the pin width
69
+ """,
70
+ units="µm",
71
+ pdk=True,
72
+ deprecated_names=["FP_IO_HLENGTH"],
45
73
  ),
46
74
  ]
47
75
 
48
76
  pdn_variables = [
49
77
  Variable(
50
- "FP_PDN_SKIPTRIM",
78
+ "PDN_SKIPTRIM",
51
79
  bool,
52
80
  "Enables `-skip_trim` option during pdngen which skips the metal trim step, which attempts to remove metal stubs.",
53
81
  default=False,
82
+ deprecated_names=["FP_PDN_SKIPTRIM"],
54
83
  ),
55
84
  Variable(
56
- "FP_PDN_CORE_RING",
85
+ "PDN_CORE_RING",
57
86
  bool,
58
87
  "Enables adding a core ring around the design. More details on the control variables in the PDK config documentation.",
59
88
  default=False,
89
+ deprecated_names=["FP_PDN_CORE_RING"],
60
90
  ),
61
91
  Variable(
62
- "FP_PDN_ENABLE_RAILS",
92
+ "PDN_ENABLE_RAILS",
63
93
  bool,
64
94
  "Enables the creation of rails in the power grid.",
65
95
  default=True,
96
+ deprecated_names=["FP_PDN_ENABLE_RAILS"],
66
97
  ),
67
98
  Variable(
68
- "FP_PDN_HORIZONTAL_HALO",
99
+ "PDN_HORIZONTAL_HALO",
69
100
  Decimal,
70
101
  "Sets the horizontal halo around the macros during power grid insertion.",
71
102
  default=10,
72
103
  units="µm",
104
+ deprecated_names=["FP_PDN_HORIZONTAL_HALO"],
73
105
  ),
74
106
  Variable(
75
- "FP_PDN_VERTICAL_HALO",
107
+ "PDN_VERTICAL_HALO",
76
108
  Decimal,
77
109
  "Sets the vertical halo around the macros during power grid insertion.",
78
110
  default=10,
79
111
  units="µm",
112
+ deprecated_names=["FP_PDN_VERTICAL_HALO"],
80
113
  ),
81
114
  Variable(
82
- "FP_PDN_MULTILAYER",
115
+ "PDN_MULTILAYER",
83
116
  bool,
84
117
  "Controls the layers used in the power grid. If set to false, only the lower layer will be used, which is useful when hardening a macro for integrating into a larger top-level design.",
85
118
  default=True,
86
- deprecated_names=["DESIGN_IS_CORE"],
119
+ deprecated_names=["FP_PDN_MULTILAYER", "DESIGN_IS_CORE"],
87
120
  ),
88
121
  Variable(
89
- "FP_PDN_RAIL_OFFSET",
122
+ "PDN_RAIL_OFFSET",
90
123
  Decimal,
91
124
  "The offset for the power distribution network rails for first metal layer.",
92
125
  units="µm",
93
126
  pdk=True,
127
+ deprecated_names=["FP_PDN_RAIL_OFFSET"],
94
128
  ),
95
129
  Variable(
96
- "FP_PDN_VWIDTH",
130
+ "PDN_VWIDTH",
97
131
  Decimal,
98
132
  "The strap width for the vertical layer in generated power distribution networks.",
99
133
  units="µm",
100
134
  pdk=True,
135
+ deprecated_names=["FP_PDN_VWIDTH"],
101
136
  ),
102
137
  Variable(
103
- "FP_PDN_HWIDTH",
138
+ "PDN_HWIDTH",
104
139
  Decimal,
105
140
  "The strap width for the horizontal layer in generated power distribution networks.",
106
141
  units="µm",
107
142
  pdk=True,
143
+ deprecated_names=["FP_PDN_HWIDTH"],
108
144
  ),
109
145
  Variable(
110
- "FP_PDN_VSPACING",
146
+ "PDN_VSPACING",
111
147
  Decimal,
112
148
  "Intra-spacing (within a set) of vertical straps in generated power distribution networks.",
113
149
  units="µm",
114
150
  pdk=True,
151
+ deprecated_names=["FP_PDN_VSPACING"],
115
152
  ),
116
153
  Variable(
117
- "FP_PDN_HSPACING",
154
+ "PDN_HSPACING",
118
155
  Decimal,
119
156
  "Intra-spacing (within a set) of horizontal straps in generated power distribution networks.",
120
157
  units="µm",
121
158
  pdk=True,
159
+ deprecated_names=["FP_PDN_HSPACING"],
122
160
  ),
123
161
  Variable(
124
- "FP_PDN_VPITCH",
162
+ "PDN_VPITCH",
125
163
  Decimal,
126
164
  "Inter-distance (between sets) of vertical power straps in generated power distribution networks.",
127
165
  units="µm",
128
166
  pdk=True,
167
+ deprecated_names=["FP_PDN_VPITCH"],
129
168
  ),
130
169
  Variable(
131
- "FP_PDN_HPITCH",
170
+ "PDN_HPITCH",
132
171
  Decimal,
133
172
  "Inter-distance (between sets) of horizontal power straps in generated power distribution networks.",
134
173
  units="µm",
135
174
  pdk=True,
175
+ deprecated_names=["FP_PDN_HPITCH"],
136
176
  ),
137
177
  Variable(
138
- "FP_PDN_VOFFSET",
178
+ "PDN_VOFFSET",
139
179
  Decimal,
140
180
  "Initial offset for sets of vertical power straps.",
141
181
  units="µm",
142
182
  pdk=True,
183
+ deprecated_names=["FP_PDN_VOFFSET"],
143
184
  ),
144
185
  Variable(
145
- "FP_PDN_HOFFSET",
186
+ "PDN_HOFFSET",
146
187
  Decimal,
147
188
  "Initial offset for sets of horizontal power straps.",
148
189
  units="µm",
149
190
  pdk=True,
191
+ deprecated_names=["FP_PDN_HOFFSET"],
150
192
  ),
151
193
  Variable(
152
- "FP_PDN_CORE_RING_VWIDTH",
194
+ "PDN_CORE_RING_VWIDTH",
153
195
  Decimal,
154
196
  "The width for the vertical layer in the core ring of generated power distribution networks.",
155
197
  units="µm",
156
198
  pdk=True,
199
+ deprecated_names=["FP_PDN_CORE_RING_VWIDTH"],
157
200
  ),
158
201
  Variable(
159
- "FP_PDN_CORE_RING_HWIDTH",
202
+ "PDN_CORE_RING_HWIDTH",
160
203
  Decimal,
161
204
  "The width for the horizontal layer in the core ring of generated power distribution networks.",
162
205
  units="µm",
163
206
  pdk=True,
207
+ deprecated_names=["FP_PDN_CORE_RING_HWIDTH"],
164
208
  ),
165
209
  Variable(
166
- "FP_PDN_CORE_RING_VSPACING",
210
+ "PDN_CORE_RING_VSPACING",
167
211
  Decimal,
168
212
  "The spacing for the vertical layer in the core ring of generated power distribution networks.",
169
213
  units="µm",
170
214
  pdk=True,
215
+ deprecated_names=["FP_PDN_CORE_RING_VSPACING"],
171
216
  ),
172
217
  Variable(
173
- "FP_PDN_CORE_RING_HSPACING",
218
+ "PDN_CORE_RING_HSPACING",
174
219
  Decimal,
175
220
  "The spacing for the horizontal layer in the core ring of generated power distribution networks.",
176
221
  units="µm",
177
222
  pdk=True,
223
+ deprecated_names=["FP_PDN_CORE_RING_HSPACING"],
178
224
  ),
179
225
  Variable(
180
- "FP_PDN_CORE_RING_VOFFSET",
226
+ "PDN_CORE_RING_VOFFSET",
181
227
  Decimal,
182
228
  "The offset for the vertical layer in the core ring of generated power distribution networks.",
183
229
  units="µm",
184
230
  pdk=True,
231
+ deprecated_names=["FP_PDN_CORE_RING_VOFFSET"],
185
232
  ),
186
233
  Variable(
187
- "FP_PDN_CORE_RING_HOFFSET",
234
+ "PDN_CORE_RING_HOFFSET",
188
235
  Decimal,
189
236
  "The offset for the horizontal layer in the core ring of generated power distribution networks.",
190
237
  units="µm",
191
238
  pdk=True,
239
+ deprecated_names=["FP_PDN_CORE_RING_HOFFSET"],
192
240
  ),
193
241
  Variable(
194
- "FP_PDN_RAIL_LAYER",
242
+ "PDN_RAIL_LAYER",
195
243
  str,
196
244
  "Defines the metal layer used for PDN rails.",
197
- deprecated_names=["FP_PDN_RAILS_LAYER"],
245
+ deprecated_names=["FP_PDN_RAIL_LAYER", "FP_PDN_RAILS_LAYER"],
198
246
  pdk=True,
199
247
  ),
200
248
  Variable(
201
- "FP_PDN_RAIL_WIDTH",
249
+ "PDN_RAIL_WIDTH",
202
250
  Decimal,
203
251
  "Defines the width of PDN rails on the `FP_PDN_RAILS_LAYER` layer.",
204
252
  units="µm",
205
253
  pdk=True,
254
+ deprecated_names=["FP_PDN_RAIL_WIDTH"],
206
255
  ),
207
256
  Variable(
208
- "FP_PDN_HORIZONTAL_LAYER",
257
+ "PDN_HORIZONTAL_LAYER",
209
258
  str,
210
259
  "Defines the horizontal PDN layer.",
211
- deprecated_names=["FP_PDN_UPPER_LAYER"],
260
+ deprecated_names=["FP_PDN_HORIZONTAL_LAYER", "FP_PDN_UPPER_LAYER"],
212
261
  pdk=True,
213
262
  ),
214
263
  Variable(
215
- "FP_PDN_VERTICAL_LAYER",
264
+ "PDN_VERTICAL_LAYER",
216
265
  str,
217
266
  "Defines the vertical PDN layer.",
218
- deprecated_names=["FP_PDN_LOWER_LAYER"],
267
+ deprecated_names=["FP_PDN_VERTICAL_LAYER", "FP_PDN_LOWER_LAYER"],
219
268
  pdk=True,
220
269
  ),
221
270
  ]
librelane/steps/magic.py CHANGED
@@ -14,7 +14,6 @@
14
14
  import os
15
15
  import re
16
16
  import shutil
17
- import functools
18
17
  import subprocess
19
18
  from signal import SIGKILL
20
19
  from decimal import Decimal
@@ -34,7 +33,8 @@ from .tclstep import TclStep
34
33
  from ..state import DesignFormat, State
35
34
 
36
35
  from ..config import Variable
37
- from ..common import get_script_dir, DRC as DRCObject, Path, mkdirp
36
+ from ..common import get_script_dir, DRC as DRCObject, Path, mkdirp, count_occurences
37
+ from ..logging import warn
38
38
 
39
39
 
40
40
  DesignFormat(
@@ -480,6 +480,12 @@ class SpiceExtraction(MagicStep):
480
480
  "Extracts a SPICE netlist based on black-boxed standard cells and macros (basically, anything with a LEF) rather than transistors. An error will be thrown if both this and `MAGIC_EXT_USE_GDS` is set to ``True``.",
481
481
  default=False,
482
482
  ),
483
+ Variable(
484
+ "MAGIC_FEEDBACK_CONVERSION_THRESHOLD",
485
+ int,
486
+ "If Magic provides more feedback items than this threshold, conversion to KLayout databases is skipped (as something has gone horribly wrong.)",
487
+ default=10000,
488
+ ),
483
489
  ]
484
490
 
485
491
  def get_script_path(self):
@@ -497,22 +503,29 @@ class SpiceExtraction(MagicStep):
497
503
 
498
504
  views_updates, metrics_updates = super().run(state_in, env=env, **kwargs)
499
505
 
500
- cif_scale = Decimal(open(os.path.join(self.step_dir, "cif_scale.txt")).read())
501
506
  feedback_path = os.path.join(self.step_dir, "feedback.txt")
507
+ with open(feedback_path, encoding="utf8") as f:
508
+ illegal_overlap_count = count_occurences(f, "Illegal overlap")
509
+
510
+ metrics_updates["magic__illegal_overlap__count"] = illegal_overlap_count
511
+ threshold = self.config["MAGIC_FEEDBACK_CONVERSION_THRESHOLD"]
512
+ if illegal_overlap_count > threshold:
513
+ warn(
514
+ f"Not converting the feedback to the KLayout database format: {illegal_overlap_count} > MAGIC_FEEDBACK_CONVERSION_THRESHOLD ({threshold}). You may manually increase the threshold, but it might take forever."
515
+ )
516
+ return views_updates, metrics_updates
517
+
518
+ cif_scale = Decimal(open(os.path.join(self.step_dir, "cif_scale.txt")).read())
502
519
  try:
503
520
  se_feedback, _ = DRCObject.from_magic_feedback(
504
521
  open(feedback_path, encoding="utf8"),
505
522
  cif_scale,
506
523
  self.config["DESIGN_NAME"],
507
524
  )
508
- illegal_overlap_count = functools.reduce(
509
- lambda a, b: a + len(b.bounding_boxes),
510
- [
511
- v
512
- for v in se_feedback.violations.values()
513
- if "Illegal overlap" in v.description
514
- ],
515
- 0,
525
+ illegal_overlap_count = sum(
526
+ len(v.bounding_boxes)
527
+ for v in se_feedback.violations.values()
528
+ if "Illegal overlap" in v.description
516
529
  )
517
530
  with open(os.path.join(self.step_dir, "feedback.xml"), "wb") as f:
518
531
  se_feedback.to_klayout_xml(f)
@@ -521,9 +534,6 @@ class SpiceExtraction(MagicStep):
521
534
  self.warn(
522
535
  f"Failed to convert SPICE extraction feedback to KLayout database format: {e}"
523
536
  )
524
- metrics_updates["magic__illegal_overlap__count"] = (
525
- open(feedback_path, encoding="utf8").read().count("Illegal overlap")
526
- )
527
537
  return views_updates, metrics_updates
528
538
 
529
539
 
librelane/steps/odb.py CHANGED
@@ -17,7 +17,6 @@ import json
17
17
  import shutil
18
18
  from math import inf
19
19
  from decimal import Decimal
20
- from functools import reduce
21
20
  from abc import abstractmethod
22
21
  from dataclasses import dataclass
23
22
  from typing import Dict, List, Literal, Optional, Tuple
@@ -418,9 +417,7 @@ class ManualMacroPlacement(OdbpyStep):
418
417
  )
419
418
  shutil.copyfile(cfg_ref, cfg_file)
420
419
  elif macros := self.config.get("MACROS"):
421
- instance_count = reduce(
422
- lambda x, y: x + len(y.instances), macros.values(), 0
423
- )
420
+ instance_count = sum(len(m.instances) for m in macros.values())
424
421
  if instance_count >= 1:
425
422
  with open(cfg_file, "w") as f:
426
423
  for module, macro in macros.items():
@@ -618,31 +615,10 @@ class CustomIOPlacement(OdbpyStep):
618
615
 
619
616
  config_vars = io_layer_variables + [
620
617
  Variable(
621
- "FP_IO_VLENGTH",
622
- Optional[Decimal],
623
- """
624
- The length of the pins with a north or south orientation. If unspecified by a PDK, the script will use whichever is higher of the following two values:
625
- * The pin width
626
- * The minimum value satisfying the minimum area constraint given the pin width
627
- """,
628
- units="µm",
629
- pdk=True,
630
- ),
631
- Variable(
632
- "FP_IO_HLENGTH",
633
- Optional[Decimal],
634
- """
635
- The length of the pins with an east or west orientation. If unspecified by a PDK, the script will use whichever is higher of the following two values:
636
- * The pin width
637
- * The minimum value satisfying the minimum area constraint given the pin width
638
- """,
639
- units="µm",
640
- pdk=True,
641
- ),
642
- Variable(
643
- "FP_PIN_ORDER_CFG",
618
+ "IO_PIN_ORDER_CFG",
644
619
  Optional[Path],
645
- "Path to the configuration file. If set to `None`, this step is skipped.",
620
+ "Path to a custom pin configuration file.",
621
+ deprecated_names=["FP_PIN_ORDER_CFG"],
646
622
  ),
647
623
  Variable(
648
624
  "ERRORS_ON_UNMATCHED_IO",
@@ -660,28 +636,28 @@ class CustomIOPlacement(OdbpyStep):
660
636
 
661
637
  def get_command(self) -> List[str]:
662
638
  length_args = []
663
- if self.config["FP_IO_VLENGTH"] is not None:
664
- length_args += ["--ver-length", self.config["FP_IO_VLENGTH"]]
665
- if self.config["FP_IO_HLENGTH"] is not None:
666
- length_args += ["--hor-length", self.config["FP_IO_HLENGTH"]]
639
+ if self.config["IO_PIN_V_LENGTH"] is not None:
640
+ length_args += ["--ver-length", self.config["IO_PIN_V_LENGTH"]]
641
+ if self.config["IO_PIN_H_LENGTH"] is not None:
642
+ length_args += ["--hor-length", self.config["IO_PIN_H_LENGTH"]]
667
643
 
668
644
  return (
669
645
  super().get_command()
670
646
  + [
671
647
  "--config",
672
- self.config["FP_PIN_ORDER_CFG"],
648
+ self.config["IO_PIN_ORDER_CFG"],
673
649
  "--hor-layer",
674
650
  self.config["FP_IO_HLAYER"],
675
651
  "--ver-layer",
676
652
  self.config["FP_IO_VLAYER"],
677
653
  "--hor-width-mult",
678
- str(self.config["FP_IO_VTHICKNESS_MULT"]),
654
+ str(self.config["IO_PIN_V_THICKNESS_MULT"]),
679
655
  "--ver-width-mult",
680
- str(self.config["FP_IO_HTHICKNESS_MULT"]),
656
+ str(self.config["IO_PIN_H_THICKNESS_MULT"]),
681
657
  "--hor-extension",
682
- str(self.config["FP_IO_HEXTEND"]),
658
+ str(self.config["IO_PIN_H_EXTENSION"]),
683
659
  "--ver-extension",
684
- str(self.config["FP_IO_VEXTEND"]),
660
+ str(self.config["IO_PIN_V_EXTENSION"]),
685
661
  "--unmatched-error",
686
662
  self.config["ERRORS_ON_UNMATCHED_IO"],
687
663
  ]
@@ -689,8 +665,8 @@ class CustomIOPlacement(OdbpyStep):
689
665
  )
690
666
 
691
667
  def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
692
- if self.config["FP_PIN_ORDER_CFG"] is None:
693
- info(f"No custom floorplan file configured, skipping '{self.id}'…")
668
+ if self.config["IO_PIN_ORDER_CFG"] is None:
669
+ info(f"No custom I/O placement file configured, skipping '{self.id}'…")
694
670
  return {}, {}
695
671
  return super().run(state_in, **kwargs)
696
672