siliconcompiler 0.29.4__py3-none-any.whl → 0.31.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 (84) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/sc.py +1 -1
  3. siliconcompiler/apps/sc_install.py +35 -3
  4. siliconcompiler/apps/sc_remote.py +1 -3
  5. siliconcompiler/core.py +38 -12
  6. siliconcompiler/flowgraph.py +11 -23
  7. siliconcompiler/package.py +1 -1
  8. siliconcompiler/remote/schema.py +9 -8
  9. siliconcompiler/report/report.py +4 -3
  10. siliconcompiler/scheduler/__init__.py +109 -104
  11. siliconcompiler/scheduler/docker_runner.py +1 -1
  12. siliconcompiler/scheduler/send_messages.py +1 -1
  13. siliconcompiler/schema/schema_cfg.py +478 -411
  14. siliconcompiler/schema/schema_obj.py +32 -18
  15. siliconcompiler/schema/utils.py +19 -0
  16. siliconcompiler/sphinx_ext/schemagen.py +3 -1
  17. siliconcompiler/templates/replay/replay.sh.j2 +92 -0
  18. siliconcompiler/tools/__init__.py +3 -1
  19. siliconcompiler/tools/_common/__init__.py +8 -2
  20. siliconcompiler/tools/_common/asic.py +1 -1
  21. siliconcompiler/tools/bluespec/__init__.py +35 -0
  22. siliconcompiler/tools/bluespec/convert.py +44 -5
  23. siliconcompiler/tools/graphviz/__init__.py +12 -0
  24. siliconcompiler/tools/graphviz/screenshot.py +48 -0
  25. siliconcompiler/tools/graphviz/show.py +20 -0
  26. siliconcompiler/tools/klayout/export.py +5 -0
  27. siliconcompiler/tools/klayout/klayout.py +18 -1
  28. siliconcompiler/tools/klayout/klayout_export.py +4 -1
  29. siliconcompiler/tools/klayout/klayout_operations.py +5 -2
  30. siliconcompiler/tools/klayout/klayout_utils.py +23 -0
  31. siliconcompiler/tools/klayout/operations.py +5 -0
  32. siliconcompiler/tools/magic/magic.py +1 -1
  33. siliconcompiler/tools/openroad/_apr.py +20 -3
  34. siliconcompiler/tools/openroad/antenna_repair.py +2 -1
  35. siliconcompiler/tools/openroad/clock_tree_synthesis.py +2 -1
  36. siliconcompiler/tools/openroad/detailed_placement.py +2 -1
  37. siliconcompiler/tools/openroad/detailed_route.py +8 -0
  38. siliconcompiler/tools/openroad/fillercell_insertion.py +2 -1
  39. siliconcompiler/tools/openroad/global_placement.py +2 -1
  40. siliconcompiler/tools/openroad/macro_placement.py +9 -0
  41. siliconcompiler/tools/openroad/pin_placement.py +2 -1
  42. siliconcompiler/tools/openroad/power_grid.py +6 -0
  43. siliconcompiler/tools/openroad/repair_design.py +2 -1
  44. siliconcompiler/tools/openroad/repair_timing.py +2 -1
  45. siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +6 -0
  46. siliconcompiler/tools/openroad/scripts/apr/sc_clock_tree_synthesis.tcl +3 -0
  47. siliconcompiler/tools/openroad/scripts/apr/sc_detailed_route.tcl +10 -0
  48. siliconcompiler/tools/openroad/scripts/apr/sc_global_placement.tcl +1 -0
  49. siliconcompiler/tools/openroad/scripts/apr/sc_global_route.tcl +17 -5
  50. siliconcompiler/tools/openroad/scripts/apr/sc_macro_placement.tcl +14 -1
  51. siliconcompiler/tools/openroad/scripts/apr/sc_power_grid.tcl +54 -0
  52. siliconcompiler/tools/openroad/scripts/apr/sc_repair_design.tcl +1 -0
  53. siliconcompiler/tools/openroad/scripts/apr/sc_repair_timing.tcl +3 -0
  54. siliconcompiler/tools/openroad/scripts/common/procs.tcl +55 -17
  55. siliconcompiler/tools/openroad/scripts/common/reports.tcl +25 -3
  56. siliconcompiler/tools/openroad/scripts/common/write_images.tcl +28 -0
  57. siliconcompiler/tools/yosys/__init__.py +7 -0
  58. siliconcompiler/tools/yosys/sc_syn.tcl +33 -24
  59. siliconcompiler/tools/yosys/syn_asic.py +27 -0
  60. siliconcompiler/tools/yosys/syn_asic.tcl +27 -0
  61. siliconcompiler/toolscripts/_tools.json +16 -4
  62. siliconcompiler/toolscripts/rhel8/install-yosys-moosic.sh +17 -0
  63. siliconcompiler/toolscripts/rhel8/install-yosys-slang.sh +22 -0
  64. siliconcompiler/toolscripts/rhel9/install-openroad.sh +1 -1
  65. siliconcompiler/toolscripts/rhel9/install-yosys-moosic.sh +17 -0
  66. siliconcompiler/toolscripts/rhel9/install-yosys-slang.sh +22 -0
  67. siliconcompiler/toolscripts/ubuntu20/install-openroad.sh +1 -1
  68. siliconcompiler/toolscripts/ubuntu20/install-yosys-moosic.sh +17 -0
  69. siliconcompiler/toolscripts/ubuntu20/install-yosys-slang.sh +22 -0
  70. siliconcompiler/toolscripts/ubuntu22/install-openroad.sh +1 -1
  71. siliconcompiler/toolscripts/ubuntu22/install-yosys-moosic.sh +17 -0
  72. siliconcompiler/toolscripts/ubuntu22/install-yosys-slang.sh +22 -0
  73. siliconcompiler/toolscripts/ubuntu24/install-openroad.sh +1 -1
  74. siliconcompiler/toolscripts/ubuntu24/install-yosys-moosic.sh +17 -0
  75. siliconcompiler/toolscripts/ubuntu24/install-yosys-slang.sh +22 -0
  76. siliconcompiler/utils/__init__.py +44 -5
  77. siliconcompiler/utils/showtools.py +7 -0
  78. {siliconcompiler-0.29.4.dist-info → siliconcompiler-0.31.0.dist-info}/METADATA +8 -8
  79. {siliconcompiler-0.29.4.dist-info → siliconcompiler-0.31.0.dist-info}/RECORD +83 -70
  80. {siliconcompiler-0.29.4.dist-info → siliconcompiler-0.31.0.dist-info}/WHEEL +1 -1
  81. siliconcompiler/tools/bluespec/bluespec.py +0 -40
  82. {siliconcompiler-0.29.4.dist-info → siliconcompiler-0.31.0.dist-info}/LICENSE +0 -0
  83. {siliconcompiler-0.29.4.dist-info → siliconcompiler-0.31.0.dist-info}/entry_points.txt +0 -0
  84. {siliconcompiler-0.29.4.dist-info → siliconcompiler-0.31.0.dist-info}/top_level.txt +0 -0
