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,640 @@
1
+ # Copyright 2024 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
+ import os
15
+ import re
16
+ import io
17
+ import sys
18
+ import json
19
+ import fnmatch
20
+ import shutil
21
+ import subprocess
22
+ from decimal import Decimal
23
+ from abc import abstractmethod
24
+ from typing import List, Literal, Optional, Set, Tuple
25
+
26
+ from .step import ViewsUpdate, MetricsUpdate, Step
27
+
28
+ from ..config import Variable
29
+ from ..state import State, DesignFormat
30
+ from ..logging import debug, verbose
31
+ from ..common import Path, get_script_dir, process_list_file
32
+
33
+ starts_with_whitespace = re.compile(r"^\s+.+$")
34
+
35
+ yosys_cell_rx = r"cell\s+\S+\s+\((\S+)\)"
36
+
37
+
38
+ def _check_any_tristate(
39
+ cells: List[str],
40
+ tristate_patterns: List[str],
41
+ ):
42
+ for cell in cells:
43
+ for tristate_pattern in tristate_patterns:
44
+ if fnmatch.fnmatch(cell, tristate_pattern):
45
+ return True
46
+
47
+ return False
48
+
49
+
50
+ def _parse_yosys_check(
51
+ report: io.TextIOBase,
52
+ tristate_patterns: Optional[List[str]] = None,
53
+ tristate_okay: bool = False,
54
+ elaborate_only: bool = False,
55
+ ) -> int:
56
+ verbose("Parsing synthesis checks…")
57
+ errors_encountered: int = 0
58
+ last_warning = None
59
+ current_warning = None
60
+
61
+ tristate_patterns = tristate_patterns or []
62
+
63
+ for line in report:
64
+ if line.startswith("Warning:") or line.startswith("Found and reported"):
65
+ last_warning = current_warning
66
+ current_warning = line
67
+ if last_warning is None:
68
+ continue
69
+
70
+ cells = re.findall(yosys_cell_rx, last_warning)
71
+
72
+ if elaborate_only and "but has no driver" in last_warning:
73
+ debug("Ignoring undriven cell in elaborate-only mode:")
74
+ debug(last_warning)
75
+ elif tristate_okay and (
76
+ ("tribuf" in last_warning)
77
+ or _check_any_tristate(cells, tristate_patterns)
78
+ ):
79
+ debug("Ignoring tristate-related error:")
80
+ debug(last_warning)
81
+ else:
82
+ debug("Encountered check error:")
83
+ debug(last_warning)
84
+ errors_encountered += 1
85
+ elif (
86
+ starts_with_whitespace.match(line) is not None
87
+ and current_warning is not None
88
+ ):
89
+ current_warning += line
90
+ else:
91
+ pass
92
+ return errors_encountered
93
+
94
+
95
+ verilog_rtl_cfg_vars = [
96
+ Variable(
97
+ "VERILOG_FILES",
98
+ List[Path],
99
+ "The paths of the design's Verilog files.",
100
+ ),
101
+ Variable(
102
+ "VERILOG_DEFINES",
103
+ Optional[List[str]],
104
+ "Preprocessor defines for input Verilog files.",
105
+ deprecated_names=["SYNTH_DEFINES"],
106
+ ),
107
+ Variable(
108
+ "VERILOG_POWER_DEFINE",
109
+ Optional[str],
110
+ "Specifies the name of the define used to guard power and ground connections in the input RTL.",
111
+ deprecated_names=["SYNTH_USE_PG_PINS_DEFINES", "SYNTH_POWER_DEFINE"],
112
+ default="USE_POWER_PINS",
113
+ ),
114
+ Variable(
115
+ "VERILOG_INCLUDE_DIRS",
116
+ Optional[List[Path]],
117
+ "Specifies the Verilog `include` directories.",
118
+ ),
119
+ Variable(
120
+ "SYNTH_PARAMETERS",
121
+ Optional[List[str]],
122
+ "Key-value pairs to be `chparam`ed in Yosys, in the format `key1=value1`.",
123
+ ),
124
+ Variable(
125
+ "USE_SYNLIG",
126
+ bool,
127
+ "Use the Synlig plugin to process files, which has better SystemVerilog parsing capabilities but may not be compatible with all Yosys commands and attributes.",
128
+ default=False,
129
+ ),
130
+ Variable(
131
+ "SYNLIG_DEFER",
132
+ bool,
133
+ "Uses -defer flag when reading files the Synlig plugin, which may improve performance by reading each file separately, but is experimental.",
134
+ default=False,
135
+ ),
136
+ ]
137
+
138
+
139
+ class PyosysStep(Step):
140
+ config_vars = [
141
+ Variable(
142
+ "SYNTH_LATCH_MAP",
143
+ Optional[Path],
144
+ "A path to a file containing the latch mapping for Yosys.",
145
+ pdk=True,
146
+ ),
147
+ Variable(
148
+ "SYNTH_TRISTATE_MAP",
149
+ Optional[Path],
150
+ "A path to a file containing the tri-state buffer mapping for Yosys.",
151
+ deprecated_names=["TRISTATE_BUFFER_MAP"],
152
+ pdk=True,
153
+ ),
154
+ Variable(
155
+ "SYNTH_CSA_MAP",
156
+ Optional[Path],
157
+ "A path to a file containing the carry-select adder mapping for Yosys.",
158
+ deprecated_names=["CARRY_SELECT_ADDER_MAP"],
159
+ pdk=True,
160
+ ),
161
+ Variable(
162
+ "SYNTH_RCA_MAP",
163
+ Optional[Path],
164
+ "A path to a file containing the ripple-carry adder mapping for Yosys.",
165
+ deprecated_names=["RIPPLE_CARRY_ADDER_MAP"],
166
+ pdk=True,
167
+ ),
168
+ Variable(
169
+ "SYNTH_FA_MAP",
170
+ Optional[Path],
171
+ "A path to a file containing the full adder mapping for Yosys.",
172
+ deprecated_names=["FULL_ADDER_MAP"],
173
+ pdk=True,
174
+ ),
175
+ Variable(
176
+ "SYNTH_MUX_MAP",
177
+ Optional[Path],
178
+ "A path to a file containing the mux mapping for Yosys.",
179
+ pdk=True,
180
+ ),
181
+ Variable(
182
+ "SYNTH_MUX4_MAP",
183
+ Optional[Path],
184
+ "A path to a file containing the mux4 mapping for Yosys.",
185
+ pdk=True,
186
+ ),
187
+ Variable(
188
+ "USE_LIGHTER",
189
+ bool,
190
+ "Activates Lighter, an experimental plugin that attempts to optimize clock-gated flip-flops.",
191
+ default=False,
192
+ ),
193
+ Variable(
194
+ "LIGHTER_DFF_MAP",
195
+ Optional[Path],
196
+ "An override to the custom DFF map file provided for the given SCL by Lighter.",
197
+ ),
198
+ Variable(
199
+ "YOSYS_LOG_LEVEL",
200
+ Literal["ALL", "WARNING", "ERROR"],
201
+ "Which log level for Yosys. At WARNING or higher, the initialization splash is also disabled.",
202
+ default="ALL",
203
+ ),
204
+ ]
205
+
206
+ @abstractmethod
207
+ def get_script_path(self) -> str:
208
+ pass
209
+
210
+ def get_command(self, state_in: State) -> List[str]:
211
+ script_path = self.get_script_path()
212
+ # HACK: Get Colab working
213
+ yosys_bin = "yosys"
214
+ if "google.colab" in sys.modules:
215
+ yosys_bin = shutil.which("yosys") or "yosys"
216
+ cmd = [yosys_bin, "-y", script_path]
217
+ if self.config["YOSYS_LOG_LEVEL"] != "ALL":
218
+ cmd += ["-Q"]
219
+ if self.config["YOSYS_LOG_LEVEL"] == "WARNING":
220
+ cmd += ["-q"]
221
+ elif self.config["YOSYS_LOG_LEVEL"] == "ERROR":
222
+ cmd += ["-qq"]
223
+ cmd += ["--"]
224
+ cmd += ["--config-in", os.path.join(self.step_dir, "config.json")]
225
+ return cmd
226
+
227
+ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
228
+ cmd = self.get_command(state_in)
229
+ # HACK: Get Colab working
230
+ if "google.colab" in sys.modules:
231
+ kwargs, env = self.extract_env(kwargs)
232
+ env.pop("PATH", "")
233
+ kwargs["env"] = env
234
+ subprocess_result = super().run_subprocess(cmd, **kwargs)
235
+ return {}, subprocess_result["generated_metrics"]
236
+
237
+
238
+ class VerilogStep(PyosysStep):
239
+ power_defines: bool = False
240
+
241
+ config_vars = PyosysStep.config_vars + verilog_rtl_cfg_vars
242
+
243
+ def get_command(self, state_in: State) -> List[str]:
244
+ cmd = super().get_command(state_in)
245
+
246
+ blackbox_models = []
247
+ scl_lib_list = self.toolbox.filter_views(self.config, self.config["LIB"])
248
+ if self.power_defines and self.config["CELL_VERILOG_MODELS"] is not None:
249
+ blackbox_models.extend(
250
+ [
251
+ self.toolbox.create_blackbox_model(
252
+ frozenset(self.config["CELL_VERILOG_MODELS"]),
253
+ frozenset(["USE_POWER_PINS"]),
254
+ )
255
+ ]
256
+ )
257
+ else:
258
+ blackbox_models.extend(str(f) for f in scl_lib_list)
259
+
260
+ # Priorities from higher to lower
261
+ format_list = (
262
+ [
263
+ DesignFormat.VERILOG_HEADER,
264
+ DesignFormat.POWERED_NETLIST,
265
+ DesignFormat.NETLIST,
266
+ DesignFormat.LIB,
267
+ ]
268
+ if self.power_defines
269
+ else [
270
+ DesignFormat.VERILOG_HEADER,
271
+ DesignFormat.NETLIST,
272
+ DesignFormat.POWERED_NETLIST,
273
+ DesignFormat.LIB,
274
+ ]
275
+ )
276
+ for view, _ in self.toolbox.get_macro_views_by_priority(
277
+ self.config, format_list
278
+ ):
279
+ blackbox_models.append(str(view))
280
+
281
+ if libs := self.config.get("EXTRA_LIBS"):
282
+ blackbox_models.extend(str(f) for f in libs)
283
+ if models := self.config.get("EXTRA_VERILOG_MODELS"):
284
+ blackbox_models.extend(str(f) for f in models)
285
+
286
+ excluded_cells: Set[str] = set(self.config["EXTRA_EXCLUDED_CELLS"] or [])
287
+ excluded_cells.update(
288
+ process_list_file(self.config["SYNTH_EXCLUDED_CELL_FILE"])
289
+ )
290
+ excluded_cells.update(process_list_file(self.config["PNR_EXCLUDED_CELL_FILE"]))
291
+
292
+ libs_synth = self.toolbox.remove_cells_from_lib(
293
+ frozenset([str(lib) for lib in scl_lib_list]),
294
+ excluded_cells=frozenset(excluded_cells),
295
+ )
296
+ extra_path = os.path.join(self.step_dir, "extra.json")
297
+ with open(extra_path, "w") as f:
298
+ json.dump({"blackbox_models": blackbox_models, "libs_synth": libs_synth}, f)
299
+ cmd.extend(["--extra-in", extra_path])
300
+ return cmd
301
+
302
+
303
+ @Step.factory.register()
304
+ class JsonHeader(VerilogStep):
305
+ id = "Yosys.JsonHeader"
306
+ name = "Generate JSON Header"
307
+ long_name = "Generate JSON Header"
308
+
309
+ inputs = []
310
+ outputs = [DesignFormat.JSON_HEADER]
311
+
312
+ config_vars = PyosysStep.config_vars + verilog_rtl_cfg_vars
313
+
314
+ power_defines = True
315
+
316
+ def get_script_path(self) -> str:
317
+ return os.path.join(get_script_dir(), "pyosys", "json_header.py")
318
+
319
+ def get_command(self, state_in: State) -> List[str]:
320
+ out_file = os.path.join(
321
+ self.step_dir,
322
+ f"{self.config['DESIGN_NAME']}.{DesignFormat.JSON_HEADER.value.extension}",
323
+ )
324
+ return super().get_command(state_in) + ["--output", out_file]
325
+
326
+ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
327
+ out_file = os.path.join(
328
+ self.step_dir,
329
+ f"{self.config['DESIGN_NAME']}.{DesignFormat.JSON_HEADER.value.extension}",
330
+ )
331
+ views_updates, metrics_updates = super().run(state_in, **kwargs)
332
+ views_updates[DesignFormat.JSON_HEADER] = Path(out_file)
333
+ return views_updates, metrics_updates
334
+
335
+
336
+ class SynthesisCommon(VerilogStep):
337
+ inputs = [] # The input RTL is part of the configuration
338
+ outputs = [DesignFormat.NETLIST]
339
+
340
+ config_vars = PyosysStep.config_vars + [
341
+ Variable(
342
+ "SYNTH_CHECKS_ALLOW_TRISTATE",
343
+ bool,
344
+ "Ignore multiple-driver warnings if they are connected to tri-state buffers on a best-effort basis.",
345
+ default=True,
346
+ ),
347
+ Variable(
348
+ "SYNTH_AUTONAME",
349
+ bool,
350
+ "Generates names for netlist instances. This results in instance names that can be extremely long, but are more human-readable.",
351
+ default=False,
352
+ ),
353
+ Variable(
354
+ "SYNTH_STRATEGY",
355
+ Literal[
356
+ "AREA 0",
357
+ "AREA 1",
358
+ "AREA 2",
359
+ "AREA 3",
360
+ "DELAY 0",
361
+ "DELAY 1",
362
+ "DELAY 2",
363
+ "DELAY 3",
364
+ "DELAY 4",
365
+ ],
366
+ "Strategies for abc logic synthesis and technology mapping. AREA strategies usually result in a more compact design, while DELAY strategies usually result in a design that runs at a higher frequency. Please note that there is no way to know which strategy is the best before trying them.",
367
+ default="AREA 0",
368
+ ),
369
+ Variable(
370
+ "SYNTH_ABC_BUFFERING",
371
+ bool,
372
+ "Enables `abc` cell buffering.",
373
+ default=False,
374
+ deprecated_names=["SYNTH_BUFFERING"],
375
+ ),
376
+ Variable(
377
+ "SYNTH_ABC_LEGACY_REFACTOR",
378
+ bool,
379
+ "Replaces the ABC command `drf -l` with `refactor` which matches older versions of LibreLane but is more unstable.",
380
+ default=False,
381
+ ),
382
+ Variable(
383
+ "SYNTH_ABC_LEGACY_REWRITE",
384
+ bool,
385
+ "Replaces the ABC command `drw -l` with `rewrite` which matches older versions of LibreLane but is more unstable.",
386
+ default=False,
387
+ ),
388
+ Variable(
389
+ "SYNTH_ABC_DFF",
390
+ bool,
391
+ "Passes D-flipflop cells through ABC for optimization (which can for example, eliminate identical flip-flops).",
392
+ default=False,
393
+ ),
394
+ Variable(
395
+ "SYNTH_ABC_USE_MFS3",
396
+ bool,
397
+ "Experimental: attempts a SAT-based remapping in all area and delay strategies before 'retime', which may improve PPA results.",
398
+ default=False,
399
+ ),
400
+ Variable(
401
+ "SYNTH_ABC_AREA_USE_NF",
402
+ bool,
403
+ "Experimental: uses the &nf delay-based mapper with a very high value instead of the amap area mapper, which may be better in some scenarios at recovering area.",
404
+ default=False,
405
+ ),
406
+ Variable(
407
+ "SYNTH_DIRECT_WIRE_BUFFERING",
408
+ bool,
409
+ "Enables inserting buffer cells for directly connected wires.",
410
+ default=True,
411
+ deprecated_names=["SYNTH_BUFFER_DIRECT_WIRES"],
412
+ ),
413
+ Variable(
414
+ "SYNTH_SPLITNETS",
415
+ bool,
416
+ "Splits multi-bit nets into single-bit nets. Easier to trace but may not be supported by all tools.",
417
+ default=True,
418
+ ),
419
+ Variable(
420
+ "SYNTH_SIZING",
421
+ bool,
422
+ "Enables `abc` cell sizing (instead of buffering).",
423
+ default=False,
424
+ ),
425
+ Variable(
426
+ "SYNTH_HIERARCHY_MODE",
427
+ Literal["flatten", "deferred_flatten", "keep"],
428
+ "Affects how hierarchy is maintained throughout and after synthesis. 'flatten' flattens it during and after synthesis. 'deferred_flatten' flattens it after synthesis. 'keep' never flattens it.",
429
+ default="flatten",
430
+ deprecated_names=[
431
+ (
432
+ "SYNTH_NO_FLAT",
433
+ lambda x: "deferred_flatten" if x else "flatten",
434
+ )
435
+ ],
436
+ ),
437
+ Variable(
438
+ "SYNTH_SHARE_RESOURCES",
439
+ bool,
440
+ "A flag that enables yosys to reduce the number of cells by determining shareable resources and merging them.",
441
+ default=True,
442
+ ),
443
+ Variable(
444
+ "SYNTH_ADDER_TYPE",
445
+ Literal["YOSYS", "FA", "RCA", "CSA"],
446
+ "Adder type to which the $add and $sub operators are mapped to. Possible values are `YOSYS/FA/RCA/CSA`; where `YOSYS` refers to using Yosys internal adder definition, `FA` refers to full-adder structure, `RCA` refers to ripple carry adder structure, and `CSA` refers to carry select adder.",
447
+ default="YOSYS",
448
+ ),
449
+ Variable(
450
+ "SYNTH_EXTRA_MAPPING_FILE",
451
+ Optional[Path],
452
+ "Points to an extra techmap file for yosys that runs right after yosys `synth` before generic techmap.",
453
+ ),
454
+ Variable(
455
+ "SYNTH_ELABORATE_ONLY",
456
+ bool,
457
+ '"Elaborate" the design only without attempting any logic mapping. Useful when dealing with structural Verilog netlists.',
458
+ default=False,
459
+ ),
460
+ Variable(
461
+ "SYNTH_ELABORATE_FLATTEN",
462
+ bool,
463
+ "If `SYNTH_ELABORATE_ONLY` is specified, this variable controls whether or not the top level should be flattened.",
464
+ default=True,
465
+ deprecated_names=["SYNTH_FLAT_TOP"],
466
+ ),
467
+ Variable(
468
+ "SYNTH_MUL_BOOTH",
469
+ bool,
470
+ "Runs the booth pass as part of synthesis: See https://yosyshq.readthedocs.io/projects/yosys/en/latest/cmd/booth.html",
471
+ default=False,
472
+ ),
473
+ Variable(
474
+ "SYNTH_TIE_UNDEFINED",
475
+ Optional[Literal["high", "low"]],
476
+ "Whether to tie undefined values low or high. Explicitly provide null if you wish to simply leave them undriven.",
477
+ default="low",
478
+ ),
479
+ Variable(
480
+ "SYNTH_WRITE_NOATTR",
481
+ bool,
482
+ "If true, Verilog-2001 attributes are omitted from output netlists. Some utilities do not support attributes.",
483
+ default=True,
484
+ ),
485
+ # Variable(
486
+ # "SYNTH_SDC_FILE",
487
+ # Optional[Path],
488
+ # "Specifies the SDC file read during all Synthesis steps",
489
+ # ),
490
+ ]
491
+
492
+ def get_script_path(self) -> str:
493
+ return os.path.join(get_script_dir(), "pyosys", "synthesize.py")
494
+
495
+ def get_command(self, state_in: State) -> List[str]:
496
+ out_file = os.path.join(
497
+ self.step_dir,
498
+ f"{self.config['DESIGN_NAME']}.{DesignFormat.NETLIST.value.extension}",
499
+ )
500
+ cmd = super().get_command(state_in)
501
+ if self.config["USE_LIGHTER"]:
502
+ lighter_dff_map = self.config["LIGHTER_DFF_MAP"]
503
+ if lighter_dff_map is None:
504
+ scl = self.config["STD_CELL_LIBRARY"]
505
+ try:
506
+ raw = subprocess.check_output(
507
+ ["lighter_files", scl], encoding="utf8"
508
+ )
509
+ files = raw.strip().splitlines()
510
+ lighter_dff_map = Path(files[0])
511
+ except FileNotFoundError:
512
+ self.warn(
513
+ "Lighter not found or not set up with LibreLane: If you're using a manual Lighter install, try setting LIGHTER_DFF_MAP explicitly."
514
+ )
515
+ except subprocess.CalledProcessError:
516
+ self.warn(f"{scl} not supported by Lighter.")
517
+ cmd.extend(["--lighter-dff-map", lighter_dff_map])
518
+ return cmd + ["--output", out_file]
519
+
520
+ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
521
+ out_file = os.path.join(
522
+ self.step_dir,
523
+ f"{self.config['DESIGN_NAME']}.{DesignFormat.NETLIST.value.extension}",
524
+ )
525
+
526
+ view_updates, metric_updates = super().run(state_in, **kwargs)
527
+
528
+ stats_file = os.path.join(self.step_dir, "reports", "stat.json")
529
+ stats_str = open(stats_file).read()
530
+ stats = json.loads(stats_str, parse_float=Decimal)
531
+
532
+ metric_updates["design__instance__count"] = stats["design"]["num_cells"]
533
+ if chip_area := stats["design"].get("area"): # needs nonzero area
534
+ metric_updates["design__instance__area"] = chip_area
535
+
536
+ cells = stats["design"]["num_cells_by_type"]
537
+ safe = ["$assert"]
538
+ unmapped_cells = [
539
+ cells[y] for y in cells.keys() if y not in safe and y.startswith("$")
540
+ ]
541
+ metric_updates["design__instance_unmapped__count"] = sum(unmapped_cells)
542
+
543
+ check_error_count_file = os.path.join(
544
+ self.step_dir, "reports", "pre_synth_chk.rpt"
545
+ )
546
+ metric_updates["synthesis__check_error__count"] = 0
547
+ if os.path.exists(check_error_count_file):
548
+ metric_updates["synthesis__check_error__count"] = _parse_yosys_check(
549
+ open(check_error_count_file),
550
+ self.config["TRISTATE_CELLS"],
551
+ self.config["SYNTH_CHECKS_ALLOW_TRISTATE"],
552
+ self.config["SYNTH_ELABORATE_ONLY"],
553
+ )
554
+
555
+ view_updates[DesignFormat.NETLIST] = Path(out_file)
556
+
557
+ return view_updates, metric_updates
558
+
559
+
560
+ @Step.factory.register()
561
+ class Synthesis(SynthesisCommon):
562
+ """
563
+ Performs synthesis and technology mapping on Verilog RTL files
564
+ using Yosys and ABC, emitting a netlist.
565
+
566
+ Some metrics will also be extracted and updated, namely:
567
+
568
+ * ``design__instance__count``
569
+ * ``design__instance_unmapped__count``
570
+ * ``design__instance__area``
571
+
572
+ Note that Yosys steps do not currently support gzipped standard cell dotlib
573
+ files. They are however supported for macros:
574
+
575
+ https://github.com/YosysHQ/yosys/issues/4830
576
+ """
577
+
578
+ id = "Yosys.Synthesis"
579
+ name = "Synthesis"
580
+
581
+ config_vars = SynthesisCommon.config_vars + verilog_rtl_cfg_vars
582
+
583
+
584
+ @Step.factory.register()
585
+ class Resynthesis(SynthesisCommon):
586
+ """
587
+ Like ``Synthesis``, but operates on the input netlist instead of RTL files.
588
+ Useful to process/elaborate on netlists generated by tools other than Yosys.
589
+
590
+ Some metrics will also be extracted and updated, namely:
591
+
592
+ * ``design__instance__count``
593
+ * ``design__instance_unmapped__count``
594
+ * ``design__instance__area``
595
+
596
+ Note that Yosys steps do not currently support gzipped standard cell dotlib
597
+ files. They are however supported for macros:
598
+
599
+ https://github.com/YosysHQ/yosys/issues/4830
600
+ """
601
+
602
+ id = "Yosys.Resynthesis"
603
+ name = "Resynthesis"
604
+
605
+ config_vars = SynthesisCommon.config_vars
606
+
607
+ inputs = [DesignFormat.NETLIST]
608
+
609
+ def get_command(self, state_in):
610
+ return super().get_command(state_in) + [state_in[DesignFormat.NETLIST]]
611
+
612
+
613
+ @Step.factory.register()
614
+ class VHDLSynthesis(SynthesisCommon):
615
+ """
616
+ Performs synthesis and technology mapping on VHDL files
617
+ using Yosys, GHDL and ABC, emitting a netlist.
618
+
619
+ Some metrics will also be extracted and updated, namely:
620
+
621
+ * ``design__instance__count``
622
+ * ``design__instance_unmapped__count``
623
+ * ``design__instance__area``
624
+
625
+ Note that Yosys steps do not currently support gzipped standard cell dotlib
626
+ files. They are however supported for macros:
627
+
628
+ https://github.com/YosysHQ/yosys/issues/4830
629
+ """
630
+
631
+ id = "Yosys.VHDLSynthesis"
632
+ name = "Synthesis (VHDL)"
633
+
634
+ config_vars = SynthesisCommon.config_vars + [
635
+ Variable(
636
+ "VHDL_FILES",
637
+ List[Path],
638
+ "The paths of the design's VHDL files.",
639
+ ),
640
+ ]