librelane 2.4.0__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 (170) hide show
  1. librelane/__init__.py +38 -0
  2. librelane/__main__.py +479 -0
  3. librelane/__version__.py +43 -0
  4. librelane/common/__init__.py +63 -0
  5. librelane/common/cli.py +75 -0
  6. librelane/common/drc.py +246 -0
  7. librelane/common/generic_dict.py +319 -0
  8. librelane/common/metrics/__init__.py +35 -0
  9. librelane/common/metrics/__main__.py +413 -0
  10. librelane/common/metrics/library.py +354 -0
  11. librelane/common/metrics/metric.py +186 -0
  12. librelane/common/metrics/util.py +279 -0
  13. librelane/common/misc.py +456 -0
  14. librelane/common/ring_buffer.py +63 -0
  15. librelane/common/tcl.py +80 -0
  16. librelane/common/toolbox.py +549 -0
  17. librelane/common/tpe.py +41 -0
  18. librelane/common/types.py +116 -0
  19. librelane/config/__init__.py +32 -0
  20. librelane/config/__main__.py +155 -0
  21. librelane/config/config.py +1025 -0
  22. librelane/config/flow.py +490 -0
  23. librelane/config/pdk_compat.py +255 -0
  24. librelane/config/preprocessor.py +464 -0
  25. librelane/config/removals.py +45 -0
  26. librelane/config/variable.py +743 -0
  27. librelane/container.py +285 -0
  28. librelane/env_info.py +320 -0
  29. librelane/examples/spm/config.yaml +33 -0
  30. librelane/examples/spm/pin_order.cfg +14 -0
  31. librelane/examples/spm/src/impl.sdc +73 -0
  32. librelane/examples/spm/src/signoff.sdc +68 -0
  33. librelane/examples/spm/src/spm.v +73 -0
  34. librelane/examples/spm/verify/spm_tb.v +106 -0
  35. librelane/examples/spm-user_project_wrapper/SPM_example.v +286 -0
  36. librelane/examples/spm-user_project_wrapper/base_sdc_file.sdc +145 -0
  37. librelane/examples/spm-user_project_wrapper/config-tut.json +12 -0
  38. librelane/examples/spm-user_project_wrapper/config.json +13 -0
  39. librelane/examples/spm-user_project_wrapper/defines.v +66 -0
  40. librelane/examples/spm-user_project_wrapper/template.def +7656 -0
  41. librelane/examples/spm-user_project_wrapper/user_project_wrapper.v +123 -0
  42. librelane/flows/__init__.py +24 -0
  43. librelane/flows/builtins.py +18 -0
  44. librelane/flows/classic.py +327 -0
  45. librelane/flows/cli.py +463 -0
  46. librelane/flows/flow.py +1049 -0
  47. librelane/flows/misc.py +71 -0
  48. librelane/flows/optimizing.py +179 -0
  49. librelane/flows/sequential.py +367 -0
  50. librelane/flows/synth_explore.py +173 -0
  51. librelane/help/__main__.py +39 -0
  52. librelane/logging/__init__.py +40 -0
  53. librelane/logging/logger.py +323 -0
  54. librelane/open_pdks_rev +1 -0
  55. librelane/plugins.py +21 -0
  56. librelane/py.typed +0 -0
  57. librelane/scripts/base.sdc +80 -0
  58. librelane/scripts/klayout/Readme.md +2 -0
  59. librelane/scripts/klayout/open_design.py +63 -0
  60. librelane/scripts/klayout/render.py +121 -0
  61. librelane/scripts/klayout/stream_out.py +176 -0
  62. librelane/scripts/klayout/xml_drc_report_to_json.py +45 -0
  63. librelane/scripts/klayout/xor.drc +120 -0
  64. librelane/scripts/magic/Readme.md +1 -0
  65. librelane/scripts/magic/common/read.tcl +114 -0
  66. librelane/scripts/magic/def/antenna_check.tcl +35 -0
  67. librelane/scripts/magic/def/mag.tcl +19 -0
  68. librelane/scripts/magic/def/mag_gds.tcl +79 -0
  69. librelane/scripts/magic/drc.tcl +78 -0
  70. librelane/scripts/magic/extract_spice.tcl +98 -0
  71. librelane/scripts/magic/gds/drc_batch.tcl +74 -0
  72. librelane/scripts/magic/gds/erase_box.tcl +32 -0
  73. librelane/scripts/magic/gds/extras_mag.tcl +45 -0
  74. librelane/scripts/magic/gds/mag_with_pointers.tcl +31 -0
  75. librelane/scripts/magic/get_bbox.tcl +11 -0
  76. librelane/scripts/magic/lef/extras_maglef.tcl +61 -0
  77. librelane/scripts/magic/lef/maglef.tcl +26 -0
  78. librelane/scripts/magic/lef.tcl +57 -0
  79. librelane/scripts/magic/open.tcl +28 -0
  80. librelane/scripts/magic/wrapper.tcl +21 -0
  81. librelane/scripts/netgen/setup.tcl +28 -0
  82. librelane/scripts/odbpy/apply_def_template.py +49 -0
  83. librelane/scripts/odbpy/cell_frequency.py +107 -0
  84. librelane/scripts/odbpy/check_antenna_properties.py +116 -0
  85. librelane/scripts/odbpy/contextualize.py +109 -0
  86. librelane/scripts/odbpy/defutil.py +573 -0
  87. librelane/scripts/odbpy/diodes.py +373 -0
  88. librelane/scripts/odbpy/disconnected_pins.py +305 -0
  89. librelane/scripts/odbpy/eco_buffer.py +181 -0
  90. librelane/scripts/odbpy/eco_diode.py +139 -0
  91. librelane/scripts/odbpy/filter_unannotated.py +100 -0
  92. librelane/scripts/odbpy/io_place.py +482 -0
  93. librelane/scripts/odbpy/ioplace_parser/__init__.py +23 -0
  94. librelane/scripts/odbpy/ioplace_parser/parse.py +147 -0
  95. librelane/scripts/odbpy/label_macro_pins.py +277 -0
  96. librelane/scripts/odbpy/lefutil.py +97 -0
  97. librelane/scripts/odbpy/placers.py +162 -0
  98. librelane/scripts/odbpy/power_utils.py +397 -0
  99. librelane/scripts/odbpy/random_place.py +57 -0
  100. librelane/scripts/odbpy/reader.py +250 -0
  101. librelane/scripts/odbpy/remove_buffers.py +173 -0
  102. librelane/scripts/odbpy/snap_to_grid.py +57 -0
  103. librelane/scripts/odbpy/wire_lengths.py +93 -0
  104. librelane/scripts/openroad/antenna_check.tcl +20 -0
  105. librelane/scripts/openroad/antenna_repair.tcl +31 -0
  106. librelane/scripts/openroad/basic_mp.tcl +24 -0
  107. librelane/scripts/openroad/buffer_list.tcl +10 -0
  108. librelane/scripts/openroad/common/dpl.tcl +24 -0
  109. librelane/scripts/openroad/common/dpl_cell_pad.tcl +26 -0
  110. librelane/scripts/openroad/common/grt.tcl +32 -0
  111. librelane/scripts/openroad/common/io.tcl +540 -0
  112. librelane/scripts/openroad/common/pdn_cfg.tcl +135 -0
  113. librelane/scripts/openroad/common/resizer.tcl +103 -0
  114. librelane/scripts/openroad/common/set_global_connections.tcl +78 -0
  115. librelane/scripts/openroad/common/set_layer_adjustments.tcl +31 -0
  116. librelane/scripts/openroad/common/set_power_nets.tcl +30 -0
  117. librelane/scripts/openroad/common/set_rc.tcl +75 -0
  118. librelane/scripts/openroad/common/set_routing_layers.tcl +30 -0
  119. librelane/scripts/openroad/cts.tcl +80 -0
  120. librelane/scripts/openroad/cut_rows.tcl +24 -0
  121. librelane/scripts/openroad/dpl.tcl +24 -0
  122. librelane/scripts/openroad/drt.tcl +37 -0
  123. librelane/scripts/openroad/fill.tcl +30 -0
  124. librelane/scripts/openroad/floorplan.tcl +145 -0
  125. librelane/scripts/openroad/gpl.tcl +88 -0
  126. librelane/scripts/openroad/grt.tcl +30 -0
  127. librelane/scripts/openroad/gui.tcl +37 -0
  128. librelane/scripts/openroad/insert_buffer.tcl +127 -0
  129. librelane/scripts/openroad/ioplacer.tcl +67 -0
  130. librelane/scripts/openroad/irdrop.tcl +51 -0
  131. librelane/scripts/openroad/pdn.tcl +52 -0
  132. librelane/scripts/openroad/rcx.tcl +32 -0
  133. librelane/scripts/openroad/repair_design.tcl +70 -0
  134. librelane/scripts/openroad/repair_design_postgrt.tcl +48 -0
  135. librelane/scripts/openroad/rsz_timing_postcts.tcl +68 -0
  136. librelane/scripts/openroad/rsz_timing_postgrt.tcl +70 -0
  137. librelane/scripts/openroad/sta/check_macro_instances.tcl +53 -0
  138. librelane/scripts/openroad/sta/corner.tcl +393 -0
  139. librelane/scripts/openroad/tapcell.tcl +25 -0
  140. librelane/scripts/openroad/write_views.tcl +27 -0
  141. librelane/scripts/pyosys/construct_abc_script.py +177 -0
  142. librelane/scripts/pyosys/json_header.py +84 -0
  143. librelane/scripts/pyosys/synthesize.py +493 -0
  144. librelane/scripts/pyosys/ys_common.py +153 -0
  145. librelane/scripts/tclsh/hello.tcl +1 -0
  146. librelane/state/__init__.py +24 -0
  147. librelane/state/__main__.py +61 -0
  148. librelane/state/design_format.py +195 -0
  149. librelane/state/state.py +359 -0
  150. librelane/steps/__init__.py +61 -0
  151. librelane/steps/__main__.py +510 -0
  152. librelane/steps/checker.py +637 -0
  153. librelane/steps/common_variables.py +340 -0
  154. librelane/steps/cvc_rv.py +169 -0
  155. librelane/steps/klayout.py +509 -0
  156. librelane/steps/magic.py +576 -0
  157. librelane/steps/misc.py +160 -0
  158. librelane/steps/netgen.py +253 -0
  159. librelane/steps/odb.py +1088 -0
  160. librelane/steps/openroad.py +2460 -0
  161. librelane/steps/openroad_alerts.py +102 -0
  162. librelane/steps/pyosys.py +640 -0
  163. librelane/steps/step.py +1571 -0
  164. librelane/steps/tclstep.py +288 -0
  165. librelane/steps/verilator.py +222 -0
  166. librelane/steps/yosys.py +371 -0
  167. librelane-2.4.0.dist-info/METADATA +169 -0
  168. librelane-2.4.0.dist-info/RECORD +170 -0
  169. librelane-2.4.0.dist-info/WHEEL +4 -0
  170. librelane-2.4.0.dist-info/entry_points.txt +9 -0
