siliconcompiler 0.29.2__py3-none-any.whl → 0.29.4__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 (85) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/sc_install.py +19 -4
  3. siliconcompiler/core.py +8 -3
  4. siliconcompiler/flowgraph.py +23 -5
  5. siliconcompiler/remote/client.py +3 -0
  6. siliconcompiler/scheduler/__init__.py +30 -12
  7. siliconcompiler/tools/__init__.py +1 -1
  8. siliconcompiler/tools/_common/asic.py +3 -0
  9. siliconcompiler/tools/_common/asic_clock.py +101 -0
  10. siliconcompiler/tools/bambu/__init__.py +32 -0
  11. siliconcompiler/tools/bambu/convert.py +93 -11
  12. siliconcompiler/tools/bluespec/convert.py +2 -1
  13. siliconcompiler/tools/chisel/convert.py +2 -1
  14. siliconcompiler/tools/genfasm/bitstream.py +2 -2
  15. siliconcompiler/tools/ghdl/convert.py +2 -2
  16. siliconcompiler/tools/gtkwave/show.py +2 -1
  17. siliconcompiler/tools/icarus/compile.py +2 -2
  18. siliconcompiler/tools/klayout/drc.py +2 -1
  19. siliconcompiler/tools/magic/magic.py +1 -1
  20. siliconcompiler/tools/netgen/lvs.py +2 -1
  21. siliconcompiler/tools/openroad/_apr.py +16 -4
  22. siliconcompiler/tools/openroad/fillmetal_insertion.py +0 -1
  23. siliconcompiler/tools/openroad/init_floorplan.py +7 -1
  24. siliconcompiler/tools/openroad/macro_placement.py +1 -2
  25. siliconcompiler/tools/openroad/pin_placement.py +0 -1
  26. siliconcompiler/tools/openroad/rdlroute.py +2 -2
  27. siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +3 -2
  28. siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +1 -0
  29. siliconcompiler/tools/openroad/scripts/apr/sc_macro_placement.tcl +78 -94
  30. siliconcompiler/tools/openroad/scripts/apr/sc_power_grid.tcl +12 -1
  31. siliconcompiler/tools/openroad/scripts/apr/sc_repair_timing.tcl +24 -0
  32. siliconcompiler/tools/openroad/scripts/common/procs.tcl +3 -2
  33. siliconcompiler/tools/openroad/scripts/common/read_input_files.tcl +1 -0
  34. siliconcompiler/tools/openroad/scripts/common/reports.tcl +4 -13
  35. siliconcompiler/tools/openroad/scripts/common/write_data.tcl +2 -5
  36. siliconcompiler/tools/openroad/scripts/common/write_data_physical.tcl +3 -0
  37. siliconcompiler/tools/openroad/scripts/common/write_data_timing.tcl +1 -0
  38. siliconcompiler/tools/openroad/scripts/sc_rdlroute.tcl +1 -1
  39. siliconcompiler/tools/opensta/__init__.py +2 -2
  40. siliconcompiler/tools/opensta/report_libraries.py +2 -2
  41. siliconcompiler/tools/opensta/timing.py +2 -1
  42. siliconcompiler/tools/slang/__init__.py +79 -2
  43. siliconcompiler/tools/slang/elaborate.py +46 -0
  44. siliconcompiler/tools/slang/lint.py +10 -76
  45. siliconcompiler/tools/surelog/parse.py +1 -1
  46. siliconcompiler/tools/sv2v/convert.py +2 -2
  47. siliconcompiler/tools/template/template.py +2 -2
  48. siliconcompiler/tools/verilator/verilator.py +3 -1
  49. siliconcompiler/tools/vivado/vivado.py +2 -1
  50. siliconcompiler/tools/vpr/place.py +2 -2
  51. siliconcompiler/tools/vpr/route.py +2 -2
  52. siliconcompiler/tools/vpr/show.py +2 -1
  53. siliconcompiler/tools/yosys/__init__.py +26 -23
  54. siliconcompiler/tools/yosys/procs.tcl +17 -0
  55. siliconcompiler/tools/yosys/syn_asic.py +20 -65
  56. siliconcompiler/tools/yosys/syn_asic.tcl +10 -51
  57. siliconcompiler/toolscripts/_tools.json +4 -4
  58. siliconcompiler/toolscripts/rhel8/install-slang.sh +0 -0
  59. siliconcompiler/toolscripts/rhel8/install-sv2v.sh +7 -1
  60. siliconcompiler/toolscripts/rhel8/install-yosys.sh +1 -1
  61. siliconcompiler/toolscripts/rhel9/install-openroad.sh +34 -0
  62. siliconcompiler/toolscripts/rhel9/install-slang.sh +0 -0
  63. siliconcompiler/toolscripts/rhel9/install-sv2v.sh +7 -1
  64. siliconcompiler/toolscripts/rhel9/install-yosys.sh +1 -1
  65. siliconcompiler/toolscripts/ubuntu20/install-slang.sh +0 -0
  66. siliconcompiler/toolscripts/ubuntu20/install-surelog.sh +1 -0
  67. siliconcompiler/toolscripts/ubuntu20/install-sv2v.sh +7 -1
  68. siliconcompiler/toolscripts/ubuntu20/install-yosys.sh +1 -1
  69. siliconcompiler/toolscripts/ubuntu22/install-surelog.sh +7 -1
  70. siliconcompiler/toolscripts/ubuntu22/install-sv2v.sh +7 -1
  71. siliconcompiler/toolscripts/ubuntu22/install-yosys.sh +1 -1
  72. siliconcompiler/toolscripts/ubuntu24/install-bambu.sh +3 -4
  73. siliconcompiler/toolscripts/ubuntu24/install-slang.sh +0 -0
  74. siliconcompiler/toolscripts/ubuntu24/install-surelog.sh +7 -1
  75. siliconcompiler/toolscripts/ubuntu24/install-sv2v.sh +7 -1
  76. siliconcompiler/toolscripts/ubuntu24/install-yosys.sh +1 -1
  77. siliconcompiler/utils/__init__.py +24 -0
  78. siliconcompiler/utils/logging.py +67 -0
  79. {siliconcompiler-0.29.2.dist-info → siliconcompiler-0.29.4.dist-info}/METADATA +8 -8
  80. {siliconcompiler-0.29.2.dist-info → siliconcompiler-0.29.4.dist-info}/RECORD +80 -75
  81. siliconcompiler/tools/bambu/bambu.py +0 -32
  82. {siliconcompiler-0.29.2.dist-info → siliconcompiler-0.29.4.dist-info}/LICENSE +0 -0
  83. {siliconcompiler-0.29.2.dist-info → siliconcompiler-0.29.4.dist-info}/WHEEL +0 -0
  84. {siliconcompiler-0.29.2.dist-info → siliconcompiler-0.29.4.dist-info}/entry_points.txt +0 -0
  85. {siliconcompiler-0.29.2.dist-info → siliconcompiler-0.29.4.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
1
  # Version number following semver standard.
2
- version = '0.29.2'
2
+ version = '0.29.4'
3
3
 
4
4
  # Default server address for remote runs, if unspecified.
5
5
  default_server = 'https://server.siliconcompiler.com'
@@ -73,16 +73,18 @@ def show_tool(tool, script):
73
73
  def _get_os_name():
74
74
  machine_info = _get_machine_info()
75
75
  system = machine_info.get('system', "").lower()
76
- distro = machine_info.get('distro', "").lower()
77
- osversion = machine_info.get('osversion', "").lower()
78
76
  if system == 'linux':
77
+ distro = machine_info.get('distro', "").lower()
79
78
  if distro == 'ubuntu':
79
+ osversion = machine_info.get('osversion', "").lower()
80
80
  version, _ = osversion.split('.')
81
81
  return f"{distro}{version}"
82
82
  elif distro == 'rocky':
83
+ osversion = machine_info.get('osversion', "").lower()
83
84
  version, _ = osversion.split('.')
84
85
  return f"rhel{version}"
85
86
  elif distro == 'rhel':
87
+ osversion = machine_info.get('osversion', "").lower()
86
88
  version, _ = osversion.split('.')
87
89
  return f"rhel{version}"
88
90
  return None
@@ -134,6 +136,10 @@ def _recommended_tool_groups(tools):
134
136
  for group, group_tools in groups.items():
135
137
  if all([tool in tools for tool in group_tools]):
136
138
  filter_groups[group] = group_tools
139
+ else:
140
+ missing = sorted([tool for tool in group_tools if tool not in tools])
141
+ filter_groups[group] = f"{group} group is not available for {_get_os_name()} " \
142
+ f"due to lack of support for the following tools: {', '.join(missing)}"
137
143
  return filter_groups
138
144
 
139
145
 
@@ -168,10 +174,15 @@ To system debugging information (this should only be used to debug):
168
174
  parser = argparse.ArgumentParser(
169
175
  prog=progname,
170
176
  description=description,
171
- formatter_class=argparse.RawDescriptionHelpFormatter)
177
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
172
178
 
173
179
  tools = _get_tools_list()
174
180
 
181
+ if _get_os_name() is None:
182
+ print("Unsupported operating system", file=sys.stderr)
183
+ print_machine_info()
184
+ return 1
185
+
175
186
  tool_choices = ChoiceOptional(tools.keys())
176
187
  parser.add_argument(
177
188
  "tool",
@@ -220,7 +231,11 @@ To system debugging information (this should only be used to debug):
220
231
  args.tool = list(args.tool)
221
232
  if args.group:
222
233
  for group in args.group:
223
- args.tool.extend(tool_groups[group])
234
+ if isinstance(tool_groups[group], str):
235
+ print(tool_groups[group], file=sys.stderr)
236
+ return 1
237
+ else:
238
+ args.tool.extend(tool_groups[group])
224
239
 
225
240
  tools_handled = set()
226
241
  for tool in args.tool:
siliconcompiler/core.py CHANGED
@@ -21,6 +21,7 @@ from siliconcompiler.remote import client
21
21
  from siliconcompiler.schema import Schema, SCHEMA_VERSION
22
22
  from siliconcompiler.schema import utils as schema_utils
23
23
  from siliconcompiler import utils
24
+ from siliconcompiler.utils.logging import LoggerFormatter, ColorStreamFormatter
24
25
  from siliconcompiler import _metadata
25
26
  from siliconcompiler import NodeStatus, SiliconCompilerError
26
27
  from siliconcompiler.report import _show_summary_table
@@ -225,7 +226,8 @@ class Chip:
225
226
  else:
226
227
  in_run = False
227
228
 
228
- log_format = ['%(levelname)-7s']
229
+ level_format = '%(levelname)-7s'
230
+ log_format = [level_format]
229
231
  if loglevel == 'debug':
230
232
  log_format.append('%(funcName)-10s')
231
233
  log_format.append('%(lineno)-4s')
@@ -261,14 +263,17 @@ class Chip:
261
263
  log_formatprefix = ""
262
264
 
263
265
  log_format.append('%(message)s')
264
- logformat = log_formatprefix + ' | '.join(log_format)
266
+ stream_logformat = log_formatprefix + ' | '.join(log_format[1:])
265
267
 
266
268
  if not self.logger.hasHandlers():
267
269
  stream_handler = logging.StreamHandler(stream=sys.stdout)
268
270
  self.logger.addHandler(stream_handler)
269
271
 
270
272
  for handler in self.logger.handlers:
271
- formatter = logging.Formatter(logformat)
273
+ if ColorStreamFormatter.supports_color(handler):
274
+ formatter = ColorStreamFormatter(log_formatprefix, level_format, stream_logformat)
275
+ else:
276
+ formatter = LoggerFormatter(log_formatprefix, level_format, stream_logformat)
272
277
  handler.setFormatter(formatter)
273
278
 
274
279
  self.logger.setLevel(schema_utils.translate_loglevel(loglevel))
@@ -205,18 +205,36 @@ def _get_flowgraph_execution_order(chip, flow, reverse=False):
205
205
  else:
206
206
  ex_map.setdefault((istep, iindex), set()).add((step, index))
207
207
 
208
+ rev_ex_map = {}
209
+ for node, edges in ex_map.items():
210
+ for step, index in edges:
211
+ rev_ex_map.setdefault((step, index), set()).add(node)
212
+
208
213
  # Collect execution order of nodes
209
214
  if reverse:
210
215
  order = [set(_get_flowgraph_exit_nodes(chip, flow))]
211
216
  else:
212
217
  order = [set(_get_flowgraph_entry_nodes(chip, flow))]
213
218
 
219
+ visited = set()
214
220
  while True:
215
221
  next_level = set()
216
- for step, index in order[-1]:
217
- if (step, index) in ex_map and \
218
- not any([(step, index) in v for v in ex_map.values()]):
219
- next_level.update(ex_map.pop((step, index)))
222
+ next_visited = set()
223
+ for step, index in sorted(order[-1]):
224
+ if (step, index) not in rev_ex_map:
225
+ # No edges so assume inputs are okay
226
+ inputs_valid = True
227
+ else:
228
+ inputs_valid = all([node in visited for node in rev_ex_map[(step, index)]])
229
+
230
+ if inputs_valid:
231
+ next_visited.add((step, index))
232
+ if (step, index) in ex_map:
233
+ next_level.update(ex_map.pop((step, index)))
234
+ else:
235
+ next_level.add((step, index))
236
+
237
+ visited.update(next_visited)
220
238
 
221
239
  if not next_level:
222
240
  break
@@ -233,7 +251,7 @@ def _get_flowgraph_execution_order(chip, flow, reverse=False):
233
251
 
234
252
  exec_order.reverse()
235
253
 
236
- return exec_order
254
+ return [sorted(level) for level in exec_order]
237
255
 
238
256
 
239
257
  def get_executed_nodes(chip, flow):
@@ -477,6 +477,9 @@ service, provided by SiliconCompiler, is not intended to process proprietary IP.
477
477
  # Flush file to ensure everything is written
478
478
  upload_file.flush()
479
479
 
480
+ # We no longer need the collected files
481
+ shutil.rmtree(self.__chip._getcollectdir(jobname=self.__chip.get('option', 'jobname')))
482
+
480
483
  if 'pre_upload' in remote_status:
481
484
  self.__logger.info(remote_status['pre_upload']['message'])
482
485
  time.sleep(remote_status['pre_upload']['delay'])
@@ -55,6 +55,10 @@ def _get_callback(hook):
55
55
  return None
56
56
 
57
57
 
58
+ # Max lines to print from failed node log
59
+ _failed_log_lines = 20
60
+
61
+
58
62
  ###############################################################################
59
63
  class SiliconCompilerTimeout(Exception):
60
64
  ''' Minimal Exception wrapper used to raise sc timeout errors.
@@ -833,6 +837,8 @@ def _run_executable_or_builtin(chip, step, index, version, toolpath, workdir, ru
833
837
  is_stderr_log = chip.get('tool', tool, 'task', task, 'stderr', 'destination',
834
838
  step=step, index=index) == 'log' and stderr_file != stdout_file
835
839
 
840
+ chip.logger.info(f'Running in {workdir}')
841
+
836
842
  retcode = 0
837
843
  cmdlist = []
838
844
  cmd_args = []
@@ -877,7 +883,6 @@ def _run_executable_or_builtin(chip, step, index, version, toolpath, workdir, ru
877
883
  # Make record of tool options
878
884
  __record_tool(chip, step, index, version, toolpath, cmd_args)
879
885
 
880
- chip.logger.info('Running in %s', workdir)
881
886
  chip.logger.info('%s', printable_cmd)
882
887
  timeout = chip.get('option', 'timeout', step=step, index=index)
883
888
  logfile = step + '.log'
@@ -988,10 +993,10 @@ def _run_executable_or_builtin(chip, step, index, version, toolpath, workdir, ru
988
993
  msg = f'Command failed with code {retcode}.'
989
994
  if logfile:
990
995
  if quiet:
991
- # Print last 10 lines of log when in quiet mode
996
+ # Print last N lines of log when in quiet mode
992
997
  with sc_open(logfile) as logfd:
993
998
  loglines = logfd.read().splitlines()
994
- for logline in loglines[-10:]:
999
+ for logline in loglines[-_failed_log_lines:]:
995
1000
  chip.logger.error(logline)
996
1001
  # No log file for pure-Python tools.
997
1002
  msg += f' See log file {os.path.abspath(logfile)}'
@@ -1239,6 +1244,13 @@ def _finalizenode(chip, step, index, replay):
1239
1244
 
1240
1245
  if not is_skipped:
1241
1246
  _check_logfile(chip, step, index, quiet, run_func)
1247
+
1248
+ # Report metrics
1249
+ for metric in ['errors', 'warnings']:
1250
+ val = chip.get('metric', metric, step=step, index=index)
1251
+ if val is not None:
1252
+ chip.logger.info(f'Number of {metric}: {val}')
1253
+
1242
1254
  _hash_files(chip, step, index)
1243
1255
 
1244
1256
  # Capture wall runtime and cpu cores
@@ -1535,12 +1547,13 @@ def _check_node_dependencies(chip, node, deps, deps_was_successful):
1535
1547
  def _launch_nodes(chip, nodes_to_run, processes, local_processes):
1536
1548
  running_nodes = {}
1537
1549
  max_parallel_run = chip.get('option', 'scheduler', 'maxnodes')
1538
- max_threads = os.cpu_count()
1550
+ max_cores = utils.get_cores(chip)
1551
+ max_threads = utils.get_cores(chip)
1539
1552
  if not max_parallel_run:
1540
- max_parallel_run = max_threads
1553
+ max_parallel_run = utils.get_cores(chip)
1541
1554
 
1542
- # clip max parallel jobs to 1 <= jobs <= max_threads
1543
- max_parallel_run = max(1, min(max_parallel_run, max_threads))
1555
+ # clip max parallel jobs to 1 <= jobs <= max_cores
1556
+ max_parallel_run = max(1, min(max_parallel_run, max_cores))
1544
1557
 
1545
1558
  def allow_start(node):
1546
1559
  if node not in local_processes:
@@ -1561,7 +1574,7 @@ def _launch_nodes(chip, nodes_to_run, processes, local_processes):
1561
1574
  # clamp to max_parallel to avoid getting locked up
1562
1575
  requested_threads = max(1, min(requested_threads, max_threads))
1563
1576
 
1564
- if requested_threads + sum(running_nodes.values()) > max_threads:
1577
+ if requested_threads + sum(running_nodes.values()) > max_cores:
1565
1578
  # delay until there are enough core available
1566
1579
  return False, 0
1567
1580
 
@@ -1615,8 +1628,14 @@ def _launch_nodes(chip, nodes_to_run, processes, local_processes):
1615
1628
  # Update dashboard if the manifest changed
1616
1629
  chip._dash.update_manifest()
1617
1630
 
1618
- # TODO: exponential back-off with max?
1619
- time.sleep(0.1)
1631
+ if len(running_nodes) == 1:
1632
+ # if there is only one node running, just join the thread
1633
+ running_node = list(running_nodes.keys())[0]
1634
+ processes[running_node]["proc"].join()
1635
+ elif len(running_nodes) > 1:
1636
+ # if there are more than 1, join the first with a timeout
1637
+ running_node = list(running_nodes.keys())[0]
1638
+ processes[running_node]["proc"].join(timeout=0.1)
1620
1639
 
1621
1640
 
1622
1641
  def _process_completed_nodes(chip, processes, running_nodes):
@@ -1936,7 +1955,7 @@ def check_node_inputs(chip, step, index):
1936
1955
  step=check_step, index=check_index)
1937
1956
 
1938
1957
  if check_hash != prev_hash:
1939
- print_warning(key)
1958
+ print_warning(key, "file hash")
1940
1959
  return False
1941
1960
  else:
1942
1961
  # check timestamps on current files
@@ -2062,7 +2081,6 @@ def check_logfile(chip, jobname=None, step=None, index='0',
2062
2081
  chip.logger.info(f'{suffix}: {line_with_num}')
2063
2082
 
2064
2083
  for suffix in ordered_suffixes:
2065
- chip.logger.info(f'Number of {suffix}: {matches[suffix]}')
2066
2084
  checks[suffix]['report'].close()
2067
2085
 
2068
2086
  return matches
@@ -1,4 +1,4 @@
1
- from siliconcompiler.tools.bambu import bambu
1
+ from siliconcompiler.tools import bambu
2
2
  from siliconcompiler.tools.bluespec import bluespec
3
3
  from siliconcompiler.tools.builtin import builtin
4
4
  from siliconcompiler.tools.chisel import chisel
@@ -194,6 +194,9 @@ def set_tool_task_lib_var(chip,
194
194
 
195
195
  values.update(chip.get(*lib_key, step=get_step, index=get_index))
196
196
 
197
+ if default_value and not check_value(values):
198
+ values = default_value
199
+
197
200
  if check_value(values):
198
201
  chip.set('tool', tool, 'task', task, 'var', param_key, values,
199
202
  step=step, index=index, clobber=False)
@@ -0,0 +1,101 @@
1
+ import re
2
+ from siliconcompiler.utils import sc_open
3
+ from siliconcompiler.tools._common.asic import get_tool_task
4
+
5
+
6
+ def __get_clock_data(chip, clock_units_multiplier=1):
7
+ step = chip.get('arg', 'step')
8
+ index = chip.get('arg', 'index')
9
+
10
+ period = None
11
+ # get clock information from sdc files
12
+ if chip.valid('input', 'constraint', 'sdc'):
13
+ for sdc in chip.find_files('input', 'constraint', 'sdc', step=step, index=index):
14
+ lines = []
15
+ with sc_open(sdc) as f:
16
+ lines = f.read().splitlines()
17
+
18
+ # collect simple variables in case clock is specified with a variable
19
+ re_var = r"[A-Za-z0-9_]+"
20
+ re_num = r"[0-9\.]+"
21
+ sdc_vars = {}
22
+ for line in lines:
23
+ tcl_variable = re.findall(fr"^\s*set\s+({re_var})\s+({re_num}|\${re_var})", line)
24
+ if tcl_variable:
25
+ var_name, var_value = tcl_variable[0]
26
+ sdc_vars[f'${var_name}'] = var_value
27
+
28
+ # TODO: handle line continuations
29
+ for line in lines:
30
+ clock_period = re.findall(fr"create_clock\s.*-period\s+({re_num}|\${re_var})",
31
+ line)
32
+ if clock_period:
33
+ convert_period = clock_period[0]
34
+ while isinstance(convert_period, str) and convert_period[0] == "$":
35
+ if convert_period in sdc_vars:
36
+ convert_period = sdc_vars[convert_period]
37
+ else:
38
+ break
39
+ if isinstance(convert_period, str) and convert_period[0] == "$":
40
+ chip.logger.warning('Unable to identify clock period from '
41
+ f'{clock_period[0]}.')
42
+ continue
43
+ else:
44
+ try:
45
+ clock_period = float(convert_period)
46
+ except TypeError:
47
+ continue
48
+
49
+ clock_period = clock_period * clock_units_multiplier
50
+
51
+ if period is None:
52
+ period = clock_period
53
+ else:
54
+ period = min(period, clock_period)
55
+
56
+ if period is not None:
57
+ return period, None, [('input', 'constraint', 'sdc')]
58
+
59
+ if period is None:
60
+ keys = []
61
+ key_pin = None
62
+ # get clock information from defined clocks
63
+ for pin in chip.getkeys('datasheet', 'pin'):
64
+ for mode in chip.getkeys('datasheet', 'pin', pin, 'type'):
65
+ if chip.get('datasheet', 'pin', pin, 'type', mode) == 'clock':
66
+ clock_period = min(chip.get('datasheet', 'pin', pin, 'tperiod', mode)) * 1e9
67
+
68
+ if period is None:
69
+ period = clock_period
70
+ keys = [
71
+ ('datasheet', 'pin', pin, 'type', mode),
72
+ ('datasheet', 'pin', pin, 'tperiod', mode)
73
+ ]
74
+ key_pin = pin
75
+ else:
76
+ if clock_period < period:
77
+ period = clock_period
78
+ keys = [
79
+ ('datasheet', 'pin', pin, 'type', mode),
80
+ ('datasheet', 'pin', pin, 'tperiod', mode)
81
+ ]
82
+ key_pin = pin
83
+ return period, key_pin, keys
84
+
85
+ return None, None, []
86
+
87
+
88
+ def add_clock_requirements(chip):
89
+ _, _, keys = __get_clock_data(chip)
90
+
91
+ step = chip.get('arg', 'step')
92
+ index = chip.get('arg', 'index')
93
+ tool, task = get_tool_task(chip, step, index)
94
+ for key in keys:
95
+ chip.add('tool', tool, 'task', task, 'require', ','.join(key),
96
+ step=step, index=index)
97
+
98
+
99
+ def get_clock_period(chip, clock_units_multiplier=1):
100
+ period, name, _ = __get_clock_data(chip, clock_units_multiplier=clock_units_multiplier)
101
+ return name, period
@@ -0,0 +1,32 @@
1
+ '''
2
+ The primary objective of the PandA project is to develop a usable framework that will
3
+ enable the research of new ideas in the HW-SW Co-Design field.
4
+
5
+ The PandA framework includes methodologies supporting the research on high-level synthesis
6
+ of hardware accelerators, on parallelism extraction for embedded systems, on hardware/software
7
+ partitioning and mapping, on metrics for performance estimation of embedded software
8
+ applications and on dynamic reconfigurable devices.
9
+
10
+ Documentation: https://github.com/ferrandi/PandA-bambu
11
+
12
+ Sources: https://github.com/ferrandi/PandA-bambu
13
+
14
+ Installation: https://panda.dei.polimi.it/?page_id=88
15
+ '''
16
+
17
+ from siliconcompiler.tools.bambu import convert
18
+
19
+
20
+ ####################################################################
21
+ # Make Docs
22
+ ####################################################################
23
+ def make_docs(chip):
24
+ convert.setup(chip)
25
+ return chip
26
+
27
+
28
+ def parse_version(stdout):
29
+ # Long multiline output, but second-to-last line looks like:
30
+ # Version: PandA 0.9.6 - Revision 5e5e306b86383a7d85274d64977a3d71fdcff4fe-main
31
+ version_line = stdout.split('\n')[-3]
32
+ return version_line.split()[2]
@@ -1,8 +1,19 @@
1
1
  import os
2
+ import re
2
3
  import shutil
4
+ from siliconcompiler.utils import sc_open
5
+ from siliconcompiler.tools._common.asic import set_tool_task_var, set_tool_task_lib_var, get_mainlib
6
+ from siliconcompiler.tools._common.asic_clock import get_clock_period, add_clock_requirements
3
7
  from siliconcompiler.tools._common import \
4
8
  add_frontend_requires, add_require_input, get_frontend_options, get_input_files, \
5
- get_tool_task, has_input_files
9
+ get_tool_task, has_input_files, record_metric
10
+
11
+
12
+ def make_docs(chip):
13
+ from siliconcompiler.targets import freepdk45_demo
14
+ chip.use(freepdk45_demo)
15
+ chip.input('<design>.c')
16
+ return setup(chip)
6
17
 
7
18
 
8
19
  def setup(chip):
@@ -10,13 +21,13 @@ def setup(chip):
10
21
  Performs high level synthesis to generate a verilog output
11
22
  '''
12
23
 
13
- if not has_input_files(chip, 'input', 'hll', 'c'):
14
- return "no files in [input,hll,c]"
24
+ if not has_input_files(chip, 'input', 'hll', 'c') and \
25
+ not has_input_files(chip, 'input', 'hll', 'llvm'):
26
+ return "no files in [input,hll,c] or [input,hll,llvm]"
15
27
 
16
- tool = 'bambu'
17
28
  step = chip.get('arg', 'step')
18
29
  index = chip.get('arg', 'index')
19
- _, task = get_tool_task(chip, step, index)
30
+ tool, task = get_tool_task(chip, step, index)
20
31
 
21
32
  # Standard Setup
22
33
  refdir = 'tools/' + tool
@@ -27,24 +38,41 @@ def setup(chip):
27
38
  chip.set('tool', tool, 'task', task, 'refdir', refdir,
28
39
  step=step, index=index,
29
40
  package='siliconcompiler', clobber=False)
30
- chip.set('tool', tool, 'task', task, 'threads', os.cpu_count(),
31
- step=step, index=index, clobber=False)
32
41
 
33
42
  # Input/Output requirements
34
43
  chip.add('tool', tool, 'task', task, 'output', chip.top() + '.v', step=step, index=index)
35
44
 
45
+ add_clock_requirements(chip)
46
+
36
47
  # Schema requirements
37
48
  add_require_input(chip, 'input', 'hll', 'c')
49
+ add_require_input(chip, 'input', 'hll', 'llvm')
38
50
  add_frontend_requires(chip, ['idir', 'define'])
39
51
 
52
+ set_tool_task_var(chip, 'device',
53
+ schelp="Device to use during bambu synthesis")
54
+ set_tool_task_lib_var(chip, 'memorychannels', default_value=1,
55
+ schelp="Number of memory channels available")
56
+
57
+ # Require clock conversion factor, from library units to ns
58
+ mainlib = get_mainlib(chip)
59
+ chip.add('tool', tool, 'task', task, 'require',
60
+ ','.join(['library', mainlib, 'option', 'var', 'bambu_clock_multiplier']),
61
+ step=step, index=index)
62
+
63
+ set_tool_task_var(chip, 'clock_multiplier',
64
+ schelp="Clock multiplier used to convert library units to ns")
65
+
40
66
 
41
67
  ################################
42
68
  # Custom runtime options
43
69
  ################################
44
70
  def runtime_options(chip):
45
- cmdlist = []
71
+ step = chip.get('arg', 'step')
72
+ index = chip.get('arg', 'index')
73
+ tool, task = get_tool_task(chip, step, index)
46
74
 
47
- cmdlist.append('--memory-allocation-policy=NO_BRAM')
75
+ cmdlist = []
48
76
 
49
77
  opts = get_frontend_options(chip, ['idir', 'define'])
50
78
 
@@ -54,11 +82,34 @@ def runtime_options(chip):
54
82
  cmdlist.append('-D' + value)
55
83
  for value in get_input_files(chip, 'input', 'hll', 'c'):
56
84
  cmdlist.append(value)
85
+ if not has_input_files(chip, 'input', 'hll', 'c'):
86
+ # Only use llvm if C is empty
87
+ for value in get_input_files(chip, 'input', 'hll', 'llvm'):
88
+ cmdlist.append(value)
57
89
 
90
+ cmdlist.append('--soft-float')
58
91
  cmdlist.append('--memory-allocation-policy=NO_BRAM')
59
92
 
60
- step = chip.get('arg', 'step')
61
- index = chip.get('arg', 'index')
93
+ mem_channels = int(chip.get('tool', tool, 'task', task, 'var', 'memorychannels',
94
+ step=step, index=index)[0])
95
+ if mem_channels > 0:
96
+ cmdlist.append(f'--channels-number={mem_channels}')
97
+
98
+ mainlib = get_mainlib(chip)
99
+ clock_multiplier = float(chip.get('library', mainlib, 'option', 'var',
100
+ 'bambu_clock_multiplier')[0])
101
+ clock_name, period = get_clock_period(chip, clock_units_multiplier=clock_multiplier)
102
+ if clock_name:
103
+ cmdlist.append(f'--clock-name={clock_name}')
104
+ if period:
105
+ cmdlist.append(f'--clock-period={period}')
106
+
107
+ cmdlist.append('--disable-function-proxy')
108
+
109
+ device = chip.get('tool', tool, 'task', task, 'var', 'device',
110
+ step=step, index=index)
111
+ if device:
112
+ cmdlist.append(f'--device={device[0]}')
62
113
 
63
114
  cmdlist.append(f'--top-fname={chip.top(step, index)}')
64
115
 
@@ -75,3 +126,34 @@ def post_process(chip):
75
126
  index = chip.get('arg', 'index')
76
127
 
77
128
  shutil.copy2(f'{chip.top(step, index)}.v', os.path.join('outputs', f'{chip.top()}.v'))
129
+
130
+ ff = re.compile(fr"Total number of flip-flops in function {chip.top(step, index)}: (\d+)")
131
+ area = re.compile(r"Total estimated area: (\d+)")
132
+ fmax = re.compile(r"Estimated max frequency \(MHz\): (\d+\.?\d*)")
133
+ slack = re.compile(r"Minimum slack: (\d+\.?\d*)")
134
+
135
+ log_file = f"{step}.log"
136
+ with sc_open(log_file) as log:
137
+ for line in log:
138
+ ff_match = ff.findall(line)
139
+ area_match = area.findall(line)
140
+ fmax_match = fmax.findall(line)
141
+ slack_match = slack.findall(line)
142
+ if ff_match:
143
+ record_metric(chip, step, index, "registers", int(ff_match[0]), log_file)
144
+ if area_match:
145
+ record_metric(chip, step, index, "cellarea", float(area_match[0]), log_file,
146
+ source_unit='um^2')
147
+ if fmax_match:
148
+ record_metric(chip, step, index, "fmax", float(fmax_match[0]), log_file,
149
+ source_unit='MHz')
150
+ if slack_match:
151
+ slack_ns = float(slack_match[0])
152
+ if slack_ns >= 0:
153
+ record_metric(chip, step, index, "setupwns", 0, log_file,
154
+ source_unit='ns')
155
+ else:
156
+ record_metric(chip, step, index, "setupwns", slack_ns, log_file,
157
+ source_unit='ns')
158
+ record_metric(chip, step, index, "setupslack", slack_ns, log_file,
159
+ source_unit='ns')
@@ -3,6 +3,7 @@ import shutil
3
3
  from siliconcompiler.tools._common import \
4
4
  add_require_input, add_frontend_requires, get_frontend_options, get_input_files, \
5
5
  get_tool_task, has_input_files
6
+ from siliconcompiler import utils
6
7
  from siliconcompiler import sc_open
7
8
 
8
9
  # Directory inside step/index dir to store bsc intermediate results.
@@ -33,7 +34,7 @@ def setup(chip):
33
34
  chip.set('tool', tool, 'task', task, 'refdir', refdir,
34
35
  step=step, index=index,
35
36
  package='siliconcompiler', clobber=False)
36
- chip.set('tool', tool, 'task', task, 'threads', os.cpu_count(),
37
+ chip.set('tool', tool, 'task', task, 'threads', utils.get_cores(chip),
37
38
  step=step, index=index, clobber=False)
38
39
 
39
40
  # Input/Output requirements
@@ -3,6 +3,7 @@ import shutil
3
3
  import glob
4
4
  from siliconcompiler.tools._common import add_frontend_requires, get_tool_task, has_input_files
5
5
  from siliconcompiler import sc_open, SiliconCompilerError
6
+ from siliconcompiler import utils
6
7
 
7
8
 
8
9
  def setup(chip):
@@ -28,7 +29,7 @@ def setup(chip):
28
29
  chip.set('tool', tool, 'task', task, 'refdir', refdir,
29
30
  step=step, index=index,
30
31
  package='siliconcompiler', clobber=False)
31
- chip.set('tool', tool, 'task', task, 'threads', os.cpu_count(),
32
+ chip.set('tool', tool, 'task', task, 'threads', utils.get_cores(chip),
32
33
  step=step, index=index, clobber=False)
33
34
 
34
35
  chip.set('tool', tool, 'task', task, 'option', ['-batch',
@@ -1,5 +1,5 @@
1
- import os
2
1
  import shutil
2
+ from siliconcompiler import utils
3
3
  from siliconcompiler.tools.genfasm import genfasm
4
4
  from siliconcompiler.tools.vpr import vpr
5
5
  from siliconcompiler.tools._common import get_tool_task
@@ -15,7 +15,7 @@ def setup(chip):
15
15
  index = chip.get('arg', 'index')
16
16
  tool, task = get_tool_task(chip, step, index)
17
17
 
18
- chip.set('tool', tool, 'task', task, 'threads', os.cpu_count(),
18
+ chip.set('tool', tool, 'task', task, 'threads', utils.get_cores(chip),
19
19
  step=step, index=index, clobber=False)
20
20
 
21
21
  chip.set('tool', tool, 'task', task, 'regex', 'warnings', "^Warning",
@@ -1,6 +1,6 @@
1
- import os
2
1
  from siliconcompiler.tools._common import add_require_input, add_frontend_requires, \
3
2
  get_input_files, get_tool_task, has_input_files
3
+ from siliconcompiler import utils
4
4
 
5
5
 
6
6
  def setup(chip):
@@ -23,7 +23,7 @@ def setup(chip):
23
23
  chip.set('tool', tool, 'vswitch', '--version')
24
24
  chip.set('tool', tool, 'version', '>=4.0.0-dev', clobber=clobber)
25
25
 
26
- chip.set('tool', tool, 'task', task, 'threads', os.cpu_count(),
26
+ chip.set('tool', tool, 'task', task, 'threads', utils.get_cores(chip),
27
27
  step=step, index=index, clobber=clobber)
28
28
  chip.set('tool', tool, 'task', task, 'option', '',
29
29
  step=step, index=index, clobber=clobber)