@@ -39,7 +39,7 @@ except ImportError:
39
39
  _has_yaml = False
40
40
 
41
41
  from .schema_cfg import schema_cfg
42
- from .utils import escape_val_tcl, PACKAGE_ROOT, translate_loglevel
42
+ from .utils import escape_val_tcl, PACKAGE_ROOT, translate_loglevel, PerNode, Scope
43
43
 
44
44
 
45
45
  class Schema:
@@ -287,7 +287,7 @@ class Schema:
287
287
  try:
288
288
  return cfg['node'][step][index][field]
289
289
  except KeyError:
290
- if cfg['pernode'] == 'required':
290
+ if PerNode(cfg['pernode']) == PerNode.REQUIRED:
291
291
  return cfg['node']['default']['default'][field]
292
292
 
293
293
  try:
@@ -300,6 +300,10 @@ class Schema:
300
300
  except KeyError:
301
301
  return cfg['node']['default']['default'][field]
302
302
  elif field in cfg:
303
+ if field == "pernode":
304
+ return PerNode(cfg[field])
305
+ if field == "scope":
306
+ return Scope(cfg[field])
303
307
  return cfg[field]
304
308
  else:
305
309
  raise ValueError(f'Invalid field {field}')
@@ -621,7 +625,7 @@ class Schema:
621
625
  has_global = True
622
626
  vals.append((cfg['node'][step][index]['value'], step_arg, index_arg))
623
627
 
