siliconcompiler 0.31.0__py3-none-any.whl → 0.32.0__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/sc.py +1 -0
- siliconcompiler/apps/sc_install.py +19 -1
- siliconcompiler/apps/utils/summarize.py +1 -1
- siliconcompiler/core.py +33 -39
- siliconcompiler/flows/_common.py +10 -4
- siliconcompiler/{package.py → package/__init__.py} +64 -177
- siliconcompiler/package/git.py +84 -0
- siliconcompiler/package/https.py +97 -0
- siliconcompiler/report/dashboard/components/__init__.py +16 -6
- siliconcompiler/report/report.py +6 -6
- siliconcompiler/scheduler/__init__.py +19 -10
- siliconcompiler/scheduler/docker_runner.py +3 -3
- siliconcompiler/scheduler/run_node.py +6 -3
- siliconcompiler/schema/schema_obj.py +7 -11
- siliconcompiler/templates/tcl/manifest.tcl.j2 +1 -1
- siliconcompiler/tools/_common/tcl/sc_pin_constraints.tcl +3 -5
- siliconcompiler/tools/genfasm/genfasm.py +1 -1
- siliconcompiler/tools/openroad/_apr.py +15 -5
- siliconcompiler/tools/openroad/rdlroute.py +4 -0
- siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +3 -3
- siliconcompiler/tools/openroad/scripts/common/reports.tcl +10 -0
- siliconcompiler/tools/openroad/scripts/common/write_images.tcl +27 -0
- siliconcompiler/tools/openroad/scripts/sc_rdlroute.tcl +3 -13
- siliconcompiler/tools/slang/__init__.py +123 -33
- siliconcompiler/tools/slang/elaborate.py +123 -18
- siliconcompiler/tools/slang/lint.py +20 -10
- siliconcompiler/tools/surelog/__init__.py +17 -4
- siliconcompiler/tools/vpr/vpr.py +86 -6
- siliconcompiler/toolscripts/_tools.json +4 -4
- siliconcompiler/units.py +10 -7
- siliconcompiler/use.py +5 -2
- {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/METADATA +17 -22
- {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/RECORD +38 -36
- {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/WHEEL +1 -1
- {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/entry_points.txt +4 -0
- {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/LICENSE +0 -0
- {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import shutil
|
|
3
|
+
import tarfile
|
|
4
|
+
import zipfile
|
|
5
|
+
|
|
6
|
+
import os.path
|
|
7
|
+
|
|
8
|
+
from fasteners import InterProcessLock
|
|
9
|
+
from io import BytesIO
|
|
10
|
+
from urllib.parse import urlparse
|
|
11
|
+
|
|
12
|
+
from siliconcompiler import SiliconCompilerError
|
|
13
|
+
from siliconcompiler.package import get_download_cache_path
|
|
14
|
+
from siliconcompiler.package import aquire_data_lock, release_data_lock
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_resolver(url):
|
|
18
|
+
if url.scheme in ("http", "https"):
|
|
19
|
+
return http_resolver
|
|
20
|
+
|
|
21
|
+
return None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def http_resolver(chip, package, path, ref, url, fetch):
|
|
25
|
+
data_path, data_path_lock = get_download_cache_path(chip, package, ref)
|
|
26
|
+
|
|
27
|
+
if not fetch:
|
|
28
|
+
return data_path, False
|
|
29
|
+
|
|
30
|
+
# Acquire lock
|
|
31
|
+
data_lock = InterProcessLock(data_path_lock)
|
|
32
|
+
aquire_data_lock(data_path, data_lock)
|
|
33
|
+
|
|
34
|
+
if os.path.exists(data_path):
|
|
35
|
+
release_data_lock(data_lock)
|
|
36
|
+
return data_path, False
|
|
37
|
+
|
|
38
|
+
extract_from_url(chip, package, path, ref, url, data_path)
|
|
39
|
+
|
|
40
|
+
release_data_lock(data_lock)
|
|
41
|
+
|
|
42
|
+
return data_path, True
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def extract_from_url(chip, package, path, ref, url, data_path):
|
|
46
|
+
data_url = path
|
|
47
|
+
headers = {}
|
|
48
|
+
if os.environ.get('GIT_TOKEN') or url.username:
|
|
49
|
+
headers['Authorization'] = f'token {os.environ.get("GIT_TOKEN") or url.username}'
|
|
50
|
+
if "github" in data_url:
|
|
51
|
+
headers['Accept'] = 'application/octet-stream'
|
|
52
|
+
data_url = path
|
|
53
|
+
if data_url.endswith('/'):
|
|
54
|
+
data_url = f"{data_url}{ref}.tar.gz"
|
|
55
|
+
chip.logger.info(f'Downloading {package} data from {data_url}')
|
|
56
|
+
response = requests.get(data_url, stream=True, headers=headers)
|
|
57
|
+
if not response.ok:
|
|
58
|
+
raise SiliconCompilerError(f'Failed to download {package} data source.', chip=chip)
|
|
59
|
+
|
|
60
|
+
fileobj = BytesIO(response.content)
|
|
61
|
+
try:
|
|
62
|
+
with tarfile.open(fileobj=fileobj, mode='r|gz') as tar_ref:
|
|
63
|
+
tar_ref.extractall(path=data_path)
|
|
64
|
+
except tarfile.ReadError:
|
|
65
|
+
fileobj.seek(0)
|
|
66
|
+
# Try as zip
|
|
67
|
+
with zipfile.ZipFile(fileobj) as zip_ref:
|
|
68
|
+
zip_ref.extractall(path=data_path)
|
|
69
|
+
|
|
70
|
+
if 'github' in url.netloc and len(os.listdir(data_path)) == 1:
|
|
71
|
+
# Github inserts one folder at the highest level of the tar file
|
|
72
|
+
# this compensates for this behavior
|
|
73
|
+
gh_url = urlparse(data_url)
|
|
74
|
+
|
|
75
|
+
repo = gh_url.path.split('/')[2]
|
|
76
|
+
|
|
77
|
+
gh_ref = gh_url.path.split('/')[-1]
|
|
78
|
+
if repo.endswith('.git'):
|
|
79
|
+
gh_ref = ref
|
|
80
|
+
elif gh_ref.endswith('.tar.gz'):
|
|
81
|
+
gh_ref = gh_ref[0:-7]
|
|
82
|
+
elif gh_ref.endswith('.tgz'):
|
|
83
|
+
gh_ref = gh_ref[0:-4]
|
|
84
|
+
else:
|
|
85
|
+
gh_ref = gh_ref.split('.')[0]
|
|
86
|
+
|
|
87
|
+
if gh_ref.startswith('v'):
|
|
88
|
+
gh_ref = gh_ref[1:]
|
|
89
|
+
|
|
90
|
+
github_folder = f"{repo}-{gh_ref}"
|
|
91
|
+
|
|
92
|
+
if github_folder in os.listdir(data_path):
|
|
93
|
+
# This moves all files one level up
|
|
94
|
+
git_path = os.path.join(data_path, github_folder)
|
|
95
|
+
for data_file in os.listdir(git_path):
|
|
96
|
+
shutil.move(os.path.join(git_path, data_file), data_path)
|
|
97
|
+
os.removedirs(git_path)
|
|
@@ -433,7 +433,7 @@ def node_file_tree_viewer(chip, step, index):
|
|
|
433
433
|
lookup = {}
|
|
434
434
|
tree_items = []
|
|
435
435
|
|
|
436
|
-
file_metrics = report.get_metrics_source(chip, step, index)
|
|
436
|
+
metrics_source, file_metrics = report.get_metrics_source(chip, step, index)
|
|
437
437
|
work_dir = chip.getworkdir(step=step, index=index)
|
|
438
438
|
|
|
439
439
|
def make_item(file):
|
|
@@ -446,12 +446,22 @@ def node_file_tree_viewer(chip, step, index):
|
|
|
446
446
|
|
|
447
447
|
check_file = os.path.relpath(file['value'], work_dir)
|
|
448
448
|
if check_file in file_metrics:
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
449
|
+
metrics = set(file_metrics[check_file])
|
|
450
|
+
primary_source = set()
|
|
451
|
+
if check_file in metrics_source:
|
|
452
|
+
primary_source = set(metrics_source[check_file])
|
|
453
|
+
metrics = metrics - primary_source
|
|
454
|
+
|
|
455
|
+
for color, metric_set in (('blue', primary_source), ('green', metrics)):
|
|
456
|
+
if len(item.tag) >= 5:
|
|
454
457
|
break
|
|
458
|
+
|
|
459
|
+
for metric in metric_set:
|
|
460
|
+
if len(item.tag) < 5:
|
|
461
|
+
item.tag.append(sac.Tag(metric, color=color))
|
|
462
|
+
else:
|
|
463
|
+
item.tag.append(sac.Tag('metrics...', color='geekblue'))
|
|
464
|
+
break
|
|
455
465
|
item.tooltip = "metrics: " + ", ".join(file_metrics[check_file])
|
|
456
466
|
|
|
457
467
|
if 'children' in file:
|
siliconcompiler/report/report.py
CHANGED
|
@@ -302,20 +302,20 @@ def get_metrics_source(chip, step, index):
|
|
|
302
302
|
index (string) : Index of node.
|
|
303
303
|
'''
|
|
304
304
|
file_to_metric = {}
|
|
305
|
+
metric_primary_source = {}
|
|
305
306
|
tool, task = get_tool_task(chip, step, index)
|
|
306
307
|
if not chip.valid('tool', tool, 'task', task, 'report'):
|
|
307
|
-
return file_to_metric
|
|
308
|
+
return metric_primary_source, file_to_metric
|
|
308
309
|
|
|
309
310
|
metrics = chip.getkeys('tool', tool, 'task', task, 'report')
|
|
310
311
|
|
|
311
312
|
for metric in metrics:
|
|
312
313
|
sources = chip.get('tool', tool, 'task', task, 'report', metric, step=step, index=index)
|
|
314
|
+
if sources:
|
|
315
|
+
metric_primary_source.setdefault(sources[0], []).append(metric)
|
|
313
316
|
for source in sources:
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
else:
|
|
317
|
-
file_to_metric[source] = [metric]
|
|
318
|
-
return file_to_metric
|
|
317
|
+
file_to_metric.setdefault(source, []).append(metric)
|
|
318
|
+
return metric_primary_source, file_to_metric
|
|
319
319
|
|
|
320
320
|
|
|
321
321
|
def get_files(chip, step, index):
|
|
@@ -1865,6 +1865,22 @@ def kill_process(chip, proc, tool, poll_interval, msg=""):
|
|
|
1865
1865
|
utils.terminate_process(proc.pid)
|
|
1866
1866
|
|
|
1867
1867
|
|
|
1868
|
+
def get_check_node_keys(chip, step, index):
|
|
1869
|
+
tool, task = get_tool_task(chip, step, index)
|
|
1870
|
+
|
|
1871
|
+
# Collect keys to check for changes
|
|
1872
|
+
required = chip.get('tool', tool, 'task', task, 'require', step=step, index=index)
|
|
1873
|
+
|
|
1874
|
+
tool_task_key = ('tool', tool, 'task', task)
|
|
1875
|
+
for key in ('option', 'threads', 'prescript', 'postscript', 'refdir', 'script',):
|
|
1876
|
+
required.append(",".join([*tool_task_key, key]))
|
|
1877
|
+
|
|
1878
|
+
for env_key in chip.getkeys(*tool_task_key, 'env'):
|
|
1879
|
+
required.append(",".join([*tool_task_key, 'env', env_key]))
|
|
1880
|
+
|
|
1881
|
+
return set(sorted(required))
|
|
1882
|
+
|
|
1883
|
+
|
|
1868
1884
|
def check_node_inputs(chip, step, index):
|
|
1869
1885
|
from siliconcompiler import Chip # import here to avoid circular import
|
|
1870
1886
|
|
|
@@ -1918,15 +1934,8 @@ def check_node_inputs(chip, step, index):
|
|
|
1918
1934
|
return False
|
|
1919
1935
|
|
|
1920
1936
|
# Collect keys to check for changes
|
|
1921
|
-
required = chip
|
|
1922
|
-
required.
|
|
1923
|
-
|
|
1924
|
-
tool_task_key = ('tool', tool, 'task', task)
|
|
1925
|
-
for key in ('option', 'threads', 'prescript', 'postscript', 'refdir', 'script',):
|
|
1926
|
-
required.append(",".join([*tool_task_key, key]))
|
|
1927
|
-
for check_chip in (chip, input_chip):
|
|
1928
|
-
for env_key in check_chip.getkeys(*tool_task_key, 'env'):
|
|
1929
|
-
required.append(",".join([*tool_task_key, 'env', env_key]))
|
|
1937
|
+
required = get_check_node_keys(chip, step, index)
|
|
1938
|
+
required.update(get_check_node_keys(input_chip, step, index))
|
|
1930
1939
|
|
|
1931
1940
|
def print_warning(key, extra=None):
|
|
1932
1941
|
if extra:
|
|
@@ -1937,7 +1946,7 @@ def check_node_inputs(chip, step, index):
|
|
|
1937
1946
|
'from previous run')
|
|
1938
1947
|
|
|
1939
1948
|
# Check if keys have been modified
|
|
1940
|
-
for check_key in
|
|
1949
|
+
for check_key in required:
|
|
1941
1950
|
key = check_key.split(',')
|
|
1942
1951
|
|
|
1943
1952
|
if not chip.valid(*key) or not input_chip.valid(*key):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import docker
|
|
2
2
|
import os
|
|
3
3
|
from siliconcompiler.package import get_cache_path
|
|
4
|
-
from siliconcompiler.package import
|
|
4
|
+
from siliconcompiler.package import path as sc_path
|
|
5
5
|
from siliconcompiler.utils import default_email_credentials_file
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
import sys
|
|
@@ -47,7 +47,7 @@ def get_volumes_directories(chip, cache_dir, workdir, step, index):
|
|
|
47
47
|
|
|
48
48
|
# Collect caches
|
|
49
49
|
for package in chip.getkeys('package', 'source'):
|
|
50
|
-
all_dirs.add(sc_path(chip, package
|
|
50
|
+
all_dirs.add(sc_path(chip, package))
|
|
51
51
|
|
|
52
52
|
all_dirs = [
|
|
53
53
|
Path(cache_dir),
|
|
@@ -215,7 +215,7 @@ def run(chip, step, index, replay):
|
|
|
215
215
|
|
|
216
216
|
cachemap = []
|
|
217
217
|
for package in chip.getkeys('package', 'source'):
|
|
218
|
-
cachemap.append(f'{package}:{sc_path(chip, package
|
|
218
|
+
cachemap.append(f'{package}:{sc_path(chip, package)}')
|
|
219
219
|
|
|
220
220
|
chip.logger.info(f'Running in docker container: {container.name} ({container.short_id})')
|
|
221
221
|
args = [
|
|
@@ -5,7 +5,7 @@ import os
|
|
|
5
5
|
import sys
|
|
6
6
|
import tarfile
|
|
7
7
|
from siliconcompiler import Chip, Schema
|
|
8
|
-
from siliconcompiler.package import
|
|
8
|
+
from siliconcompiler.package import path as sc_path
|
|
9
9
|
from siliconcompiler.scheduler import _runtask, _executenode
|
|
10
10
|
from siliconcompiler import __version__
|
|
11
11
|
|
|
@@ -45,6 +45,9 @@ def main():
|
|
|
45
45
|
metavar='<package>:<directory>',
|
|
46
46
|
nargs='+',
|
|
47
47
|
help='Map of caches to prepopulate runner with')
|
|
48
|
+
parser.add_argument('-fetch_cache',
|
|
49
|
+
action='store_true',
|
|
50
|
+
help='Allow for cache downloads')
|
|
48
51
|
parser.add_argument('-step',
|
|
49
52
|
required=True,
|
|
50
53
|
metavar='<step>',
|
|
@@ -103,9 +106,9 @@ def main():
|
|
|
103
106
|
package, path = cachepair.split(':')
|
|
104
107
|
chip._packages[package] = path
|
|
105
108
|
|
|
106
|
-
# Populate cache
|
|
109
|
+
# Populate cache
|
|
107
110
|
for package in chip.getkeys('package', 'source'):
|
|
108
|
-
sc_path(chip, package,
|
|
111
|
+
sc_path(chip, package, fetch=args.fetch_cache)
|
|
109
112
|
|
|
110
113
|
# Run the task.
|
|
111
114
|
error = True
|
|
@@ -1092,6 +1092,10 @@ class Schema:
|
|
|
1092
1092
|
|
|
1093
1093
|
tcl_set_cmds = []
|
|
1094
1094
|
for key in self.allkeys():
|
|
1095
|
+
# print out all non default values
|
|
1096
|
+
if 'default' in key:
|
|
1097
|
+
continue
|
|
1098
|
+
|
|
1095
1099
|
typestr = self.get(*key, field='type')
|
|
1096
1100
|
pernode = self.get(*key, field='pernode')
|
|
1097
1101
|
|
|
@@ -1110,19 +1114,11 @@ class Schema:
|
|
|
1110
1114
|
|
|
1111
1115
|
valstr = escape_val_tcl(value, typestr)
|
|
1112
1116
|
|
|
1113
|
-
#
|
|
1114
|
-
if not (typestr.startswith('[') or typestr.startswith('(')):
|
|
1115
|
-
valstr = f'[list {valstr}]'
|
|
1116
|
-
|
|
1117
|
-
# TODO: Temp fix to get rid of empty args
|
|
1117
|
+
# Ensure empty values get something
|
|
1118
1118
|
if valstr == '':
|
|
1119
|
-
valstr = '
|
|
1120
|
-
|
|
1121
|
-
outstr = f"{prefix} {keystr} {valstr}"
|
|
1119
|
+
valstr = '{}'
|
|
1122
1120
|
|
|
1123
|
-
|
|
1124
|
-
if 'default' not in key:
|
|
1125
|
-
tcl_set_cmds.append(outstr)
|
|
1121
|
+
tcl_set_cmds.append(f"{prefix} {keystr} {valstr}")
|
|
1126
1122
|
|
|
1127
1123
|
if template:
|
|
1128
1124
|
fout.write(template.render(manifest_dict='\n'.join(tcl_set_cmds),
|
|
@@ -15,22 +15,20 @@ proc sc_collect_pin_constraints {
|
|
|
15
15
|
set side [dict get $params side]
|
|
16
16
|
set place [dict get $params placement]
|
|
17
17
|
|
|
18
|
-
if {
|
|
18
|
+
if { $place != {} } {
|
|
19
19
|
# Pin has placement information
|
|
20
|
-
if {
|
|
20
|
+
if { $order != {} } {
|
|
21
21
|
# Pin also has order information
|
|
22
22
|
$print_func "Pin $name has placement specified in constraints, but also order."
|
|
23
23
|
}
|
|
24
24
|
lappend placement_pins $name
|
|
25
25
|
} else {
|
|
26
26
|
# Pin doesn't have placement
|
|
27
|
-
if {
|
|
27
|
+
if { $side == {} || $order == {} } {
|
|
28
28
|
# Pin information is incomplete
|
|
29
29
|
$print_func \
|
|
30
30
|
"Warning: Pin $name doesn't have enough information to perform placement."
|
|
31
31
|
} else {
|
|
32
|
-
set side [lindex $side 0]
|
|
33
|
-
set order [lindex $order 0]
|
|
34
32
|
if { ![dict exists $pin_order $side $order] } {
|
|
35
33
|
dict set pin_order $side $order []
|
|
36
34
|
}
|
|
@@ -24,7 +24,7 @@ def make_docs(chip):
|
|
|
24
24
|
def setup(chip):
|
|
25
25
|
chip.set('tool', 'genfasm', 'exe', 'genfasm', clobber=False)
|
|
26
26
|
chip.set('tool', 'genfasm', 'vswitch', '--version')
|
|
27
|
-
chip.set('tool', 'genfasm', 'version', '>=
|
|
27
|
+
chip.set('tool', 'genfasm', 'version', '>=9.0.0', clobber=False)
|
|
28
28
|
|
|
29
29
|
add_tool_requirements(chip)
|
|
30
30
|
|
|
@@ -84,12 +84,16 @@ def extract_metrics(chip):
|
|
|
84
84
|
metric_reports = {
|
|
85
85
|
"setuptns": [
|
|
86
86
|
"timing/total_negative_slack.rpt",
|
|
87
|
-
"timing/setup.rpt"
|
|
87
|
+
"timing/setup.rpt",
|
|
88
|
+
"timing/setup.histogram.rpt",
|
|
89
|
+
"images/timing/setup.histogram.png"
|
|
88
90
|
],
|
|
89
91
|
"setupslack": [
|
|
90
92
|
"timing/worst_slack.setup.rpt",
|
|
91
93
|
"timing/setup.rpt",
|
|
92
|
-
"timing/setup.topN.rpt"
|
|
94
|
+
"timing/setup.topN.rpt",
|
|
95
|
+
"timing/setup.histogram.rpt",
|
|
96
|
+
"images/timing/setup.histogram.png"
|
|
93
97
|
],
|
|
94
98
|
"setupskew": [
|
|
95
99
|
"timing/skew.setup.rpt",
|
|
@@ -99,12 +103,16 @@ def extract_metrics(chip):
|
|
|
99
103
|
],
|
|
100
104
|
"setuppaths": [
|
|
101
105
|
"timing/setup.rpt",
|
|
102
|
-
"timing/setup.topN.rpt"
|
|
106
|
+
"timing/setup.topN.rpt",
|
|
107
|
+
"timing/setup.histogram.rpt",
|
|
108
|
+
"images/timing/setup.histogram.png"
|
|
103
109
|
],
|
|
104
110
|
"holdslack": [
|
|
105
111
|
"timing/worst_slack.hold.rpt",
|
|
106
112
|
"timing/hold.rpt",
|
|
107
|
-
"timing/hold.topN.rpt"
|
|
113
|
+
"timing/hold.topN.rpt",
|
|
114
|
+
"timing/hold.histogram.rpt",
|
|
115
|
+
"images/timing/hold.histogram.png"
|
|
108
116
|
],
|
|
109
117
|
"holdskew": [
|
|
110
118
|
"timing/skew.hold.rpt",
|
|
@@ -114,7 +122,9 @@ def extract_metrics(chip):
|
|
|
114
122
|
],
|
|
115
123
|
"holdpaths": [
|
|
116
124
|
"timing/hold.rpt",
|
|
117
|
-
"timing/hold.topN.rpt"
|
|
125
|
+
"timing/hold.topN.rpt",
|
|
126
|
+
"timing/hold.histogram.rpt",
|
|
127
|
+
"images/timing/hold.histogram.png"
|
|
118
128
|
],
|
|
119
129
|
"unconstrained": [
|
|
120
130
|
"timing/unconstrained.rpt",
|
|
@@ -75,6 +75,10 @@ def setup(chip):
|
|
|
75
75
|
'if enabled by the PDK, to the design',
|
|
76
76
|
skip='lib')
|
|
77
77
|
|
|
78
|
+
chip.set('tool', tool, 'task', task, 'var', 'debug_level',
|
|
79
|
+
'list of "tool key level" to enable debugging of OpenROAD',
|
|
80
|
+
field='help')
|
|
81
|
+
|
|
78
82
|
if f'{design}.v' in input_provides(chip, step, index):
|
|
79
83
|
chip.add('tool', tool, 'task', task, 'input', design + '.v', step=step, index=index)
|
|
80
84
|
elif f'{design}.vg' in input_provides(chip, step, index):
|
|
@@ -121,11 +121,11 @@ if { [sc_cfg_exists constraint pin] } {
|
|
|
121
121
|
global sc_vpinmetal
|
|
122
122
|
|
|
123
123
|
set layer [sc_cfg_get constraint pin $pin layer]
|
|
124
|
-
if {
|
|
125
|
-
return [sc_get_layer_name
|
|
124
|
+
if { $layer != {} } {
|
|
125
|
+
return [sc_get_layer_name $layer]
|
|
126
126
|
}
|
|
127
127
|
set side [sc_cfg_get constraint pin $pin side]
|
|
128
|
-
if {
|
|
128
|
+
if { $side != {} } {
|
|
129
129
|
switch -regexp $side {
|
|
130
130
|
"1|3" {
|
|
131
131
|
return [lindex $sc_hpinmetal 0]
|
|
@@ -27,6 +27,11 @@ if { [sc_cfg_tool_task_check_in_list setup var reports] } {
|
|
|
27
27
|
tee -file reports/timing/total_negative_slack.rpt \
|
|
28
28
|
"report_tns"
|
|
29
29
|
report_tns_metric -setup
|
|
30
|
+
|
|
31
|
+
if { [sc_check_version 19519] } {
|
|
32
|
+
tee -quiet -file reports/timing/setup.histogram.rpt \
|
|
33
|
+
"report_timing_histogram -num_bins 20 -setup"
|
|
34
|
+
}
|
|
30
35
|
}
|
|
31
36
|
|
|
32
37
|
if { [sc_cfg_tool_task_check_in_list hold var reports] } {
|
|
@@ -42,6 +47,11 @@ if { [sc_cfg_tool_task_check_in_list hold var reports] } {
|
|
|
42
47
|
report_worst_slack_metric -hold
|
|
43
48
|
|
|
44
49
|
report_tns_metric -hold
|
|
50
|
+
|
|
51
|
+
if { [sc_check_version 19519] } {
|
|
52
|
+
tee -quiet -file reports/timing/hold.histogram.rpt \
|
|
53
|
+
"report_timing_histogram -num_bins 20 -hold"
|
|
54
|
+
}
|
|
45
55
|
}
|
|
46
56
|
|
|
47
57
|
if { [sc_cfg_tool_task_check_in_list unconstrained var reports] } {
|
|
@@ -304,6 +304,30 @@ proc sc_image_clocktree { } {
|
|
|
304
304
|
gui::hide_widget "Clock Tree Viewer"
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
+
proc sc_image_timing_histograms { } {
|
|
308
|
+
if { ![sc_check_version 19526] } {
|
|
309
|
+
return
|
|
310
|
+
}
|
|
311
|
+
file mkdir reports/images/timing
|
|
312
|
+
|
|
313
|
+
if { [sc_cfg_tool_task_check_in_list setup var reports] } {
|
|
314
|
+
set path reports/images/timing/setup.histogram.png
|
|
315
|
+
utl::info FLW 1 "Saving setup timing histogram to $path"
|
|
316
|
+
save_histogram_image $path \
|
|
317
|
+
-mode setup \
|
|
318
|
+
-width 500 \
|
|
319
|
+
-height 500
|
|
320
|
+
}
|
|
321
|
+
if { [sc_cfg_tool_task_check_in_list hold var reports] } {
|
|
322
|
+
set path reports/images/timing/hold.histogram.png
|
|
323
|
+
utl::info FLW 1 "Saving hold timing histogram to $path"
|
|
324
|
+
save_histogram_image $path \
|
|
325
|
+
-mode hold \
|
|
326
|
+
-width 500 \
|
|
327
|
+
-height 500
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
307
331
|
proc sc_image_optimizer { } {
|
|
308
332
|
global sc_design
|
|
309
333
|
sc_image_setup_default
|
|
@@ -390,6 +414,9 @@ if { [sc_cfg_tool_task_check_in_list module_view var reports] } {
|
|
|
390
414
|
# Markers
|
|
391
415
|
sc_image_markers
|
|
392
416
|
|
|
417
|
+
# Histograms
|
|
418
|
+
sc_image_timing_histograms
|
|
419
|
+
|
|
393
420
|
# Heatmaps
|
|
394
421
|
if { [sc_cfg_tool_task_check_in_list placement_density var reports] } {
|
|
395
422
|
sc_image_placement_density
|
|
@@ -35,21 +35,11 @@ set sc_threads [sc_cfg_tool_task_get threads]
|
|
|
35
35
|
# MACROS
|
|
36
36
|
set sc_macrolibs [sc_get_asic_libraries macro]
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
#
|
|
38
|
+
##############################
|
|
39
|
+
# Setup debugging
|
|
40
40
|
###############################
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
set or_msg [split $msg "-"]
|
|
44
|
-
if { [llength $or_msg] != 2 } {
|
|
45
|
-
utl::warn FLW 1 "$msg is not a valid message id"
|
|
46
|
-
} else {
|
|
47
|
-
set or_tool [lindex $or_msg 0]
|
|
48
|
-
set or_msg_id [expr { int([lindex $or_msg 1]) }]
|
|
49
|
-
utl::info FLW 1 "Suppressing $msg messages"
|
|
50
|
-
suppress_message $or_tool $or_msg_id
|
|
51
|
-
}
|
|
52
|
-
}
|
|
42
|
+
source -echo "$sc_refdir/common/debugging.tcl"
|
|
53
43
|
|
|
54
44
|
###############################
|
|
55
45
|
# Source helper functions
|