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