624
- if (cfg['pernode'] != 'required') and not has_global and return_defvalue:
628
+ if (PerNode(cfg['pernode']) != PerNode.REQUIRED) and not has_global and return_defvalue:
625
629
  vals.append((cfg['node']['default']['default']['value'], None, None))
626
630
 
627
631
  return vals
@@ -707,7 +711,7 @@ class Schema:
707
711
  # ignore history in case of cumulative history
708
712
  if key[0] != 'history':
709
713
  scope = self.get(*key, field='scope')
710
- if not self.is_empty(*key) and (scope == 'job'):
714
+ if not self.is_empty(*key) and (scope == Scope.JOB):
711
715
  self.__copyparam(self.cfg,
712
716
  self.cfg['history'][jobname],
713
717
  key)
@@ -865,15 +869,21 @@ class Schema:
865
869
 
866
870
  if field == 'scope':
867
871
  # Restricted allowed values
868
- if not (isinstance(value, str) and value in ('global', 'job', 'scratch')):
869
- raise TypeError(error_msg('one of "global", "job", or "scratch"'))
872
+ if isinstance(value, Scope):
873
+ return value.value
874
+ scope_values = [val.value for val in Scope]
875
+ if not (isinstance(value, str) and value in scope_values):
876
+ raise TypeError(error_msg(f'one of {", ".join(sorted(scope_values))}'))
870
877
  return value
871
878
 
872
879
  if field == 'pernode':
873
880
  # Restricted allowed values
874
- if not (isinstance(value, str) and value in ('never', 'optional', 'required')):
881
+ if isinstance(value, PerNode):
882
+ return value.value
883
+ pernode_values = [val.value for val in PerNode]
884
+ if not (isinstance(value, str) and value in pernode_values):
875
885
  raise TypeError(f'Invalid value {value} for field {field}: '
876
- 'expected one of "never", "optional", or "required"')
886
+ f'expected one of {", ".join(sorted(pernode_values))}')
877
887
  return value
878
888
 
