siliconcompiler 0.28.3__py3-none-any.whl → 0.28.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/_common.py +88 -56
  3. siliconcompiler/apps/sc.py +33 -14
  4. siliconcompiler/apps/sc_dashboard.py +17 -10
  5. siliconcompiler/apps/sc_show.py +17 -15
  6. siliconcompiler/core.py +95 -55
  7. siliconcompiler/flows/drcflow.py +13 -0
  8. siliconcompiler/flows/interposerflow.py +17 -0
  9. siliconcompiler/fpgas/vpr_example.py +8 -0
  10. siliconcompiler/libs/interposer.py +8 -0
  11. siliconcompiler/package.py +3 -2
  12. siliconcompiler/pdks/interposer.py +8 -0
  13. siliconcompiler/remote/schema.py +11 -1
  14. siliconcompiler/remote/server.py +7 -2
  15. siliconcompiler/report/dashboard/__init__.py +9 -0
  16. siliconcompiler/report/dashboard/components/__init__.py +13 -1
  17. siliconcompiler/report/dashboard/layouts/vertical_flowgraph.py +4 -3
  18. siliconcompiler/report/dashboard/layouts/vertical_flowgraph_node_tab.py +4 -1
  19. siliconcompiler/report/dashboard/layouts/vertical_flowgraph_sac_tabs.py +4 -1
  20. siliconcompiler/report/dashboard/state.py +3 -1
  21. siliconcompiler/report/summary_table.py +1 -2
  22. siliconcompiler/report/utils.py +1 -2
  23. siliconcompiler/scheduler/__init__.py +95 -0
  24. siliconcompiler/schema/schema_cfg.py +15 -3
  25. siliconcompiler/schema/schema_obj.py +51 -1
  26. siliconcompiler/sphinx_ext/dynamicgen.py +6 -0
  27. siliconcompiler/targets/interposer_demo.py +56 -0
  28. siliconcompiler/templates/tcl/manifest.tcl.j2 +2 -0
  29. siliconcompiler/tools/_common/__init__.py +44 -6
  30. siliconcompiler/tools/_common/asic.py +79 -23
  31. siliconcompiler/tools/genfasm/genfasm.py +7 -0
  32. siliconcompiler/tools/ghdl/convert.py +7 -0
  33. siliconcompiler/tools/klayout/convert_drc_db.py +60 -0
  34. siliconcompiler/tools/klayout/drc.py +156 -0
  35. siliconcompiler/tools/klayout/export.py +9 -4
  36. siliconcompiler/tools/klayout/klayout.py +0 -1
  37. siliconcompiler/tools/klayout/klayout_convert_drc_db.py +182 -0
  38. siliconcompiler/tools/klayout/klayout_export.py +3 -0
  39. siliconcompiler/tools/klayout/klayout_utils.py +8 -2
  40. siliconcompiler/tools/klayout/operations.py +2 -0
  41. siliconcompiler/tools/klayout/screenshot.py +2 -0
  42. siliconcompiler/tools/klayout/show.py +4 -4
  43. siliconcompiler/tools/magic/drc.py +21 -0
  44. siliconcompiler/tools/magic/extspice.py +21 -0
  45. siliconcompiler/tools/magic/magic.py +29 -0
  46. siliconcompiler/tools/magic/sc_drc.tcl +2 -12
  47. siliconcompiler/tools/magic/sc_extspice.tcl +3 -15
  48. siliconcompiler/tools/openroad/metrics.py +45 -0
  49. siliconcompiler/tools/openroad/openroad.py +47 -2
  50. siliconcompiler/tools/openroad/rdlroute.py +97 -0
  51. siliconcompiler/tools/openroad/scripts/sc_apr.tcl +16 -1
  52. siliconcompiler/tools/openroad/scripts/sc_floorplan.tcl +55 -9
  53. siliconcompiler/tools/openroad/scripts/sc_metrics.tcl +0 -159
  54. siliconcompiler/tools/openroad/scripts/sc_procs.tcl +3 -1
  55. siliconcompiler/tools/openroad/scripts/sc_rdlroute.tcl +184 -0
  56. siliconcompiler/tools/openroad/scripts/sc_report.tcl +170 -0
  57. siliconcompiler/tools/openroad/scripts/sc_route.tcl +8 -2
  58. siliconcompiler/tools/openroad/scripts/sc_screenshot.tcl +0 -5
  59. siliconcompiler/tools/openroad/scripts/sc_write_images.tcl +36 -6
  60. siliconcompiler/tools/opensta/scripts/sc_report_libraries.tcl +11 -1
  61. siliconcompiler/tools/surelog/__init__.py +12 -0
  62. siliconcompiler/tools/verilator/compile.py +27 -0
  63. siliconcompiler/tools/verilator/verilator.py +9 -0
  64. siliconcompiler/tools/vpr/vpr.py +18 -0
  65. siliconcompiler/tools/xyce/__init__.py +1 -1
  66. siliconcompiler/tools/yosys/{syn_asic_fpga_shared.tcl → procs.tcl} +23 -0
  67. siliconcompiler/tools/yosys/sc_screenshot.tcl +104 -0
  68. siliconcompiler/tools/yosys/sc_syn.tcl +7 -9
  69. siliconcompiler/tools/yosys/screenshot.py +153 -0
  70. siliconcompiler/tools/yosys/syn_asic.py +3 -0
  71. siliconcompiler/tools/yosys/syn_asic.tcl +1 -3
  72. siliconcompiler/tools/yosys/syn_fpga.tcl +3 -2
  73. siliconcompiler/toolscripts/_tools.json +5 -6
  74. siliconcompiler/toolscripts/rhel8/install-xyce.sh +4 -5
  75. siliconcompiler/toolscripts/rhel9/install-xyce.sh +4 -5
  76. siliconcompiler/toolscripts/ubuntu20/install-xyce.sh +5 -5
  77. siliconcompiler/toolscripts/ubuntu22/install-xyce.sh +2 -2
  78. siliconcompiler/toolscripts/ubuntu24/install-xyce.sh +2 -2
  79. siliconcompiler/utils/__init__.py +30 -1
  80. siliconcompiler/utils/showtools.py +4 -0
  81. {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.5.dist-info}/METADATA +18 -5
  82. {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.5.dist-info}/RECORD +86 -72
  83. {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.5.dist-info}/WHEEL +1 -1
  84. {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.5.dist-info}/LICENSE +0 -0
  85. {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.5.dist-info}/entry_points.txt +0 -0
  86. {siliconcompiler-0.28.3.dist-info → siliconcompiler-0.28.5.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
1
  # Version number following semver standard.
2
- version = '0.28.3'
2
+ version = '0.28.5'
3
3
 
4
4
  # Default server address for remote runs, if unspecified.
5
5
  default_server = 'https://server.siliconcompiler.com'
@@ -1,7 +1,11 @@
1
- import glob
2
1
  import os
3
2
 
4
3
 
4
+ # TODO: this is a hack to get around design name requirement: since legal
5
+ # design names probably can't contain spaces, we can detect if it is unset.
6
+ UNSET_DESIGN = ' unset '
7
+
8
+
5
9
  def manifest_switches():
6
10
  '''
7
11
  Returns a list of manifest switches that can be used
@@ -14,63 +18,91 @@ def manifest_switches():
14
18
  '-jobname']
15
19
 
16
20
 
17
- def load_manifest(chip, src_file):
18
- manifest = None
19
- if (src_file is not None) and (not chip.get('option', 'cfg')):
20
- if not os.path.exists(src_file):
21
- chip.logger.error(f'{src_file} cannot be found.')
22
- return False
23
- # only autoload manifest if user doesn't supply manually
24
- manifest = _get_manifest(os.path.dirname(src_file))
25
- if not manifest:
26
- design = os.path.splitext(os.path.basename(src_file))[0]
27
- chip.logger.error(f'Unable to automatically find manifest for design {design}. '
28
- 'Please provide a manifest explicitly using -cfg.')
29
- return False
30
- elif not chip.get('option', 'cfg'):
31
- manifest = _get_manifest_from_design(chip)
32
- if not manifest:
33
- chip.logger.error(f'Could not find manifest for {chip.design}')
34
- return False
21
+ def _get_manifests(cwd):
22
+ manifests = {}
35
23
 
36
- if manifest:
37
- chip.logger.info(f'Loading manifest: {manifest}')
38
- chip.read_manifest(manifest)
39
- return True
40
-
41
-
42
- def _get_manifest(dirname, design='*'):
43
- # pkg.json file may have a different name from the design due to the entrypoint
44
- glob_paths = [os.path.join(dirname, f'{design}.pkg.json'),
45
- os.path.join(dirname, 'outputs', f'{design}.pkg.json')]
46
- manifest = None
47
- for path in glob_paths:
48
- manifest = glob.glob(path)
49
- if manifest:
50
- manifest = manifest[0]
51
- break
52
-
53
- if not manifest or not os.path.isfile(manifest):
24
+ def get_dirs(cwd):
25
+ dirs = []
26
+ for dirname in os.listdir(cwd):
27
+ fullpath = os.path.join(cwd, dirname)
28
+ if os.path.isdir(fullpath):
29
+ dirs.append((dirname, fullpath))
30
+ return dirs
31
+
32
+ for _, buildpath in get_dirs(cwd):
33
+ for design, designdir in get_dirs(buildpath):
34
+ for jobname, jobdir in get_dirs(designdir):
35
+ manifest = os.path.join(jobdir, f'{design}.pkg.json')
36
+ if os.path.isfile(manifest):
37
+ manifests[(design, jobname, None, None)] = manifest
38
+ for step, stepdir in get_dirs(jobdir):
39
+ for index, indexdir in get_dirs(stepdir):
40
+ manifest = os.path.join(indexdir, 'outputs', f'{design}.pkg.json')
41
+ if os.path.isfile(manifest):
42
+ manifests[(design, jobname, step, index)] = manifest
43
+ else:
44
+ manifest = os.path.join(indexdir, 'inputs', f'{design}.pkg.json')
45
+ if os.path.isfile(manifest):
46
+ manifests[(design, jobname, step, index)] = manifest
47
+
48
+ organized_manifest = {}
49
+ for (design, job, step, index), manifest in manifests.items():
50
+ jobs = organized_manifest.setdefault(design, {})
51
+ jobs.setdefault(job, {})[step, index] = os.path.abspath(manifest)
52
+
53
+ return organized_manifest
54
+
55
+
56
+ def pick_manifest_from_file(chip, src_file, all_manifests):
57
+ if src_file is None:
54
58
  return None
55
- return manifest
56
59
 
60
+ if not os.path.exists(src_file):
61
+ chip.logger.error(f'{src_file} cannot be found.')
62
+ return None
63
+
64
+ src_dir = os.path.abspath(os.path.dirname(src_file))
65
+ for _, jobs in all_manifests.items():
66
+ for _, nodes in jobs.items():
67
+ for manifest in nodes.values():
68
+ if src_dir == os.path.dirname(manifest):
69
+ return manifest
57
70
 
58
- def _get_manifest_from_design(chip):
59
- for jobname, step, index in [
60
- (chip.get('option', 'jobname'),
61
- chip.get('arg', 'step'),
62
- chip.get('arg', 'index')),
63
- (chip.get('option', 'jobname'),
64
- None,
65
- None),
66
- (chip.schema.get_default('option', 'jobname'),
67
- chip.get('arg', 'step'),
68
- chip.get('arg', 'index')),
69
- (chip.schema.get_default('option', 'jobname'),
70
- None,
71
- None)]:
72
- manifest = _get_manifest(chip.getworkdir(jobname=jobname, step=step, index=index))
73
-
74
- if manifest:
75
- return manifest
76
71
  return None
72
+
73
+
74
+ def pick_manifest(chip, src_file=None):
75
+ all_manifests = _get_manifests(os.getcwd())
76
+
77
+ manifest = pick_manifest_from_file(chip, src_file, all_manifests)
78
+ if manifest:
79
+ return manifest
80
+
81
+ if chip.design == UNSET_DESIGN:
82
+ if len(all_manifests) == 1:
83
+ chip.set('design', list(all_manifests.keys())[0])
84
+ else:
85
+ chip.logger.error('Design name is not set')
86
+ return None
87
+
88
+ if chip.design not in all_manifests:
89
+ chip.logger.error(f'Could not find manifest for {chip.design}')
90
+ return None
91
+
92
+ if chip.get('option', 'jobname') not in all_manifests[chip.design] and \
93
+ len(all_manifests[chip.design]) != 1:
94
+ chip.logger.error(f'Could not determine jobname for {chip.design}')
95
+ return None
96
+
97
+ jobname = chip.get('option', 'jobname')
98
+ if chip.get('option', 'jobname') not in all_manifests[chip.design]:
99
+ jobname = list(all_manifests[chip.design].keys())[0]
100
+
101
+ if (None, None) in all_manifests[chip.design][jobname]:
102
+ manifest = all_manifests[chip.design][jobname][None, None]
103
+ else:
104
+ # pick newest manifest
105
+ manifest = list(sorted(all_manifests[chip.design][jobname].values(),
106
+ key=lambda file: os.stat(file).st_ctime))[-1]
107
+
108
+ return manifest
@@ -10,6 +10,37 @@ from siliconcompiler.targets import skywater130_demo
10
10
  from siliconcompiler import SiliconCompilerError
11
11
 
12
12
 
13
+ def _infer_designname(chip):
14
+ topfile = None
15
+ sourcesets = chip.getkeys('input')
16
+ for sourceset in reversed(('rtl', 'hll')):
17
+ if sourceset in sourcesets:
18
+ sourcesets.remove(sourceset)
19
+ sourcesets.insert(0, sourceset)
20
+ for sourceset in sourcesets:
21
+ for filetype in chip.getkeys('input', sourceset):
22
+ all_vals = chip.schema._getvals('input', sourceset, filetype)
23
+ if all_vals:
24
+ # just look at first value
25
+ sources, _, _ = all_vals[0]
26
+ # grab first source
27
+ topfile = sources[0]
28
+ break
29
+ if topfile:
30
+ break
31
+
32
+ if not topfile:
33
+ return None
34
+
35
+ root = os.path.basename(topfile)
36
+ while True:
37
+ root, ext = os.path.splitext(root)
38
+ if not ext:
39
+ break
40
+
41
+ return root
42
+
43
+
13
44
  ###########################
14
45
  def main():
15
46
  progname = "sc"
@@ -50,24 +81,12 @@ def main():
50
81
 
51
82
  # Set design if none specified
52
83
  if chip.get('design') == UNSET_DESIGN:
53
- topfile = None
54
- for sourceset in ('rtl', 'hll'):
55
- for filetype in chip.getkeys('input', sourceset):
56
- all_vals = chip.schema._getvals('input', sourceset, filetype)
57
- if all_vals:
58
- # just look at first value
59
- sources, _, _ = all_vals[0]
60
- # grab first source
61
- topfile = sources[0]
62
- break
63
- if topfile:
64
- break
84
+ topmodule = _infer_designname(chip)
65
85
 
66
- if not topfile:
86
+ if not topmodule:
67
87
  chip.logger.error('Invalid arguments: either specify -design or provide sources.')
68
88
  return 1
69
89
 
70
- topmodule = os.path.splitext(os.path.basename(topfile))[0]
71
90
  chip.set('design', topmodule)
72
91
 
73
92
  # Set demo target if none specified
@@ -2,7 +2,7 @@
2
2
  import sys
3
3
  import siliconcompiler
4
4
  import os
5
- from siliconcompiler.apps._common import load_manifest, manifest_switches
5
+ from siliconcompiler.apps._common import pick_manifest, manifest_switches, UNSET_DESIGN
6
6
 
7
7
 
8
8
  def main():
@@ -11,9 +11,16 @@ def main():
11
11
  -----------------------------------------------------------
12
12
  SC app to open a dashboard for a given manifest.
13
13
 
14
- To open:
14
+ To open and allow sc-dashboard to autoload manifest:
15
+ sc-dashboard
16
+
17
+ To open by specifying manifest:
15
18
  sc-dashboard -cfg <path to manifest>
16
19
 
20
+ To open by specifying design and optionally jobname:
21
+ sc-dashboard -design <name>
22
+ sc-dashboard -design <name> -jobname <jobname>
23
+
17
24
  To specify a different port than the default:
18
25
  sc-dashboard -cfg <path to manifest> -port 10000
19
26
 
@@ -23,10 +30,6 @@ To include another chip object to compare to:
23
30
  -----------------------------------------------------------
24
31
  """
25
32
 
26
- # TODO: this is a hack to get around design name requirement: since legal
27
- # design names probably can't contain spaces, we can detect if it is unset.
28
- UNSET_DESIGN = ' unset '
29
-
30
33
  # Create a base chip class.
31
34
  chip = siliconcompiler.Chip(UNSET_DESIGN)
32
35
 
@@ -54,15 +57,19 @@ To include another chip object to compare to:
54
57
  chip.logger.error(e)
55
58
  return 1
56
59
 
60
+ if not chip.get('option', 'cfg'):
61
+ manifest = pick_manifest(chip)
62
+
63
+ if manifest:
64
+ chip.logger.info(f'Loading manifest: {manifest}')
65
+ chip.read_manifest(manifest)
66
+
57
67
  # Error checking
58
68
  design = chip.get('design')
59
69
  if design == UNSET_DESIGN:
60
70
  chip.logger.error('Design not loaded')
61
71
  return 1
62
72
 
63
- if not load_manifest(chip, None):
64
- return 1
65
-
66
73
  graph_chips = []
67
74
  if switches['graph_cfg']:
68
75
  for i, name_and_file_path in enumerate(switches['graph_cfg']):
@@ -88,7 +95,7 @@ To include another chip object to compare to:
88
95
  'cfg_path': os.path.abspath(file_path)
89
96
  })
90
97
 
91
- chip._dashboard(wait=True, port=switches['port'], graph_chips=graph_chips)
98
+ chip.dashboard(wait=True, port=switches['port'], graph_chips=graph_chips)
92
99
 
93
100
  return 0
94
101
 
@@ -3,7 +3,7 @@ import sys
3
3
  import os
4
4
  import siliconcompiler
5
5
  from siliconcompiler.utils import get_default_iomap
6
- from siliconcompiler.apps._common import load_manifest, manifest_switches
6
+ from siliconcompiler.apps._common import manifest_switches, pick_manifest, UNSET_DESIGN
7
7
  from siliconcompiler.utils import get_file_ext
8
8
 
9
9
 
@@ -18,6 +18,9 @@ def main():
18
18
 
19
19
  Examples:
20
20
 
21
+ sc-show
22
+ (displays build/adder/job0/write_gds/0/outputs/adder.gds)
23
+
21
24
  sc-show -design adder
22
25
  (displays build/adder/job0/write_gds/0/outputs/adder.gds)
23
26
 
@@ -40,10 +43,6 @@ def main():
40
43
  (displays build/adder/job0/route/1/outputs/adder.def)
41
44
  """
42
45
 
43
- # TODO: this is a hack to get around design name requirement: since legal
44
- # design names probably can't contain spaces, we can detect if it is unset.
45
- UNSET_DESIGN = ' unset '
46
-
47
46
  # Create a base chip class.
48
47
  chip = siliconcompiler.Chip(UNSET_DESIGN)
49
48
 
@@ -81,10 +80,6 @@ def main():
81
80
  chip.logger.error(e)
82
81
  return 1
83
82
 
84
- # Error checking
85
- design = chip.get('design')
86
- design_set = design != UNSET_DESIGN
87
-
88
83
  # Search input keys for files
89
84
  input_mode = []
90
85
  for fileset in chip.getkeys('input'):
@@ -92,11 +87,6 @@ def main():
92
87
  if chip.schema._getvals('input', fileset, mode):
93
88
  input_mode = [('input', fileset, mode)]
94
89
 
95
- if not (design_set or input_mode):
96
- chip.logger.error('Nothing to load: please define a target with '
97
- '-cfg, -design, and/or inputs.')
98
- return 1
99
-
100
90
  filename = None
101
91
  if input_mode:
102
92
  check_ext = list(chip._showtools.keys())
@@ -115,7 +105,19 @@ def main():
115
105
 
116
106
  filename = get_file_from_keys()
117
107
 
118
- if not load_manifest(chip, filename):
108
+ # Attempt to load a manifest
109
+ if not chip.get('option', 'cfg'):
110
+ manifest = pick_manifest(chip, src_file=filename)
111
+ if manifest:
112
+ chip.logger.info(f'Loading manifest: {manifest}')
113
+ chip.read_manifest(manifest)
114
+
115
+ # Error checking
116
+ design = chip.get('design')
117
+ design_set = design != UNSET_DESIGN
118
+ if not (design_set or input_mode):
119
+ chip.logger.error('Nothing to load: please define a target with '
120
+ '-cfg, -design, and/or inputs.')
119
121
  return 1
120
122
 
121
123
  # Read in file
siliconcompiler/core.py CHANGED
@@ -1363,7 +1363,7 @@ class Chip:
1363
1363
  basename = str(pathlib.PurePosixPath(*path_paths[0:n]))
1364
1364
  endname = str(pathlib.PurePosixPath(*path_paths[n:]))
1365
1365
 
1366
- import_name = self.__get_imported_filename(basename, package)
1366
+ import_name = utils.get_hashed_filename(basename, package=package)
1367
1367
  if import_name not in collected_files:
1368
1368
  continue
1369
1369
 
@@ -2051,6 +2051,30 @@ class Chip:
2051
2051
  dot.graph_attr['ranksep'] = '0.75'
2052
2052
  dot.attr(bgcolor=background)
2053
2053
 
2054
+ subgraphs = {
2055
+ "graphs": {
2056
+ "sc-inputs": {
2057
+ "graphs": {},
2058
+ "nodes": []
2059
+ }
2060
+ },
2061
+ "nodes": []
2062
+ }
2063
+ for node, info in nodes.items():
2064
+ if info['is_input']:
2065
+ subgraph_temp = subgraphs["graphs"]["sc-inputs"]
2066
+ else:
2067
+ subgraph_temp = subgraphs
2068
+
2069
+ for key in node.split(".")[0:-1]:
2070
+ if key not in subgraph_temp["graphs"]:
2071
+ subgraph_temp["graphs"][key] = {
2072
+ "graphs": {},
2073
+ "nodes": []
2074
+ }
2075
+ subgraph_temp = subgraph_temp["graphs"][key]
2076
+ subgraph_temp["nodes"].append(node)
2077
+
2054
2078
  with dot.subgraph(name='inputs') as input_graph:
2055
2079
  input_graph.graph_attr['cluster'] = 'true'
2056
2080
  input_graph.graph_attr['color'] = background
@@ -2062,34 +2086,74 @@ class Chip:
2062
2086
  fontcolor=fontcolor, fontsize=fontsize, ordering="in",
2063
2087
  penwidth=penwidth, fillcolor=fillcolor, shape="box")
2064
2088
 
2065
- with dot.subgraph(name='input_nodes') as input_graph_nodes:
2066
- input_graph_nodes.graph_attr['cluster'] = 'true'
2067
- input_graph_nodes.graph_attr['color'] = background
2089
+ def make_node(graph, node, prefix):
2090
+ info = nodes[node]
2068
2091
 
2069
- # add nodes
2070
2092
  shape = "oval" if not show_io else "Mrecord"
2071
- for node, info in nodes.items():
2072
- task_label = f"\\n ({info['task']})" if info['task'] is not None else ""
2073
- if show_io:
2074
- input_labels = [f"<{ikey}> {ifile}" for ifile, ikey in info['inputs'].items()]
2075
- output_labels = [f"<{okey}> {ofile}" for ofile, okey in info['outputs'].items()]
2076
- center_text = f"\\n {node} {task_label} \\n\\n"
2077
- labelname = "{"
2078
- if input_labels:
2079
- labelname += f"{{ {' | '.join(input_labels)} }} |"
2080
- labelname += center_text
2081
- if output_labels:
2082
- labelname += f"| {{ {' | '.join(output_labels)} }}"
2083
- labelname += "}"
2093
+ task_label = f"\\n ({info['task']})" if info['task'] is not None else ""
2094
+ if show_io:
2095
+ input_labels = [f"<{ikey}> {ifile}" for ifile, ikey in info['inputs'].items()]
2096
+ output_labels = [f"<{okey}> {ofile}" for ofile, okey in info['outputs'].items()]
2097
+ center_text = f"\\n {node.replace(prefix, '')} {task_label} \\n\\n"
2098
+ labelname = "{"
2099
+ if input_labels:
2100
+ labelname += f"{{ {' | '.join(input_labels)} }} |"
2101
+ labelname += center_text
2102
+ if output_labels:
2103
+ labelname += f"| {{ {' | '.join(output_labels)} }}"
2104
+ labelname += "}"
2105
+ else:
2106
+ labelname = f"{node.replace(prefix, '')}{task_label}"
2107
+
2108
+ graph.node(node, label=labelname, bordercolor=fontcolor, style='filled',
2109
+ fontcolor=fontcolor, fontsize=fontsize, ordering="in",
2110
+ penwidth=penwidth, fillcolor=fillcolor, shape=shape)
2111
+
2112
+ graph_idx = 0
2113
+
2114
+ def get_node_count(graph_info):
2115
+ nodes = len(graph_info["nodes"])
2116
+
2117
+ for subgraph in graph_info["graphs"]:
2118
+ nodes += get_node_count(graph_info["graphs"][subgraph])
2119
+
2120
+ return nodes
2121
+
2122
+ def build_graph(graph_info, parent, prefix):
2123
+ nonlocal graph_idx
2124
+
2125
+ for subgraph in graph_info["graphs"]:
2126
+ child_prefix = prefix
2127
+ if get_node_count(graph_info["graphs"][subgraph]) > 1:
2128
+ child_prefix = f"{child_prefix}{subgraph}."
2129
+ graph = graphviz.Digraph(name=f"cluster_{graph_idx}")
2130
+ graph_idx += 1
2131
+
2132
+ graph.graph_attr['rankdir'] = rankdir
2133
+ graph.attr(bgcolor=background)
2134
+
2135
+ if subgraph == "sc-inputs":
2136
+ graph.attr(style='invis')
2137
+ else:
2138
+ graph.attr(color=fontcolor)
2139
+ graph.attr(style='rounded')
2140
+ graph.attr(shape='oval')
2141
+ graph.attr(label=subgraph)
2142
+ graph.attr(labeljust='l')
2143
+ graph.attr(fontcolor=fontcolor)
2144
+ graph.attr(fontsize=str(int(fontsize) + 2))
2084
2145
  else:
2085
- labelname = f"{node}{task_label}"
2146
+ graph = parent
2147
+
2148
+ build_graph(graph_info["graphs"][subgraph], graph, child_prefix)
2149
+
2150
+ if graph is not parent:
2151
+ parent.subgraph(graph)
2086
2152
 
2087
- dst = dot
2088
- if info['is_input']:
2089
- dst = input_graph_nodes
2090
- dst.node(node, label=labelname, bordercolor=fontcolor, style='filled',
2091
- fontcolor=fontcolor, fontsize=fontsize, ordering="in",
2092
- penwidth=penwidth, fillcolor=fillcolor, shape=shape)
2153
+ for subnode in graph_info["nodes"]:
2154
+ make_node(parent, subnode, prefix)
2155
+
2156
+ build_graph(subgraphs, dot, "")
2093
2157
 
2094
2158
  for edge0, edge1, weight in edges:
2095
2159
  dot.edge(f'{edge0}{out_label_suffix}', f'{edge1}{in_label_suffix}', weight=str(weight))
@@ -2394,7 +2458,7 @@ class Chip:
2394
2458
 
2395
2459
  abspath = dirs[(package, path)]
2396
2460
  if abspath:
2397
- filename = self.__get_imported_filename(posix_path, package)
2461
+ filename = utils.get_hashed_filename(posix_path, package=package)
2398
2462
  dst_path = os.path.join(directory, filename)
2399
2463
  if os.path.exists(dst_path):
2400
2464
  continue
@@ -2466,7 +2530,7 @@ class Chip:
2466
2530
 
2467
2531
  abspath = files[(package, path)]
2468
2532
  if abspath:
2469
- filename = self.__get_imported_filename(posix_path, package)
2533
+ filename = utils.get_hashed_filename(posix_path, package=package)
2470
2534
  dst_path = os.path.join(directory, filename)
2471
2535
  if verbose:
2472
2536
  self.logger.info(f"Copying {abspath} to '{directory}' directory")
@@ -2702,12 +2766,12 @@ class Chip:
2702
2766
  return hashlist
2703
2767
 
2704
2768
  ###########################################################################
2705
- def _dashboard(self, wait=True, port=None, graph_chips=None):
2769
+ def dashboard(self, wait=True, port=None, graph_chips=None):
2706
2770
  '''
2707
2771
  Open a session of the dashboard.
2708
2772
 
2709
2773
  The dashboard can be viewed in any webbrowser and can be accessed via:
2710
- http://localhost:8501/
2774
+ http://localhost:<port>/
2711
2775
 
2712
2776
  Args:
2713
2777
  wait (bool): If True, this call will wait in this method
@@ -2718,7 +2782,7 @@ class Chip:
2718
2782
  {'chip': chip object, 'name': chip name}
2719
2783
 
2720
2784
  Examples:
2721
- >>> chip._dashboard()
2785
+ >>> chip.dashboard()
2722
2786
  Opens a sesison of the dashboard.
2723
2787
  '''
2724
2788
  if self._dash:
@@ -3143,6 +3207,7 @@ class Chip:
3143
3207
  self.set('option', 'nodisplay', False, clobber=True)
3144
3208
  self.set('option', 'continue', True, clobber=True)
3145
3209
  self.set('option', 'quiet', False, clobber=True)
3210
+ self.set('option', 'clean', True, clobber=True)
3146
3211
  self.set('arg', 'step', None, clobber=True)
3147
3212
  self.set('arg', 'index', None, clobber=True)
3148
3213
  self.unset('option', 'to')
@@ -3237,31 +3302,6 @@ class Chip:
3237
3302
 
3238
3303
  return os.path.join(*dirlist)
3239
3304
 
3240
- #######################################
3241
- def __get_imported_filename(self, pathstr, package=None):
3242
- ''' Utility to map collected file to an unambiguous name based on its path.
3243
-
3244
- The mapping looks like:
3245
- path/to/file.ext => file_<md5('path/to/file.ext')>.ext
3246
- '''
3247
- path = pathlib.PurePosixPath(pathstr)
3248
- ext = ''.join(path.suffixes)
3249
-
3250
- # strip off all file suffixes to get just the bare name
3251
- barepath = path
3252
- while barepath.suffix:
3253
- barepath = pathlib.PurePosixPath(barepath.stem)
3254
- filename = str(barepath.parts[-1])
3255
-
3256
- if not package:
3257
- package = ''
3258
- else:
3259
- package = f'{package}:'
3260
- path_to_hash = f'{package}{str(path)}'
3261
- pathhash = hashlib.sha1(path_to_hash.encode('utf-8')).hexdigest()
3262
-
3263
- return f'{filename}_{pathhash}{ext}'
3264
-
3265
3305
  def error(self, msg):
3266
3306
  '''
3267
3307
  Raises error.
@@ -0,0 +1,13 @@
1
+ from siliconcompiler import Flow
2
+
3
+ from siliconcompiler.tools.klayout import drc
4
+
5
+
6
+ def setup():
7
+ '''
8
+ Perform a DRC run on an input GDS
9
+ '''
10
+ flow = Flow('drcflow')
11
+ flow.node('drcflow', 'drc', drc)
12
+
13
+ return flow
@@ -0,0 +1,17 @@
1
+ from siliconcompiler import Flow
2
+
3
+ from siliconcompiler.tools.openroad import rdlroute
4
+ from siliconcompiler.tools.klayout import export
5
+
6
+
7
+ def setup():
8
+ '''
9
+ A flow to perform RDL routing and generate a GDS
10
+ '''
11
+ flow = Flow('interposerflow')
12
+ flow.node('interposerflow', 'rdlroute', rdlroute)
13
+ flow.node('interposerflow', 'write_gds', export)
14
+
15
+ flow.edge('interposerflow', 'rdlroute', 'write_gds')
16
+
17
+ return flow
@@ -43,6 +43,14 @@ def setup():
43
43
 
44
44
  fpga.set('fpga', part_name, 'vendor', vendor)
45
45
 
46
+ # Part name is specified per architecture file. Device code specifies
47
+ # which <fixed_layout> name to use when running VPR. These examples
48
+ # use the following names:
49
+ if (part_name == 'example_arch_X005Y005'):
50
+ fpga.set('fpga', part_name, 'var', 'vpr_device_code', 'fpga_beta')
51
+ else:
52
+ fpga.set('fpga', part_name, 'var', 'vpr_device_code', part_name)
53
+
46
54
  fpga.set('fpga', part_name, 'lutsize', lut_size)
47
55
 
48
56
  arch_root = os.path.join(flow_root, 'arch', part_name)
@@ -0,0 +1,8 @@
1
+ import siliconcompiler
2
+ from lambdapdk.interposer.libs.bumps import setup
3
+
4
+
5
+ #########################
6
+ if __name__ == "__main__":
7
+ lib = setup(siliconcompiler.Chip('<lib>'))
8
+ lib.write_manifest(f'{lib.top()}.json')
@@ -88,7 +88,8 @@ def _path(chip, package, download_handler):
88
88
  chip._packages[package] = data_path
89
89
  return data_path
90
90
 
91
- raise SiliconCompilerError(f'Extracting {package} data to {data_path} failed')
91
+ raise SiliconCompilerError(f'Extracting {package} data to {data_path} failed',
92
+ chip=chip)
92
93
 
93
94
 
94
95
  def path(chip, package):
@@ -188,7 +189,7 @@ def clone_synchronized(chip, package, data, data_path):
188
189
  elif url.scheme in ['git', 'git+https']:
189
190
  chip.logger.error('Failed to authenticate. Please use a token or ssh.')
190
191
  else:
191
- raise e
192
+ chip.logger.error(str(e))
192
193
 
193
194
 
194
195
  def clone_from_git(chip, package, data, repo_path):