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.
Files changed (38) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/sc.py +1 -0
  3. siliconcompiler/apps/sc_install.py +19 -1
  4. siliconcompiler/apps/utils/summarize.py +1 -1
  5. siliconcompiler/core.py +33 -39
  6. siliconcompiler/flows/_common.py +10 -4
  7. siliconcompiler/{package.py → package/__init__.py} +64 -177
  8. siliconcompiler/package/git.py +84 -0
  9. siliconcompiler/package/https.py +97 -0
  10. siliconcompiler/report/dashboard/components/__init__.py +16 -6
  11. siliconcompiler/report/report.py +6 -6
  12. siliconcompiler/scheduler/__init__.py +19 -10
  13. siliconcompiler/scheduler/docker_runner.py +3 -3
  14. siliconcompiler/scheduler/run_node.py +6 -3
  15. siliconcompiler/schema/schema_obj.py +7 -11
  16. siliconcompiler/templates/tcl/manifest.tcl.j2 +1 -1
  17. siliconcompiler/tools/_common/tcl/sc_pin_constraints.tcl +3 -5
  18. siliconcompiler/tools/genfasm/genfasm.py +1 -1
  19. siliconcompiler/tools/openroad/_apr.py +15 -5
  20. siliconcompiler/tools/openroad/rdlroute.py +4 -0
  21. siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +3 -3
  22. siliconcompiler/tools/openroad/scripts/common/reports.tcl +10 -0
  23. siliconcompiler/tools/openroad/scripts/common/write_images.tcl +27 -0
  24. siliconcompiler/tools/openroad/scripts/sc_rdlroute.tcl +3 -13
  25. siliconcompiler/tools/slang/__init__.py +123 -33
  26. siliconcompiler/tools/slang/elaborate.py +123 -18
  27. siliconcompiler/tools/slang/lint.py +20 -10
  28. siliconcompiler/tools/surelog/__init__.py +17 -4
  29. siliconcompiler/tools/vpr/vpr.py +86 -6
  30. siliconcompiler/toolscripts/_tools.json +4 -4
  31. siliconcompiler/units.py +10 -7
  32. siliconcompiler/use.py +5 -2
  33. {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/METADATA +17 -22
  34. {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/RECORD +38 -36
  35. {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/WHEEL +1 -1
  36. {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/entry_points.txt +4 -0
  37. {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/LICENSE +0 -0
  38. {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/top_level.txt +0 -0
@@ -10,55 +10,56 @@ Sources: https://github.com/MikePopoloski/slang
10
10
 
11
11
  Installation: https://sv-lang.com/building.html
12
12
  '''
13
- import re
14
- from siliconcompiler import sc_open
15
- from siliconcompiler.tools._common import record_metric
13
+ import os
14
+
15
+ try:
16
+ import pyslang
17
+ except ModuleNotFoundError:
18
+ pyslang = None
19
+
16
20
  from siliconcompiler.tools._common import \
17
- get_frontend_options, get_input_files, get_tool_task
21
+ add_require_input, add_frontend_requires, get_frontend_options, get_input_files, \
22
+ get_tool_task, record_metric
18
23
 
19
24
 
20
- ################################
21
- # Setup Tool (pre executable)
22
- ################################
23
- def setup(chip):
24
- tool = 'slang'
25
+ def has_pyslang():
26
+ return pyslang is not None
25
27
 
26
- # Standard Setup
27
- chip.set('tool', tool, 'exe', 'slang')
28
- chip.set('tool', tool, 'vswitch', '--version')
29
- chip.set('tool', tool, 'version', '>=6.0', clobber=False)
30
28
 
29
+ def test_version():
30
+ if not has_pyslang():
31
+ return "pyslang is not installed"
31
32
 
32
- def parse_version(stdout):
33
- # slang --version output looks like:
34
- # slang version 6.0.121+c2c478cf
33
+ version = pyslang.VersionInfo
34
+ if version.getMajor() >= 7 and version.getMinor() >= 0:
35
+ return None
35
36
 
36
- # grab version # by splitting on whitespace
37
- return stdout.strip().split()[-1].split('+')[0]
37
+ ver = f"{version.getMajor()}.{version.getMinor()}.{version.getPatch()}"
38
38
 
39
+ return f"incorrect pyslang version: {ver}"
39
40
 
40
- def post_process(chip):
41
- step = chip.get('arg', 'step')
42
- index = chip.get('arg', 'index')
43
41
 
44
- log = f'{step}.log'
45
- with sc_open(log) as f:
46
- for line in f:
47
- match = re.search(r'(\d+) errors, (\d+) warnings', line)
48
- if match:
49
- record_metric(chip, step, index, 'errors', match.group(1), log)
50
- record_metric(chip, step, index, 'warnings', match.group(2), log)
42
+ ################################
43
+ # Setup Tool (pre executable)
44
+ ################################
45
+ def setup(chip):
46
+ add_require_input(chip, 'input', 'rtl', 'verilog')
47
+ add_require_input(chip, 'input', 'rtl', 'systemverilog')
48
+ add_require_input(chip, 'input', 'cmdfile', 'f')
49
+ add_frontend_requires(chip, ['ydir', 'idir', 'vlib', 'libext', 'define', 'param'])
51
50
 
52
51
 
53
52
  def common_runtime_options(chip):
54
- options = []
55
-
56
53
  step = chip.get('arg', 'step')
57
54
  index = chip.get('arg', 'index')
58
55
  tool, task = get_tool_task(chip, step, index)
59
56
 
60
- options.extend(['-j', str(chip.get('tool', tool, 'task', task, 'threads',
61
- step=step, index=index))])
57
+ options = chip.get('tool', tool, 'task', task, 'option', step=step, index=index)
58
+
59
+ options.append('--single-unit')
60
+
61
+ options.extend(['--threads', str(chip.get('tool', tool, 'task', task, 'threads',
62
+ step=step, index=index))])
62
63
 
63
64
  opts = get_frontend_options(chip,
64
65
  ['ydir',
@@ -113,7 +114,7 @@ def common_runtime_options(chip):
113
114
  #######################
114
115
  # Top Module
115
116
  #######################
116
- options.append('--top ' + chip.top())
117
+ options.append('--top ' + chip.top(step, index))
117
118
 
118
119
  ###############################
119
120
  # Parameters (top module only)
@@ -124,3 +125,92 @@ def common_runtime_options(chip):
124
125
  options.append(f'-G {param}={value}')
125
126
 
126
127
  return options
128
+
129
+
130
+ def _get_driver(chip, options_func, ignored_diagnotics=None):
131
+ driver = pyslang.Driver()
132
+ driver.addStandardArgs()
133
+
134
+ options = options_func(chip)
135
+
136
+ parseOpts = pyslang.CommandLineOptions()
137
+ parseOpts.ignoreProgramName = True
138
+ opts = " ".join(options)
139
+ code = 0
140
+ if not driver.parseCommandLine(opts, parseOpts):
141
+ code = 1
142
+
143
+ if code == 0 and not driver.processOptions():
144
+ code = 2
145
+
146
+ step = chip.get('arg', 'step')
147
+ index = chip.get('arg', 'index')
148
+ tool, task = get_tool_task(chip, step, index)
149
+ for warning in chip.get('tool', tool, 'task', task, 'warningoff', step=step, index=index):
150
+ if hasattr(pyslang.Diags, warning):
151
+ driver.diagEngine.setSeverity(
152
+ getattr(pyslang.Diags, warning),
153
+ pyslang.DiagnosticSeverity.Ignored)
154
+ elif not chip.get('option', 'quiet', step=step, index=index):
155
+ chip.logger.warning(f'{warning} is not a valid slang category')
156
+
157
+ if not ignored_diagnotics:
158
+ ignored_diagnotics = []
159
+ for ignore in ignored_diagnotics:
160
+ driver.diagEngine.setSeverity(
161
+ ignore,
162
+ pyslang.DiagnosticSeverity.Ignored)
163
+
164
+ return driver, code
165
+
166
+
167
+ def _compile(chip, driver):
168
+ ok = driver.parseAllSources()
169
+ compilation = driver.createCompilation()
170
+ return compilation, ok
171
+
172
+
173
+ def _diagnostics(chip, driver, compilation):
174
+ step = chip.get('arg', 'step')
175
+ index = chip.get('arg', 'index')
176
+
177
+ report = {
178
+ "error": [],
179
+ "warning": [],
180
+ }
181
+ diags = driver.diagEngine
182
+ for diag in compilation.getAllDiagnostics():
183
+ severity = diags.getSeverity(diag.code, diag.location)
184
+ report_level = None
185
+ if severity == pyslang.DiagnosticSeverity.Warning:
186
+ report_level = "warning"
187
+ elif severity == pyslang.DiagnosticSeverity.Error:
188
+ report_level = "error"
189
+ elif severity == pyslang.DiagnosticSeverity.Fatal:
190
+ report_level = "error"
191
+
192
+ if report_level:
193
+ for n, line in enumerate(diags.reportAll(driver.sourceManager, [diag]).splitlines()):
194
+ if line.strip():
195
+ if n == 0:
196
+ line_parts = line.split(":")
197
+ if os.path.exists(line_parts[0]):
198
+ line_parts[0] = os.path.abspath(line_parts[0])
199
+ line = ":".join(line_parts)
200
+
201
+ report[report_level].append(line)
202
+
203
+ if not chip.get('option', 'quiet', step=step, index=index):
204
+ if report["warning"]:
205
+ for line in report["warning"]:
206
+ chip.logger.warning(line)
207
+ if report["error"]:
208
+ for line in report["error"]:
209
+ chip.logger.error(line)
210
+
211
+ diags.clearCounts()
212
+ for diag in compilation.getAllDiagnostics():
213
+ diags.issue(diag)
214
+
215
+ record_metric(chip, step, index, 'errors', diags.numErrors, [])
216
+ record_metric(chip, step, index, 'warnings', diags.numWarnings, [])
@@ -1,13 +1,21 @@
1
1
  from siliconcompiler import utils
2
2
  from siliconcompiler.tools import slang
3
- from siliconcompiler.tools._common import \
4
- add_require_input, add_frontend_requires, get_tool_task, has_input_files
3
+ import os
4
+ from siliconcompiler.tools._common import get_tool_task, has_input_files
5
+ from siliconcompiler.tools.slang import pyslang
5
6
 
6
7
 
7
8
  def setup(chip):
8
9
  '''
9
10
  Elaborate verilog design files and generate a unified file.
10
11
  '''
12
+ if slang.test_version():
13
+ return slang.test_version()
14
+
15
+ if not has_input_files(chip, 'input', 'rtl', 'verilog') and \
16
+ not has_input_files(chip, 'input', 'rtl', 'systemverilog'):
17
+ return "no files in [input,rtl,systemverilog] or [input,rtl,verilog]"
18
+
11
19
  slang.setup(chip)
12
20
 
13
21
  step = chip.get('arg', 'step')
@@ -17,30 +25,127 @@ def setup(chip):
17
25
  chip.set('tool', tool, 'task', task, 'threads', utils.get_cores(chip),
18
26
  clobber=False, step=step, index=index)
19
27
 
20
- add_require_input(chip, 'input', 'rtl', 'verilog')
21
- add_require_input(chip, 'input', 'rtl', 'systemverilog')
22
- add_frontend_requires(chip, ['ydir', 'idir', 'vlib', 'libext', 'define', 'param'])
23
-
24
- chip.set('tool', tool, 'task', task, 'stdout', 'destination', 'output', step=step, index=index)
25
- chip.set('tool', tool, 'task', task, 'stdout', 'suffix', 'v', step=step, index=index)
28
+ chip.set('tool', tool, 'task', task, 'stdout', 'destination', 'log', step=step, index=index)
29
+ chip.set('tool', tool, 'task', task, 'stderr', 'destination', 'log', step=step, index=index)
26
30
 
27
31
  chip.set('tool', tool, 'task', task, 'output', __outputfile(chip), step=step, index=index)
28
32
 
33
+ chip.set('tool', tool, 'task', task, 'var', 'include_source_paths', True,
34
+ step=step, index=index, clobber=False)
35
+ chip.set('tool', tool, 'task', task, 'var', 'include_source_paths',
36
+ "true/false, if true add the source file path information", field="help")
37
+
38
+
39
+ def __outputfile(chip):
40
+ is_systemverilog = has_input_files(chip, 'input', 'rtl', 'systemverilog')
41
+ if is_systemverilog:
42
+ return f'{chip.top()}.sv'
43
+ return f'{chip.top()}.v'
44
+
45
+
46
+ def __get_files(manager, tree):
47
+ files = set()
48
+
49
+ from queue import Queue
50
+ nodes = Queue(maxsize=0)
51
+ nodes.put(tree.root)
52
+
53
+ def procRange(range):
54
+ files.add(manager.getFileName(range.start))
55
+ files.add(manager.getFileName(range.end))
56
+
57
+ while not nodes.empty():
58
+ node = nodes.get()
59
+ procRange(node.sourceRange)
60
+ for token in node:
61
+ if isinstance(token, pyslang.Token):
62
+ procRange(token.range)
63
+ else:
64
+ nodes.put(token)
65
+
66
+ return sorted([os.path.abspath(f) for f in files if os.path.isfile(f)])
67
+
68
+
69
+ def run(chip):
70
+ # Override default errors
71
+ ignored = [
72
+ pyslang.Diags.MissingTimeScale,
73
+ pyslang.Diags.UsedBeforeDeclared,
74
+ pyslang.Diags.UnusedParameter,
75
+ pyslang.Diags.UnusedDefinition,
76
+ pyslang.Diags.UnusedVariable,
77
+ pyslang.Diags.UnusedPort,
78
+ pyslang.Diags.UnusedButSetNet,
79
+ pyslang.Diags.UnusedImplicitNet,
80
+ pyslang.Diags.UnusedButSetVariable,
81
+ pyslang.Diags.UnusedButSetPort,
82
+ pyslang.Diags.UnusedTypedef,
83
+ pyslang.Diags.UnusedGenvar,
84
+ pyslang.Diags.UnusedAssertionDecl
85
+ ]
86
+
87
+ driver, exitcode = slang._get_driver(
88
+ chip,
89
+ runtime_options,
90
+ ignored_diagnotics=ignored)
91
+ if exitcode:
92
+ return exitcode
93
+
94
+ compilation, ok = slang._compile(chip, driver)
95
+
96
+ slang._diagnostics(chip, driver, compilation)
97
+
98
+ manager = compilation.sourceManager
99
+
100
+ step = chip.get('arg', 'step')
101
+ index = chip.get('arg', 'index')
102
+ tool, task = get_tool_task(chip, step, index)
103
+ add_source = chip.get('tool', tool, 'task', task, 'var', 'include_source_paths',
104
+ step=step, index=index)[0] == 'true'
105
+
106
+ def printFiles(out, files):
107
+ for src_file in files:
108
+ out.write(f'// File: {src_file}\n')
109
+
110
+ with open(f'outputs/{__outputfile(chip)}', 'w') as out:
111
+ for tree in compilation.getSyntaxTrees():
112
+ files = []
113
+ if add_source:
114
+ files = __get_files(manager, tree)
115
+
116
+ writer = pyslang.SyntaxPrinter(manager)
117
+
118
+ writer.setIncludeMissing(False)
119
+ writer.setIncludeSkipped(False)
120
+ writer.setIncludeDirectives(False)
121
+
122
+ writer.setIncludePreprocessed(True)
123
+ writer.setIncludeTrivia(True)
124
+ writer.setIncludeComments(True)
125
+ writer.setSquashNewlines(True)
126
+
127
+ out.write("////////////////////////////////////////////////////////////////\n")
128
+ out.write("// Start:\n")
129
+ printFiles(out, files)
130
+
131
+ out.write(writer.print(tree).str() + '\n')
132
+
133
+ out.write("// End:\n")
134
+ printFiles(out, files)
135
+ out.write("////////////////////////////////////////////////////////////////\n")
136
+
137
+ if ok:
138
+ return 0
139
+ else:
140
+ return 1
141
+
29
142
 
30
143
  def runtime_options(chip):
31
144
  options = slang.common_runtime_options(chip)
32
145
  options.extend([
33
- "--preprocess",
34
- "--comments",
146
+ "--allow-use-before-declare",
35
147
  "--ignore-unknown-modules",
36
- "--allow-use-before-declare"
148
+ "-Weverything"
37
149
  ])
38
150
 
39
151
  return options
40
-
41
-
42
- def __outputfile(chip):
43
- is_systemverilog = has_input_files(chip, 'input', 'rtl', 'systemverilog')
44
- if is_systemverilog:
45
- return f'{chip.top()}.sv'
46
- return f'{chip.top()}.v'
@@ -1,13 +1,15 @@
1
1
  from siliconcompiler import utils
2
2
  from siliconcompiler.tools import slang
3
- from siliconcompiler.tools._common import \
4
- add_require_input, add_frontend_requires, get_tool_task
3
+ from siliconcompiler.tools._common import get_tool_task
5
4
 
6
5
 
7
6
  def setup(chip):
8
7
  '''
9
8
  Lint system verilog
10
9
  '''
10
+ if slang.test_version():
11
+ return slang.test_version()
12
+
11
13
  slang.setup(chip)
12
14
 
13
15
  step = chip.get('arg', 'step')
@@ -17,19 +19,27 @@ def setup(chip):
17
19
  chip.set('tool', tool, 'task', task, 'threads', utils.get_cores(chip),
18
20
  clobber=False, step=step, index=index)
19
21
 
20
- add_require_input(chip, 'input', 'rtl', 'verilog')
21
- add_require_input(chip, 'input', 'rtl', 'systemverilog')
22
- add_frontend_requires(chip, ['ydir', 'idir', 'vlib', 'libext', 'define', 'param'])
22
+
23
+ def run(chip):
24
+ driver, exitcode = slang._get_driver(chip, runtime_options)
25
+ if exitcode:
26
+ return exitcode
27
+
28
+ compilation, ok = slang._compile(chip, driver)
29
+ slang._diagnostics(chip, driver, compilation)
30
+
31
+ if ok:
32
+ return 0
33
+ else:
34
+ return 1
23
35
 
24
36
 
25
37
  def runtime_options(chip):
26
38
  options = slang.common_runtime_options(chip)
27
39
  options.extend([
28
- "--lint-only"
40
+ "--lint-only",
41
+ "-Weverything",
42
+ "-Werror"
29
43
  ])
30
44
 
31
45
  return options
32
-
33
-
34
- def post_process(chip):
35
- slang.post_process(chip)
@@ -10,7 +10,12 @@ Sources: https://github.com/chipsalliance/Surelog
10
10
  Installation: https://github.com/chipsalliance/Surelog
11
11
  '''
12
12
 
13
- import surelog
13
+ import sys
14
+ try:
15
+ import surelog
16
+ except ModuleNotFoundError:
17
+ surelog = None
18
+
14
19
  from siliconcompiler.tools._common import get_tool_task
15
20
 
16
21
 
@@ -31,9 +36,17 @@ def setup(chip):
31
36
 
32
37
  is_docker = chip.get('option', 'scheduler', 'name', step=step, index=index) == 'docker'
33
38
  if not is_docker:
34
- exe = surelog.get_bin()
39
+ if surelog:
40
+ exe = surelog.get_bin()
41
+ else:
42
+ exe = 'surelog'
43
+ if sys.platform.startswith("win32"):
44
+ exe = f"{exe}.exe"
35
45
  else:
36
- exe = surelog.get_bin('linux')
46
+ if surelog:
47
+ exe = surelog.get_bin('linux')
48
+ else:
49
+ exe = 'surelog'
37
50
 
38
51
  # Standard Setup
39
52
  chip.set('tool', tool, 'exe', exe)
@@ -43,7 +56,7 @@ def setup(chip):
43
56
  # We package SC wheels with a precompiled copy of Surelog installed to
44
57
  # tools/surelog/bin. If the user doesn't have Surelog installed on their
45
58
  # system path, set the path to the bundled copy in the schema.
46
- if not surelog.has_system_surelog() and not is_docker:
59
+ if surelog and not surelog.has_system_surelog() and not is_docker:
47
60
  chip.set('tool', tool, 'path', surelog.get_path(), clobber=False)
48
61
 
49
62
  # Log file parsing
@@ -16,6 +16,7 @@ Sources: https://github.com/verilog-to-routing/vtr-verilog-to-routing
16
16
  Installation: https://github.com/verilog-to-routing/vtr-verilog-to-routing
17
17
  '''
18
18
 
19
+ import glob
19
20
  import os
20
21
  import shutil
21
22
  import json
@@ -42,7 +43,7 @@ def setup_tool(chip, clobber=True):
42
43
 
43
44
  chip.set('tool', 'vpr', 'exe', 'vpr', clobber=clobber)
44
45
  chip.set('tool', 'vpr', 'vswitch', '--version')
45
- chip.set('tool', 'vpr', 'version', '>=8.1.0', clobber=clobber)
46
+ chip.set('tool', 'vpr', 'version', '>=9.0.0', clobber=clobber)
46
47
 
47
48
  step = chip.get('arg', 'step')
48
49
  index = chip.get('arg', 'index')
@@ -80,6 +81,16 @@ def add_tool_requirements(chip):
80
81
  chip.add('tool', tool, 'task', task, 'require', f'fpga,{part_name},var,vpr_device_code',
81
82
  step=step, index=index)
82
83
 
84
+ chip.set('tool', tool, 'task', task, 'var', 'timing_paths',
85
+ 'number of timing paths to report', field='help')
86
+ chip.set('tool', tool, 'task', task, 'var', 'timing_paths', '20',
87
+ step=step, index=index, clobber=False)
88
+
89
+ chip.set('tool', tool, 'task', task, 'var', 'timing_report_type',
90
+ 'type of timing report', field='help')
91
+ chip.set('tool', tool, 'task', task, 'var', 'timing_report_type', 'aggregated',
92
+ step=step, index=index, clobber=False)
93
+
83
94
 
84
95
  def runtime_options(chip):
85
96
 
@@ -163,13 +174,22 @@ def runtime_options(chip):
163
174
  'vpr_clock model must be set to ideal, route, or dedicated_clock_network',
164
175
  chip=chip)
165
176
 
177
+ sdc_file = None
166
178
  if chip.valid('input', 'constraint', 'sdc'):
167
179
  sdc_file = find_single_file(chip, 'input', 'constraint', 'sdc',
168
180
  step=step, index=index,
169
181
  file_not_found_msg="SDC file not found")
170
- if (sdc_file is not None):
171
- sdc_arg = f"--sdc_file {sdc_file}"
172
- options.append(sdc_arg)
182
+
183
+ if sdc_file:
184
+ sdc_arg = f"--sdc_file {sdc_file}"
185
+ options.append(sdc_arg)
186
+
187
+ report_type = chip.get('tool', tool, 'task', task, 'var', 'timing_report_type',
188
+ step=step, index=index)[0]
189
+ options.append(f'--timing_report_detail {report_type}')
190
+ report_paths = chip.get('tool', tool, 'task', task, 'var', 'timing_paths',
191
+ step=step, index=index)[0]
192
+ options.append(f'--timing_report_npaths {report_paths}')
173
193
  else:
174
194
  options.append("--timing_analysis off")
175
195
 
@@ -295,8 +315,8 @@ def vpr_post_process(chip):
295
315
  step = chip.get('arg', 'step')
296
316
  index = chip.get('arg', 'index')
297
317
 
298
- if os.path.exists('packing_pin_util.rpt'):
299
- shutil.move('packing_pin_util.rpt', 'reports')
318
+ for report in glob.glob("*.rpt"):
319
+ shutil.move(report, 'reports')
300
320
 
301
321
  part_name = chip.get('fpga', 'partname')
302
322
  dff_cells = []
@@ -379,6 +399,66 @@ def vpr_post_process(chip):
379
399
 
380
400
  record_metric(chip, step, index, "pins", io, __block_file)
381
401
 
402
+ for setup_report in ("reports/report_timing.setup.rpt",
403
+ "reports/pre_pack.report_timing.setup.rpt"):
404
+ if not os.path.exists(setup_report):
405
+ continue
406
+
407
+ slack = _parse_timing_report(setup_report)
408
+ if slack is not None:
409
+ wns = min([slack, 0])
410
+ record_metric(chip, step, index, "setupslack", slack, setup_report, source_unit="ns")
411
+ record_metric(chip, step, index, "setupwns", wns, setup_report, source_unit="ns")
412
+ break
413
+
414
+ for hold_report in ("reports/report_timing.hold.rpt", ):
415
+ if not os.path.exists(hold_report):
416
+ continue
417
+
418
+ slack = _parse_timing_report(hold_report)
419
+ if slack is not None:
420
+ wns = min([slack, 0])
421
+ record_metric(chip, step, index, "holdslack", slack, hold_report, source_unit="ns")
422
+ record_metric(chip, step, index, "holdwns", wns, hold_report, source_unit="ns")
423
+ break
424
+
425
+ unconstrained = None
426
+ unconstrained_reports = []
427
+ for unconstrained_report in ("reports/report_unconstrained_timing.hold.rpt",
428
+ "reports/report_unconstrained_timing.setup.rpt"):
429
+ if not os.path.exists(unconstrained_report):
430
+ continue
431
+
432
+ paths = _parse_unconstrained_report(unconstrained_report)
433
+ if unconstrained is None:
434
+ unconstrained = paths
435
+
436
+ unconstrained = max([paths, unconstrained])
437
+ unconstrained_reports.append(unconstrained_report)
438
+
439
+ if unconstrained is not None:
440
+ record_metric(chip, step, index, "unconstrained", unconstrained, unconstrained_reports)
441
+
442
+
443
+ def _parse_timing_report(report):
444
+ slack = re.compile(r"slack \(.*\)\s+(-?\d+\.?\d*)")
445
+ with sc_open(report) as f:
446
+ for line in f:
447
+ match_slack = slack.findall(line)
448
+ if match_slack:
449
+ return float(match_slack[0])
450
+ return None
451
+
452
+
453
+ def _parse_unconstrained_report(report):
454
+ path = re.compile(r"\d+ .*")
455
+ count = 0
456
+ with sc_open(report) as f:
457
+ for line in f:
458
+ if path.match(line):
459
+ count += 1
460
+ return count
461
+
382
462
 
383
463
  ##################################################
384
464
  if __name__ == "__main__":
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "openroad": {
3
3
  "git-url": "https://github.com/The-OpenROAD-Project/OpenROAD.git",
4
- "git-commit": "6e6fccbbe0ffbe683a51de3ecac2a24958a53fa1",
4
+ "git-commit": "0fbd4d94c81ef070249ad9d9037a740d0c6e58fa",
5
5
  "docker-cmds": [
6
6
  "# Remove OR-Tools files",
7
7
  "RUN rm -f $SC_PREFIX/Makefile $SC_PREFIX/README.md",
@@ -36,7 +36,7 @@
36
36
  "auto-update": false
37
37
  },
38
38
  "klayout": {
39
- "version": "0.29.11",
39
+ "version": "0.29.12",
40
40
  "git-url": "https://github.com/KLayout/klayout.git",
41
41
  "docker-skip": true,
42
42
  "auto-update": true,
@@ -66,7 +66,7 @@
66
66
  },
67
67
  "vpr": {
68
68
  "git-url": "https://github.com/verilog-to-routing/vtr-verilog-to-routing.git",
69
- "git-commit": "de31f094aa4f894a5e6e0dc32c66365f4b341190",
69
+ "git-commit": "v9.0.0",
70
70
  "auto-update": false
71
71
  },
72
72
  "icepack": {
@@ -139,7 +139,7 @@
139
139
  },
140
140
  "yosys-slang": {
141
141
  "git-url": "https://github.com/povik/yosys-slang.git",
142
- "git-commit": "0adba99ea43331235506b9b154c78a401f4fe9b6",
142
+ "git-commit": "8f2239b2b12dac43f8f47f56deef1095d5262fa2",
143
143
  "docker-depends": "yosys",
144
144
  "auto-update": true
145
145
  },
siliconcompiler/units.py CHANGED
@@ -41,7 +41,7 @@ SI_TYPES = (
41
41
  'V',
42
42
  'W',
43
43
  'ohm',
44
- 'C',
44
+ 'C'
45
45
  )
46
46
 
47
47
 
@@ -107,8 +107,6 @@ def get_si_prefix(unit):
107
107
  if matches:
108
108
  return matches[0][0]
109
109
 
110
- return ''
111
-
112
110
 
113
111
  def get_si_power(unit):
114
112
  '''
@@ -164,6 +162,11 @@ def format_si(value, unit, margin=3, digits=3):
164
162
  digits (int): number of digits to print after .
165
163
  '''
166
164
  scaled_value, prefix = scale_si(value, unit, margin=margin, digits=digits)
165
+
166
+ if digits < 0:
167
+ # Default to 1
168
+ digits = 1
169
+
167
170
  # need to do this in case float shortens scaled_value
168
171
  return f'{scaled_value:.{digits}f}{prefix}'
169
172
 
@@ -179,14 +182,14 @@ def scale_si(value, unit, margin=3, digits=3):
179
182
  when picking the right magnitude
180
183
  digits (int): number of digits to print after .
181
184
  '''
185
+ if digits < 0:
186
+ # Default to 1
187
+ digits = 1
188
+
182
189
  if unit and is_base_si_unit(unit):
183
190
  value = float(value)
184
191
  log_value = math.log10(value) - margin
185
192
 
186
- if digits < 0:
187
- # Default to 0
188
- digits = 0
189
-
190
193
  for prefix, scale in SI_UNITS:
191
194
  if log_value <= scale:
192
195
  value /= 10**scale