@@ -0,0 +1,359 @@
1
+ # Copyright 2023 Efabless Corporation
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ from __future__ import annotations
15
+
16
+ import io
17
+ import os
18
+ import csv
19
+ import sys
20
+ import json
21
+ import shutil
22
+ from decimal import Decimal
23
+ from typing import Callable, List, Mapping, Tuple, Union, Optional, Dict, Any
24
+
25
+ from .design_format import (
26
+ DesignFormat,
27
+ DesignFormatObject,
28
+ )
29
+
30
+ from ..common import (
31
+ Path,
32
+ GenericImmutableDict,
33
+ mkdirp,
34
+ copy_recursive,
35
+ )
36
+ from ..logging import info
37
+
38
+
39
+ class InvalidState(RuntimeError):
40
+ pass
41
+
42
+
43
+ StateElement = Union[Path, List[Path], Dict[str, Union[Path, List[Path]]], None]
44
+
45
+
46
+ class State(GenericImmutableDict[str, StateElement]):
47
+ """
48
+ Basically, a dictionary from :class:`DesignFormat`\\s and values
49
+ of (nested dictionaries of) :class:`librelane.common.Path`\\.
50
+
51
+ The state is the only thing that can be altered by steps other than the
52
+ filesystem.
53
+
54
+ States are **immutable**. To construct a new state with some modifications,
55
+ you may do so as follows::
56
+
57
+ state_b = State(
58
+ copying=state_a,
59
+ overrides={
60
+
61
+ },
62
+ metrics=GenericImmutableDict(copying=state_a.metrics, overrides={
63
+
64
+ })
65
+ )
66
+
67
+ Though in the majority of cases, you do not have to construct States on your
68
+ own: after executing a Step, you only return your deltas and then the Flow
69
+ is responsible for the creation of a new Step object.
70
+
71
+ :param copying: A mutable or immutable mapping to use as the starting
72
+ value for this State.
73
+ :param overrides: A mutable or immutable mapping to override the starting
74
+ values with.
75
+ :param metrics: A dictionary that carries statistics about the design: area,
76
+ wire length, et cetera, but also miscellaneous data, for example, whether
77
+ it passed a certain check or not.
78
+ """
79
+
80
+ def __init__(
81
+ self,
82
+ copying: Optional[
83
+ Union[Mapping[str, StateElement], Mapping[DesignFormat, StateElement]]
84
+ ] = None,
85
+ *args,
86
+ overrides: Optional[
87
+ Union[Mapping[str, StateElement], Mapping[DesignFormat, StateElement]]
88
+ ] = None,
89
+ metrics: Optional[Mapping[str, Any]] = None,
90
+ **kwargs,
91
+ ) -> None:
92
+ copying_resolved: Dict[str, StateElement] = {}
93
+ if c_mapping := copying:
94
+ for key, value in c_mapping.items():
95
+ if isinstance(key, DesignFormat):
96
+ copying_resolved[key.value.id] = value
97
+ else:
98
+ copying_resolved[key] = value
99
+
100
+ for format in DesignFormat:
101
+ assert isinstance(format.value, DesignFormatObject) # type checker shut up
102
+ if format.value.id not in copying_resolved:
103
+ copying_resolved[format.value.id] = None
104
+
105
+ overrides_resolved = {}
106
+ if o_mapping := overrides:
107
+ for k, value in o_mapping.items():
108
+ if isinstance(k, DesignFormat):
109
+ assert isinstance(
110
+ k.value, DesignFormatObject
111
+ ) # type checker shut up
112
+ k = k.value.id
113
+ overrides_resolved[k] = value
114
+
115
+ self.metrics = GenericImmutableDict(metrics or {})
116
+
117
+ super().__init__(
118
+ copying_resolved,
119
+ *args,
120
+ overrides=overrides_resolved,
121
+ **kwargs,
122
+ )
123
+
124
+ def __getitem__(self, key: Union[DesignFormat, str]) -> StateElement:
125
+ if isinstance(key, DesignFormat):
126
+ id: str = key.value.id
127
+ key = id
128
+ return super().__getitem__(key)
129
+
130
+ def __setitem__(self, key: Union[DesignFormat, str], item: StateElement):
131
+ if isinstance(key, DesignFormat):
132
+ id: str = key.value.id
133
+ key = id
134
+ return super().__setitem__(key, item)
135
+
136
+ def __delitem__(self, key: Union[DesignFormat, str]):
137
+ if isinstance(key, DesignFormat):
138
+ id: str = key.value.id
139
+ key = id
140
+ return super().__delitem__(key)
141
+
142
+ def to_raw_dict(self, metrics: bool = True) -> Dict[str, Any]:
143
+ final = super().to_raw_dict()
144
+ if metrics:
145
+ final["metrics"] = self.metrics.to_raw_dict()
146
+ return final
147
+
148
+ def copy(self: "State") -> "State":
149
+ metrics: GenericImmutableDict[str, Any] = GenericImmutableDict(
150
+ copy_recursive(self.metrics)
151
+ )
152
+ new = State(self, metrics=metrics)
153
+ return new
154
+
155
+ def _walk(
156
+ self,
157
+ views: Union[Dict, "State"],
158
+ save_directory: Union[str, os.PathLike],
159
+ visit: Callable[[str, StateElement, str, str, int], StateElement],
160
+ key_path: str = "",
161
+ depth: int = 0,
162
+ top_key: Optional[str] = None,
163
+ ):
164
+ for key, value in views.items():
165
+ current_top_key = top_key
166
+ if current_top_key is None:
167
+ current_top_key = key
168
+ current_folder = key.strip("_*")
169
+ if df := DesignFormat.by_id(key):
170
+ # For type-checker: all guaranteed to be DesignFormatObjects
171
+ assert isinstance(df.value, DesignFormatObject)
172
+ current_folder = df.value.folder
173
+
174
+ target_dir = os.path.join(save_directory, current_folder)
175
+
176
+ current_key_path = f"{key_path}.{key}"
177
+ visit(current_key_path, value, current_top_key, target_dir, depth)
178
+ if isinstance(value, dict):
179
+ self._walk(
180
+ value,
181
+ target_dir,
182
+ visit,
183
+ current_key_path,
184
+ depth + 1,
185
+ current_top_key,
186
+ )
187
+ if isinstance(value, list):
188
+ for i, element in enumerate(value):
189
+ element_key_path = f"{current_key_path}[{i}]"
190
+ visit(
191
+ element_key_path,
192
+ element,
193
+ current_top_key,
194
+ target_dir,
195
+ depth + 1,
196
+ )
197
+
198
+ def save_snapshot(self, path: Union[str, os.PathLike]):
199
+ """
200
+ Validates the current state then saves all views to a folder by
201
+ design format, including the metrics.
202
+
203
+ :param path: The folder that would contain other folders.
204
+ """
205
+
206
+ def visitor(key, value, top_key, save_directory, depth):
207
+ if not isinstance(value, Path):
208
+ return
209
+ mkdirp(save_directory)
210
+ target_path = os.path.join(save_directory, os.path.basename(value))
211
+ shutil.copyfile(value, target_path, follow_symlinks=True)
212
+
213
+ self.validate()
214
+ info(f"Saving views to '{os.path.abspath(path)}'…")
215
+ mkdirp(path)
216
+ self._walk(self, path, visitor)
217
+ metrics_csv_path = os.path.join(path, "metrics.csv")
218
+ with open(metrics_csv_path, "w", encoding="utf8") as f:
219
+ self.metrics_to_csv(f)
220
+
221
+ metrics_json_path = os.path.join(path, "metrics.json")
222
+ with open(metrics_json_path, "w", encoding="utf8") as f:
223
+ f.write(self.metrics.dumps())
224
+
225
+ def metrics_to_csv(
226
+ self, fp: io.TextIOWrapper, metrics_object: Optional[Dict[str, Any]] = None
227
+ ):
228
+ w = csv.writer(fp)
229
+ w.writerow(("Metric", "Value"))
230
+ for entry in (metrics_object or self.metrics).items():
231
+ w.writerow(entry)
232
+
233
+ def validate(self):
234
+ """
235
+ Ensures that all paths exist in a State.
236
+ """
237
+
238
+ def visitor(key, value, top_key, _, depth):
239
+ if depth == 0 and DesignFormat.by_id(top_key) is None:
240
+ raise InvalidState(
241
+ f"Key '{top_key}' does not match a known design format."
242
+ )
243
+ if value is None:
244
+ return
245
+ if not (
246
+ isinstance(value, Path)
247
+ or isinstance(value, dict)
248
+ or isinstance(value, list)
249
+ ):
250
+ raise InvalidState(
251
+ f"Value at '{key}' is not a Path nor a dictionary/list of Paths: '{value}'."
252
+ )
253
+
254
+ self._walk(self.to_raw_dict(metrics=False), "", visit=visitor)
255
+
256
+ @classmethod
257
+ def __loads_recursive(
258
+ Self,
259
+ views: Dict,
260
+ validate_path: bool = True,
261
+ key_path: str = "",
262
+ ) -> dict:
263
+ target: dict = {}
264
+ for key, value in views.items():
265
+ current_key_path = f"{key_path}.{key}"
266
+ if value is None:
267
+ target[key] = value
268
+ continue
269
+
270
+ if isinstance(value, dict):
271
+ target[key] = Self.__loads_recursive(
272
+ value,
273
+ validate_path,
274
+ key_path=current_key_path,
275
+ )
276
+ else:
277
+ if validate_path and not os.path.exists(value):
278
+ raise ValueError(
279
+ f"Provided path '{value}' to design format '{current_key_path}' does not exist."
280
+ )
281
+ target[key] = Path(value)
282
+ return target
283
+
284
+ @classmethod
285
+ def loads(Self, json_in: str, validate_path: bool = True) -> "State":
286
+ try:
287
+ raw = json.loads(json_in, parse_float=Decimal)
288
+ except json.JSONDecodeError as e:
289
+ raise InvalidState(f"Invalid JSON string provided for state: {e}")
290
+
291
+ if not isinstance(raw, dict):
292
+ raise InvalidState("Failed to load state: JSON result is not a dictionary")
293
+
294
+ metrics = raw.get("metrics")
295
+ if metrics is not None:
296
+ del raw["metrics"]
297
+
298
+ views = Self.__loads_recursive(raw, validate_path)
299
+ state = Self(views, metrics=metrics)
300
+
301
+ return state
302
+
303
+ def __mapping_to_html_rec(
304
+ self,
305
+ mapping: Mapping[str, Any],
306
+ header_optional: Optional[Tuple[str, str]] = None,
307
+ ):
308
+ result = """
309
+ <table style="grid-column-start: 1; grid-column-end: 2; ">
310
+ """
311
+ if header := header_optional:
312
+ key_h, value_h = header
313
+ result += f"""
314
+ <tr>
315
+ <th style="text-align: left;">{key_h}</th>
316
+ <th style="text-align: left;">{value_h}</th>
317
+ </tr>
318
+ """
319
+
320
+ for id, value in mapping.items():
321
+ if value is None:
322
+ continue
323
+
324
+ key_content = id
325
+ if format := DesignFormat.by_id(id):
326
+ key_content = format.value.id
327
+
328
+ value_content = str(value)
329
+ if isinstance(value, Mapping):
330
+ value_content = self.__mapping_to_html_rec(value)
331
+ elif isinstance(value, Path):
332
+ value_rel = os.path.relpath(value, ".")
333
+
334
+ value_content = f'<a href="{value_rel}">{value_rel}</a>'
335
+ if "google.colab" in sys.modules:
336
+ # Can't link in colab
337
+ value_content = value_rel
338
+
339
+ result += f"""
340
+ <tr>
341
+ <td style="text-align: left;">{key_content}</td>
342
+ <td style="text-align: left;">{value_content}</td>
343
+ </tr>
344
+ """
345
+
346
+ result += """
347
+ </table>
348
+ """
349
+ return result
350
+
351
+ def _repr_html_(self) -> str:
352
+ return (
353
+ '<div style="display: grid; grid-auto-columns: minmax(0, 1fr); grid-auto-rows: minmax(0, 1fr); grid-auto-flow: column;">'
354
+ + self.__mapping_to_html_rec(
355
+ self.to_raw_dict(metrics=False),
356
+ ("Format", "Path"),
357
+ )
358
+ + "</div>"
359
+ )
@@ -0,0 +1,61 @@
1
+ # Copyright 2023 Efabless Corporation
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ The Step Module
17
+ ---------------
18
+
19
+ This modules includes various functions for importing and/or generating LibreLane
20
+ configuration objects. Configuration objects are the primary input to a flow.
21
+ """
22
+ from .step import (
23
+ StepError,
24
+ DeferredStepError,
25
+ StepException,
26
+ StepNotFound,
27
+ Step,
28
+ OutputProcessor,
29
+ DefaultOutputProcessor,
30
+ MetricsUpdate,
31
+ ViewsUpdate,
32
+ )
33
+ from .tclstep import TclStep
34
+ from . import checker as Checker
35
+
36
+ # You'll notice some TclStep subclasses are exposed separately-
37
+ # this is for documentation.
38
+ from . import yosys as Yosys
39
+ from .yosys import YosysStep
40
+
41
+ from .openroad_alerts import (
42
+ OpenROADAlert,
43
+ OpenROADOutputProcessor,
44
+ SupportsOpenROADAlerts,
45
+ )
46
+
47
+ from . import openroad as OpenROAD
48
+ from .openroad import OpenROADStep
49
+
50
+ from . import odb as Odb
51
+ from .odb import OdbpyStep, ECOBuffer, ECODiode
52
+
53
+ from . import magic as Magic
54
+ from .magic import MagicStep
55
+
56
+ from . import netgen as Netgen
57
+ from .netgen import NetgenStep
58
+
59
+ from . import klayout as KLayout
60
+ from . import misc as Misc
61
+ from . import verilator as Verilator