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,41 @@
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
+ from .misc import _get_process_limit
15
+
16
+ from concurrent.futures import ThreadPoolExecutor
17
+
18
+ TPE = ThreadPoolExecutor(max_workers=_get_process_limit())
19
+
20
+
21
+ def set_tpe(tpe: ThreadPoolExecutor):
22
+ """
23
+ Allows replacing LibreLane's global ``ThreadPoolExecutor`` with a customized
24
+ one.
25
+
26
+ It will be used inside steps, so use different TPEs inside steps to avoid
27
+ a deadlock.
28
+
29
+ :param tpe: The replacement ThreadPoolExecutor
30
+ """
31
+ global TPE
32
+ TPE = tpe
33
+
34
+
35
+ def get_tpe() -> ThreadPoolExecutor:
36
+ """
37
+ :returns: LibreLane's global ``ThreadPoolExecutor``. This is used to run
38
+ steps, so do not use them inside steps to avoid a deadlock.
39
+ """
40
+ global TPE
41
+ return TPE
@@ -0,0 +1,117 @@
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 os
15
+ import sys
16
+ import tempfile
17
+ from math import isfinite
18
+ from decimal import Decimal
19
+ from collections import UserString
20
+ from typing import Any, Union, ClassVar, Tuple, Optional
21
+
22
+
23
+ def is_string(obj: Any) -> bool:
24
+ return isinstance(obj, str) or isinstance(obj, UserString)
25
+
26
+
27
+ Number = Union[int, float, Decimal]
28
+
29
+
30
+ def is_number(obj: Any) -> bool:
31
+ return isinstance(obj, int) or isinstance(obj, float) or isinstance(obj, Decimal)
32
+
33
+
34
+ def is_real_number(obj: Any) -> bool:
35
+ return is_number(obj) and isfinite(obj)
36
+
37
+
38
+ class Path(UserString, os.PathLike):
39
+ """
40
+ A Path type for LibreLane configuration variables.
41
+
42
+ Basically just a string.
43
+ """
44
+
45
+ # This path will pass the validate() call, but will
46
+ # fail to open. It should be used for deprecated variable
47
+ # translation only.
48
+ _dummy_path: ClassVar[str] = "__librelane_dummy_path"
49
+
50
+ def __fspath__(self) -> str:
51
+ return str(self)
52
+
53
+ def __repr__(self) -> str:
54
+ return f"{self.__class__.__qualname__}('{self}')"
55
+
56
+ def exists(self) -> bool:
57
+ """
58
+ A convenience method calling :meth:`os.path.exists`
59
+ """
60
+ return os.path.exists(self)
61
+
62
+ def validate(self, message_on_err: str = ""):
63
+ """
64
+ Raises an error if the path does not exist.
65
+ """
66
+ if not self.exists() and not self == Path._dummy_path:
67
+ raise ValueError(f"{message_on_err}: '{self}' does not exist")
68
+
69
+ def startswith(
70
+ self,
71
+ prefix: Union[str, Tuple[str, ...], UserString, os.PathLike],
72
+ start: Optional[int] = 0,
73
+ end: Optional[int] = sys.maxsize,
74
+ ) -> bool:
75
+ if isinstance(prefix, UserString) or isinstance(prefix, os.PathLike):
76
+ prefix = str(prefix)
77
+ return super().startswith(prefix, start, end)
78
+
79
+ def rel_if_child(
80
+ self,
81
+ start: Union[str, os.PathLike] = os.getcwd(),
82
+ *,
83
+ relative_prefix: str = "",
84
+ ) -> "Path":
85
+ my_abspath = os.path.abspath(self)
86
+ start_abspath = os.path.abspath(start)
87
+ if my_abspath.startswith(start_abspath):
88
+ return Path(relative_prefix + os.path.relpath(self, start_abspath))
89
+ else:
90
+ return Path(my_abspath)
91
+
92
+
93
+ AnyPath = Union[str, os.PathLike]
94
+
95
+
96
+ class ScopedFile(Path):
97
+ """
98
+ Creates a temporary file that remains valid while this variable is in scope,
99
+ and is deleted upon deconstruction.
100
+
101
+ The object itself is a string pointing to that file path.
102
+
103
+ :param contents: The contents of the temporary file to create.
104
+ """
105
+
106
+ def __init__(self, *, contents="") -> None:
107
+ self._ntf = tempfile.NamedTemporaryFile(
108
+ "w",
109
+ delete=False,
110
+ encoding="utf8",
111
+ )
112
+ super().__init__(self._ntf.name)
113
+ self._ntf.write(contents)
114
+ self._ntf.close()
115
+
116
+ def __del__(self):
117
+ os.unlink(self._ntf.name)
@@ -0,0 +1,32 @@
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
+ The Configuration Module
16
+ ------------------------
17
+
18
+ This modules includes various functions for importing and/or generating LibreLane
19
+ configuration objects. Configuration objects are the primary input to a flow.
20
+ """
21
+ from .preprocessor import Keys
22
+ from .variable import Instance, Macro, Variable
23
+ from .config import (
24
+ Meta,
25
+ Config,
26
+ InvalidConfig,
27
+ AnyConfig,
28
+ AnyConfigs,
29
+ PassedDirectoryError,
30
+ UnknownExtensionError,
31
+ )
32
+ from .flow import flow_common_variables as universal_flow_config_variables
@@ -0,0 +1,158 @@
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 os
15
+ import sys
16
+ import json
17
+ import functools
18
+ from decimal import Decimal
19
+
20
+ import click
21
+
22
+ from .config import Config
23
+ from ..flows.flow import universal_flow_config_variables
24
+ from ..steps.yosys import verilog_rtl_cfg_vars
25
+ from ..flows.cli import cloup_flow_opts
26
+
27
+
28
+ @click.group
29
+ def cli():
30
+ pass
31
+
32
+
33
+ @click.command()
34
+ @click.option(
35
+ "--file-name",
36
+ type=click.Path(exists=False, file_okay=True, dir_okay=False),
37
+ default="config.json",
38
+ prompt="Please input the file name for the configuration file",
39
+ help="The file name of the configuration file.",
40
+ )
41
+ @click.option(
42
+ "--design-dir",
43
+ type=click.Path(exists=True, dir_okay=True, file_okay=False),
44
+ default=".",
45
+ prompt="Enter the base directory for your design",
46
+ help="The top-level design directory. Typically, the configuration file goes in the design directory as well.",
47
+ )
48
+ @click.option(
49
+ "--design-name",
50
+ "--top-module",
51
+ type=str,
52
+ prompt="Enter the design name (which should be equal to the HDL name of your top module)",
53
+ help="The name of the design, i.e. the name of the top-level module of the design.",
54
+ )
55
+ @click.option(
56
+ "--clock-port",
57
+ type=str,
58
+ prompt="Enter the name of your design's clock port",
59
+ help="The identifier for the clock port.",
60
+ )
61
+ @click.option(
62
+ "--clock-period",
63
+ type=Decimal,
64
+ prompt="Enter your desired clock period in nanoseconds",
65
+ help="The clock period, in nanoseconds.",
66
+ )
67
+ @cloup_flow_opts(
68
+ config_options=False,
69
+ run_options=False,
70
+ sequential_flow_controls=False,
71
+ jobs=False,
72
+ accept_config_files=False,
73
+ )
74
+ @click.argument(
75
+ "source_rtl",
76
+ type=click.Path(
77
+ exists=True,
78
+ dir_okay=False,
79
+ file_okay=True,
80
+ ),
81
+ nargs=-1,
82
+ )
83
+ def create_config(
84
+ pdk_root,
85
+ pdk,
86
+ scl,
87
+ file_name,
88
+ design_name,
89
+ design_dir,
90
+ clock_port,
91
+ clock_period,
92
+ source_rtl,
93
+ ):
94
+ """
95
+ Generates an LibreLane JSON configuration file for a design interactively.
96
+ """
97
+ if len(source_rtl) == 0:
98
+ source_rtl = []
99
+ try:
100
+ while True:
101
+ file = input(
102
+ f"Input the RTL source file #{len(source_rtl)} (Ctrl+D to stop): "
103
+ )
104
+ if not os.path.isfile(file):
105
+ print(f"Invalid file {file}.", file=sys.stderr)
106
+ exit(1)
107
+ source_rtl.append(file)
108
+ except EOFError:
109
+ print("")
110
+ if len(source_rtl) == 0:
111
+ print("At least one source RTL file is required.", file=sys.stderr)
112
+ exit(1)
113
+ source_rtl_key = "VERILOG_FILES"
114
+ if not functools.reduce(
115
+ lambda acc, x: acc and (x.endswith(".sv") or x.endswith(".v")), source_rtl, True
116
+ ):
117
+ print(
118
+ "Only Verilog/SystemVerilog files are supported by create-config.",
119
+ file=sys.stderr,
120
+ )
121
+ exit(-1)
122
+ source_rtl_rel = [f"dir::{os.path.relpath(x, design_dir)}" for x in source_rtl]
123
+ config_dict = {
124
+ "DESIGN_NAME": design_name,
125
+ "CLOCK_PORT": clock_port,
126
+ "CLOCK_PERIOD": clock_period,
127
+ source_rtl_key: source_rtl_rel,
128
+ "meta": {
129
+ "version": 2,
130
+ },
131
+ }
132
+ config, _ = Config.load(
133
+ config_dict,
134
+ universal_flow_config_variables + verilog_rtl_cfg_vars,
135
+ design_dir=design_dir,
136
+ pdk=pdk,
137
+ pdk_root=pdk_root,
138
+ scl=scl,
139
+ )
140
+ with open(file_name, "w") as f:
141
+ print(
142
+ json.dumps(config_dict, cls=config.get_encoder(), indent=4),
143
+ file=f,
144
+ )
145
+
146
+ design_dir_opt = ""
147
+ if os.path.abspath(design_dir) != os.path.abspath(os.path.dirname(file_name)):
148
+ design_dir_opt = f"--design-dir {design_dir} "
149
+
150
+ print(f"Wrote config to '{file_name}'.")
151
+ print("To run this design, invoke:")
152
+ print(f"\tlibrelane {design_dir_opt}{file_name}")
153
+
154
+
155
+ cli.add_command(create_config)
156
+
157
+ if __name__ == "__main__":
158
+ cli()