siliconcompiler 0.26.2__cp39-cp39-win_amd64.whl → 0.26.4.post1__cp39-cp39-win_amd64.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 (41) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/sc_issue.py +4 -11
  3. siliconcompiler/apps/smake.py +59 -19
  4. siliconcompiler/core.py +158 -56
  5. siliconcompiler/flowgraph.py +2 -1
  6. siliconcompiler/flows/dvflow.py +13 -8
  7. siliconcompiler/issue.py +3 -0
  8. siliconcompiler/report/html_report.py +1 -1
  9. siliconcompiler/report/summary_table.py +26 -14
  10. siliconcompiler/report/utils.py +1 -1
  11. siliconcompiler/scheduler/__init__.py +11 -6
  12. siliconcompiler/schema/schema_cfg.py +8 -8
  13. siliconcompiler/schema/schema_obj.py +6 -5
  14. siliconcompiler/templates/tcl/manifest.tcl.j2 +52 -0
  15. siliconcompiler/tools/_common/__init__.py +10 -2
  16. siliconcompiler/tools/_common/asic.py +26 -6
  17. siliconcompiler/tools/klayout/export.py +3 -2
  18. siliconcompiler/tools/klayout/klayout_export.py +4 -4
  19. siliconcompiler/tools/klayout/klayout_utils.py +4 -4
  20. siliconcompiler/tools/magic/sc_drc.tcl +1 -1
  21. siliconcompiler/tools/magic/sc_extspice.tcl +3 -2
  22. siliconcompiler/tools/netgen/sc_lvs.tcl +1 -1
  23. siliconcompiler/tools/openroad/export.py +3 -3
  24. siliconcompiler/tools/openroad/openroad.py +5 -5
  25. siliconcompiler/tools/openroad/scripts/sc_apr.tcl +2 -2
  26. siliconcompiler/tools/opensta/__init__.py +3 -2
  27. siliconcompiler/tools/opensta/scripts/sc_report_libraries.tcl +2 -2
  28. siliconcompiler/tools/opensta/scripts/sc_timing.tcl +2 -2
  29. siliconcompiler/tools/surelog/bin/surelog.exe +0 -0
  30. siliconcompiler/tools/verilator/compile.py +9 -3
  31. siliconcompiler/tools/yosys/sc_lec.tcl +1 -1
  32. siliconcompiler/tools/yosys/syn_asic.py +21 -17
  33. siliconcompiler/tools/yosys/syn_asic.tcl +3 -3
  34. siliconcompiler/use.py +12 -0
  35. siliconcompiler/utils/__init__.py +17 -0
  36. {siliconcompiler-0.26.2.dist-info → siliconcompiler-0.26.4.post1.dist-info}/METADATA +4 -2
  37. {siliconcompiler-0.26.2.dist-info → siliconcompiler-0.26.4.post1.dist-info}/RECORD +41 -41
  38. {siliconcompiler-0.26.2.dist-info → siliconcompiler-0.26.4.post1.dist-info}/WHEEL +1 -1
  39. {siliconcompiler-0.26.2.dist-info → siliconcompiler-0.26.4.post1.dist-info}/LICENSE +0 -0
  40. {siliconcompiler-0.26.2.dist-info → siliconcompiler-0.26.4.post1.dist-info}/entry_points.txt +0 -0
  41. {siliconcompiler-0.26.2.dist-info → siliconcompiler-0.26.4.post1.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
1
  # Version number following semver standard.
2
- version = '0.26.2'
2
+ version = '0.26.4.post1'
3
3
 
4
4
  # Default server address for remote runs, if unspecified.
5
5
  default_server = 'https://server.siliconcompiler.com'
@@ -25,13 +25,13 @@ Restricted SC app that generates a sharable testcase from a
25
25
  failed flow or runs an issue generated with this program.
26
26
 
27
27
  To generate a testcase, use:
28
- sc-issue -generate -cfg <stepdir>/outputs/<design>.pkg.json
28
+ sc-issue -cfg <stepdir>/outputs/<design>.pkg.json
29
29
 
30
30
  or include a different step/index than what the cfg_file is pointing to:
31
- sc-issue -generate -cfg <otherdir>/outputs/<design>.pkg.json -arg_step <step> -arg_index <index>
31
+ sc-issue -cfg <otherdir>/outputs/<design>.pkg.json -arg_step <step> -arg_index <index>
32
32
 
33
33
  or include specific libraries while excluding others:
34
- sc-issue -generate -cfg <stepdir>/outputs/<design>.pkg.json -exclude_libraries -add_library sram -add_library gpio
34
+ sc-issue -cfg <stepdir>/outputs/<design>.pkg.json -exclude_libraries -add_library sram -add_library gpio
35
35
 
36
36
  To run a testcase, use:
37
37
  sc-issue -run -file sc_issue_<...>.tar.gz
@@ -39,10 +39,6 @@ To run a testcase, use:
39
39
  """ # noqa E501
40
40
 
41
41
  issue_arguments = {
42
- '-generate': {'action': 'store_true',
43
- 'help': 'generate a testcase',
44
- 'sc_print': False},
45
-
46
42
  '-exclude_libraries': {'action': 'store_true',
47
43
  'help': 'flag to ensure libraries are excluded in the testcase',
48
44
  'sc_print': False},
@@ -88,10 +84,7 @@ To run a testcase, use:
88
84
  chip.logger.error(e)
89
85
  return 1
90
86
 
91
- if switches['generate'] and switches['run']:
92
- raise ValueError('Only one of -generate or -run can be used')
93
-
94
- if switches['generate']:
87
+ if not switches['run']:
95
88
  step = chip.get('arg', 'step')
96
89
  index = chip.get('arg', 'index')
97
90
 
@@ -41,7 +41,20 @@ def __process_file(path):
41
41
  arg_type = str
42
42
  if arg in func_spec.annotations:
43
43
  arg_type = func_spec.annotations[arg]
44
- func_args[arg] = arg_type
44
+ func_args[arg] = {
45
+ "type": arg_type
46
+ }
47
+
48
+ if func_spec.defaults:
49
+ for arg, defval in zip(reversed(func_spec.args), reversed(func_spec.defaults)):
50
+ func_args[arg]["default"] = defval
51
+
52
+ if defval is None:
53
+ continue
54
+
55
+ if type(defval) is not func_args[arg]["type"]:
56
+ if isinstance(defval, (bool, str, float, int)):
57
+ func_args[arg]["type"] = type(defval)
45
58
 
46
59
  args[name] = {
47
60
  "function": func,
@@ -62,7 +75,7 @@ def __process_file(path):
62
75
  return args, default_arg, module_help
63
76
 
64
77
 
65
- def main():
78
+ def main(source_file=None):
66
79
  progname = "smake"
67
80
  description = f"""-----------------------------------------------------------
68
81
  SC app that provides an Makefile like interface to python
@@ -90,16 +103,18 @@ To run a target with supported arguments, use:
90
103
  -----------------------------------------------------------"""
91
104
 
92
105
  # handle source file identification before arg parse
93
- source_file = __default_source_file
94
- file_args = ('--file', '-f')
95
- for file_arg in file_args:
96
- if file_arg in sys.argv:
97
- source_file_idx = sys.argv.index(file_arg) + 1
98
- if source_file_idx < len(sys.argv):
99
- source_file = sys.argv[source_file_idx]
100
- else:
101
- source_file = None
102
- break
106
+ file_args = None
107
+ if not source_file:
108
+ source_file = __default_source_file
109
+ file_args = ('--file', '-f')
110
+ for file_arg in file_args:
111
+ if file_arg in sys.argv:
112
+ source_file_idx = sys.argv.index(file_arg) + 1
113
+ if source_file_idx < len(sys.argv):
114
+ source_file = sys.argv[source_file_idx]
115
+ else:
116
+ source_file = None
117
+ break
103
118
 
104
119
  # handle directory identification before arg parse
105
120
  source_dir = os.getcwd()
@@ -135,10 +150,11 @@ To run a target with supported arguments, use:
135
150
  description=description,
136
151
  formatter_class=argparse.RawDescriptionHelpFormatter)
137
152
 
138
- parser.add_argument(
139
- *file_args,
140
- metavar='<file>',
141
- help=f'Use file as makefile, default is {__default_source_file}')
153
+ if file_args:
154
+ parser.add_argument(
155
+ *file_args,
156
+ metavar='<file>',
157
+ help=f'Use file as makefile, default is {__default_source_file}')
142
158
 
143
159
  parser.add_argument(
144
160
  *dir_args,
@@ -159,14 +175,38 @@ To run a target with supported arguments, use:
159
175
  subparse = targetparsers.add_parser(
160
176
  arg,
161
177
  description=info['full_help'],
162
- help=info['help'])
178
+ help=info['help'],
179
+ formatter_class=argparse.RawDescriptionHelpFormatter)
180
+
181
+ for subarg, subarg_info in info['args'].items():
182
+ # print(subarg, subarg_info)
183
+ add_args = {}
184
+
185
+ if "default" not in subarg_info:
186
+ add_args["required"] = True
187
+ else:
188
+ if type(subarg_info["default"]) is subarg_info["type"]:
189
+ add_args["default"] = subarg_info["default"]
190
+
191
+ if subarg_info["type"] is bool:
192
+ def str2bool(v):
193
+ # modified from:
194
+ # https://github.com/pypa/distutils/blob/8993718731b951ee36d08cb784f02aa13542ce15/distutils/util.py
195
+ val = v.lower()
196
+ if val in ('y', 'yes', 't', 'true', 'on', '1'):
197
+ return True
198
+ elif val in ('n', 'no', 'f', 'false', 'off', '0'):
199
+ return False
200
+ else:
201
+ raise ValueError(f"invalid truth value {val!r}")
202
+ subarg_info["type"] = str2bool
163
203
 
164
- for subarg, subarg_type in info['args'].items():
165
204
  subparse.add_argument(
166
205
  f'--{subarg}',
167
206
  dest=f'sub_{subarg}',
168
207
  metavar=f'<{subarg}>',
169
- type=subarg_type)
208
+ type=subarg_info["type"],
209
+ **add_args)
170
210
 
171
211
  args = parser.parse_args()
172
212
  target = args.target
siliconcompiler/core.py CHANGED
@@ -15,6 +15,7 @@ import inspect
15
15
  import textwrap
16
16
  import graphviz
17
17
  import codecs
18
+ import copy
18
19
  from siliconcompiler.remote import client
19
20
  from siliconcompiler.schema import Schema, SCHEMA_VERSION
20
21
  from siliconcompiler.schema import utils as schema_utils
@@ -234,6 +235,7 @@ class Chip:
234
235
  for future_step, future_index in nodes_to_run:
235
236
  max_step_len = max(len(future_step), max_step_len)
236
237
  max_index_len = max(len(future_index), max_index_len)
238
+ max_step_len = min(max_step_len, 20)
237
239
 
238
240
  jobname = self.get('option', 'jobname')
239
241
 
@@ -243,7 +245,7 @@ class Chip:
243
245
  index = '-' * max(max_index_len // 4, 1)
244
246
 
245
247
  log_format.append(jobname)
246
- log_format.append(f'{step: <{max_step_len}}')
248
+ log_format.append(f'{utils.truncate_text(step, max_step_len): <{max_step_len}}')
247
249
  log_format.append(f'{index: >{max_index_len}}')
248
250
 
249
251
  log_format.append('%(message)s')
@@ -555,7 +557,12 @@ class Chip:
555
557
 
556
558
  elif isinstance(use_module, (Library, Chip)):
557
559
  self._loaded_modules['libs'].append(use_module.design)
558
- self.__import_library(use_module.design, use_module.schema.cfg)
560
+ cfg = use_module.schema.cfg
561
+ keep_inputs = True
562
+ if not isinstance(use_module, Library):
563
+ keep_inputs = False
564
+ self.__import_library(use_module.design, cfg,
565
+ keep_input=keep_inputs)
559
566
 
560
567
  is_auto_enable = getattr(use_module, 'is_auto_enable', None)
561
568
  if is_auto_enable:
@@ -1001,8 +1008,8 @@ class Chip:
1001
1008
  package (str): Name of package where this file can be found
1002
1009
  '''
1003
1010
 
1004
- self.__add_input_output('input', filename, fileset, filetype, iomap,
1005
- step=step, index=index, package=package)
1011
+ self._add_input_output('input', filename, fileset, filetype, iomap,
1012
+ step=step, index=index, package=package)
1006
1013
  # Replace {iotable} in __doc__ with actual table for fileset/filetype and extension mapping
1007
1014
  input.__doc__ = input.__doc__.replace("{iotable}",
1008
1015
  utils.format_fileset_type_table())
@@ -1012,14 +1019,14 @@ class Chip:
1012
1019
  step=None, index=None, package=None):
1013
1020
  '''Same as input'''
1014
1021
 
1015
- self.__add_input_output('output', filename, fileset, filetype, iomap,
1016
- step=step, index=index, package=package)
1022
+ self._add_input_output('output', filename, fileset, filetype, iomap,
1023
+ step=step, index=index, package=package)
1017
1024
  # Copy input functions __doc__ and replace 'input' with 'output' to make constant
1018
1025
  output.__doc__ = input.__doc__.replace("input", "output")
1019
1026
 
1020
1027
  ###########################################################################
1021
- def __add_input_output(self, category, filename, fileset, filetype, iomap,
1022
- step=None, index=None, package=None):
1028
+ def _add_input_output(self, category, filename, fileset, filetype, iomap,
1029
+ step=None, index=None, package=None, quiet=False):
1023
1030
  '''
1024
1031
  Adds file to input or output groups.
1025
1032
  Performs a lookup in the io map for the fileset and filetype
@@ -1051,12 +1058,13 @@ class Chip:
1051
1058
  if not use_fileset or not use_filetype:
1052
1059
  self.logger.error(f'Unable to infer {category} fileset and/or filetype for '
1053
1060
  f'{filename} based on file extension.')
1054
- elif not fileset and not filetype:
1055
- self.logger.info(f'{filename} inferred as {use_fileset}/{use_filetype}')
1056
- elif not filetype:
1057
- self.logger.info(f'{filename} inferred as filetype {use_filetype}')
1058
- elif not fileset:
1059
- self.logger.info(f'{filename} inferred as fileset {use_fileset}')
1061
+ elif not quiet:
1062
+ if not fileset and not filetype:
1063
+ self.logger.info(f'{filename} inferred as {use_fileset}/{use_filetype}')
1064
+ elif not filetype:
1065
+ self.logger.info(f'{filename} inferred as filetype {use_filetype}')
1066
+ elif not fileset:
1067
+ self.logger.info(f'{filename} inferred as fileset {use_fileset}')
1060
1068
 
1061
1069
  self.add(category, use_fileset, use_filetype, filename,
1062
1070
  step=step, index=index, package=package)
@@ -1162,6 +1170,10 @@ class Chip:
1162
1170
 
1163
1171
  result = []
1164
1172
 
1173
+ collection_dir = self._getcollectdir(jobname=job)
1174
+ if not os.path.exists(collection_dir):
1175
+ collection_dir = None
1176
+
1165
1177
  # Special cases for various ['tool', ...] files that may be implicitly
1166
1178
  # under the workdir (or refdir in the case of scripts).
1167
1179
  # TODO: it may be cleaner to have a file resolution scope flag in schema
@@ -1190,10 +1202,8 @@ class Chip:
1190
1202
  search_paths = self.__convert_paths_to_posix(search_paths)
1191
1203
 
1192
1204
  for (dependency, path) in zip(dependencies, paths):
1193
- if not search_paths:
1194
- import_path = self.__find_sc_imported_file(path,
1195
- dependency,
1196
- self._getcollectdir(jobname=job))
1205
+ if not search_paths and collection_dir:
1206
+ import_path = self.__find_sc_imported_file(path, dependency, collection_dir)
1197
1207
  if import_path:
1198
1208
  result.append(import_path)
1199
1209
  continue
@@ -1238,6 +1248,10 @@ class Chip:
1238
1248
  if not path:
1239
1249
  return None
1240
1250
 
1251
+ collected_files = os.listdir(collected_dir)
1252
+ if not collected_files:
1253
+ return None
1254
+
1241
1255
  path_paths = pathlib.PurePosixPath(path).parts
1242
1256
  for n in range(len(path_paths)):
1243
1257
  # Search through the path elements to see if any of the previous path parts
@@ -1247,7 +1261,11 @@ class Chip:
1247
1261
  basename = str(pathlib.PurePosixPath(*path_paths[0:n]))
1248
1262
  endname = str(pathlib.PurePosixPath(*path_paths[n:]))
1249
1263
 
1250
- abspath = os.path.join(collected_dir, self.__get_imported_filename(basename, package))
1264
+ import_name = self.__get_imported_filename(basename, package)
1265
+ if import_name not in collected_files:
1266
+ continue
1267
+
1268
+ abspath = os.path.join(collected_dir, import_name)
1251
1269
  if endname:
1252
1270
  abspath = os.path.join(abspath, endname)
1253
1271
  abspath = os.path.abspath(abspath)
@@ -1256,19 +1274,18 @@ class Chip:
1256
1274
 
1257
1275
  return None
1258
1276
 
1259
- ###########################################################################
1260
- def find_result(self, filetype, step, jobname=None, index='0'):
1277
+ def find_node_file(self, path, step, jobname=None, index='0'):
1261
1278
  """
1262
- Returns the absolute path of a compilation result.
1279
+ Returns the absolute path of a file from a particular node.
1263
1280
 
1264
- Utility function that returns the absolute path to a results
1281
+ Utility function that returns the absolute path to a node
1265
1282
  file based on the provided arguments. The result directory
1266
1283
  structure is:
1267
1284
 
1268
- <dir>/<design>/<jobname>/<step>/<index>/outputs/<design>.filetype
1285
+ <dir>/<design>/<jobname>/<step>/<index>/<path>
1269
1286
 
1270
1287
  Args:
1271
- filetype (str): File extension (v, def, etc)
1288
+ path (str): Path to file inside node run directory
1272
1289
  step (str): Task step name ('syn', 'place', etc)
1273
1290
  jobname (str): Jobid directory name
1274
1291
  index (str): Task index
@@ -1277,23 +1294,54 @@ class Chip:
1277
1294
  Returns absolute path to file.
1278
1295
 
1279
1296
  Examples:
1280
- >>> manifest_filepath = chip.find_result('vg', 'syn')
1281
- Returns the absolute path to the manifest.
1297
+ >>> manifest_filepath = chip.find_node_file('outputs/heartbeat.vg', 'syn')
1298
+ Returns the absolute path to the gate level verilog.
1282
1299
  """
1283
1300
  if jobname is None:
1284
1301
  jobname = self.get('option', 'jobname')
1285
1302
 
1286
1303
  workdir = self.getworkdir(jobname, step, index)
1287
- design = self.top()
1288
- filename = f"{workdir}/outputs/{design}.{filetype}"
1304
+ filename = f"{workdir}/{path}"
1289
1305
 
1290
- self.logger.debug("Finding result %s", filename)
1306
+ self.logger.debug(f"Finding node file: {filename}")
1291
1307
 
1292
1308
  if os.path.exists(filename):
1293
1309
  return filename
1294
1310
  else:
1295
1311
  return None
1296
1312
 
1313
+ ###########################################################################
1314
+ def find_result(self, filetype, step, jobname=None, index='0'):
1315
+ """
1316
+ Returns the absolute path of a compilation result.
1317
+
1318
+ Utility function that returns the absolute path to a results
1319
+ file based on the provided arguments. The result directory
1320
+ structure is:
1321
+
1322
+ <dir>/<design>/<jobname>/<step>/<index>/outputs/<design>.filetype
1323
+
1324
+ Args:
1325
+ filetype (str): File extension (v, def, etc)
1326
+ step (str): Task step name ('syn', 'place', etc)
1327
+ jobname (str): Jobid directory name
1328
+ index (str): Task index
1329
+
1330
+ Returns:
1331
+ Returns absolute path to file.
1332
+
1333
+ Examples:
1334
+ >>> vg_filepath = chip.find_result('vg', 'syn')
1335
+ Returns the absolute path to the gate level verilog.
1336
+ """
1337
+
1338
+ design = self.top()
1339
+ return self.find_node_file(
1340
+ f"outputs/{design}.{filetype}",
1341
+ step=step,
1342
+ jobname=jobname,
1343
+ index=index)
1344
+
1297
1345
  ###########################################################################
1298
1346
  def __abspath(self):
1299
1347
  '''
@@ -1568,13 +1616,15 @@ class Chip:
1568
1616
  if not os.path.exists(os.path.dirname(filepath)):
1569
1617
  os.makedirs(os.path.dirname(filepath))
1570
1618
 
1619
+ schema = self.schema
1571
1620
  # resolve absolute paths
1572
1621
  if abspath:
1573
1622
  schema = self.__abspath()
1574
- else:
1575
- schema = self.schema.copy()
1576
1623
 
1577
1624
  if prune:
1625
+ if schema is self.schema:
1626
+ schema = schema.copy()
1627
+
1578
1628
  self.logger.debug('Pruning dictionary before writing file %s', filepath)
1579
1629
  schema.prune()
1580
1630
 
@@ -1797,7 +1847,7 @@ class Chip:
1797
1847
  return not error
1798
1848
 
1799
1849
  ###########################################################################
1800
- def __import_library(self, libname, libcfg, job=None, clobber=True):
1850
+ def __import_library(self, libname, libcfg, job=None, clobber=True, keep_input=True):
1801
1851
  '''Helper to import library with config 'libconfig' as a library
1802
1852
  'libname' in current Chip object.'''
1803
1853
  if job:
@@ -1808,19 +1858,22 @@ class Chip:
1808
1858
  if 'library' in libcfg:
1809
1859
  for sublib_name, sublibcfg in libcfg['library'].items():
1810
1860
  self.__import_library(sublib_name, sublibcfg,
1811
- job=job, clobber=clobber)
1812
-
1813
- del libcfg['library']
1861
+ job=job, clobber=clobber, keep_input=keep_input)
1814
1862
 
1815
1863
  if libname in cfg:
1816
1864
  if not clobber:
1817
1865
  return
1818
1866
 
1819
- cfg[libname] = libcfg
1820
1867
  self.__import_data_sources(libcfg)
1868
+ cfg[libname] = {}
1821
1869
 
1822
- if 'pdk' in cfg[libname]:
1823
- del cfg[libname]['pdk']
1870
+ # Only keep some sections to avoid recursive bloat
1871
+ keeps = ['asic', 'design', 'fpga', 'option', 'output', 'package']
1872
+ if keep_input:
1873
+ keeps.append('input')
1874
+ for section in list(libcfg.keys()):
1875
+ if section in keeps:
1876
+ cfg[libname][section] = copy.deepcopy(libcfg[section])
1824
1877
 
1825
1878
  ###########################################################################
1826
1879
  def write_flowgraph(self, filename, flow=None,
@@ -1946,7 +1999,7 @@ class Chip:
1946
1999
 
1947
2000
  ###########################################################################
1948
2001
  def write_dependencygraph(self, filename, flow=None,
1949
- fillcolor='#ffffff', fontcolor='#000000',
2002
+ fontcolor='#000000', color_scheme=None,
1950
2003
  background='transparent', fontsize='14',
1951
2004
  border=True, landscape=False):
1952
2005
  r'''
@@ -1964,8 +2017,9 @@ class Chip:
1964
2017
  Args:
1965
2018
  filename (filepath): Output filepath
1966
2019
  flow (str): Name of flowgraph to render
1967
- fillcolor(str): Node fill RGB color hex value
1968
2020
  fontcolor (str): Node font RGB color hex value
2021
+ color_scheme (str): Name of the color scheme to apply to the nodes.
2022
+ Valid choices are: "none", "simple", "detailed"
1969
2023
  background (str): Background color
1970
2024
  fontsize (str): Node text font size
1971
2025
  border (bool): Enables node border if True
@@ -1981,6 +2035,33 @@ class Chip:
1981
2035
  fileroot, ext = os.path.splitext(filepath)
1982
2036
  fileformat = ext.replace(".", "")
1983
2037
 
2038
+ color_schemes = {
2039
+ "none": {
2040
+ "design": "white",
2041
+ "library": "white",
2042
+ "logiclib": "white",
2043
+ "macrolib": "white"
2044
+ },
2045
+ "simple": {
2046
+ "design": "lightgreen",
2047
+ "library": "white",
2048
+ "logiclib": "lightgreen",
2049
+ "macrolib": "lightgreen"
2050
+ },
2051
+ "detailed": {
2052
+ "design": "lightgreen",
2053
+ "library": "white",
2054
+ "logiclib": "lightskyblue",
2055
+ "macrolib": "lightgoldenrod2"
2056
+ },
2057
+ }
2058
+
2059
+ if not color_scheme:
2060
+ color_scheme = "none"
2061
+
2062
+ if color_scheme not in color_schemes:
2063
+ raise ValueError(f'{color_scheme} is not a valid color scheme')
2064
+
1984
2065
  # controlling border width
1985
2066
  if border:
1986
2067
  penwidth = '1'
@@ -2006,7 +2087,7 @@ class Chip:
2006
2087
  nodes.add(node)
2007
2088
  dot.node(node, label=node, bordercolor=fontcolor, style='filled',
2008
2089
  fontcolor=fontcolor, fontsize=fontsize, ordering="in",
2009
- penwidth=penwidth, fillcolor=fillcolor)
2090
+ penwidth=penwidth, fillcolor="white")
2010
2091
  return node
2011
2092
 
2012
2093
  nodes = {}
@@ -2019,32 +2100,53 @@ class Chip:
2019
2100
  if root_label in nodes:
2020
2101
  return
2021
2102
 
2022
- in_libs = lib.get('option', 'library',
2023
- step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY) + \
2024
- lib.get('asic', 'logiclib',
2025
- step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY) + \
2026
- lib.get('asic', 'macrolib',
2027
- step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY)
2028
-
2029
2103
  in_labels = []
2030
- for in_lib in in_libs:
2104
+ for in_lib in lib.get('option', 'library',
2105
+ step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY):
2031
2106
  in_labels.append(f'library-{in_lib}')
2107
+ for in_lib in lib.get('asic', 'logiclib',
2108
+ step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY):
2109
+ in_labels.append(f'logiclib-{in_lib}')
2110
+ for in_lib in lib.get('asic', 'macrolib',
2111
+ step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY):
2112
+ in_labels.append(f'macrolib-{in_lib}')
2113
+
2114
+ shape = "oval"
2115
+ if root_type == "logiclib":
2116
+ shape = "box"
2117
+ elif root_type == "macrolib":
2118
+ shape = "box"
2119
+ elif root_type == "design":
2120
+ shape = "box"
2121
+
2122
+ color = color_schemes[color_scheme][root_type]
2032
2123
 
2033
2124
  nodes[root_label] = {
2034
2125
  "text": name,
2035
- "shape": "oval" if root_type == "library" else "box",
2126
+ "shape": shape,
2127
+ "color": color,
2036
2128
  "connects_to": set(in_labels)
2037
2129
  }
2038
2130
 
2039
- for in_lib in in_libs:
2040
- collect_library("library", Schema(cfg=self.getdict('library', in_lib)), name=in_lib)
2131
+ for in_lib in lib.get('option', 'library',
2132
+ step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY):
2133
+ collect_library("library", Schema(cfg=self.getdict('library', in_lib)),
2134
+ name=in_lib)
2135
+ for in_lib in lib.get('asic', 'logiclib',
2136
+ step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY):
2137
+ collect_library("logiclib", Schema(cfg=self.getdict('library', in_lib)),
2138
+ name=in_lib)
2139
+ for in_lib in lib.get('asic', 'macrolib',
2140
+ step=Schema.GLOBAL_KEY, index=Schema.GLOBAL_KEY):
2141
+ collect_library("macrolib", Schema(cfg=self.getdict('library', in_lib)),
2142
+ name=in_lib)
2041
2143
 
2042
2144
  collect_library("design", self)
2043
2145
 
2044
2146
  for label, info in nodes.items():
2045
2147
  dot.node(label, label=info['text'], bordercolor=fontcolor, style='filled',
2046
2148
  fontcolor=fontcolor, fontsize=fontsize, ordering="in",
2047
- penwidth=penwidth, fillcolor=fillcolor, shape=info['shape'])
2149
+ penwidth=penwidth, fillcolor=info["color"], shape=info['shape'])
2048
2150
 
2049
2151
  for conn in info['connects_to']:
2050
2152
  dot.edge(label, conn, dir='back')
@@ -2086,7 +2188,7 @@ class Chip:
2086
2188
  step=r_step, index=r_index)
2087
2189
  else:
2088
2190
  self.set(*key,
2089
- list(map(lambda x: x.replace(org_library, new_library), val)),
2191
+ list(map(lambda x: new_library if x == org_library else x, val)),
2090
2192
  step=r_step, index=r_index)
2091
2193
  else:
2092
2194
  for val, r_step, r_index in self.schema._getvals(*key):
@@ -2100,7 +2202,7 @@ class Chip:
2100
2202
  step=r_step, index=r_index)
2101
2203
  else:
2102
2204
  self.set(*key,
2103
- list(map(lambda x: x.replace(org_library, new_library), val)),
2205
+ list(map(lambda x: new_library if x == org_library else x, val)),
2104
2206
  step=r_step, index=r_index)
2105
2207
 
2106
2208
  swap('option', 'library')
@@ -423,7 +423,8 @@ def _get_flowgraph_information(chip, flow, io=True):
423
423
  from siliconcompiler.tools._common import input_provides, input_file_node_name
424
424
 
425
425
  # Save schema to avoid making permanent changes
426
- org_schema = chip.schema.copy()
426
+ org_schema = chip.schema
427
+ chip.schema = chip.schema.copy()
427
428
 
428
429
  # Setup nodes
429
430
  node_exec_order = _get_flowgraph_execution_order(chip, flow)
@@ -1,6 +1,7 @@
1
1
  import siliconcompiler
2
2
 
3
3
  from siliconcompiler.tools.icarus import compile as icarus_compile
4
+ from siliconcompiler.tools.verilator import compile as verilator_compile
4
5
  from siliconcompiler.tools.execute import exec_input
5
6
 
6
7
 
@@ -44,17 +45,21 @@ def setup(chip,
44
45
  if tool == 'icarus':
45
46
  tasks['compile'] = icarus_compile
46
47
  tasks['sim'] = exec_input
47
- flowpipe = [
48
- 'compile',
49
- 'sim'
50
- ]
51
- flow_np = {
52
- 'compile': 1,
53
- 'sim': np
54
- }
48
+ elif tool == 'verilator':
49
+ tasks['compile'] = verilator_compile
50
+ tasks['sim'] = exec_input
55
51
  else:
56
52
  raise ValueError(f'{tool} is not a supported tool for {flowname}: icarus')
57
53
 
54
+ flowpipe = [
55
+ 'compile',
56
+ 'sim'
57
+ ]
58
+ flow_np = {
59
+ 'compile': 1,
60
+ 'sim': np
61
+ }
62
+
58
63
  prevstep = None
59
64
  # Flow setup
60
65
  for step in flowpipe:
siliconcompiler/issue.py CHANGED
@@ -153,6 +153,8 @@ def generate_testcase(chip,
153
153
  os.chdir(new_work_dir)
154
154
 
155
155
  # Rewrite replay.sh
156
+ prev_quiet = chip.get('option', 'quiet', step=step, index=index)
157
+ chip.set('option', 'quiet', True, step=step, index=index)
156
158
  from siliconcompiler import SiliconCompilerError
157
159
  try:
158
160
  # Rerun setup
@@ -167,6 +169,7 @@ def generate_testcase(chip,
167
169
  pass
168
170
  except SiliconCompilerError:
169
171
  pass
172
+ chip.set('option', 'quiet', prev_quiet, step=step, index=index)
170
173
 
171
174
  flow = chip.get('option', 'flow')
172
175
  is_python_tool = hasattr(chip._get_task_module(step, index, flow=flow), 'run')
@@ -14,7 +14,7 @@ def _generate_html_report(chip, flow, flowgraph_nodes, results_html):
14
14
  '''
15
15
 
16
16
  # only report tool based steps functions
17
- for (step, index) in flowgraph_nodes.copy():
17
+ for (step, index) in list(flowgraph_nodes):
18
18
  tool, task = get_tool_task(chip, step, '0', flow=flow)
19
19
  if tool == 'builtin':
20
20
  index = flowgraph_nodes.index((step, index))