ciel 0.21.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.
- ciel/__init__.py +29 -0
- ciel/__main__.py +429 -0
- ciel/__version__.py +44 -0
- ciel/build/__init__.py +267 -0
- ciel/build/common.py +98 -0
- ciel/build/gf180mcu.py +263 -0
- ciel/build/git_multi_clone.py +220 -0
- ciel/build/ihp_sg13g2.py +148 -0
- ciel/build/sky130.py +358 -0
- ciel/click_common.py +119 -0
- ciel/common.py +256 -0
- ciel/families.py +119 -0
- ciel/github.py +184 -0
- ciel/manage.py +355 -0
- ciel/py.typed +0 -0
- ciel-0.21.0.dev0.dist-info/METADATA +168 -0
- ciel-0.21.0.dev0.dist-info/RECORD +19 -0
- ciel-0.21.0.dev0.dist-info/WHEEL +4 -0
- ciel-0.21.0.dev0.dist-info/entry_points.txt +3 -0
ciel/build/__init__.py
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# Copyright 2022-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 uuid
|
|
16
|
+
import pathlib
|
|
17
|
+
import tarfile
|
|
18
|
+
import tempfile
|
|
19
|
+
import importlib
|
|
20
|
+
import subprocess
|
|
21
|
+
from typing import Optional, List, Dict
|
|
22
|
+
|
|
23
|
+
import click
|
|
24
|
+
import zstandard as zstd
|
|
25
|
+
from rich.console import Console
|
|
26
|
+
from rich.progress import Progress
|
|
27
|
+
|
|
28
|
+
from ..github import (
|
|
29
|
+
GitHubSession,
|
|
30
|
+
get_commit_date,
|
|
31
|
+
volare_repo,
|
|
32
|
+
)
|
|
33
|
+
from ..common import (
|
|
34
|
+
Version,
|
|
35
|
+
mkdirp,
|
|
36
|
+
resolve_version,
|
|
37
|
+
date_to_iso8601,
|
|
38
|
+
)
|
|
39
|
+
from ..click_common import (
|
|
40
|
+
opt_push,
|
|
41
|
+
opt_build,
|
|
42
|
+
opt_pdk_root,
|
|
43
|
+
opt_token,
|
|
44
|
+
)
|
|
45
|
+
from ..families import Family
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def build(
|
|
49
|
+
pdk_root: str,
|
|
50
|
+
pdk: str,
|
|
51
|
+
version: str,
|
|
52
|
+
jobs: int = 1,
|
|
53
|
+
sram: bool = True, # Deprecated
|
|
54
|
+
clear_build_artifacts: bool = True,
|
|
55
|
+
include_libraries: Optional[List[str]] = None,
|
|
56
|
+
use_repo_at: Optional[List[str]] = None,
|
|
57
|
+
):
|
|
58
|
+
use_repos = {}
|
|
59
|
+
if use_repo_at is not None:
|
|
60
|
+
for repo in use_repo_at:
|
|
61
|
+
name, path = repo.split("=")
|
|
62
|
+
use_repos[name] = os.path.abspath(path)
|
|
63
|
+
|
|
64
|
+
if pdk not in Family.by_name:
|
|
65
|
+
raise Exception(f"Unsupported PDK family '{pdk}'.")
|
|
66
|
+
|
|
67
|
+
kwargs = {
|
|
68
|
+
"pdk_root": pdk_root,
|
|
69
|
+
"version": version,
|
|
70
|
+
"jobs": jobs,
|
|
71
|
+
"clear_build_artifacts": clear_build_artifacts,
|
|
72
|
+
"include_libraries": include_libraries,
|
|
73
|
+
"using_repos": use_repos,
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
build_module = importlib.import_module(f".{pdk}", package=__name__)
|
|
77
|
+
build_function = build_module.build
|
|
78
|
+
build_function(**kwargs)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@click.command("build")
|
|
82
|
+
@opt_token
|
|
83
|
+
@opt_pdk_root
|
|
84
|
+
@opt_build
|
|
85
|
+
@click.option(
|
|
86
|
+
"-f",
|
|
87
|
+
"--metadata-file",
|
|
88
|
+
"tool_metadata_file_path",
|
|
89
|
+
default=None,
|
|
90
|
+
help="Explicitly define a tool metadata file instead of searching for a metadata file",
|
|
91
|
+
)
|
|
92
|
+
@click.argument("version", required=False)
|
|
93
|
+
def build_cmd(
|
|
94
|
+
include_libraries,
|
|
95
|
+
jobs,
|
|
96
|
+
pdk_root,
|
|
97
|
+
pdk,
|
|
98
|
+
clear_build_artifacts,
|
|
99
|
+
tool_metadata_file_path,
|
|
100
|
+
version,
|
|
101
|
+
use_repo_at,
|
|
102
|
+
):
|
|
103
|
+
"""
|
|
104
|
+
Builds the requested PDK.
|
|
105
|
+
|
|
106
|
+
Parameters: <version> (Optional)
|
|
107
|
+
|
|
108
|
+
If a version is not given, and you run this in the top level directory of
|
|
109
|
+
tools with a tool_metadata.yml file, for example OpenLane or DFFRAM,
|
|
110
|
+
the appropriate version will be enabled automatically.
|
|
111
|
+
"""
|
|
112
|
+
if include_libraries == ():
|
|
113
|
+
include_libraries = None
|
|
114
|
+
|
|
115
|
+
console = Console()
|
|
116
|
+
try:
|
|
117
|
+
version = resolve_version(version, tool_metadata_file_path)
|
|
118
|
+
except Exception as e:
|
|
119
|
+
console.print(f"Could not determine open_pdks version: {e}")
|
|
120
|
+
exit(-1)
|
|
121
|
+
|
|
122
|
+
build(
|
|
123
|
+
pdk_root=pdk_root,
|
|
124
|
+
pdk=pdk,
|
|
125
|
+
version=version,
|
|
126
|
+
jobs=jobs,
|
|
127
|
+
clear_build_artifacts=clear_build_artifacts,
|
|
128
|
+
include_libraries=include_libraries,
|
|
129
|
+
use_repo_at=use_repo_at,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def push(
|
|
134
|
+
pdk_root,
|
|
135
|
+
pdk,
|
|
136
|
+
version,
|
|
137
|
+
*,
|
|
138
|
+
owner=volare_repo.owner,
|
|
139
|
+
repository=volare_repo.name,
|
|
140
|
+
pre=False,
|
|
141
|
+
push_libraries=None,
|
|
142
|
+
session: Optional[GitHubSession] = None,
|
|
143
|
+
):
|
|
144
|
+
family = Family.by_name[pdk]
|
|
145
|
+
|
|
146
|
+
if session is None:
|
|
147
|
+
session = GitHubSession()
|
|
148
|
+
if session.github_token is None:
|
|
149
|
+
raise TypeError("No GitHub token was provided.")
|
|
150
|
+
|
|
151
|
+
console = Console()
|
|
152
|
+
|
|
153
|
+
if push_libraries is None or len(push_libraries) == 0:
|
|
154
|
+
push_libraries = family.all_libraries
|
|
155
|
+
library_list = set(push_libraries)
|
|
156
|
+
|
|
157
|
+
version_object = Version(version, pdk)
|
|
158
|
+
version_directory = version_object.get_dir(pdk_root)
|
|
159
|
+
if not os.path.isdir(version_directory):
|
|
160
|
+
raise FileNotFoundError(f"Version {version} not found.")
|
|
161
|
+
|
|
162
|
+
tempdir = tempfile.gettempdir()
|
|
163
|
+
tarball_directory = os.path.join(tempdir, "cielo", f"{uuid.uuid4()}", version)
|
|
164
|
+
mkdirp(tarball_directory)
|
|
165
|
+
|
|
166
|
+
final_tarballs = []
|
|
167
|
+
|
|
168
|
+
with Progress() as progress:
|
|
169
|
+
collections: Dict[str, List[str]] = {"common": []}
|
|
170
|
+
path_it = pathlib.Path(version_directory).glob("**/*")
|
|
171
|
+
for path in path_it:
|
|
172
|
+
if not path.is_file():
|
|
173
|
+
continue
|
|
174
|
+
relative = os.path.relpath(path, version_directory)
|
|
175
|
+
path_components = relative.split(os.sep)
|
|
176
|
+
if path_components[1] == "libs.ref":
|
|
177
|
+
lib = path_components[2]
|
|
178
|
+
if lib not in library_list:
|
|
179
|
+
continue
|
|
180
|
+
collections[lib] = collections.get(lib) or []
|
|
181
|
+
collections[lib].append(str(path))
|
|
182
|
+
else:
|
|
183
|
+
collections["common"].append(str(path))
|
|
184
|
+
|
|
185
|
+
for name, files in collections.items():
|
|
186
|
+
tarball_path = os.path.join(tarball_directory, f"{name}.tar.zst")
|
|
187
|
+
task = progress.add_task(f"Compressing {name}…", total=len(files))
|
|
188
|
+
with zstd.open(tarball_path, mode="wb") as stream:
|
|
189
|
+
with tarfile.TarFile(fileobj=stream, mode="w") as tf:
|
|
190
|
+
for i, file in enumerate(files):
|
|
191
|
+
progress.update(task, completed=i + 1)
|
|
192
|
+
path_in_tarball = os.path.relpath(file, version_directory)
|
|
193
|
+
tf.add(file, arcname=path_in_tarball)
|
|
194
|
+
console.log(f"\nCompressed to {tarball_path}.")
|
|
195
|
+
progress.remove_task(task)
|
|
196
|
+
final_tarballs.append(tarball_path)
|
|
197
|
+
|
|
198
|
+
tag = f"{pdk}-{version}"
|
|
199
|
+
|
|
200
|
+
# If someone wants to rewrite this to not use ghr, please, by all means.
|
|
201
|
+
console.log("Starting upload…")
|
|
202
|
+
|
|
203
|
+
body = f"{pdk} variants built using cielo"
|
|
204
|
+
date = get_commit_date(version, family.repo, session)
|
|
205
|
+
if date is not None:
|
|
206
|
+
body = f"{pdk} variants (released on {date_to_iso8601(date)})"
|
|
207
|
+
|
|
208
|
+
for tarball_path in final_tarballs:
|
|
209
|
+
subprocess.check_call(
|
|
210
|
+
[
|
|
211
|
+
"ghr",
|
|
212
|
+
"-owner",
|
|
213
|
+
owner,
|
|
214
|
+
"-repository",
|
|
215
|
+
repository,
|
|
216
|
+
"-token",
|
|
217
|
+
session.github_token,
|
|
218
|
+
"-body",
|
|
219
|
+
body,
|
|
220
|
+
"-commitish",
|
|
221
|
+
"releases",
|
|
222
|
+
"-replace",
|
|
223
|
+
]
|
|
224
|
+
+ (["-prerelease"] if pre else [])
|
|
225
|
+
+ [
|
|
226
|
+
tag,
|
|
227
|
+
tarball_path,
|
|
228
|
+
]
|
|
229
|
+
)
|
|
230
|
+
console.log("Done.")
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
@click.command("push", hidden=True)
|
|
234
|
+
@opt_token
|
|
235
|
+
@opt_pdk_root
|
|
236
|
+
@opt_push
|
|
237
|
+
@click.argument("version")
|
|
238
|
+
def push_cmd(
|
|
239
|
+
owner,
|
|
240
|
+
repository,
|
|
241
|
+
pre,
|
|
242
|
+
pdk_root,
|
|
243
|
+
pdk,
|
|
244
|
+
version,
|
|
245
|
+
push_libraries,
|
|
246
|
+
):
|
|
247
|
+
"""
|
|
248
|
+
For maintainers: Package and release a build to the public.
|
|
249
|
+
|
|
250
|
+
Requires ghr: github.com/tcnksm/ghr
|
|
251
|
+
|
|
252
|
+
Parameters: <version> (required)
|
|
253
|
+
"""
|
|
254
|
+
console = Console()
|
|
255
|
+
try:
|
|
256
|
+
push(
|
|
257
|
+
pdk_root,
|
|
258
|
+
pdk,
|
|
259
|
+
version,
|
|
260
|
+
owner=owner,
|
|
261
|
+
repository=repository,
|
|
262
|
+
pre=pre,
|
|
263
|
+
push_libraries=push_libraries,
|
|
264
|
+
)
|
|
265
|
+
except Exception as e:
|
|
266
|
+
console.print(f"[red]Failed to push version: {e}")
|
|
267
|
+
exit(-1)
|
ciel/build/common.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Copyright 2022-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 shutil
|
|
16
|
+
import subprocess
|
|
17
|
+
|
|
18
|
+
from cielo.github import GitHubSession
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def open_pdks_fix_makefile(at_path: str):
|
|
22
|
+
backup_path = f"{at_path}.bak"
|
|
23
|
+
shutil.move(at_path, backup_path)
|
|
24
|
+
|
|
25
|
+
fix_fi = False
|
|
26
|
+
|
|
27
|
+
with open(backup_path, "r") as file_in, open(at_path, "w") as file_out:
|
|
28
|
+
for line in file_in:
|
|
29
|
+
if "_COMMIT = `" in line:
|
|
30
|
+
line = line.replace("_COMMIT = ", "_COMMIT=")
|
|
31
|
+
if fix_fi:
|
|
32
|
+
file_out.write(line.replace("fi", "fi ; \\"))
|
|
33
|
+
fix_fi = False
|
|
34
|
+
else:
|
|
35
|
+
file_out.write(line)
|
|
36
|
+
if "_COMMIT=`" in line:
|
|
37
|
+
fix_fi = True
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def patch_open_pdks(at_path: str):
|
|
41
|
+
"""
|
|
42
|
+
This functions applies various patches based on the current version of
|
|
43
|
+
open_pdks in use.
|
|
44
|
+
"""
|
|
45
|
+
head = subprocess.check_output(
|
|
46
|
+
["git", "rev-parse", "HEAD"], cwd=at_path, encoding="utf8"
|
|
47
|
+
).strip()
|
|
48
|
+
|
|
49
|
+
def is_ancestor(commit: str):
|
|
50
|
+
nonlocal head, at_path
|
|
51
|
+
return (
|
|
52
|
+
subprocess.call(
|
|
53
|
+
["git", "merge-base", "--is-ancestor", commit, head],
|
|
54
|
+
stdout=open(os.devnull, "w"),
|
|
55
|
+
stderr=open(os.devnull, "w"),
|
|
56
|
+
cwd=at_path,
|
|
57
|
+
)
|
|
58
|
+
== 0
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
can_build = is_ancestor(
|
|
62
|
+
"c74daac794c83327e54b91cbaf426f722574665c"
|
|
63
|
+
) # First one with --with-reference
|
|
64
|
+
if not can_build:
|
|
65
|
+
print(
|
|
66
|
+
f"Commit {head} cannot be built using Cielo: the minimum version of open_pdks buildable with Cielo is 1.0.381."
|
|
67
|
+
)
|
|
68
|
+
exit(-1)
|
|
69
|
+
|
|
70
|
+
gf180mcu_sources_ok = is_ancestor(
|
|
71
|
+
"c1e2118846fd216b2c065a216950e75d2d67ccb8"
|
|
72
|
+
) # gf180mcu sources fix
|
|
73
|
+
if not gf180mcu_sources_ok:
|
|
74
|
+
print(
|
|
75
|
+
"Patching gf180mcu Makefile.in…",
|
|
76
|
+
)
|
|
77
|
+
open_pdks_fix_makefile(os.path.join(at_path, "gf180mcu", "Makefile.in"))
|
|
78
|
+
|
|
79
|
+
download_script_ok = is_ancestor(
|
|
80
|
+
"ebffedd16788db327af050ac01c3fb1558ebffd1"
|
|
81
|
+
) # download script fix
|
|
82
|
+
if not download_script_ok:
|
|
83
|
+
print("Replacing download.sh…")
|
|
84
|
+
session = GitHubSession()
|
|
85
|
+
r = session.get(
|
|
86
|
+
"https://raw.githubusercontent.com/RTimothyEdwards/open_pdks/ebffedd16788db327af050ac01c3fb1558ebffd1/scripts/download.sh"
|
|
87
|
+
)
|
|
88
|
+
with open(os.path.join(at_path, "scripts", "download.sh"), "wb") as f:
|
|
89
|
+
f.write(r.content)
|
|
90
|
+
|
|
91
|
+
sky130_sources_ok = is_ancestor(
|
|
92
|
+
"274040274a7dfb5fd2c69e0e9c643f80507df3fe"
|
|
93
|
+
) # sky130 sources fix
|
|
94
|
+
if not sky130_sources_ok:
|
|
95
|
+
print(
|
|
96
|
+
"Patching sky130 Makefile.in…",
|
|
97
|
+
)
|
|
98
|
+
open_pdks_fix_makefile(os.path.join(at_path, "sky130", "Makefile.in"))
|
ciel/build/gf180mcu.py
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# Copyright 2022-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 io
|
|
16
|
+
import json
|
|
17
|
+
import shlex
|
|
18
|
+
import shutil
|
|
19
|
+
import subprocess
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
from typing import Optional, List, Tuple, Dict
|
|
22
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
23
|
+
|
|
24
|
+
import pcpp
|
|
25
|
+
from rich.console import Console
|
|
26
|
+
from rich.progress import Progress
|
|
27
|
+
|
|
28
|
+
from .git_multi_clone import GitMultiClone
|
|
29
|
+
from .common import patch_open_pdks
|
|
30
|
+
from ..families import Family
|
|
31
|
+
from ..github import opdks_repo
|
|
32
|
+
from ..common import (
|
|
33
|
+
Version,
|
|
34
|
+
get_cielo_dir,
|
|
35
|
+
mkdirp,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
MAGIC_DEFAULT_TAG = "085131b090cb511d785baf52a10cf6df8a657d44"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_open_pdks(
|
|
42
|
+
version, build_directory, jobs=1, repo_path=None
|
|
43
|
+
) -> Tuple[str, Optional[str], Optional[str]]:
|
|
44
|
+
try:
|
|
45
|
+
console = Console()
|
|
46
|
+
|
|
47
|
+
open_pdks_repo = None
|
|
48
|
+
if repo_path is None:
|
|
49
|
+
with Progress() as progress:
|
|
50
|
+
with ThreadPoolExecutor(max_workers=jobs) as executor:
|
|
51
|
+
gmc = GitMultiClone(build_directory, progress)
|
|
52
|
+
open_pdks_future = executor.submit(
|
|
53
|
+
GitMultiClone.clone,
|
|
54
|
+
gmc,
|
|
55
|
+
opdks_repo.link,
|
|
56
|
+
version,
|
|
57
|
+
default_branch="master",
|
|
58
|
+
)
|
|
59
|
+
open_pdks_repo = open_pdks_future.result()
|
|
60
|
+
repo_path = open_pdks_repo.path
|
|
61
|
+
|
|
62
|
+
console.log(f"Done fetching {open_pdks_repo.name}.")
|
|
63
|
+
else:
|
|
64
|
+
console.log(f"Using open_pdks at {repo_path} unaltered.")
|
|
65
|
+
|
|
66
|
+
patch_open_pdks(repo_path)
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
json_raw = open(f"{repo_path}/gf180mcu/gf180mcu.json").read()
|
|
70
|
+
cpp = pcpp.Preprocessor()
|
|
71
|
+
cpp.line_directive = None
|
|
72
|
+
cpp.parse(json_raw)
|
|
73
|
+
json_str = None
|
|
74
|
+
with io.StringIO() as sio:
|
|
75
|
+
cpp.write(sio)
|
|
76
|
+
json_str = sio.getvalue()
|
|
77
|
+
manifest = json.loads(json_str)
|
|
78
|
+
reference_commits = manifest["reference"]
|
|
79
|
+
print(f"Reference commits: {reference_commits}")
|
|
80
|
+
except FileNotFoundError:
|
|
81
|
+
console.log("Warning: Couldn't find open_pdks/sky130 JSON manifest.")
|
|
82
|
+
except json.JSONDecodeError:
|
|
83
|
+
console.log("Warning: Failed to parse open_pdks/sky130 JSON manifest..")
|
|
84
|
+
except KeyError:
|
|
85
|
+
console.log(
|
|
86
|
+
"Warning: Failed to extract reference commits from open_pdks/sky130 JSON manifest."
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
return repo_path
|
|
90
|
+
|
|
91
|
+
except subprocess.CalledProcessError as e:
|
|
92
|
+
print(e)
|
|
93
|
+
print(e.stderr)
|
|
94
|
+
exit(-1)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
LIB_FLAG_MAP = {
|
|
98
|
+
"gf180mcu_fd_pr": "--enable-primitive-gf180mcu",
|
|
99
|
+
"gf180mcu_fd_sc_mcu7t5v0": "--enable-sc-7t5v0-gf180mcu",
|
|
100
|
+
"gf180mcu_fd_sc_mcu9t5v0": "--enable-sc-9t5v0-gf180mcu",
|
|
101
|
+
"gf180mcu_fd_io": "--enable-io-gf180mcu",
|
|
102
|
+
"gf180mcu_fd_ip_sram": "--enable-sram-gf180mcu",
|
|
103
|
+
"gf180mcu_osu_sc_gp12t3v3": "--enable-osu-sc-gf180mcu",
|
|
104
|
+
"gf180mcu_osu_sc_gp9t3v3": "--enable-osu-sc-gf180mcu",
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def build_variants(
|
|
109
|
+
magic_bin, include_libraries, build_directory, open_pdks_path, log_dir, jobs=1
|
|
110
|
+
):
|
|
111
|
+
try:
|
|
112
|
+
pdk_root_abs = os.path.abspath(build_directory)
|
|
113
|
+
console = Console()
|
|
114
|
+
|
|
115
|
+
def run_sh(script, log_to):
|
|
116
|
+
output_file = open(log_to, "w")
|
|
117
|
+
try:
|
|
118
|
+
subprocess.check_call(
|
|
119
|
+
["sh", "-c", script],
|
|
120
|
+
cwd=open_pdks_path,
|
|
121
|
+
stdout=output_file,
|
|
122
|
+
stderr=output_file,
|
|
123
|
+
stdin=open(os.devnull),
|
|
124
|
+
)
|
|
125
|
+
except subprocess.CalledProcessError as e:
|
|
126
|
+
console.log(
|
|
127
|
+
f"An error occurred while building the PDK. Check {log_to} for more information."
|
|
128
|
+
)
|
|
129
|
+
raise e
|
|
130
|
+
|
|
131
|
+
library_flags = set([LIB_FLAG_MAP[library] for library in include_libraries])
|
|
132
|
+
library_flags_disable = set(
|
|
133
|
+
[
|
|
134
|
+
LIB_FLAG_MAP[library].replace("enable", "disable")
|
|
135
|
+
for library in LIB_FLAG_MAP
|
|
136
|
+
if library not in include_libraries
|
|
137
|
+
]
|
|
138
|
+
)
|
|
139
|
+
magic_dirname = os.path.dirname(magic_bin)
|
|
140
|
+
|
|
141
|
+
configuration_flags = ["--enable-gf180mcu-pdk", "--with-reference"] + list(
|
|
142
|
+
library_flags.union(library_flags_disable)
|
|
143
|
+
)
|
|
144
|
+
console.log(f"Configuring with flags {shlex.join(configuration_flags)}")
|
|
145
|
+
|
|
146
|
+
with console.status("Configuring open_pdks…"):
|
|
147
|
+
run_sh(
|
|
148
|
+
f"""
|
|
149
|
+
set -e
|
|
150
|
+
export PATH="{magic_dirname}:$PATH"
|
|
151
|
+
./configure {shlex.join(configuration_flags)}
|
|
152
|
+
""",
|
|
153
|
+
log_to=os.path.join(log_dir, "config.log"),
|
|
154
|
+
)
|
|
155
|
+
console.log("Configured open_pdks.")
|
|
156
|
+
|
|
157
|
+
with console.status("Building variants using open_pdks…"):
|
|
158
|
+
run_sh(
|
|
159
|
+
f"""
|
|
160
|
+
set -e
|
|
161
|
+
export LC_ALL=en_US.UTF-8
|
|
162
|
+
export PATH="{magic_dirname}:$PATH"
|
|
163
|
+
make -j{jobs}
|
|
164
|
+
make 'SHARED_PDKS_PATH={pdk_root_abs}' install
|
|
165
|
+
""",
|
|
166
|
+
log_to=os.path.join(log_dir, "install.log"),
|
|
167
|
+
)
|
|
168
|
+
console.log("Built PDK variants.")
|
|
169
|
+
with console.status("Cleaning build artifacts…"):
|
|
170
|
+
run_sh(
|
|
171
|
+
"""
|
|
172
|
+
set -e
|
|
173
|
+
rm -rf sources
|
|
174
|
+
""",
|
|
175
|
+
log_to=os.path.join(log_dir, "clean.log"),
|
|
176
|
+
)
|
|
177
|
+
console.log("Cleaned build artifacts.")
|
|
178
|
+
|
|
179
|
+
console.log("Done.")
|
|
180
|
+
|
|
181
|
+
except subprocess.CalledProcessError as e:
|
|
182
|
+
print(e)
|
|
183
|
+
print(e.stderr)
|
|
184
|
+
exit(-1)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def install_gf180mcu(build_directory, pdk_root, version):
|
|
188
|
+
console = Console()
|
|
189
|
+
with console.status("Adding build to list of installed versions…"):
|
|
190
|
+
version_directory = Version(version, "gf180mcu").get_dir(pdk_root)
|
|
191
|
+
if (
|
|
192
|
+
os.path.exists(version_directory)
|
|
193
|
+
and len(os.listdir(version_directory)) != 0
|
|
194
|
+
):
|
|
195
|
+
backup_path = version_directory
|
|
196
|
+
it = 0
|
|
197
|
+
while os.path.exists(backup_path) and len(os.listdir(backup_path)) != 0:
|
|
198
|
+
it += 1
|
|
199
|
+
backup_path = Version(f"{version}.bk{it}", "gf180mcu").get_dir(pdk_root)
|
|
200
|
+
console.log(
|
|
201
|
+
f"Build already found at {version_directory}, moving to {backup_path}…"
|
|
202
|
+
)
|
|
203
|
+
shutil.move(version_directory, backup_path)
|
|
204
|
+
|
|
205
|
+
console.log("Copying…")
|
|
206
|
+
mkdirp(version_directory)
|
|
207
|
+
|
|
208
|
+
gf180mcu_family = Family.by_name["gf180mcu"]
|
|
209
|
+
|
|
210
|
+
for variant in gf180mcu_family.variants:
|
|
211
|
+
variant_build_path = os.path.join(build_directory, variant)
|
|
212
|
+
variant_install_path = os.path.join(version_directory, variant)
|
|
213
|
+
if os.path.isdir(variant_build_path):
|
|
214
|
+
shutil.copytree(variant_build_path, variant_install_path)
|
|
215
|
+
|
|
216
|
+
console.log("Done.")
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def build(
|
|
220
|
+
pdk_root: str,
|
|
221
|
+
version: str,
|
|
222
|
+
jobs: int = 1,
|
|
223
|
+
clear_build_artifacts: bool = True,
|
|
224
|
+
include_libraries: Optional[List[str]] = None,
|
|
225
|
+
using_repos: Optional[Dict[str, str]] = None,
|
|
226
|
+
):
|
|
227
|
+
family = Family.by_name["gf180mcu"]
|
|
228
|
+
library_set = family.resolve_libraries(include_libraries)
|
|
229
|
+
|
|
230
|
+
if using_repos is None:
|
|
231
|
+
using_repos = {}
|
|
232
|
+
|
|
233
|
+
timestamp = datetime.now().strftime("build_gf180mcu-%Y-%m-%d-%H-%M-%S")
|
|
234
|
+
build_directory = os.path.join(
|
|
235
|
+
get_cielo_dir(pdk_root, "gf180mcu"), "build", version
|
|
236
|
+
)
|
|
237
|
+
log_dir = os.path.join(build_directory, "logs", timestamp)
|
|
238
|
+
mkdirp(log_dir)
|
|
239
|
+
|
|
240
|
+
console = Console()
|
|
241
|
+
console.log(f"Logging to '{log_dir}'…")
|
|
242
|
+
|
|
243
|
+
open_pdks_path = get_open_pdks(
|
|
244
|
+
version, build_directory, jobs, using_repos.get("open_pdks")
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
magic_bin = shutil.which("magic")
|
|
248
|
+
if magic_bin is None:
|
|
249
|
+
print("Magic is either not installed or not in PATH.")
|
|
250
|
+
exit(-1)
|
|
251
|
+
|
|
252
|
+
build_variants(
|
|
253
|
+
magic_bin,
|
|
254
|
+
library_set,
|
|
255
|
+
build_directory,
|
|
256
|
+
open_pdks_path,
|
|
257
|
+
log_dir,
|
|
258
|
+
jobs,
|
|
259
|
+
)
|
|
260
|
+
install_gf180mcu(build_directory, pdk_root, version)
|
|
261
|
+
|
|
262
|
+
if clear_build_artifacts:
|
|
263
|
+
shutil.rmtree(build_directory)
|