879
889
  if field in (
@@ -955,10 +965,10 @@ class Schema:
955
965
  return 'step and index are only valid for value fields'
956
966
  return None
957
967
 
958
- if pernode == 'never' and (step is not None or index is not None):
968
+ if PerNode(pernode) == PerNode.NEVER and (step is not None or index is not None):
959
969
  return 'step and index are not valid for this parameter'
960
970
 
961
- if pernode == 'required' and (step is None or index is None):
971
+ if PerNode(pernode) == PerNode.REQUIRED and (step is None or index is None):
962
972
  return 'step and index are required for this parameter'
963
973
 
964
974
  if step is None and index is not None:
@@ -989,11 +999,15 @@ class Schema:
989
999
  if key in cfg:
990
1000
  cfg = cfg[key]
991
1001
  elif 'default' in cfg:
1002
+ cfg_default = cfg['default']
992
1003
  if insert_defaults:
993
- cfg[key] = copy.deepcopy(cfg['default'])
1004
+ if Schema._is_leaf(cfg_default) and cfg_default['lock']:
1005
+ raise ValueError(f'{keypath} is locked and key cannot be added')
1006
+
1007
+ cfg[key] = copy.deepcopy(cfg_default)
994
1008
  cfg = cfg[key]
995
1009
  elif use_default:
996
- cfg = cfg['default']
1010
+ cfg = cfg_default
997
1011
  else:
998
1012
  raise ValueError(f'Invalid keypath {keypath}: unexpected key: {key}')
999
1013
  else:
@@ -1081,12 +1095,12 @@ class Schema:
1081
1095
  typestr = self.get(*key, field='type')
1082
1096
  pernode = self.get(*key, field='pernode')
1083
1097
 
1084
- if pernode == 'required' and (step is None or index is None):
1098
+ if PerNode(pernode) == PerNode.REQUIRED and (step is None or index is None):
1085
1099
  # Skip mandatory per-node parameters if step and index are not specified
1086
1100
  # TODO: how should we dump these?
1087
1101
  continue
1088
1102
 
1089
- if pernode != 'never':
1103
+ if not pernode.is_never():
1090
1104
  value = self.get(*key, step=step, index=index)
1091
1105
  else:
1092
1106
  value = self.get(*key)
@@ -1515,7 +1529,7 @@ class Schema:
1515
1529
  used_switches.update(switchstrs)
1516
1530
  if typestr == 'bool':
1517
1531
  # Boolean type arguments
1518
- if pernodestr == 'never':
1532
+ if pernodestr.is_never():
1519
1533
  parser.add_argument(*switchstrs,
1520
1534
  nargs='?',
1521
1535
  metavar=metavar,
@@ -1531,7 +1545,7 @@ class Schema:
1531
1545
  action='append',
1532
1546
  help=helpstr,
1533
1547
  default=argparse.SUPPRESS)
1534
- elif '[' in typestr or pernodestr != 'never':
1548
+ elif '[' in typestr or not pernodestr.is_never():
1535
1549
  # list type arguments
1536
1550
  parser.add_argument(*switchstrs,
1537
1551
  metavar=metavar,
@@ -1683,13 +1697,13 @@ class Schema:
1683
1697
  sctype = self.get(*keypath, field='type')
1684
1698
  pernode = self.get(*keypath, field='pernode')
1685
1699
  step, index = None, None
1686
- if pernode == 'required':
1700
+ if PerNode(pernode) == PerNode.REQUIRED:
1687
1701
  try:
1688
1702
  step, index, val = remainder.split(' ', 2)
1689
1703
  except ValueError:
1690
1704
  self.logger.error(f"Invalid value '{item}' for switch {switchstr}. "
1691
1705
  "Requires step and index before final value.")
1692
- elif pernode == 'optional':
1706
+ elif PerNode(pernode) == PerNode.OPTIONAL:
1693
1707
  # Split on spaces, preserving items that are grouped in quotes
1694
1708
  items = shlex.split(remainder)
1695
1709
  if len(items) > 3:
@@ -7,10 +7,29 @@
7
7
  import os
8
8
  import re
9
9
  import sys
10
+ from enum import Enum
10
11
 
11
12
  PACKAGE_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')
12
13
 
13
14
 
15
+ #############################################################################
16
+ # ENUM DEFINITIONs
17
+ #############################################################################
18
+ class Scope(Enum):
19
+ GLOBAL = 'global'
20
+ JOB = 'job'
21
+ SCRATCH = 'scratch'
22
+
23
+
24
+ class PerNode(Enum):
25
+ NEVER = 'never'
26
+ OPTIONAL = 'optional'
27
+ REQUIRED = 'required'
28
+
29
+ def is_never(self):
30
+ return self == PerNode.NEVER
31
+
32
+
14
33
  def escape_val_tcl(val, typestr):
15
34
  '''Recursive helper function for converting Python values to safe TCL
16
35
  values, based on the SC type string.'''
@@ -37,9 +37,11 @@ class SchemaGen(SphinxDirective):
37
37
  entries = [[strong('Description'), para(schema['shorthelp'])],
38
38
  [strong('Type'), para(schema['type'])]]
39
39
 
40
- if schema['pernode'] != 'never':
40
+ if schema['pernode'] != utils.PerNode.NEVER:
41
41
  entries.append([strong('Per step/index'), para(schema['pernode'])])
42
42
 
43
+ entries.append([strong('Scope'), para(schema['scope'])])
44
+
43
45
  if 'enum' in schema['type']:
44
46
  entries.append([strong('Allowed Values'),
45
47
  build_list([code(val) for val in schema['enum']])])
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env bash
2
+ if [ "${BASH_SOURCE[0]}" != "$0" ]; then
3
+ echo "${BASH_SOURCE[0]} must be executed."
4
+ return
5
+ fi
6
+
7
+ # Parse replay arguments
8
+ CD_WORK="{{ work_dir }}"
9
+ PRINT=""
10
+ CMDPREFIX=""
11
+ SKIPEXPORT=0
12
+ while [[ $# -gt 0 ]]; do
13
+ case $1 in
14
+ --which)
15
+ PRINT="which"
16
+ shift
17
+ ;;
18
+ --version)
19
+ PRINT="version"
20
+ shift
21
+ ;;
22
+ --directory)
23
+ PRINT="directory"
24
+ shift
25
+ ;;
26
+ --command)
27
+ PRINT="command"
28
+ shift
29
+ ;;
30
+ --skipcd)
31
+ CD_WORK="."
32
+ shift
33
+ ;;
34
+ --skipexports)
35
+ SKIPEXPORT=1
36
+ shift
37
+ ;;
38
+ --cmdprefix)
39
+ CMDPREFIX="$2"
40
+ shift
41
+ shift
42
+ ;;
43
+ -h|--help)
44
+ echo "Usage: $0"
45
+ echo " Options:"
46
+ echo " --which print which executable would be used"
47
+ echo " --version print the version of the executable, if supported"
48
+ echo " --directory print the execution directory"
49
+ echo " --command print the execution command"
50
+ echo " --skipcd do not change directory into replay directory"
51
+ echo " --skipexports do not export environmental variables"
52
+ echo " --cmdprefix <cmd> prefix to add to the replay command, such as gdb"
53
+ echo " -h,--help print this help"
54
+ exit 0
55
+ ;;
56
+ *)
57
+ echo "Unknown option $1"
58
+ exit 1
59
+ ;;
60
+ esac
61
+ done
62
+
63
+ if [ $SKIPEXPORT == 0 ]; then
64
+ # Environmental variables{% for key, value in exports.items() %}
65
+ export {{ key }}="{{ value }}"{% endfor %}
66
+ fi
67
+
68
+ # Switch to the working directory
69
+ cd "$CD_WORK"
70
+
71
+ case $PRINT in
72
+ "which")
73
+ which {{ executable }}
74
+ exit 0
75
+ ;;
76
+ "version")
77
+ {% if version_flag is defined %}{{ executable }} {{ version_flag }}{% else %}echo "--version is not supported"{% endif %}
78
+ exit 0
79
+ ;;
80
+ "directory")
81
+ echo "Working directory: $PWD"
82
+ exit 0
83
+ ;;
84
+ "command")
85
+ echo "{% for cmd in cmds %}{% if not loop.first %} {% endif %}{{ cmd }}{% endfor %}"
86
+ exit 0
87
+ ;;
88
+ esac
89
+
90
+ # Command execution
91
+ $CMDPREFIX \{% for cmd in cmds %}
92
+ {% if not loop.first %} {% endif %}{{ cmd }}{% if not loop.last %} \{% endif %}{% endfor %}
@@ -1,11 +1,12 @@
1
1
  from siliconcompiler.tools import bambu
