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.
- librelane/__init__.py +38 -0
- librelane/__main__.py +470 -0
- librelane/__version__.py +43 -0
- librelane/common/__init__.py +61 -0
- librelane/common/cli.py +75 -0
- librelane/common/drc.py +245 -0
- librelane/common/generic_dict.py +319 -0
- librelane/common/metrics/__init__.py +35 -0
- librelane/common/metrics/__main__.py +413 -0
- librelane/common/metrics/library.py +354 -0
- librelane/common/metrics/metric.py +186 -0
- librelane/common/metrics/util.py +279 -0
- librelane/common/misc.py +402 -0
- librelane/common/ring_buffer.py +63 -0
- librelane/common/tcl.py +80 -0
- librelane/common/toolbox.py +549 -0
- librelane/common/tpe.py +41 -0
- librelane/common/types.py +117 -0
- librelane/config/__init__.py +32 -0
- librelane/config/__main__.py +158 -0
- librelane/config/config.py +1025 -0
- librelane/config/flow.py +490 -0
- librelane/config/pdk_compat.py +255 -0
- librelane/config/preprocessor.py +464 -0
- librelane/config/removals.py +45 -0
- librelane/config/variable.py +722 -0
- librelane/container.py +264 -0
- librelane/env_info.py +306 -0
- librelane/examples/spm/config.yaml +33 -0
- librelane/examples/spm/pin_order.cfg +14 -0
- librelane/examples/spm/src/impl.sdc +73 -0
- librelane/examples/spm/src/signoff.sdc +68 -0
- librelane/examples/spm/src/spm.v +73 -0
- librelane/examples/spm/verify/spm_tb.v +106 -0
- librelane/examples/spm-user_project_wrapper/SPM_example.v +286 -0
- librelane/examples/spm-user_project_wrapper/base_sdc_file.sdc +145 -0
- librelane/examples/spm-user_project_wrapper/config-tut.json +12 -0
- librelane/examples/spm-user_project_wrapper/config.json +13 -0
- librelane/examples/spm-user_project_wrapper/defines.v +66 -0
- librelane/examples/spm-user_project_wrapper/template.def +7656 -0
- librelane/examples/spm-user_project_wrapper/user_project_wrapper.v +123 -0
- librelane/flows/__init__.py +24 -0
- librelane/flows/builtins.py +18 -0
- librelane/flows/classic.py +330 -0
- librelane/flows/cli.py +463 -0
- librelane/flows/flow.py +985 -0
- librelane/flows/misc.py +71 -0
- librelane/flows/optimizing.py +179 -0
- librelane/flows/sequential.py +367 -0
- librelane/flows/synth_explore.py +173 -0
- librelane/logging/__init__.py +40 -0
- librelane/logging/logger.py +323 -0
- librelane/open_pdks_rev +1 -0
- librelane/plugins.py +21 -0
- librelane/py.typed +0 -0
- librelane/scripts/base.sdc +80 -0
- librelane/scripts/klayout/Readme.md +2 -0
- librelane/scripts/klayout/open_design.py +63 -0
- librelane/scripts/klayout/render.py +121 -0
- librelane/scripts/klayout/stream_out.py +176 -0
- librelane/scripts/klayout/xml_drc_report_to_json.py +45 -0
- librelane/scripts/klayout/xor.drc +120 -0
- librelane/scripts/magic/Readme.md +1 -0
- librelane/scripts/magic/common/read.tcl +114 -0
- librelane/scripts/magic/def/antenna_check.tcl +35 -0
- librelane/scripts/magic/def/mag.tcl +19 -0
- librelane/scripts/magic/def/mag_gds.tcl +81 -0
- librelane/scripts/magic/drc.tcl +79 -0
- librelane/scripts/magic/extract_spice.tcl +98 -0
- librelane/scripts/magic/gds/drc_batch.tcl +74 -0
- librelane/scripts/magic/gds/erase_box.tcl +32 -0
- librelane/scripts/magic/gds/extras_mag.tcl +47 -0
- librelane/scripts/magic/gds/mag_with_pointers.tcl +32 -0
- librelane/scripts/magic/get_bbox.tcl +11 -0
- librelane/scripts/magic/lef/extras_maglef.tcl +63 -0
- librelane/scripts/magic/lef/maglef.tcl +27 -0
- librelane/scripts/magic/lef.tcl +57 -0
- librelane/scripts/magic/open.tcl +28 -0
- librelane/scripts/magic/wrapper.tcl +19 -0
- librelane/scripts/netgen/setup.tcl +28 -0
- librelane/scripts/odbpy/apply_def_template.py +49 -0
- librelane/scripts/odbpy/cell_frequency.py +107 -0
- librelane/scripts/odbpy/check_antenna_properties.py +116 -0
- librelane/scripts/odbpy/contextualize.py +109 -0
- librelane/scripts/odbpy/defutil.py +574 -0
- librelane/scripts/odbpy/diodes.py +373 -0
- librelane/scripts/odbpy/disconnected_pins.py +305 -0
- librelane/scripts/odbpy/exception_codes.py +17 -0
- librelane/scripts/odbpy/filter_unannotated.py +100 -0
- librelane/scripts/odbpy/io_place.py +482 -0
- librelane/scripts/odbpy/label_macro_pins.py +277 -0
- librelane/scripts/odbpy/lefutil.py +97 -0
- librelane/scripts/odbpy/placers.py +162 -0
- librelane/scripts/odbpy/power_utils.py +395 -0
- librelane/scripts/odbpy/random_place.py +57 -0
- librelane/scripts/odbpy/reader.py +246 -0
- librelane/scripts/odbpy/remove_buffers.py +173 -0
- librelane/scripts/odbpy/snap_to_grid.py +57 -0
- librelane/scripts/odbpy/wire_lengths.py +93 -0
- librelane/scripts/openroad/antenna_check.tcl +20 -0
- librelane/scripts/openroad/antenna_repair.tcl +31 -0
- librelane/scripts/openroad/basic_mp.tcl +24 -0
- librelane/scripts/openroad/buffer_list.tcl +10 -0
- librelane/scripts/openroad/common/dpl.tcl +24 -0
- librelane/scripts/openroad/common/dpl_cell_pad.tcl +26 -0
- librelane/scripts/openroad/common/grt.tcl +32 -0
- librelane/scripts/openroad/common/io.tcl +476 -0
- librelane/scripts/openroad/common/pdn_cfg.tcl +135 -0
- librelane/scripts/openroad/common/resizer.tcl +103 -0
- librelane/scripts/openroad/common/set_global_connections.tcl +78 -0
- librelane/scripts/openroad/common/set_layer_adjustments.tcl +31 -0
- librelane/scripts/openroad/common/set_power_nets.tcl +30 -0
- librelane/scripts/openroad/common/set_rc.tcl +75 -0
- librelane/scripts/openroad/common/set_routing_layers.tcl +30 -0
- librelane/scripts/openroad/cts.tcl +80 -0
- librelane/scripts/openroad/cut_rows.tcl +24 -0
- librelane/scripts/openroad/dpl.tcl +24 -0
- librelane/scripts/openroad/drt.tcl +37 -0
- librelane/scripts/openroad/fill.tcl +30 -0
- librelane/scripts/openroad/floorplan.tcl +145 -0
- librelane/scripts/openroad/gpl.tcl +88 -0
- librelane/scripts/openroad/grt.tcl +30 -0
- librelane/scripts/openroad/gui.tcl +15 -0
- librelane/scripts/openroad/insert_buffer.tcl +127 -0
- librelane/scripts/openroad/ioplacer.tcl +67 -0
- librelane/scripts/openroad/irdrop.tcl +51 -0
- librelane/scripts/openroad/pdn.tcl +52 -0
- librelane/scripts/openroad/rcx.tcl +32 -0
- librelane/scripts/openroad/repair_design.tcl +70 -0
- librelane/scripts/openroad/repair_design_postgrt.tcl +48 -0
- librelane/scripts/openroad/rsz_timing_postcts.tcl +68 -0
- librelane/scripts/openroad/rsz_timing_postgrt.tcl +70 -0
- librelane/scripts/openroad/sta/check_macro_instances.tcl +53 -0
- librelane/scripts/openroad/sta/corner.tcl +393 -0
- librelane/scripts/openroad/tapcell.tcl +25 -0
- librelane/scripts/openroad/write_views.tcl +27 -0
- librelane/scripts/pyosys/construct_abc_script.py +177 -0
- librelane/scripts/pyosys/json_header.py +84 -0
- librelane/scripts/pyosys/synthesize.py +493 -0
- librelane/scripts/pyosys/ys_common.py +153 -0
- librelane/scripts/tclsh/hello.tcl +1 -0
- librelane/state/__init__.py +24 -0
- librelane/state/__main__.py +61 -0
- librelane/state/design_format.py +180 -0
- librelane/state/state.py +351 -0
- librelane/steps/__init__.py +61 -0
- librelane/steps/__main__.py +511 -0
- librelane/steps/checker.py +637 -0
- librelane/steps/common_variables.py +340 -0
- librelane/steps/cvc_rv.py +169 -0
- librelane/steps/klayout.py +509 -0
- librelane/steps/magic.py +566 -0
- librelane/steps/misc.py +160 -0
- librelane/steps/netgen.py +253 -0
- librelane/steps/odb.py +955 -0
- librelane/steps/openroad.py +2433 -0
- librelane/steps/openroad_alerts.py +102 -0
- librelane/steps/pyosys.py +629 -0
- librelane/steps/step.py +1547 -0
- librelane/steps/tclstep.py +288 -0
- librelane/steps/verilator.py +222 -0
- librelane/steps/yosys.py +371 -0
- librelane-2.4.0.dev0.dist-info/METADATA +151 -0
- librelane-2.4.0.dev0.dist-info/RECORD +166 -0
- librelane-2.4.0.dev0.dist-info/WHEEL +4 -0
- librelane-2.4.0.dev0.dist-info/entry_points.txt +8 -0
librelane/common/tpe.py
ADDED
|
@@ -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()
|