siliconcompiler 0.29.0__py3-none-any.whl → 0.29.1__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.
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/__init__.py +26 -0
- siliconcompiler/apps/utils/replay.py +96 -38
- siliconcompiler/checklists/__init__.py +12 -0
- siliconcompiler/core.py +75 -10
- siliconcompiler/flows/__init__.py +34 -0
- siliconcompiler/flows/showflow.py +1 -1
- siliconcompiler/libs/__init__.py +5 -0
- siliconcompiler/optimizer/__init__.py +199 -0
- siliconcompiler/optimizer/vizier.py +259 -0
- siliconcompiler/pdks/__init__.py +5 -0
- siliconcompiler/scheduler/__init__.py +67 -49
- siliconcompiler/scheduler/send_messages.py +1 -1
- siliconcompiler/schema/schema_cfg.py +2 -2
- siliconcompiler/schema/schema_obj.py +13 -10
- siliconcompiler/schema/utils.py +2 -0
- siliconcompiler/sphinx_ext/__init__.py +85 -0
- siliconcompiler/sphinx_ext/dynamicgen.py +17 -33
- siliconcompiler/sphinx_ext/schemagen.py +3 -2
- siliconcompiler/targets/__init__.py +26 -0
- siliconcompiler/templates/replay/replay.py.j2 +62 -0
- siliconcompiler/templates/replay/requirements.txt +2 -1
- siliconcompiler/templates/replay/setup.sh +119 -6
- siliconcompiler/tools/__init__.py +60 -0
- siliconcompiler/tools/_common/asic.py +7 -6
- siliconcompiler/tools/ghdl/ghdl.py +1 -2
- siliconcompiler/tools/klayout/convert_drc_db.py +1 -1
- siliconcompiler/tools/klayout/drc.py +1 -1
- siliconcompiler/tools/klayout/export.py +8 -1
- siliconcompiler/tools/klayout/klayout.py +2 -2
- siliconcompiler/tools/klayout/klayout_convert_drc_db.py +2 -2
- siliconcompiler/tools/klayout/klayout_export.py +7 -5
- siliconcompiler/tools/klayout/klayout_operations.py +4 -3
- siliconcompiler/tools/klayout/klayout_show.py +3 -2
- siliconcompiler/tools/klayout/klayout_utils.py +1 -1
- siliconcompiler/tools/klayout/operations.py +8 -0
- siliconcompiler/tools/klayout/screenshot.py +6 -1
- siliconcompiler/tools/klayout/show.py +8 -1
- siliconcompiler/tools/magic/magic.py +1 -1
- siliconcompiler/tools/openroad/__init__.py +1 -1
- siliconcompiler/tools/openroad/_apr.py +2 -1
- siliconcompiler/tools/openroad/init_floorplan.py +1 -1
- siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +1 -1
- siliconcompiler/tools/openroad/scripts/apr/sc_clock_tree_synthesis.tcl +4 -0
- siliconcompiler/tools/openroad/scripts/apr/sc_repair_timing.tcl +2 -2
- siliconcompiler/tools/openroad/scripts/common/procs.tcl +52 -0
- siliconcompiler/tools/openroad/scripts/common/reports.tcl +1 -1
- siliconcompiler/tools/openroad/scripts/sc_show.tcl +5 -0
- siliconcompiler/tools/opensta/__init__.py +1 -1
- siliconcompiler/tools/opensta/check_library.py +27 -0
- siliconcompiler/tools/opensta/scripts/sc_check_library.tcl +255 -0
- siliconcompiler/tools/opensta/scripts/sc_timing.tcl +1 -1
- siliconcompiler/tools/sv2v/sv2v.py +1 -2
- siliconcompiler/tools/verilator/verilator.py +6 -7
- siliconcompiler/tools/vivado/vivado.py +1 -1
- siliconcompiler/tools/yosys/__init__.py +149 -0
- siliconcompiler/tools/yosys/lec.py +22 -9
- siliconcompiler/tools/yosys/sc_lec.tcl +94 -49
- siliconcompiler/tools/yosys/sc_syn.tcl +1 -0
- siliconcompiler/tools/yosys/screenshot.py +2 -2
- siliconcompiler/tools/yosys/syn_asic.py +98 -74
- siliconcompiler/tools/yosys/syn_asic.tcl +31 -6
- siliconcompiler/tools/yosys/syn_fpga.py +2 -3
- siliconcompiler/tools/yosys/syn_fpga.tcl +0 -1
- siliconcompiler/toolscripts/_tools.json +3 -3
- siliconcompiler/utils/__init__.py +7 -3
- {siliconcompiler-0.29.0.dist-info → siliconcompiler-0.29.1.dist-info}/METADATA +13 -10
- {siliconcompiler-0.29.0.dist-info → siliconcompiler-0.29.1.dist-info}/RECORD +72 -82
- {siliconcompiler-0.29.0.dist-info → siliconcompiler-0.29.1.dist-info}/WHEEL +1 -1
- {siliconcompiler-0.29.0.dist-info → siliconcompiler-0.29.1.dist-info}/entry_points.txt +13 -0
- siliconcompiler/libs/asap7sc7p5t.py +0 -8
- siliconcompiler/libs/gf180mcu.py +0 -8
- siliconcompiler/libs/interposer.py +0 -8
- siliconcompiler/libs/nangate45.py +0 -8
- siliconcompiler/libs/sg13g2_stdcell.py +0 -8
- siliconcompiler/libs/sky130hd.py +0 -8
- siliconcompiler/libs/sky130io.py +0 -8
- siliconcompiler/pdks/asap7.py +0 -8
- siliconcompiler/pdks/freepdk45.py +0 -8
- siliconcompiler/pdks/gf180.py +0 -8
- siliconcompiler/pdks/ihp130.py +0 -8
- siliconcompiler/pdks/interposer.py +0 -8
- siliconcompiler/pdks/skywater130.py +0 -8
- siliconcompiler/templates/replay/run.py.j2 +0 -22
- siliconcompiler/tools/yosys/yosys.py +0 -148
- {siliconcompiler-0.29.0.dist-info → siliconcompiler-0.29.1.dist-info}/LICENSE +0 -0
- {siliconcompiler-0.29.0.dist-info → siliconcompiler-0.29.1.dist-info}/top_level.txt +0 -0
siliconcompiler/_metadata.py
CHANGED
siliconcompiler/apps/__init__.py
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from siliconcompiler.apps import sc_dashboard
|
|
2
|
+
from siliconcompiler.apps import sc_install
|
|
3
|
+
from siliconcompiler.apps import sc_issue
|
|
4
|
+
from siliconcompiler.apps import sc_remote
|
|
5
|
+
from siliconcompiler.apps import sc_server
|
|
6
|
+
from siliconcompiler.apps import sc_show
|
|
7
|
+
from siliconcompiler.apps import sc
|
|
8
|
+
from siliconcompiler.apps import smake
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_apps():
|
|
12
|
+
'''
|
|
13
|
+
Returns a dict of builtin apps
|
|
14
|
+
'''
|
|
15
|
+
return {
|
|
16
|
+
module.__name__.split(".")[-1]: module for module in (
|
|
17
|
+
sc_dashboard,
|
|
18
|
+
sc_install,
|
|
19
|
+
sc_issue,
|
|
20
|
+
sc_remote,
|
|
21
|
+
sc_server,
|
|
22
|
+
sc_show,
|
|
23
|
+
sc,
|
|
24
|
+
smake
|
|
25
|
+
)
|
|
26
|
+
}
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
# Copyright 2024 Silicon Compiler Authors. All Rights Reserved.
|
|
2
2
|
|
|
3
3
|
# Standard Modules
|
|
4
|
+
import base64
|
|
5
|
+
import io
|
|
6
|
+
import json
|
|
7
|
+
import gzip
|
|
4
8
|
import os
|
|
5
9
|
import stat
|
|
6
10
|
import sys
|
|
11
|
+
import tarfile
|
|
12
|
+
import tempfile
|
|
13
|
+
import textwrap
|
|
14
|
+
|
|
15
|
+
from datetime import datetime
|
|
7
16
|
|
|
8
17
|
import siliconcompiler
|
|
9
18
|
from siliconcompiler.apps._common import UNSET_DESIGN
|
|
@@ -11,6 +20,26 @@ from siliconcompiler import SiliconCompilerError
|
|
|
11
20
|
from siliconcompiler import utils
|
|
12
21
|
|
|
13
22
|
|
|
23
|
+
def make_bytes(data):
|
|
24
|
+
if isinstance(data, bytes):
|
|
25
|
+
return data
|
|
26
|
+
return data.encode('utf-8')
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def compress(data):
|
|
30
|
+
return gzip.compress(make_bytes(data))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def convert_base64(data):
|
|
34
|
+
return base64.b64encode(make_bytes(data))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def wrap_text(data):
|
|
38
|
+
if isinstance(data, bytes):
|
|
39
|
+
data = data.decode('utf-8')
|
|
40
|
+
return textwrap.wrap(data)
|
|
41
|
+
|
|
42
|
+
|
|
14
43
|
###########################
|
|
15
44
|
def main():
|
|
16
45
|
progname = "summarize"
|
|
@@ -25,9 +54,10 @@ def main():
|
|
|
25
54
|
|
|
26
55
|
# Read command-line inputs and generate Chip objects to run the flow on.
|
|
27
56
|
try:
|
|
28
|
-
|
|
29
|
-
'metavar': '<
|
|
30
|
-
'help': '
|
|
57
|
+
file_arg = {
|
|
58
|
+
'metavar': '<file>',
|
|
59
|
+
'help': 'Path to generate replay file to.',
|
|
60
|
+
'default': 'replay.sh',
|
|
31
61
|
'sc_print': True
|
|
32
62
|
}
|
|
33
63
|
args = chip.create_cmdline(
|
|
@@ -37,7 +67,7 @@ def main():
|
|
|
37
67
|
'-jobname',
|
|
38
68
|
'-loglevel'],
|
|
39
69
|
additional_args={
|
|
40
|
-
'-
|
|
70
|
+
'-file': file_arg
|
|
41
71
|
})
|
|
42
72
|
except SiliconCompilerError:
|
|
43
73
|
return 1
|
|
@@ -93,40 +123,68 @@ def main():
|
|
|
93
123
|
for tool, version in tools.items():
|
|
94
124
|
print(f" {os.path.basename(tool):<{tool_len}}: {', '.join(version)}")
|
|
95
125
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
126
|
+
path = os.path.abspath(args['file'])
|
|
127
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
128
|
+
|
|
129
|
+
starttimes = set()
|
|
130
|
+
for starttime, step, index in chip.schema._getvals('history', jobname, 'record', 'starttime'):
|
|
131
|
+
starttimes.add(datetime.strptime(starttime, '%Y-%m-%d %H:%M:%S'))
|
|
132
|
+
starttime = min(starttimes).strftime('%Y-%m-%d %H:%M:%S')
|
|
133
|
+
|
|
134
|
+
with io.StringIO() as fd:
|
|
135
|
+
fd.write(utils.get_file_template('replay/requirements.txt').render(
|
|
136
|
+
design=chip.design,
|
|
137
|
+
jobname=jobname,
|
|
138
|
+
date=starttime,
|
|
139
|
+
pkgs=pythonpackages
|
|
140
|
+
))
|
|
141
|
+
fd.flush()
|
|
142
|
+
requirements_file = fd.getvalue()
|
|
143
|
+
|
|
144
|
+
with tempfile.TemporaryDirectory() as collect:
|
|
145
|
+
chip.collect(directory=collect, verbose=True, exclude_packages=['siliconcompiler'])
|
|
146
|
+
|
|
147
|
+
with io.BytesIO() as fd:
|
|
148
|
+
with tarfile.open(fileobj=fd, mode='w:gz') as tar:
|
|
149
|
+
tar.add(collect, arcname='')
|
|
150
|
+
|
|
151
|
+
fd.flush()
|
|
152
|
+
collect_files = convert_base64(fd.getvalue())
|
|
153
|
+
|
|
154
|
+
with io.StringIO() as fd:
|
|
155
|
+
fd.write(utils.get_file_template('replay/replay.py.j2').render(
|
|
156
|
+
design=chip.design,
|
|
157
|
+
jobname=jobname,
|
|
158
|
+
date=starttime,
|
|
159
|
+
src_file=wrap_text(collect_files),
|
|
160
|
+
tool_versions=sorted(tool_versions)
|
|
161
|
+
))
|
|
162
|
+
fd.flush()
|
|
163
|
+
script = convert_base64(compress(fd.getvalue()))
|
|
164
|
+
|
|
165
|
+
manifest = convert_base64(compress(json.dumps(chip.schema.cfg, indent=2)))
|
|
166
|
+
|
|
167
|
+
tool_info = []
|
|
168
|
+
for tool, version in tools.items():
|
|
169
|
+
tool_info.append(f"{os.path.basename(tool):<{tool_len}}: {', '.join(version)}")
|
|
170
|
+
|
|
171
|
+
description = f"Replay for {chip.design} / {jobname}\nRun on: {starttime}"
|
|
172
|
+
|
|
173
|
+
with open(path, 'w', encoding='utf-8') as wf:
|
|
174
|
+
wf.write(utils.get_file_template('replay/setup.sh').render(
|
|
175
|
+
design=chip.design,
|
|
176
|
+
jobname=jobname,
|
|
177
|
+
date=starttime,
|
|
178
|
+
description=description,
|
|
179
|
+
pythonversion=pythonversion,
|
|
180
|
+
requirements=requirements_file.splitlines(),
|
|
181
|
+
script=wrap_text(script),
|
|
182
|
+
manifest=wrap_text(manifest),
|
|
183
|
+
tools=tool_info
|
|
184
|
+
))
|
|
185
|
+
|
|
186
|
+
permissions = stat.S_IMODE(os.lstat(path).st_mode)
|
|
187
|
+
os.chmod(path, permissions | stat.S_IXUSR)
|
|
130
188
|
|
|
131
189
|
return 0
|
|
132
190
|
|
siliconcompiler/core.py
CHANGED
|
@@ -255,8 +255,13 @@ class Chip:
|
|
|
255
255
|
log_format.append(f'{utils.truncate_text(step, max_step_len): <{max_step_len}}')
|
|
256
256
|
log_format.append(f'{utils.truncate_text(index, max_step_len): >{max_index_len}}')
|
|
257
257
|
|
|
258
|
+
log_formatprefix = "| "
|
|
259
|
+
if loglevel == "quiet":
|
|
260
|
+
log_format = []
|
|
261
|
+
log_formatprefix = ""
|
|
262
|
+
|
|
258
263
|
log_format.append('%(message)s')
|
|
259
|
-
logformat =
|
|
264
|
+
logformat = log_formatprefix + ' | '.join(log_format)
|
|
260
265
|
|
|
261
266
|
if not self.logger.hasHandlers():
|
|
262
267
|
stream_handler = logging.StreamHandler(stream=sys.stdout)
|
|
@@ -402,19 +407,24 @@ class Chip:
|
|
|
402
407
|
if extra_params is not None and "target" in extra_params:
|
|
403
408
|
if extra_params["target"]:
|
|
404
409
|
# running target command
|
|
405
|
-
# Search order
|
|
410
|
+
# Search order target plugins -> "{name}"
|
|
406
411
|
modules = []
|
|
407
412
|
module = extra_params["target"]
|
|
408
|
-
for
|
|
409
|
-
|
|
410
|
-
if
|
|
411
|
-
modules.append(
|
|
413
|
+
for plugin in utils.get_plugins('target'):
|
|
414
|
+
plugin_targets = plugin()
|
|
415
|
+
if module in plugin_targets:
|
|
416
|
+
modules.append(plugin_targets[module])
|
|
417
|
+
|
|
418
|
+
mod = self._load_module(module)
|
|
419
|
+
if mod:
|
|
420
|
+
modules.append(mod)
|
|
412
421
|
|
|
413
422
|
if len(modules) == 0:
|
|
414
423
|
raise SiliconCompilerError(f'Could not find target {module}', chip=self)
|
|
415
424
|
|
|
416
|
-
|
|
417
|
-
|
|
425
|
+
target = modules[0]
|
|
426
|
+
self.use(target)
|
|
427
|
+
extra_params["target"] = target.__name__
|
|
418
428
|
|
|
419
429
|
if extra_params is not None and "use" in extra_params:
|
|
420
430
|
if extra_params["use"]:
|
|
@@ -975,7 +985,7 @@ class Chip:
|
|
|
975
985
|
self.logger.debug(f'Setting {keypath} to {value}')
|
|
976
986
|
|
|
977
987
|
# Special case to ensure loglevel is updated ASAP
|
|
978
|
-
if keypath ==
|
|
988
|
+
if tuple(keypath) == ('option', 'loglevel') and field == 'value' and \
|
|
979
989
|
step == self.get('arg', 'step') and index == self.get('arg', 'index'):
|
|
980
990
|
self.logger.setLevel(schema_utils.translate_loglevel(value))
|
|
981
991
|
|
|
@@ -1074,6 +1084,54 @@ class Chip:
|
|
|
1074
1084
|
except (ValueError, TypeError) as e:
|
|
1075
1085
|
self.error(str(e))
|
|
1076
1086
|
|
|
1087
|
+
def import_flist(self, filename, package=None):
|
|
1088
|
+
'''
|
|
1089
|
+
Add input files, include directories, and defines from an flist
|
|
1090
|
+
|
|
1091
|
+
Args:
|
|
1092
|
+
filename (path): Path to flist file
|
|
1093
|
+
package (str): name of package
|
|
1094
|
+
'''
|
|
1095
|
+
|
|
1096
|
+
if package:
|
|
1097
|
+
filename = os.path.join(sc_package.path(self, package), filename)
|
|
1098
|
+
|
|
1099
|
+
if not os.path.isfile(filename):
|
|
1100
|
+
raise FileNotFoundError(filename)
|
|
1101
|
+
|
|
1102
|
+
package_name = f'flist-{os.path.basename(filename)}'
|
|
1103
|
+
package_dir = os.path.dirname(os.path.abspath(filename))
|
|
1104
|
+
|
|
1105
|
+
def __make_path(rel, path):
|
|
1106
|
+
path = utils._resolve_env_vars(self, path)
|
|
1107
|
+
if os.path.isabs(path):
|
|
1108
|
+
if path.startswith(rel):
|
|
1109
|
+
return os.path.relpath(path, rel), package_name
|
|
1110
|
+
else:
|
|
1111
|
+
return path, None
|
|
1112
|
+
return path, package_name
|
|
1113
|
+
|
|
1114
|
+
self.register_source(
|
|
1115
|
+
package_name,
|
|
1116
|
+
path=package_dir)
|
|
1117
|
+
with utils.sc_open(filename) as f:
|
|
1118
|
+
for line in f:
|
|
1119
|
+
line = line.strip()
|
|
1120
|
+
if not line:
|
|
1121
|
+
continue
|
|
1122
|
+
if line.startswith("//"):
|
|
1123
|
+
continue
|
|
1124
|
+
if line.startswith("+incdir+"):
|
|
1125
|
+
line = line[8:]
|
|
1126
|
+
path, package = __make_path(package_dir, line)
|
|
1127
|
+
self.add('option', 'idir', path, package=package)
|
|
1128
|
+
elif line.startswith("+define+"):
|
|
1129
|
+
line = line[8:]
|
|
1130
|
+
self.add('option', 'define', line)
|
|
1131
|
+
else:
|
|
1132
|
+
path, package = __make_path(package_dir, line)
|
|
1133
|
+
self.input(path, package=package)
|
|
1134
|
+
|
|
1077
1135
|
###########################################################################
|
|
1078
1136
|
def input(self, filename, fileset=None, filetype=None, iomap=None,
|
|
1079
1137
|
step=None, index=None, package=None):
|
|
@@ -2384,7 +2442,7 @@ class Chip:
|
|
|
2384
2442
|
swap('library', lib, 'option', 'library')
|
|
2385
2443
|
|
|
2386
2444
|
########################################################################
|
|
2387
|
-
def collect(self, directory=None, verbose=True, whitelist=None):
|
|
2445
|
+
def collect(self, directory=None, verbose=True, whitelist=None, exclude_packages=None):
|
|
2388
2446
|
'''
|
|
2389
2447
|
Collects files found in the configuration dictionary and places
|
|
2390
2448
|
them in inputs/. The function only copies in files that have the 'copy'
|
|
@@ -2402,6 +2460,8 @@ class Chip:
|
|
|
2402
2460
|
whitelist (list[path]): List of directories that are allowed to be
|
|
2403
2461
|
collected. If a directory is is found that is not on this list
|
|
2404
2462
|
a RuntimeError will be raised.
|
|
2463
|
+
package_filter (list[str]): List of packages to exclude from
|
|
2464
|
+
collection.
|
|
2405
2465
|
'''
|
|
2406
2466
|
|
|
2407
2467
|
if not directory:
|
|
@@ -2414,6 +2474,9 @@ class Chip:
|
|
|
2414
2474
|
if verbose:
|
|
2415
2475
|
self.logger.info('Collecting input sources')
|
|
2416
2476
|
|
|
2477
|
+
if not exclude_packages:
|
|
2478
|
+
exclude_packages = []
|
|
2479
|
+
|
|
2417
2480
|
dirs = {}
|
|
2418
2481
|
files = {}
|
|
2419
2482
|
|
|
@@ -2453,6 +2516,8 @@ class Chip:
|
|
|
2453
2516
|
if not package:
|
|
2454
2517
|
# Ensure package is an empty string
|
|
2455
2518
|
package = ''
|
|
2519
|
+
if package in exclude_packages:
|
|
2520
|
+
continue
|
|
2456
2521
|
if is_dir:
|
|
2457
2522
|
dirs[(package, path)] = abspath
|
|
2458
2523
|
else:
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from siliconcompiler.flows import asicflow
|
|
2
|
+
from siliconcompiler.flows import asictopflow
|
|
3
|
+
from siliconcompiler.flows import drcflow
|
|
4
|
+
from siliconcompiler.flows import dvflow
|
|
5
|
+
from siliconcompiler.flows import fpgaflow
|
|
6
|
+
from siliconcompiler.flows import generate_openroad_rcx
|
|
7
|
+
from siliconcompiler.flows import interposerflow
|
|
8
|
+
from siliconcompiler.flows import lintflow
|
|
9
|
+
from siliconcompiler.flows import screenshotflow
|
|
10
|
+
from siliconcompiler.flows import showflow
|
|
11
|
+
from siliconcompiler.flows import signoffflow
|
|
12
|
+
from siliconcompiler.flows import synflow
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_flows():
|
|
16
|
+
'''
|
|
17
|
+
Returns a dict of builtin flows
|
|
18
|
+
'''
|
|
19
|
+
return {
|
|
20
|
+
module.__name__.split(".")[-1]: module for module in (
|
|
21
|
+
asicflow,
|
|
22
|
+
asictopflow,
|
|
23
|
+
drcflow,
|
|
24
|
+
dvflow,
|
|
25
|
+
fpgaflow,
|
|
26
|
+
generate_openroad_rcx,
|
|
27
|
+
interposerflow,
|
|
28
|
+
lintflow,
|
|
29
|
+
screenshotflow,
|
|
30
|
+
showflow,
|
|
31
|
+
signoffflow,
|
|
32
|
+
synflow
|
|
33
|
+
)
|
|
34
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import siliconcompiler
|
|
2
2
|
from siliconcompiler import SiliconCompilerError
|
|
3
|
-
from siliconcompiler.targets import freepdk45_demo
|
|
4
3
|
|
|
5
4
|
|
|
6
5
|
############################################################################
|
|
7
6
|
# DOCS
|
|
8
7
|
############################################################################
|
|
9
8
|
def make_docs(chip):
|
|
9
|
+
from siliconcompiler.targets import freepdk45_demo
|
|
10
10
|
chip.use(freepdk45_demo)
|
|
11
11
|
return setup(filetype='gds', showtools=chip._showtools, np=3)
|
|
12
12
|
|
siliconcompiler/libs/__init__.py
CHANGED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
class Optimizer:
|
|
2
|
+
def __init__(self, chip):
|
|
3
|
+
self._chip = chip
|
|
4
|
+
|
|
5
|
+
self._parameters = {}
|
|
6
|
+
self._goals = {}
|
|
7
|
+
self._assertions = {}
|
|
8
|
+
|
|
9
|
+
self.__results = []
|
|
10
|
+
|
|
11
|
+
def __generate_print_name(self, key, step, index):
|
|
12
|
+
name = f'[{",".join(key)}]'
|
|
13
|
+
|
|
14
|
+
node_name = None
|
|
15
|
+
if step is not None:
|
|
16
|
+
node_name = step
|
|
17
|
+
|
|
18
|
+
if index is not None:
|
|
19
|
+
node_name += f'{index}'
|
|
20
|
+
|
|
21
|
+
if node_name:
|
|
22
|
+
name += f' ({node_name})'
|
|
23
|
+
|
|
24
|
+
return name
|
|
25
|
+
|
|
26
|
+
def __generate_param_name(self, key, step, index):
|
|
27
|
+
name = ",".join(key)
|
|
28
|
+
|
|
29
|
+
if step is not None:
|
|
30
|
+
name += f'-step-{step}'
|
|
31
|
+
|
|
32
|
+
if index is not None:
|
|
33
|
+
name += f'-index-{index}'
|
|
34
|
+
|
|
35
|
+
return name
|
|
36
|
+
|
|
37
|
+
def add_parameter(self, key, values, value_type=None, step=None, index=None):
|
|
38
|
+
if value_type is None:
|
|
39
|
+
value_type = self._chip.get(*key, field='type')
|
|
40
|
+
if value_type.startswith('['):
|
|
41
|
+
value_type = value_type[1:-1]
|
|
42
|
+
elif value_type.startswith('('):
|
|
43
|
+
value_type = value_type[1:-1].split(",")
|
|
44
|
+
value_type = [value.strip() for value in value_type]
|
|
45
|
+
if not all([value == value_type[0] for value in value_type]):
|
|
46
|
+
raise ValueError("Cannot support unequal tuples")
|
|
47
|
+
value_type = value_type[0]
|
|
48
|
+
|
|
49
|
+
if value_type not in ('float', 'int', 'bool', 'enum', 'str'):
|
|
50
|
+
raise ValueError(f"{value_type} is not supported")
|
|
51
|
+
|
|
52
|
+
if value_type in ('float', 'int'):
|
|
53
|
+
if 'max' not in values:
|
|
54
|
+
raise ValueError("value must have a max key")
|
|
55
|
+
if 'min' not in values:
|
|
56
|
+
raise ValueError("value must have a min key")
|
|
57
|
+
values = [values["min"], values["max"]]
|
|
58
|
+
elif value_type in ('enum', 'str', 'bool'):
|
|
59
|
+
if not isinstance(values, (tuple, list, set)):
|
|
60
|
+
raise ValueError("value must be a list")
|
|
61
|
+
if value_type == 'str':
|
|
62
|
+
value_type = 'enum'
|
|
63
|
+
|
|
64
|
+
if value_type == 'bool' and not values:
|
|
65
|
+
values = [True, False]
|
|
66
|
+
|
|
67
|
+
self._parameters["param-" + self.__generate_param_name(key, step, index)] = {
|
|
68
|
+
"print": self.__generate_print_name(key, step, index),
|
|
69
|
+
"key": tuple(key),
|
|
70
|
+
"type": value_type,
|
|
71
|
+
"values": tuple(values),
|
|
72
|
+
"step": step,
|
|
73
|
+
"index": index
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
def _set_parameter(self, parameter, value, chip, flow_prefix=None):
|
|
77
|
+
param_entry = self._parameters[parameter]
|
|
78
|
+
|
|
79
|
+
self._chip.logger.info(f' Setting {param_entry["print"]} = {value}')
|
|
80
|
+
if param_entry["step"]:
|
|
81
|
+
if not flow_prefix:
|
|
82
|
+
flow_prefix = ""
|
|
83
|
+
step = f'{flow_prefix}{param_entry["step"]}'
|
|
84
|
+
else:
|
|
85
|
+
step = param_entry["step"]
|
|
86
|
+
|
|
87
|
+
key_type = chip.get(*param_entry["key"], field='type')
|
|
88
|
+
if key_type[0] == "(":
|
|
89
|
+
key_type = key_type[1:-1].split(",")
|
|
90
|
+
value = len(key_type) * [value]
|
|
91
|
+
|
|
92
|
+
chip.set(
|
|
93
|
+
*param_entry["key"],
|
|
94
|
+
value,
|
|
95
|
+
step=step,
|
|
96
|
+
index=param_entry["index"])
|
|
97
|
+
|
|
98
|
+
def add_assertion(self, key, criteria, step=None, index=None):
|
|
99
|
+
if not callable(criteria):
|
|
100
|
+
raise ValueError('criteria must be a function')
|
|
101
|
+
|
|
102
|
+
if not step:
|
|
103
|
+
raise ValueError('step is required')
|
|
104
|
+
|
|
105
|
+
if not index:
|
|
106
|
+
raise ValueError('index is required')
|
|
107
|
+
|
|
108
|
+
self._assertions["assert-" + self.__generate_param_name(key, step, index)] = {
|
|
109
|
+
"print": self.__generate_print_name(key, step, index),
|
|
110
|
+
"key": tuple(key),
|
|
111
|
+
"criteria": criteria,
|
|
112
|
+
"step": step,
|
|
113
|
+
"index": index
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
def _check_assertions(self, chip, step_prefix):
|
|
117
|
+
if not step_prefix:
|
|
118
|
+
step_prefix = ""
|
|
119
|
+
|
|
120
|
+
for info in self._assertions.values():
|
|
121
|
+
value = chip.get(
|
|
122
|
+
*info["key"],
|
|
123
|
+
step=f'{step_prefix}{info["step"]}',
|
|
124
|
+
index=info["index"])
|
|
125
|
+
if not info["criteria"](value):
|
|
126
|
+
self._chip.logger.error(f"Failed to meet assertion: {info['print']} with {value}")
|
|
127
|
+
return False
|
|
128
|
+
|
|
129
|
+
return True
|
|
130
|
+
|
|
131
|
+
def add_goal(self, key, goal, stop_goal=None, step=None, index=None):
|
|
132
|
+
if goal not in ('min', 'max'):
|
|
133
|
+
raise ValueError(f"{goal} is not supported")
|
|
134
|
+
|
|
135
|
+
if not step:
|
|
136
|
+
raise ValueError('step is required')
|
|
137
|
+
|
|
138
|
+
if not index:
|
|
139
|
+
raise ValueError('index is required')
|
|
140
|
+
|
|
141
|
+
self._goals["goal-" + self.__generate_param_name(key, step, index)] = {
|
|
142
|
+
"print": self.__generate_print_name(key, step, index),
|
|
143
|
+
"key": tuple(key),
|
|
144
|
+
"goal": goal,
|
|
145
|
+
"stop": stop_goal,
|
|
146
|
+
"step": step,
|
|
147
|
+
"index": index
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
def _check_stop_goal(self, measurements):
|
|
151
|
+
cont = []
|
|
152
|
+
|
|
153
|
+
for param, info in self._goals.items():
|
|
154
|
+
if info["stop"] is None:
|
|
155
|
+
continue
|
|
156
|
+
|
|
157
|
+
if param not in measurements:
|
|
158
|
+
cont.append(False)
|
|
159
|
+
continue
|
|
160
|
+
|
|
161
|
+
if info["goal"] == "min":
|
|
162
|
+
if measurements[param] <= info["stop"]:
|
|
163
|
+
cont.append(True)
|
|
164
|
+
elif info["goal"] == "max":
|
|
165
|
+
if measurements[param] >= info["stop"]:
|
|
166
|
+
cont.append(True)
|
|
167
|
+
|
|
168
|
+
if not cont:
|
|
169
|
+
return False
|
|
170
|
+
|
|
171
|
+
return all(cont)
|
|
172
|
+
|
|
173
|
+
def run(self, experiments=None, parallel=None):
|
|
174
|
+
raise NotImplementedError
|
|
175
|
+
|
|
176
|
+
def _clear_results(self):
|
|
177
|
+
self.__results.clear()
|
|
178
|
+
|
|
179
|
+
def _add_result(self, parameters, measurements):
|
|
180
|
+
self.__results.append({
|
|
181
|
+
"parameters": parameters,
|
|
182
|
+
"measurements": measurements
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
def report(self, count=None):
|
|
186
|
+
for n, result in enumerate(self.__results):
|
|
187
|
+
if count and n >= count:
|
|
188
|
+
return
|
|
189
|
+
|
|
190
|
+
self._chip.logger.info(f"Result {n+1} / {len(self.__results)}:")
|
|
191
|
+
self._chip.logger.info(" Parameters:")
|
|
192
|
+
for param_name, param_key in result["parameters"].items():
|
|
193
|
+
param_print = self._parameters[param_name]['print']
|
|
194
|
+
self._chip.logger.info(f" {param_print} = {param_key}")
|
|
195
|
+
|
|
196
|
+
self._chip.logger.info(" Measurements:")
|
|
197
|
+
for meas_name, meas_key in result["measurements"].metrics.items():
|
|
198
|
+
goal_print = self._goals[meas_name]['print']
|
|
199
|
+
self._chip.logger.info(f" {goal_print} = {meas_key.value}")
|