2
- from siliconcompiler.tools.bluespec import bluespec
2
+ from siliconcompiler.tools import bluespec
3
3
  from siliconcompiler.tools.builtin import builtin
4
4
  from siliconcompiler.tools.chisel import chisel
5
5
  from siliconcompiler.tools.execute import execute
6
6
  from siliconcompiler.tools.genfasm import genfasm
7
7
  from siliconcompiler.tools.ghdl import ghdl
8
8
  from siliconcompiler.tools import gtkwave
9
+ from siliconcompiler.tools import graphviz
9
10
  from siliconcompiler.tools.icarus import icarus
10
11
  from siliconcompiler.tools.icepack import icepack
11
12
  from siliconcompiler.tools.klayout import klayout
@@ -39,6 +40,7 @@ def get_tools():
39
40
  execute,
40
41
  genfasm,
41
42
  ghdl,
43
+ graphviz,
42
44
  gtkwave,
43
45
  icarus,
44
46
  icepack,
@@ -161,7 +161,7 @@ def __get_step_index(chip, *key):
161
161
  step = chip.get('arg', 'step')
162
162
  index = chip.get('arg', 'index')
163
163
 
164
- if chip.get(*key, field='pernode') == 'never':
164
+ if chip.get(*key, field='pernode').is_never():
165
165
  step = None
166
166
  index = None
167
167
 
@@ -330,7 +330,7 @@ def pick_key(chip, check_keys, step=None, index=None):
330
330
  check_step = step
331
331
  check_index = index
332
332
 
333
- if chip.get(*key, field='pernode') == 'never':
333
+ if chip.get(*key, field='pernode').is_never():
334
334
  check_step = None
335
335
  check_index = None
336
336
 
@@ -347,9 +347,15 @@ def input_provides(chip, step, index, flow=None):
347
347
  if not flow:
348
348
  flow = chip.get('option', 'flow')
349
349
 
350
+ pruned_nodes = chip.get('option', 'prune')
351
+
350
352
  nodes = chip.get('flowgraph', flow, step, index, 'input')
351
353
  inputs = {}
352
354
  for in_step, in_index in nodes:
355
+ if (in_step, in_index) in pruned_nodes:
356
+ # node has been pruned so will not provide anything
357
+ continue
358
+
353
359
  if chip.get('record', 'status', step=in_step, index=in_index) == \
