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,464 @@
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
+ import re
15
+ import os
16
+ import glob
17
+ import fnmatch
18
+ from enum import Enum
19
+ from decimal import Decimal
20
+ from types import SimpleNamespace
21
+ from typing import Any, Dict, List, Mapping, Sequence, Tuple, Union, Optional
22
+
23
+ from ..common import is_string
24
+
25
+ Keys = SimpleNamespace(
26
+ pdk_root="PDK_ROOT",
27
+ pdk="PDK",
28
+ pdkpath="PDKPATH",
29
+ scl="STD_CELL_LIBRARY",
30
+ design_dir="DESIGN_DIR",
31
+ )
32
+
33
+ PROCESS_INFO_ALLOWLIST = [
34
+ Keys.pdk,
35
+ Keys.scl,
36
+ f"{Keys.scl}_OPT",
37
+ ]
38
+
39
+
40
+ Scalar = Union[str, int, Decimal, float, bool, None]
41
+ Valid = Union[Scalar, dict, list]
42
+
43
+
44
+ class Expr(object):
45
+ class Token(object):
46
+ class Type(Enum):
47
+ VAR = 0
48
+ NUMBER = 1
49
+ OP = 2
50
+ LPAREN = 3
51
+ RPAREN = 4
52
+
53
+ def __init__(self, type: "Expr.Token.Type", value: str) -> None:
54
+ self.type: Expr.Token.Type = type
55
+ self.value: str = value
56
+
57
+ def __repr__(self):
58
+ return f"<Token:{self.type} '{self.value}'>"
59
+
60
+ def prec_assoc(self) -> Tuple[int, bool]:
61
+ """
62
+ Returns (precedence, is_left_assoc)
63
+ """
64
+
65
+ if self.value in ["**"]:
66
+ return (20, False)
67
+ elif self.value in ["*", "/"]:
68
+ return (10, True)
69
+ elif self.value in ["+", "-"]:
70
+ return (0, True)
71
+ else:
72
+ raise TypeError(
73
+ f"pre-assoc not supported for non-token operators: '{self.value}'"
74
+ )
75
+
76
+ @staticmethod
77
+ def tokenize(expr: str) -> List["Expr.Token"]:
78
+ rx_list = [
79
+ (re.compile(r"^\$([A-Za-z_][A-Za-z0-9_\.\[\]]*)"), Expr.Token.Type.VAR),
80
+ (re.compile(r"^(-?\d+\.?\d*)"), Expr.Token.Type.NUMBER),
81
+ (re.compile(r"^(\*\*)"), Expr.Token.Type.OP),
82
+ (re.compile(r"^(\+|\-|\*|\/)"), Expr.Token.Type.OP),
83
+ (re.compile(r"^(\()"), Expr.Token.Type.LPAREN),
84
+ (re.compile(r"^(\))"), Expr.Token.Type.RPAREN),
85
+ (re.compile(r"^\s+"), None),
86
+ ]
87
+ tokens = []
88
+ str_so_far = expr
89
+ while not str_so_far.strip() == "":
90
+ found = False
91
+
92
+ for element in rx_list:
93
+ rx, type = element
94
+ m = rx.match(str_so_far)
95
+ if m is None:
96
+ continue
97
+ found = True
98
+ if type is not None:
99
+ tokens.append(Expr.Token(type, m[1]))
100
+ str_so_far = str_so_far[len(m[0]) :]
101
+ break
102
+
103
+ if not found:
104
+ raise SyntaxError(
105
+ f"Unexpected token at the start of the following string '{str_so_far}'."
106
+ )
107
+ return tokens
108
+
109
+ @staticmethod
110
+ def evaluate(expression: str, symbols: Mapping[str, Any]) -> Decimal:
111
+ tokens: List["Expr.Token"] = Expr.tokenize(expression)
112
+ ETT = Expr.Token.Type
113
+
114
+ # Infix to Postfix
115
+ postfix: List["Expr.Token"] = []
116
+ opstack: List["Expr.Token"] = []
117
+ for token in tokens:
118
+ if token.type == ETT.OP:
119
+ prec, assoc = token.prec_assoc()
120
+
121
+ top_prec = None
122
+ try:
123
+ top_prec, _ = opstack[-1].prec_assoc()
124
+ except TypeError:
125
+ pass
126
+ except IndexError:
127
+ pass
128
+
129
+ while top_prec is not None and (
130
+ (assoc and prec <= top_prec) or (not assoc and prec < top_prec)
131
+ ):
132
+ postfix.append(opstack.pop())
133
+ top_prec = None
134
+ try:
135
+ top_prec, _ = opstack[-1].prec_assoc()
136
+ except IndexError:
137
+ pass
138
+ opstack.append(token)
139
+ elif token.type == ETT.LPAREN:
140
+ opstack.append(token)
141
+ elif token.type == ETT.RPAREN:
142
+ top = opstack[-1]
143
+ while top.type != ETT.LPAREN:
144
+ postfix.append(top)
145
+ opstack.pop()
146
+ top = opstack[-1]
147
+ opstack.pop() # drop the LPAREN
148
+ else:
149
+ postfix.append(token)
150
+
151
+ while len(opstack):
152
+ postfix.append(opstack[-1])
153
+ opstack.pop()
154
+
155
+ # Evaluate
156
+ eval_stack = []
157
+ for token in postfix:
158
+ if token.type == ETT.NUMBER:
159
+ eval_stack.append(Decimal(token.value))
160
+ elif token.type == ETT.VAR:
161
+ try:
162
+ value = symbols[token.value]
163
+ if not (
164
+ isinstance(value, int)
165
+ or isinstance(value, float)
166
+ or isinstance(value, Decimal)
167
+ ):
168
+ raise TypeError(
169
+ f"Referenced variable {token.value} is not of a valid numeric type: f{type(value)}"
170
+ )
171
+ eval_stack.append(Decimal(value))
172
+ except KeyError:
173
+ raise TypeError(
174
+ f"Configuration variable '{token.value}' not found."
175
+ )
176
+ elif token.type == ETT.OP:
177
+ try:
178
+ number1 = eval_stack[-2]
179
+ number2 = eval_stack[-1]
180
+ eval_stack.pop()
181
+ eval_stack.pop()
182
+
183
+ result = Decimal(0.0)
184
+ if token.value == "**":
185
+ result = number1**number2
186
+ elif token.value == "*":
187
+ result = number1 * number2
188
+ elif token.value == "/":
189
+ result = number1 / number2
190
+ elif token.value == "+":
191
+ result = number1 + number2
192
+ elif token.value == "-":
193
+ result = number1 + number2
194
+
195
+ eval_stack.append(result)
196
+ except IndexError:
197
+ raise SyntaxError(
198
+ f"not enough operands for operator '{token.value}'"
199
+ )
200
+
201
+ if len(eval_stack) > 1:
202
+ raise ValueError("expression reduces to multiple values")
203
+ elif len(eval_stack) == 0:
204
+ raise ValueError("expression is empty")
205
+
206
+ return eval_stack[0]
207
+
208
+
209
+ ref_rx = re.compile(r"^\$([A-Za-z_][A-Za-z0-9_\.\[\]]*)")
210
+
211
+
212
+ def process_string(
213
+ value: str,
214
+ symbols: Mapping[str, Any],
215
+ readable_paths: Optional[List[str]] = None,
216
+ ) -> Valid:
217
+ global ref_rx
218
+ EXPR_PREFIX = "expr::"
219
+ REF_PREFIX = "ref::"
220
+ REFG_PREFIX = "refg::"
221
+
222
+ DIR_PREFIX = "dir::"
223
+ PDK_DIR_PREFIX = "pdk_dir::"
224
+
225
+ mutable: str = value
226
+
227
+ if value.startswith(DIR_PREFIX):
228
+ mutable = value.replace(DIR_PREFIX, f"refg::${Keys.design_dir}/")
229
+ elif value.startswith(PDK_DIR_PREFIX):
230
+ mutable = value.replace(PDK_DIR_PREFIX, f"refg::${Keys.pdkpath}/")
231
+
232
+ if mutable.startswith(EXPR_PREFIX):
233
+ try:
234
+ return Expr.evaluate(value[len(EXPR_PREFIX) :], symbols)
235
+ except SyntaxError as e:
236
+ raise SyntaxError(f"Invalid expression '{value}': {e}") from None
237
+ elif mutable.startswith(REF_PREFIX) or mutable.startswith(REFG_PREFIX):
238
+ reference = mutable[mutable.index("::") + 2 :]
239
+ match = ref_rx.match(reference)
240
+ if match is None:
241
+ raise SyntaxError(f"Invalid reference string '{reference}'") from None
242
+
243
+ reference_variable = match[1]
244
+ if reference_variable not in symbols:
245
+ raise KeyError(
246
+ f"Referenced variable '{reference_variable}' not found"
247
+ ) from None
248
+
249
+ target = symbols[reference_variable]
250
+ if target is None:
251
+ return None
252
+
253
+ if not is_string(target):
254
+ if type(target) in [int, float, Decimal]:
255
+ raise TypeError(
256
+ f"Referenced variable {reference_variable} is a number and not a string: use expr::{match[0]} if you want to reference this number."
257
+ ) from None
258
+ else:
259
+ raise TypeError(
260
+ f"Referenced variable {reference_variable} is not a valid string: {type(target)}."
261
+ ) from None
262
+
263
+ target = str(target)
264
+ concatenated = reference.replace(match[0], target)
265
+
266
+ # Glob only if Refg
267
+ if not mutable.startswith(REFG_PREFIX):
268
+ return concatenated
269
+
270
+ ## If we're refg, all returns beyond this point must be of type
271
+ ## List[str]
272
+
273
+ # Glob only if readable_paths isn't null
274
+ if readable_paths is None:
275
+ return [target]
276
+
277
+ final_abspath = os.path.abspath(concatenated)
278
+
279
+ # Glob only if it doesn't already resolve to a valid file
280
+ if os.path.exists(final_abspath):
281
+ return [final_abspath]
282
+
283
+ in_exposed = [final_abspath.startswith(p) for p in readable_paths]
284
+ if True not in in_exposed:
285
+ raise PermissionError(
286
+ f"'{concatenated}' is not located any path readable to LibreLane"
287
+ )
288
+ files = sorted(glob.glob(final_abspath))
289
+ files_escaped = [file.replace("$", r"\$") for file in files]
290
+ files_escaped.sort()
291
+
292
+ if len(files_escaped) == 0:
293
+ files_escaped = [concatenated]
294
+
295
+ return files_escaped
296
+ else:
297
+ return mutable
298
+
299
+
300
+ PDK_PREFIX = "pdk::"
301
+ SCL_PREFIX = "scl::"
302
+
303
+
304
+ def process_list_recursive(
305
+ input: Sequence[Any],
306
+ ref: List[Any],
307
+ symbols: Dict[str, Any],
308
+ readable_paths: Optional[List[str]],
309
+ *,
310
+ key_path: str = "",
311
+ ):
312
+ for i, value in enumerate(input):
313
+ current_key_path = f"{key_path}[{i}]"
314
+ processed: Any = None
315
+ if isinstance(value, Mapping):
316
+ processed = {}
317
+ process_dict_recursive(
318
+ value,
319
+ processed,
320
+ symbols,
321
+ readable_paths,
322
+ key_path=current_key_path,
323
+ )
324
+ elif isinstance(value, Sequence) and not is_string(value):
325
+ processed = []
326
+ process_list_recursive(
327
+ value,
328
+ processed,
329
+ symbols,
330
+ readable_paths,
331
+ key_path=current_key_path,
332
+ )
333
+ elif is_string(value):
334
+ processed = process_string(value, symbols, readable_paths)
335
+ else:
336
+ processed = value
337
+
338
+ if processed is not None:
339
+ ref.append(processed)
340
+ symbols[current_key_path] = processed
341
+
342
+
343
+ def process_dict_recursive(
344
+ input: Mapping[str, Any],
345
+ ref: Dict[str, Any],
346
+ symbols: Dict[str, Any],
347
+ readable_paths: Optional[List[str]],
348
+ *,
349
+ key_path: str = "",
350
+ ):
351
+ for key, value in input.items():
352
+ current_key_path = key
353
+ if key_path != "":
354
+ current_key_path = f"{key_path}.{key}"
355
+ processed: Any = None
356
+ if isinstance(value, Mapping):
357
+ if key.startswith(PDK_PREFIX):
358
+ pdk_match = key[len(PDK_PREFIX) :]
359
+ if fnmatch.fnmatch(ref[Keys.pdk], pdk_match):
360
+ process_dict_recursive(
361
+ value,
362
+ ref,
363
+ symbols,
364
+ readable_paths,
365
+ key_path=key_path,
366
+ )
367
+ elif key.startswith(SCL_PREFIX):
368
+ scl_match = key[len(SCL_PREFIX) :]
369
+ if ref[Keys.scl] is not None and fnmatch.fnmatch(
370
+ ref[Keys.scl], scl_match
371
+ ):
372
+ process_dict_recursive(
373
+ value,
374
+ ref,
375
+ symbols,
376
+ readable_paths,
377
+ key_path=key_path,
378
+ )
379
+ else:
380
+ processed = {}
381
+ process_dict_recursive(
382
+ value,
383
+ processed,
384
+ symbols,
385
+ readable_paths,
386
+ key_path=current_key_path,
387
+ )
388
+
389
+ elif isinstance(value, Sequence) and not is_string(value):
390
+ processed = []
391
+ process_list_recursive(
392
+ value,
393
+ processed,
394
+ symbols,
395
+ readable_paths,
396
+ key_path=current_key_path,
397
+ )
398
+ elif is_string(value):
399
+ processed = process_string(value, symbols, readable_paths)
400
+ else:
401
+ processed = value
402
+
403
+ if not key.startswith(PDK_PREFIX) and not key.startswith(SCL_PREFIX):
404
+ ref[key] = processed
405
+ symbols[current_key_path] = processed
406
+
407
+
408
+ def process_config_dict(
409
+ config_in: Mapping[str, Any],
410
+ exposed_variables: Dict[str, Any],
411
+ readable_paths: Optional[List[str]],
412
+ ) -> Dict[str, Any]:
413
+ state = dict(exposed_variables)
414
+ symbols = dict(exposed_variables)
415
+ process_dict_recursive(config_in, state, symbols, readable_paths)
416
+ return state
417
+
418
+
419
+ def extract_process_vars(config_in: Dict[str, str]) -> Dict[str, str]:
420
+ return {
421
+ key: config_in[key]
422
+ for key in PROCESS_INFO_ALLOWLIST
423
+ if config_in.get(key) is not None and config_in.get(key) != ""
424
+ }
425
+
426
+
427
+ def preprocess_dict(
428
+ config_dict: Mapping[str, Any],
429
+ design_dir: str,
430
+ only_extract_process_info: bool = False,
431
+ pdk: Optional[str] = None,
432
+ pdkpath: Optional[str] = None,
433
+ scl: Optional[str] = None,
434
+ readable_paths: Optional[List[str]] = None,
435
+ ) -> Dict[str, Any]:
436
+ """
437
+ If readable_paths are set to None, refg:: will not work
438
+ """
439
+ if None in (pdk, pdkpath, scl):
440
+ if only_extract_process_info:
441
+ pdkpath = ""
442
+ scl = ""
443
+ pdk = ""
444
+ else:
445
+ raise TypeError(
446
+ "pdk, pdkpath and scl all need to be non-None unless only_extract_process_info is passed"
447
+ )
448
+
449
+ base_vars = {
450
+ Keys.pdk: pdk,
451
+ Keys.pdkpath: pdkpath,
452
+ Keys.scl: scl,
453
+ Keys.design_dir: design_dir,
454
+ }
455
+
456
+ preprocessed = process_config_dict(
457
+ config_dict,
458
+ base_vars,
459
+ readable_paths,
460
+ )
461
+ if only_extract_process_info:
462
+ preprocessed = extract_process_vars(preprocessed)
463
+
464
+ return preprocessed
@@ -0,0 +1,45 @@
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 typing import Dict
15
+
16
+ removed_variables: Dict[str, str] = {
17
+ "PL_RANDOM_GLB_PLACEMENT": "The random global placer no longer yields a tangible benefit with newer versions of OpenROAD.",
18
+ "PL_RANDOM_INITIAL_PLACEMENT": "A random initial placer no longer yields a tangible benefit with newer versions of OpenROAD.",
19
+ "KLAYOUT_XOR_GDS": "The GDS output is of limited utility compared to the XML database.",
20
+ "KLAYOUT_XOR_XML": "The XML database is always generated.",
21
+ "MAGIC_GENERATE_GDS": "The GDS view is always generated when MAGIC_RUN_STREAMOUT is set.",
22
+ "CLOCK_BUFFER_FANOUT": "The simple CTS script that used this variable no longer exists.",
23
+ "FP_IO_HMETAL": "Replaced by FP_IO_HLAYER in the PDK configuration variables, which uses a more specific layer name.",
24
+ "FP_IO_VMETAL": "Replaced by FP_IO_VLAYER in the PDK configuration variables, which uses a more specific layer name.",
25
+ "GLB_OPTIMIZE_MIRRORING": "Shares DPL_OPTIMIZE_MIRRORING.",
26
+ "GRT_MAX_DIODE_INS_ITERS": "Relevant diode insertion strategies removed.",
27
+ "TAKE_LAYOUT_SCROT": "Buggy/dubious utility.",
28
+ "MAGIC_PAD": "Hacky/dubious utility.",
29
+ "GENERATE_FINAL_SUMMARY_REPORT": "To be specified via API/CLI- not much of a configuration variable.",
30
+ "USE_GPIO_PADS": "Add the pad's files to EXTRA_LEFS and EXTRA_VERILOG_MODELS as apprioriate.",
31
+ "PL_ESTIMATE_PARASITICS": "Parasitics are always estimated whenever possible.",
32
+ "GRT_ESTIMATE_PARASITICS": "Parasitics are always estimated whenever possible.",
33
+ "FP_PDN_AUTO_ADJUST": "Too situational. It's always best to be more explicit.",
34
+ "SYNTH_READ_BLACKBOX_LIB": "Changed to always be on.",
35
+ "CTS_TOLERANCE": "No longer supported by OpenROAD.",
36
+ "MAGIC_GDS_ALLOW_ABSTRACT": "Bad practice. If an abstract view is needed, a GDS file can be generated from the abstract LEF file.",
37
+ "PLACE_SITE_HEIGHT": "Now automatically extracted from PLACE_SITE.",
38
+ "PLACE_SITE_WIDTH": "Now automatically extracted from PLACE_SITE.",
39
+ "LEC_ENABLE": "Buggy/doesn't scale properly.",
40
+ "LVS_INSERT_POWER_PINS": "No longer necessary.",
41
+ "RUN_CVC": "Upstream no longer supports CVC for use within LibreLane.",
42
+ "FP_PADFRAME_CFG": "To be implemented.",
43
+ "FP_CONTEXT_DEF": "To be implemented.",
44
+ "FP_CONTEXT_LEF": "To be implemented.",
45
+ }