siliconcompiler 0.28.4__py3-none-any.whl → 0.28.5__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/_common.py +88 -56
- siliconcompiler/apps/sc.py +33 -14
- siliconcompiler/apps/sc_dashboard.py +16 -9
- siliconcompiler/apps/sc_show.py +17 -15
- siliconcompiler/core.py +3 -1
- siliconcompiler/flows/drcflow.py +13 -0
- siliconcompiler/flows/interposerflow.py +17 -0
- siliconcompiler/libs/interposer.py +8 -0
- siliconcompiler/pdks/interposer.py +8 -0
- siliconcompiler/remote/schema.py +11 -1
- siliconcompiler/remote/server.py +7 -2
- siliconcompiler/scheduler/__init__.py +93 -0
- siliconcompiler/schema/schema_cfg.py +15 -3
- siliconcompiler/schema/schema_obj.py +51 -1
- siliconcompiler/targets/interposer_demo.py +56 -0
- siliconcompiler/templates/tcl/manifest.tcl.j2 +2 -0
- siliconcompiler/tools/klayout/export.py +7 -4
- siliconcompiler/tools/klayout/klayout_export.py +3 -0
- siliconcompiler/tools/klayout/klayout_utils.py +8 -2
- siliconcompiler/tools/openroad/metrics.py +45 -0
- siliconcompiler/tools/openroad/openroad.py +3 -0
- siliconcompiler/tools/openroad/rdlroute.py +97 -0
- siliconcompiler/tools/openroad/scripts/sc_apr.tcl +1 -1
- siliconcompiler/tools/openroad/scripts/sc_metrics.tcl +0 -169
- siliconcompiler/tools/openroad/scripts/sc_rdlroute.tcl +184 -0
- siliconcompiler/tools/openroad/scripts/sc_report.tcl +170 -0
- siliconcompiler/tools/opensta/scripts/sc_report_libraries.tcl +11 -1
- siliconcompiler/tools/xyce/__init__.py +1 -1
- siliconcompiler/toolscripts/_tools.json +3 -4
- siliconcompiler/toolscripts/rhel8/install-xyce.sh +4 -5
- siliconcompiler/toolscripts/rhel9/install-xyce.sh +4 -5
- siliconcompiler/toolscripts/ubuntu20/install-xyce.sh +5 -5
- siliconcompiler/toolscripts/ubuntu22/install-xyce.sh +2 -2
- siliconcompiler/toolscripts/ubuntu24/install-xyce.sh +2 -2
- {siliconcompiler-0.28.4.dist-info → siliconcompiler-0.28.5.dist-info}/METADATA +4 -4
- {siliconcompiler-0.28.4.dist-info → siliconcompiler-0.28.5.dist-info}/RECORD +41 -32
- {siliconcompiler-0.28.4.dist-info → siliconcompiler-0.28.5.dist-info}/WHEEL +1 -1
- {siliconcompiler-0.28.4.dist-info → siliconcompiler-0.28.5.dist-info}/LICENSE +0 -0
- {siliconcompiler-0.28.4.dist-info → siliconcompiler-0.28.5.dist-info}/entry_points.txt +0 -0
- {siliconcompiler-0.28.4.dist-info → siliconcompiler-0.28.5.dist-info}/top_level.txt +0 -0
siliconcompiler/_metadata.py
CHANGED
siliconcompiler/apps/_common.py
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import glob
|
|
2
1
|
import os
|
|
3
2
|
|
|
4
3
|
|
|
4
|
+
# TODO: this is a hack to get around design name requirement: since legal
|
|
5
|
+
# design names probably can't contain spaces, we can detect if it is unset.
|
|
6
|
+
UNSET_DESIGN = ' unset '
|
|
7
|
+
|
|
8
|
+
|
|
5
9
|
def manifest_switches():
|
|
6
10
|
'''
|
|
7
11
|
Returns a list of manifest switches that can be used
|
|
@@ -14,63 +18,91 @@ def manifest_switches():
|
|
|
14
18
|
'-jobname']
|
|
15
19
|
|
|
16
20
|
|
|
17
|
-
def
|
|
18
|
-
|
|
19
|
-
if (src_file is not None) and (not chip.get('option', 'cfg')):
|
|
20
|
-
if not os.path.exists(src_file):
|
|
21
|
-
chip.logger.error(f'{src_file} cannot be found.')
|
|
22
|
-
return False
|
|
23
|
-
# only autoload manifest if user doesn't supply manually
|
|
24
|
-
manifest = _get_manifest(os.path.dirname(src_file))
|
|
25
|
-
if not manifest:
|
|
26
|
-
design = os.path.splitext(os.path.basename(src_file))[0]
|
|
27
|
-
chip.logger.error(f'Unable to automatically find manifest for design {design}. '
|
|
28
|
-
'Please provide a manifest explicitly using -cfg.')
|
|
29
|
-
return False
|
|
30
|
-
elif not chip.get('option', 'cfg'):
|
|
31
|
-
manifest = _get_manifest_from_design(chip)
|
|
32
|
-
if not manifest:
|
|
33
|
-
chip.logger.error(f'Could not find manifest for {chip.design}')
|
|
34
|
-
return False
|
|
21
|
+
def _get_manifests(cwd):
|
|
22
|
+
manifests = {}
|
|
35
23
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
24
|
+
def get_dirs(cwd):
|
|
25
|
+
dirs = []
|
|
26
|
+
for dirname in os.listdir(cwd):
|
|
27
|
+
fullpath = os.path.join(cwd, dirname)
|
|
28
|
+
if os.path.isdir(fullpath):
|
|
29
|
+
dirs.append((dirname, fullpath))
|
|
30
|
+
return dirs
|
|
31
|
+
|
|
32
|
+
for _, buildpath in get_dirs(cwd):
|
|
33
|
+
for design, designdir in get_dirs(buildpath):
|
|
34
|
+
for jobname, jobdir in get_dirs(designdir):
|
|
35
|
+
manifest = os.path.join(jobdir, f'{design}.pkg.json')
|
|
36
|
+
if os.path.isfile(manifest):
|
|
37
|
+
manifests[(design, jobname, None, None)] = manifest
|
|
38
|
+
for step, stepdir in get_dirs(jobdir):
|
|
39
|
+
for index, indexdir in get_dirs(stepdir):
|
|
40
|
+
manifest = os.path.join(indexdir, 'outputs', f'{design}.pkg.json')
|
|
41
|
+
if os.path.isfile(manifest):
|
|
42
|
+
manifests[(design, jobname, step, index)] = manifest
|
|
43
|
+
else:
|
|
44
|
+
manifest = os.path.join(indexdir, 'inputs', f'{design}.pkg.json')
|
|
45
|
+
if os.path.isfile(manifest):
|
|
46
|
+
manifests[(design, jobname, step, index)] = manifest
|
|
47
|
+
|
|
48
|
+
organized_manifest = {}
|
|
49
|
+
for (design, job, step, index), manifest in manifests.items():
|
|
50
|
+
jobs = organized_manifest.setdefault(design, {})
|
|
51
|
+
jobs.setdefault(job, {})[step, index] = os.path.abspath(manifest)
|
|
52
|
+
|
|
53
|
+
return organized_manifest
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def pick_manifest_from_file(chip, src_file, all_manifests):
|
|
57
|
+
if src_file is None:
|
|
54
58
|
return None
|
|
55
|
-
return manifest
|
|
56
59
|
|
|
60
|
+
if not os.path.exists(src_file):
|
|
61
|
+
chip.logger.error(f'{src_file} cannot be found.')
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
src_dir = os.path.abspath(os.path.dirname(src_file))
|
|
65
|
+
for _, jobs in all_manifests.items():
|
|
66
|
+
for _, nodes in jobs.items():
|
|
67
|
+
for manifest in nodes.values():
|
|
68
|
+
if src_dir == os.path.dirname(manifest):
|
|
69
|
+
return manifest
|
|
57
70
|
|
|
58
|
-
def _get_manifest_from_design(chip):
|
|
59
|
-
for jobname, step, index in [
|
|
60
|
-
(chip.get('option', 'jobname'),
|
|
61
|
-
chip.get('arg', 'step'),
|
|
62
|
-
chip.get('arg', 'index')),
|
|
63
|
-
(chip.get('option', 'jobname'),
|
|
64
|
-
None,
|
|
65
|
-
None),
|
|
66
|
-
(chip.schema.get_default('option', 'jobname'),
|
|
67
|
-
chip.get('arg', 'step'),
|
|
68
|
-
chip.get('arg', 'index')),
|
|
69
|
-
(chip.schema.get_default('option', 'jobname'),
|
|
70
|
-
None,
|
|
71
|
-
None)]:
|
|
72
|
-
manifest = _get_manifest(chip.getworkdir(jobname=jobname, step=step, index=index))
|
|
73
|
-
|
|
74
|
-
if manifest:
|
|
75
|
-
return manifest
|
|
76
71
|
return None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def pick_manifest(chip, src_file=None):
|
|
75
|
+
all_manifests = _get_manifests(os.getcwd())
|
|
76
|
+
|
|
77
|
+
manifest = pick_manifest_from_file(chip, src_file, all_manifests)
|
|
78
|
+
if manifest:
|
|
79
|
+
return manifest
|
|
80
|
+
|
|
81
|
+
if chip.design == UNSET_DESIGN:
|
|
82
|
+
if len(all_manifests) == 1:
|
|
83
|
+
chip.set('design', list(all_manifests.keys())[0])
|
|
84
|
+
else:
|
|
85
|
+
chip.logger.error('Design name is not set')
|
|
86
|
+
return None
|
|
87
|
+
|
|
88
|
+
if chip.design not in all_manifests:
|
|
89
|
+
chip.logger.error(f'Could not find manifest for {chip.design}')
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
if chip.get('option', 'jobname') not in all_manifests[chip.design] and \
|
|
93
|
+
len(all_manifests[chip.design]) != 1:
|
|
94
|
+
chip.logger.error(f'Could not determine jobname for {chip.design}')
|
|
95
|
+
return None
|
|
96
|
+
|
|
97
|
+
jobname = chip.get('option', 'jobname')
|
|
98
|
+
if chip.get('option', 'jobname') not in all_manifests[chip.design]:
|
|
99
|
+
jobname = list(all_manifests[chip.design].keys())[0]
|
|
100
|
+
|
|
101
|
+
if (None, None) in all_manifests[chip.design][jobname]:
|
|
102
|
+
manifest = all_manifests[chip.design][jobname][None, None]
|
|
103
|
+
else:
|
|
104
|
+
# pick newest manifest
|
|
105
|
+
manifest = list(sorted(all_manifests[chip.design][jobname].values(),
|
|
106
|
+
key=lambda file: os.stat(file).st_ctime))[-1]
|
|
107
|
+
|
|
108
|
+
return manifest
|
siliconcompiler/apps/sc.py
CHANGED
|
@@ -10,6 +10,37 @@ from siliconcompiler.targets import skywater130_demo
|
|
|
10
10
|
from siliconcompiler import SiliconCompilerError
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
def _infer_designname(chip):
|
|
14
|
+
topfile = None
|
|
15
|
+
sourcesets = chip.getkeys('input')
|
|
16
|
+
for sourceset in reversed(('rtl', 'hll')):
|
|
17
|
+
if sourceset in sourcesets:
|
|
18
|
+
sourcesets.remove(sourceset)
|
|
19
|
+
sourcesets.insert(0, sourceset)
|
|
20
|
+
for sourceset in sourcesets:
|
|
21
|
+
for filetype in chip.getkeys('input', sourceset):
|
|
22
|
+
all_vals = chip.schema._getvals('input', sourceset, filetype)
|
|
23
|
+
if all_vals:
|
|
24
|
+
# just look at first value
|
|
25
|
+
sources, _, _ = all_vals[0]
|
|
26
|
+
# grab first source
|
|
27
|
+
topfile = sources[0]
|
|
28
|
+
break
|
|
29
|
+
if topfile:
|
|
30
|
+
break
|
|
31
|
+
|
|
32
|
+
if not topfile:
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
root = os.path.basename(topfile)
|
|
36
|
+
while True:
|
|
37
|
+
root, ext = os.path.splitext(root)
|
|
38
|
+
if not ext:
|
|
39
|
+
break
|
|
40
|
+
|
|
41
|
+
return root
|
|
42
|
+
|
|
43
|
+
|
|
13
44
|
###########################
|
|
14
45
|
def main():
|
|
15
46
|
progname = "sc"
|
|
@@ -50,24 +81,12 @@ def main():
|
|
|
50
81
|
|
|
51
82
|
# Set design if none specified
|
|
52
83
|
if chip.get('design') == UNSET_DESIGN:
|
|
53
|
-
|
|
54
|
-
for sourceset in ('rtl', 'hll'):
|
|
55
|
-
for filetype in chip.getkeys('input', sourceset):
|
|
56
|
-
all_vals = chip.schema._getvals('input', sourceset, filetype)
|
|
57
|
-
if all_vals:
|
|
58
|
-
# just look at first value
|
|
59
|
-
sources, _, _ = all_vals[0]
|
|
60
|
-
# grab first source
|
|
61
|
-
topfile = sources[0]
|
|
62
|
-
break
|
|
63
|
-
if topfile:
|
|
64
|
-
break
|
|
84
|
+
topmodule = _infer_designname(chip)
|
|
65
85
|
|
|
66
|
-
if not
|
|
86
|
+
if not topmodule:
|
|
67
87
|
chip.logger.error('Invalid arguments: either specify -design or provide sources.')
|
|
68
88
|
return 1
|
|
69
89
|
|
|
70
|
-
topmodule = os.path.splitext(os.path.basename(topfile))[0]
|
|
71
90
|
chip.set('design', topmodule)
|
|
72
91
|
|
|
73
92
|
# Set demo target if none specified
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import sys
|
|
3
3
|
import siliconcompiler
|
|
4
4
|
import os
|
|
5
|
-
from siliconcompiler.apps._common import
|
|
5
|
+
from siliconcompiler.apps._common import pick_manifest, manifest_switches, UNSET_DESIGN
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def main():
|
|
@@ -11,9 +11,16 @@ def main():
|
|
|
11
11
|
-----------------------------------------------------------
|
|
12
12
|
SC app to open a dashboard for a given manifest.
|
|
13
13
|
|
|
14
|
-
To open:
|
|
14
|
+
To open and allow sc-dashboard to autoload manifest:
|
|
15
|
+
sc-dashboard
|
|
16
|
+
|
|
17
|
+
To open by specifying manifest:
|
|
15
18
|
sc-dashboard -cfg <path to manifest>
|
|
16
19
|
|
|
20
|
+
To open by specifying design and optionally jobname:
|
|
21
|
+
sc-dashboard -design <name>
|
|
22
|
+
sc-dashboard -design <name> -jobname <jobname>
|
|
23
|
+
|
|
17
24
|
To specify a different port than the default:
|
|
18
25
|
sc-dashboard -cfg <path to manifest> -port 10000
|
|
19
26
|
|
|
@@ -23,10 +30,6 @@ To include another chip object to compare to:
|
|
|
23
30
|
-----------------------------------------------------------
|
|
24
31
|
"""
|
|
25
32
|
|
|
26
|
-
# TODO: this is a hack to get around design name requirement: since legal
|
|
27
|
-
# design names probably can't contain spaces, we can detect if it is unset.
|
|
28
|
-
UNSET_DESIGN = ' unset '
|
|
29
|
-
|
|
30
33
|
# Create a base chip class.
|
|
31
34
|
chip = siliconcompiler.Chip(UNSET_DESIGN)
|
|
32
35
|
|
|
@@ -54,15 +57,19 @@ To include another chip object to compare to:
|
|
|
54
57
|
chip.logger.error(e)
|
|
55
58
|
return 1
|
|
56
59
|
|
|
60
|
+
if not chip.get('option', 'cfg'):
|
|
61
|
+
manifest = pick_manifest(chip)
|
|
62
|
+
|
|
63
|
+
if manifest:
|
|
64
|
+
chip.logger.info(f'Loading manifest: {manifest}')
|
|
65
|
+
chip.read_manifest(manifest)
|
|
66
|
+
|
|
57
67
|
# Error checking
|
|
58
68
|
design = chip.get('design')
|
|
59
69
|
if design == UNSET_DESIGN:
|
|
60
70
|
chip.logger.error('Design not loaded')
|
|
61
71
|
return 1
|
|
62
72
|
|
|
63
|
-
if not load_manifest(chip, None):
|
|
64
|
-
return 1
|
|
65
|
-
|
|
66
73
|
graph_chips = []
|
|
67
74
|
if switches['graph_cfg']:
|
|
68
75
|
for i, name_and_file_path in enumerate(switches['graph_cfg']):
|
siliconcompiler/apps/sc_show.py
CHANGED
|
@@ -3,7 +3,7 @@ import sys
|
|
|
3
3
|
import os
|
|
4
4
|
import siliconcompiler
|
|
5
5
|
from siliconcompiler.utils import get_default_iomap
|
|
6
|
-
from siliconcompiler.apps._common import
|
|
6
|
+
from siliconcompiler.apps._common import manifest_switches, pick_manifest, UNSET_DESIGN
|
|
7
7
|
from siliconcompiler.utils import get_file_ext
|
|
8
8
|
|
|
9
9
|
|
|
@@ -18,6 +18,9 @@ def main():
|
|
|
18
18
|
|
|
19
19
|
Examples:
|
|
20
20
|
|
|
21
|
+
sc-show
|
|
22
|
+
(displays build/adder/job0/write_gds/0/outputs/adder.gds)
|
|
23
|
+
|
|
21
24
|
sc-show -design adder
|
|
22
25
|
(displays build/adder/job0/write_gds/0/outputs/adder.gds)
|
|
23
26
|
|
|
@@ -40,10 +43,6 @@ def main():
|
|
|
40
43
|
(displays build/adder/job0/route/1/outputs/adder.def)
|
|
41
44
|
"""
|
|
42
45
|
|
|
43
|
-
# TODO: this is a hack to get around design name requirement: since legal
|
|
44
|
-
# design names probably can't contain spaces, we can detect if it is unset.
|
|
45
|
-
UNSET_DESIGN = ' unset '
|
|
46
|
-
|
|
47
46
|
# Create a base chip class.
|
|
48
47
|
chip = siliconcompiler.Chip(UNSET_DESIGN)
|
|
49
48
|
|
|
@@ -81,10 +80,6 @@ def main():
|
|
|
81
80
|
chip.logger.error(e)
|
|
82
81
|
return 1
|
|
83
82
|
|
|
84
|
-
# Error checking
|
|
85
|
-
design = chip.get('design')
|
|
86
|
-
design_set = design != UNSET_DESIGN
|
|
87
|
-
|
|
88
83
|
# Search input keys for files
|
|
89
84
|
input_mode = []
|
|
90
85
|
for fileset in chip.getkeys('input'):
|
|
@@ -92,11 +87,6 @@ def main():
|
|
|
92
87
|
if chip.schema._getvals('input', fileset, mode):
|
|
93
88
|
input_mode = [('input', fileset, mode)]
|
|
94
89
|
|
|
95
|
-
if not (design_set or input_mode):
|
|
96
|
-
chip.logger.error('Nothing to load: please define a target with '
|
|
97
|
-
'-cfg, -design, and/or inputs.')
|
|
98
|
-
return 1
|
|
99
|
-
|
|
100
90
|
filename = None
|
|
101
91
|
if input_mode:
|
|
102
92
|
check_ext = list(chip._showtools.keys())
|
|
@@ -115,7 +105,19 @@ def main():
|
|
|
115
105
|
|
|
116
106
|
filename = get_file_from_keys()
|
|
117
107
|
|
|
118
|
-
|
|
108
|
+
# Attempt to load a manifest
|
|
109
|
+
if not chip.get('option', 'cfg'):
|
|
110
|
+
manifest = pick_manifest(chip, src_file=filename)
|
|
111
|
+
if manifest:
|
|
112
|
+
chip.logger.info(f'Loading manifest: {manifest}')
|
|
113
|
+
chip.read_manifest(manifest)
|
|
114
|
+
|
|
115
|
+
# Error checking
|
|
116
|
+
design = chip.get('design')
|
|
117
|
+
design_set = design != UNSET_DESIGN
|
|
118
|
+
if not (design_set or input_mode):
|
|
119
|
+
chip.logger.error('Nothing to load: please define a target with '
|
|
120
|
+
'-cfg, -design, and/or inputs.')
|
|
119
121
|
return 1
|
|
120
122
|
|
|
121
123
|
# Read in file
|
siliconcompiler/core.py
CHANGED
|
@@ -2123,7 +2123,9 @@ class Chip:
|
|
|
2123
2123
|
nonlocal graph_idx
|
|
2124
2124
|
|
|
2125
2125
|
for subgraph in graph_info["graphs"]:
|
|
2126
|
+
child_prefix = prefix
|
|
2126
2127
|
if get_node_count(graph_info["graphs"][subgraph]) > 1:
|
|
2128
|
+
child_prefix = f"{child_prefix}{subgraph}."
|
|
2127
2129
|
graph = graphviz.Digraph(name=f"cluster_{graph_idx}")
|
|
2128
2130
|
graph_idx += 1
|
|
2129
2131
|
|
|
@@ -2143,7 +2145,7 @@ class Chip:
|
|
|
2143
2145
|
else:
|
|
2144
2146
|
graph = parent
|
|
2145
2147
|
|
|
2146
|
-
build_graph(graph_info["graphs"][subgraph], graph,
|
|
2148
|
+
build_graph(graph_info["graphs"][subgraph], graph, child_prefix)
|
|
2147
2149
|
|
|
2148
2150
|
if graph is not parent:
|
|
2149
2151
|
parent.subgraph(graph)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from siliconcompiler import Flow
|
|
2
|
+
|
|
3
|
+
from siliconcompiler.tools.openroad import rdlroute
|
|
4
|
+
from siliconcompiler.tools.klayout import export
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def setup():
|
|
8
|
+
'''
|
|
9
|
+
A flow to perform RDL routing and generate a GDS
|
|
10
|
+
'''
|
|
11
|
+
flow = Flow('interposerflow')
|
|
12
|
+
flow.node('interposerflow', 'rdlroute', rdlroute)
|
|
13
|
+
flow.node('interposerflow', 'write_gds', export)
|
|
14
|
+
|
|
15
|
+
flow.edge('interposerflow', 'rdlroute', 'write_gds')
|
|
16
|
+
|
|
17
|
+
return flow
|
siliconcompiler/remote/schema.py
CHANGED
|
@@ -2,7 +2,7 @@ from siliconcompiler.schema.schema_cfg import scparam
|
|
|
2
2
|
from siliconcompiler.schema import Schema
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
SCHEMA_VERSION = '0.0.
|
|
5
|
+
SCHEMA_VERSION = '0.0.2'
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def schema_cfg():
|
|
@@ -93,6 +93,16 @@ def schema_cfg():
|
|
|
93
93
|
schelp="""
|
|
94
94
|
Provides explicit control over the level of debug logging printed.""")
|
|
95
95
|
|
|
96
|
+
scparam(cfg, ['option', 'checkinterval'],
|
|
97
|
+
sctype='int',
|
|
98
|
+
defvalue=30,
|
|
99
|
+
shorthelp="Interval for client",
|
|
100
|
+
switch="-checkinterval <int>",
|
|
101
|
+
example=["cli: -checkinterval 10",
|
|
102
|
+
"api: chip.set('option', 'checkinterval', 10)"],
|
|
103
|
+
schelp="""
|
|
104
|
+
Interval between checks to announce to clients""")
|
|
105
|
+
|
|
96
106
|
return cfg
|
|
97
107
|
|
|
98
108
|
|
siliconcompiler/remote/server.py
CHANGED
|
@@ -239,7 +239,7 @@ class Server:
|
|
|
239
239
|
|
|
240
240
|
# Return a response to the client.
|
|
241
241
|
return web.json_response({'message': f"Starting job: {job_hash}",
|
|
242
|
-
'interval':
|
|
242
|
+
'interval': self.checkinterval,
|
|
243
243
|
'job_hash': job_hash})
|
|
244
244
|
|
|
245
245
|
####################
|
|
@@ -375,7 +375,7 @@ class Server:
|
|
|
375
375
|
'sc_schema': sc_schema_version,
|
|
376
376
|
'sc_server': Server.__version__,
|
|
377
377
|
},
|
|
378
|
-
'progress_interval':
|
|
378
|
+
'progress_interval': self.checkinterval
|
|
379
379
|
}
|
|
380
380
|
|
|
381
381
|
username = job_params['username']
|
|
@@ -490,6 +490,11 @@ class Server:
|
|
|
490
490
|
# Ensure that NFS mounting path is absolute.
|
|
491
491
|
return os.path.abspath(self.get('option', 'nfsmount'))
|
|
492
492
|
|
|
493
|
+
###################
|
|
494
|
+
@property
|
|
495
|
+
def checkinterval(self):
|
|
496
|
+
return self.get('option', 'checkinterval')
|
|
497
|
+
|
|
493
498
|
def get(self, *keypath, field='value'):
|
|
494
499
|
return self.schema.get(*keypath, field=field)
|
|
495
500
|
|
|
@@ -688,7 +688,9 @@ def _makecmd(chip, tool, task, step, index, script_name='replay.sh', include_pat
|
|
|
688
688
|
runtime_options = getattr(chip._get_tool_module(step, index), 'runtime_options', None)
|
|
689
689
|
if runtime_options:
|
|
690
690
|
try:
|
|
691
|
+
chip.schema._start_record_access()
|
|
691
692
|
cmdlist.extend(parse_options(runtime_options(chip)))
|
|
693
|
+
chip.schema._stop_record_access()
|
|
692
694
|
except Exception as e:
|
|
693
695
|
chip.logger.error(f'Failed to get runtime options for {tool}/{task}')
|
|
694
696
|
raise e
|
|
@@ -983,7 +985,9 @@ def _post_process(chip, step, index):
|
|
|
983
985
|
func = getattr(chip._get_task_module(step, index, flow=flow), 'post_process', None)
|
|
984
986
|
if func:
|
|
985
987
|
try:
|
|
988
|
+
chip.schema._start_record_access()
|
|
986
989
|
func(chip)
|
|
990
|
+
chip.schema._stop_record_access()
|
|
987
991
|
except Exception as e:
|
|
988
992
|
chip.logger.error(f'Failed to run post-process for {tool}/{task}.')
|
|
989
993
|
print_traceback(chip, e)
|
|
@@ -1076,7 +1080,9 @@ def _pre_process(chip, step, index):
|
|
|
1076
1080
|
func = getattr(chip._get_task_module(step, index, flow=flow), 'pre_process', None)
|
|
1077
1081
|
if func:
|
|
1078
1082
|
try:
|
|
1083
|
+
chip.schema._start_record_access()
|
|
1079
1084
|
func(chip)
|
|
1085
|
+
chip.schema._stop_record_access()
|
|
1080
1086
|
except Exception as e:
|
|
1081
1087
|
chip.logger.error(f"Pre-processing failed for '{tool}/{task}'.")
|
|
1082
1088
|
raise e
|
|
@@ -1088,6 +1094,8 @@ def _pre_process(chip, step, index):
|
|
|
1088
1094
|
def _set_env_vars(chip, step, index):
|
|
1089
1095
|
flow = chip.get('option', 'flow')
|
|
1090
1096
|
tool, task = get_tool_task(chip, step, index, flow)
|
|
1097
|
+
|
|
1098
|
+
chip.schema._start_record_access()
|
|
1091
1099
|
# License file configuration.
|
|
1092
1100
|
for item in chip.getkeys('tool', tool, 'licenseserver'):
|
|
1093
1101
|
license_file = chip.get('tool', tool, 'licenseserver', item, step=step, index=index)
|
|
@@ -1100,6 +1108,8 @@ def _set_env_vars(chip, step, index):
|
|
|
1100
1108
|
if val:
|
|
1101
1109
|
os.environ[item] = val
|
|
1102
1110
|
|
|
1111
|
+
chip.schema._stop_record_access()
|
|
1112
|
+
|
|
1103
1113
|
|
|
1104
1114
|
def _check_tool_version(chip, step, index, run_func=None):
|
|
1105
1115
|
'''
|
|
@@ -1191,6 +1201,9 @@ def _hash_files(chip, step, index, setup=False):
|
|
|
1191
1201
|
|
|
1192
1202
|
|
|
1193
1203
|
def _finalizenode(chip, step, index, replay):
|
|
1204
|
+
if chip.schema._do_record_access():
|
|
1205
|
+
assert_required_accesses(chip, step, index)
|
|
1206
|
+
|
|
1194
1207
|
flow = chip.get('option', 'flow')
|
|
1195
1208
|
tool, task = get_tool_task(chip, step, index, flow)
|
|
1196
1209
|
quiet = (
|
|
@@ -1286,6 +1299,86 @@ def assert_output_files(chip, step, index):
|
|
|
1286
1299
|
chip=chip)
|
|
1287
1300
|
|
|
1288
1301
|
|
|
1302
|
+
def assert_required_accesses(chip, step, index):
|
|
1303
|
+
flow = chip.get('option', 'flow')
|
|
1304
|
+
jobname = chip.get('option', 'jobname')
|
|
1305
|
+
tool, task = get_tool_task(chip, step, index, flow)
|
|
1306
|
+
|
|
1307
|
+
if tool == 'builtin':
|
|
1308
|
+
return
|
|
1309
|
+
|
|
1310
|
+
gets = chip.schema._get_record_access()
|
|
1311
|
+
logfile = os.path.join(
|
|
1312
|
+
chip.getworkdir(jobname=jobname, step=step, index=index),
|
|
1313
|
+
f'{step}.log')
|
|
1314
|
+
|
|
1315
|
+
with sc_open(logfile) as f:
|
|
1316
|
+
for line in f:
|
|
1317
|
+
if line.startswith(Schema._RECORD_ACCESS_IDENTIFIER):
|
|
1318
|
+
key = line[len(Schema._RECORD_ACCESS_IDENTIFIER):].strip().split(',')
|
|
1319
|
+
if chip.valid(*key, check_complete=True):
|
|
1320
|
+
gets.add(tuple(key))
|
|
1321
|
+
|
|
1322
|
+
def get_value(*key):
|
|
1323
|
+
if chip.get(*key, field='pernode') == 'never':
|
|
1324
|
+
return chip.get(*key)
|
|
1325
|
+
else:
|
|
1326
|
+
return chip.get(*key, step=step, index=index)
|
|
1327
|
+
|
|
1328
|
+
getkeys = set()
|
|
1329
|
+
# Remove keys with empty values
|
|
1330
|
+
for key in set(sorted(gets)):
|
|
1331
|
+
if get_value(*key):
|
|
1332
|
+
getkeys.add(key)
|
|
1333
|
+
|
|
1334
|
+
# Remove keys that dont matter
|
|
1335
|
+
exempt = [
|
|
1336
|
+
('design',),
|
|
1337
|
+
('arg', 'step'), ('arg', 'index'),
|
|
1338
|
+
('option', 'jobname'), ('option', 'flow'), ('option', 'strict'), ('option', 'builddir'),
|
|
1339
|
+
('option', 'quiet'),
|
|
1340
|
+
('tool', tool, 'exe'),
|
|
1341
|
+
('tool', tool, 'task', task, 'require'),
|
|
1342
|
+
('tool', tool, 'task', task, 'threads'),
|
|
1343
|
+
('flowgraph', flow, step, index, 'tool'), ('flowgraph', flow, step, index, 'task'),
|
|
1344
|
+
('flowgraph', flow, step, index, 'taskmodule')]
|
|
1345
|
+
for key in chip.getkeys('metric'):
|
|
1346
|
+
exempt.append(('metric', key))
|
|
1347
|
+
for key in chip.getkeys('tool', tool, 'task', task, 'report'):
|
|
1348
|
+
exempt.append(('tool', tool, 'task', task, 'report', key))
|
|
1349
|
+
|
|
1350
|
+
# Get exempted keys from task
|
|
1351
|
+
func = getattr(chip._get_task_module(step, index, flow=flow), 'exempt_keys', None)
|
|
1352
|
+
if func:
|
|
1353
|
+
# No need for try / except since this must work properly
|
|
1354
|
+
exempt.extend(func(chip))
|
|
1355
|
+
|
|
1356
|
+
required = set(
|
|
1357
|
+
[tuple(key.split(',')) for key in chip.get('tool', tool, 'task', task, 'require',
|
|
1358
|
+
step=step, index=index)])
|
|
1359
|
+
|
|
1360
|
+
for key in set(exempt):
|
|
1361
|
+
if key in getkeys:
|
|
1362
|
+
getkeys.remove(key)
|
|
1363
|
+
if key in required:
|
|
1364
|
+
required.remove(key)
|
|
1365
|
+
|
|
1366
|
+
excess_require = required.difference(getkeys)
|
|
1367
|
+
if True:
|
|
1368
|
+
for key in sorted(excess_require):
|
|
1369
|
+
chip.logger.error(f"{step}{index} does not require requirement: {','.join(key)}")
|
|
1370
|
+
missing_require = getkeys.difference(required)
|
|
1371
|
+
for key in sorted(missing_require):
|
|
1372
|
+
chip.logger.error(f"{step}{index} has an unexpressed requirement: "
|
|
1373
|
+
f"{','.join(key)} = {get_value(*key)}")
|
|
1374
|
+
|
|
1375
|
+
if missing_require:
|
|
1376
|
+
raise SiliconCompilerError(
|
|
1377
|
+
f'Requirements for {step}{index} does not match access list: '
|
|
1378
|
+
f'{", ".join([",".join(key) for key in sorted(missing_require)])}',
|
|
1379
|
+
chip=chip)
|
|
1380
|
+
|
|
1381
|
+
|
|
1289
1382
|
def _reset_flow_nodes(chip, flow, nodes_to_execute):
|
|
1290
1383
|
# Reset flowgraph/records/metrics by probing build directory. We need
|
|
1291
1384
|
# to set values to None for steps we may re-run so that merging
|
|
@@ -10,7 +10,7 @@ try:
|
|
|
10
10
|
except ImportError:
|
|
11
11
|
from siliconcompiler.schema.utils import trim
|
|
12
12
|
|
|
13
|
-
SCHEMA_VERSION = '0.48.
|
|
13
|
+
SCHEMA_VERSION = '0.48.4'
|
|
14
14
|
|
|
15
15
|
#############################################################################
|
|
16
16
|
# PARAM DEFINITION
|
|
@@ -1252,7 +1252,6 @@ def schema_datasheet(cfg, name='default', mode='default'):
|
|
|
1252
1252
|
# Package Description
|
|
1253
1253
|
#########################
|
|
1254
1254
|
|
|
1255
|
-
# high level description
|
|
1256
1255
|
scparam(cfg, ['datasheet', 'package', name, 'type'],
|
|
1257
1256
|
sctype='enum',
|
|
1258
1257
|
enum=['bga', 'lga', 'csp', 'qfn', 'qfp', 'sop', 'die', 'wafer'],
|
|
@@ -1263,6 +1262,16 @@ def schema_datasheet(cfg, name='default', mode='default'):
|
|
|
1263
1262
|
"api: chip.set('datasheet', 'package', 'abcd', 'type', 'bga')"],
|
|
1264
1263
|
schelp="""Package type specified on a named package basis.""")
|
|
1265
1264
|
|
|
1265
|
+
scparam(cfg, ['datasheet', 'package', name, 'footprint'],
|
|
1266
|
+
sctype='str',
|
|
1267
|
+
shorthelp="Datasheet: package footprint",
|
|
1268
|
+
switch="-datasheet_package_footprint 'name <str>'",
|
|
1269
|
+
example=[
|
|
1270
|
+
"cli: -datasheet_package_footprint 'abcd soic8'",
|
|
1271
|
+
"api: chip.set('datasheet', 'package', 'abcd', 'footprint', 'soic8')"],
|
|
1272
|
+
schelp="""Package footprint name. The name of the footprint can be a standard
|
|
1273
|
+
footprint name or a reference designator from a footprint library.""")
|
|
1274
|
+
|
|
1266
1275
|
scparam(cfg, ['datasheet', 'package', name, 'drawing'],
|
|
1267
1276
|
sctype='[file]',
|
|
1268
1277
|
shorthelp="Datasheet: package drawing",
|
|
@@ -2158,7 +2167,10 @@ def schema_metric(cfg, step='default', index='default'):
|
|
|
2158
2167
|
device families.""")
|
|
2159
2168
|
|
|
2160
2169
|
metrics = {'cellarea': 'cell area (ignoring fillers)',
|
|
2161
|
-
'totalarea': 'physical die area'
|
|
2170
|
+
'totalarea': 'physical die area',
|
|
2171
|
+
'macroarea': 'macro cell area',
|
|
2172
|
+
'padcellarea': 'io pad cell area',
|
|
2173
|
+
'stdcellarea': 'standard cell area'}
|
|
2162
2174
|
|
|
2163
2175
|
for item, val in metrics.items():
|
|
2164
2176
|
scparam(cfg, ['metric', item],
|