354
360
  NodeStatus.SKIPPED:
355
361
  for file, nodes in input_provides(chip, in_step, in_index, flow=flow).items():
@@ -188,7 +188,7 @@ def set_tool_task_lib_var(chip,
188
188
  get_step = step
189
189
  get_index = index
190
190
 
191
- if chip.get(*lib_key, field='pernode') == 'never':
191
+ if chip.get(*lib_key, field='pernode').is_never():
192
192
  get_step = None
193
193
  get_index = None
194
194
 
@@ -0,0 +1,35 @@
1
+ '''
2
+ Bluespec is a high-level hardware description language. It has a variety of
3
+ advanced features including a powerful type system that can prevent errors
4
+ prior to synthesis time, and its most distinguishing feature, Guarded Atomic
5
+ Actions, allow you to define hardware components in a modular manner based
6
+ on their invariants, and let the compiler pick a scheduler.
7
+
8
+ Documentation: https://github.com/B-Lang-org/bsc#documentation
9
+
10
+ Sources: https://github.com/B-Lang-org/bsc
11
+
12
+ Installation: https://github.com/B-Lang-org/bsc#download
13
+ '''
14
+
15
+ from siliconcompiler.tools.bluespec import convert
16
+
17
+
18
+ ####################################################################
19
+ # Make Docs
20
+ ####################################################################
21
+ def make_docs(chip):
22
+ convert.setup(chip)
23
+ return chip
24
+
25
+
26
+ ################################
27
+ # Setup Tool (pre executable)
28
+ ################################
29
+ def parse_version(stdout):
30
+ # Examples:
31
+ # Bluespec Compiler, version 2021.12.1-27-g9a7d5e05 (build 9a7d5e05)
32
+ # Bluespec Compiler, version 2021.07 (build 4cac6eba)
33
+
34
+ long_version = stdout.split()[3]
35
+ return long_version.split('-')[0]
@@ -8,6 +8,7 @@ from siliconcompiler import sc_open
8
8
 
9
9
  # Directory inside step/index dir to store bsc intermediate results.
10
10
  VLOG_DIR = 'verilog'
11
+ BSC_DIR = 'bluespec'
11
12
 
12
13
 
13
14
  def setup(chip):
@@ -39,6 +40,7 @@ def setup(chip):
39
40
 
40
41
  # Input/Output requirements
41
42
  chip.add('tool', tool, 'task', task, 'output', chip.top() + '.v', step=step, index=index)
43
+ chip.add('tool', tool, 'task', task, 'output', chip.top() + '.dot', step=step, index=index)
42
44
 
43
45
  # Schema requirements
44
46
  add_require_input(chip, 'input', 'hll', 'bsv')
@@ -50,9 +52,10 @@ def setup(chip):
50
52
  ################################
51
53
  def pre_process(chip):
52
54
  # bsc requires its output directory exists before being called.
53
- if os.path.isdir(VLOG_DIR):
54
- shutil.rmtree(VLOG_DIR)
55
- os.makedirs(VLOG_DIR)
55
+ for path in (VLOG_DIR, BSC_DIR):
56
+ if os.path.isdir(path):
57
+ shutil.rmtree(path)
58
+ os.makedirs(path)
56
59
 
57
60
 
58
61
  ################################
@@ -68,7 +71,13 @@ def runtime_options(chip):
68
71
 
69
72
  cmdlist.append('-verilog')
70
73
  cmdlist.append(f'-vdir {VLOG_DIR}')
74
+ cmdlist.append(f'-bdir {BSC_DIR}')
75
+ cmdlist.append('-info-dir reports')
71
76
  cmdlist.append('-u')
77
+ cmdlist.append('-v')
78
+
79
+ cmdlist.append('-show-module-use')
80
+ cmdlist.append('-sched-dot')
72
81
 
73
82
  cmdlist.append(f'-g {chip.top(step, index)}')
74
83
 
@@ -95,10 +104,40 @@ def post_process(chip):
95
104
  ''' Tool specific function to run after step execution
96
105
  '''
97
106
 
107
+ step = chip.get('arg', 'step')
108
+ index = chip.get('arg', 'index')
109
+
110
+ shutil.copyfile(f"reports/{chip.top(step, index)}_combined_full.dot",
111
+ f"outputs/{chip.top()}.dot")
112
+
113
+ extra_modules = set()
114
+ use_file = os.path.join(VLOG_DIR, f"{chip.top(step, index)}.use")
115
+ if os.path.exists(use_file):
116
+ BSC_BASE = os.path.dirname(
117
+ os.path.dirname(
118
+ chip.get('record', 'toolpath', step=step, index=index)))
119
+ BSC_LIB = os.path.join(BSC_BASE, "lib", "Verilog")
120
+
121
+ with sc_open(use_file) as f:
122
+ for module in f:
123
+ module = module.strip()
124
+ mod_path = os.path.join(BSC_LIB, f"{module}.v")
125
+ if os.path.exists(mod_path):
126
+ extra_modules.add(mod_path)
127
+ else:
128
+ chip.logger.warn(f"Unable to find module {module} source files at: {BSC_LIB}")
129
+
98
130
  # bsc outputs each compiled module to its own Verilog file, so we
99
131
  # concatenate them all to create a pickled output we can pass along.
100
132
  design = chip.top()
101
133
  with open(os.path.join('outputs', f'{design}.v'), 'w') as pickled_vlog:
102
134
  for src in os.listdir(VLOG_DIR):
103
- with sc_open(os.path.join(VLOG_DIR, src)) as vlog_mod:
104
- pickled_vlog.write(vlog_mod.read())
135
+ if src.endswith(".v"):
136
+ with sc_open(os.path.join(VLOG_DIR, src)) as vlog_mod:
137
+ pickled_vlog.write(vlog_mod.read())
138
+
139
+ pickled_vlog.write("\n")
140
+ pickled_vlog.write("// Bluespec imports\n\n")
141
+ for vfile in extra_modules:
142
+ with sc_open(os.path.join(BSC_LIB, vfile)) as vlog_mod:
143
+ pickled_vlog.write(vlog_mod.read() + "\n")
@@ -0,0 +1,12 @@
1
+ '''
2
+ Graphviz is open source graph visualization software.
3
+ Graph visualization is a way of representing structural information as diagrams
4
+ of abstract graphs and networks.
5
+ It has important applications in networking, bioinformatics, software engineering,
6
+ database and web design, machine learning, and in visual interfaces for other
7
+ technical domains.
8
+ '''
9
+
10
+
11
+ def make_docs(chip):
12
+ return chip
@@ -0,0 +1,48 @@
1
+ import graphviz
2
+ import os
3
+
4
+ from siliconcompiler import sc_open
5
+ from siliconcompiler.tools._common import get_tool_task
6
+
7
+
8
+ def setup(chip):
9
+ '''
10
+ Generate a screenshot of a dot file
11
+ '''
12
+
13
+ step = chip.get('arg', 'step')
14
+ index = chip.get('arg', 'index')
15
+ tool, task = get_tool_task(chip, step, index)
16
+
17
+ chip.set('tool', tool, 'task', task, 'threads', 1, step=step, index=index)
18
+
19
+ chip.add('tool', tool, 'task', task, 'output', chip.top() + '.png', step=step, index=index)
20
+
21
+
22
+ def run(chip):
23
+ step = chip.get('arg', 'step')
24
+ index = chip.get('arg', 'index')
25
+ tool, task = get_tool_task(chip, step, index)
26
+
27
+ if os.path.exists(f'inputs/{chip.top()}.dot'):
28
+ file = f'inputs/{chip.top()}.dot'
29
+ elif os.path.exists(f'inputs/{chip.top()}.xdot'):
30
+ file = f'inputs/{chip.top()}.xdot'
31
+ elif chip.valid('tool', tool, 'task', task, 'var', 'show_filepath') and \
32
+ chip.get('tool', tool, 'task', task, 'var', 'show_filepath', step=step, index=index):
33
+ file = chip.get('tool', tool, 'task', task, 'var', 'show_filepath',
34
+ step=step, index=index)[0]
35
+ else:
36
+ file = chip.find_files('input', 'image', 'dot', step=step, index=index)[0]
37
+
38
+ with sc_open(file) as dot:
39
+ dot_content = dot.read()
40
+
41
+ try:
42
+ dot = graphviz.Source(dot_content, format="png")
43
+ dot.render(filename=f"outputs/{chip.top()}", cleanup=True)
44
+ pass
45
+ except graphviz.ExecutableNotFound:
46
+ return 1
47
+
48
+ return 0
@@ -0,0 +1,20 @@
1
+ from PIL import Image
2
+ from siliconcompiler.tools.graphviz import screenshot
3
+
4
+
5
+ def setup(chip):
6
+ '''
7
+ Show a graphviz dot file
8
+ '''
9
+
10
+ screenshot.setup(chip)
11
+
12
+
13
+ def run(chip):
14
+ screenshot_ret = screenshot.run(chip)
15
+ if screenshot_ret != 0:
16
+ return screenshot_ret
17
+
18
+ Image.open(f"outputs/{chip.top()}.png").show()
19
+
20
+ return 0
@@ -1,5 +1,6 @@
1
1
  import os
2
2
  from siliconcompiler.tools.klayout.klayout import setup as setup_tool
3
+ from siliconcompiler.tools.klayout.klayout import process_metrics
3
4
  from siliconcompiler.tools.klayout.klayout import runtime_options as runtime_options_tool
4
5
  from siliconcompiler.tools.klayout.screenshot import setup_gui_screenshot
5
6
  from siliconcompiler.tools._common import input_provides, get_tool_task
@@ -127,3 +128,7 @@ def runtime_options(chip):
127
128
  return runtime_options_tool(chip) + [
128
129
  '-rd', f'SC_TOOLS_ROOT={os.path.dirname(os.path.dirname(__file__))}'
129
130
  ]
131
+
132
+
133
+ def post_process(chip):
134
+ process_metrics(chip)
@@ -12,9 +12,11 @@ Installation: https://www.klayout.de/build.html
12
12
 
13
13
  import os
14
14
  from pathlib import Path
15
+ import json
15
16
  import platform
16
17
  import shutil
17
- from siliconcompiler.tools._common import get_tool_task
18
+ from siliconcompiler.tools._common import get_tool_task, record_metric
19
+ from siliconcompiler import sc_open
18
20
 
19
21
 
20
22
  ####################################################################
@@ -113,6 +115,21 @@ def parse_version(stdout):
113
115
  return stdout.split()[1]
114
116
 
115
117
 
118
+ def process_metrics(chip):
119
+ metrics_file = "reports/metrics.json"
120
+ if not os.path.exists(metrics_file):
121
+ return
122
+
123
+ step = chip.get('arg', 'step')
124
+ index = chip.get('arg', 'index')
125
+
126
+ with sc_open(metrics_file) as f:
127
+ metrics = json.load(f)
128
+
129
+ if "area" in metrics:
130
+ record_metric(chip, step, index, "totalarea", metrics["area"], metrics_file, "um^2")
131
+
132
+
116
133
  ##################################################
117
134
  if __name__ == "__main__":
118
135
 
@@ -127,7 +127,8 @@ def main():
127
127
  technology,
128
128
  get_streams,
129
129
  save_technology,
130
- get_schema
130
+ get_schema,
131
+ generate_metrics
131
132
  )
132
133
  from klayout_show import show
133
134
  from _common.asic import get_libraries
@@ -205,6 +206,8 @@ def main():
205
206
  # Save tech files
206
207
  save_technology(design, sc_tech)
207
208
 
209
+ generate_metrics()
210
+
208
211
 
209
212
  if __name__ == '__main__':
210
213
  main()
@@ -25,7 +25,7 @@ def __get_keypath_step_index(schema, *keypath):
25
25
  'index': schema.get('arg', 'index')
26
26
  }
27
27
  pernode = schema.get(*keypath, field='pernode')
28
- if pernode == 'never':
28
+ if pernode.is_never():
29
29
  ret['step'] = None
30
30
  ret['index'] = None
31
31
 
@@ -330,7 +330,8 @@ if __name__ == "__main__":
330
330
  from klayout_utils import (
331
331
  technology,
332
332
  get_streams,
333
- get_schema
333
+ get_schema,
334
+ generate_metrics
334
335
  )
335
336
 
336
337
  schema = get_schema(manifest='sc_manifest.json')
@@ -362,3 +363,5 @@ if __name__ == "__main__":
362
363
  parse_operations(schema, base_layout, sc_klayout_ops)
363
364
 
364
365
  write_stream(base_layout, out_gds, __with_timestamps(schema))
366
+
367
+ generate_metrics()