siliconcompiler 0.34.1__py3-none-any.whl → 0.34.3__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 (129) hide show
  1. siliconcompiler/__init__.py +23 -4
  2. siliconcompiler/__main__.py +1 -7
  3. siliconcompiler/_metadata.py +1 -1
  4. siliconcompiler/apps/_common.py +104 -23
  5. siliconcompiler/apps/sc.py +4 -8
  6. siliconcompiler/apps/sc_dashboard.py +6 -4
  7. siliconcompiler/apps/sc_install.py +10 -6
  8. siliconcompiler/apps/sc_issue.py +7 -5
  9. siliconcompiler/apps/sc_remote.py +1 -1
  10. siliconcompiler/apps/sc_server.py +9 -14
  11. siliconcompiler/apps/sc_show.py +7 -6
  12. siliconcompiler/apps/smake.py +130 -94
  13. siliconcompiler/apps/utils/replay.py +4 -7
  14. siliconcompiler/apps/utils/summarize.py +3 -5
  15. siliconcompiler/asic.py +420 -0
  16. siliconcompiler/checklist.py +25 -2
  17. siliconcompiler/cmdlineschema.py +534 -0
  18. siliconcompiler/constraints/__init__.py +17 -0
  19. siliconcompiler/constraints/asic_component.py +378 -0
  20. siliconcompiler/constraints/asic_floorplan.py +449 -0
  21. siliconcompiler/constraints/asic_pins.py +489 -0
  22. siliconcompiler/constraints/asic_timing.py +517 -0
  23. siliconcompiler/core.py +10 -35
  24. siliconcompiler/data/templates/tcl/manifest.tcl.j2 +8 -0
  25. siliconcompiler/dependencyschema.py +96 -202
  26. siliconcompiler/design.py +327 -241
  27. siliconcompiler/filesetschema.py +250 -0
  28. siliconcompiler/flowgraph.py +298 -106
  29. siliconcompiler/fpga.py +124 -1
  30. siliconcompiler/library.py +331 -0
  31. siliconcompiler/metric.py +327 -92
  32. siliconcompiler/metrics/__init__.py +7 -0
  33. siliconcompiler/metrics/asic.py +245 -0
  34. siliconcompiler/metrics/fpga.py +220 -0
  35. siliconcompiler/package/__init__.py +391 -67
  36. siliconcompiler/package/git.py +92 -16
  37. siliconcompiler/package/github.py +114 -22
  38. siliconcompiler/package/https.py +79 -16
  39. siliconcompiler/packageschema.py +341 -16
  40. siliconcompiler/pathschema.py +255 -0
  41. siliconcompiler/pdk.py +566 -1
  42. siliconcompiler/project.py +1460 -0
  43. siliconcompiler/record.py +38 -1
  44. siliconcompiler/remote/__init__.py +5 -2
  45. siliconcompiler/remote/client.py +11 -6
  46. siliconcompiler/remote/schema.py +5 -23
  47. siliconcompiler/remote/server.py +41 -54
  48. siliconcompiler/report/__init__.py +3 -3
  49. siliconcompiler/report/dashboard/__init__.py +48 -14
  50. siliconcompiler/report/dashboard/cli/__init__.py +99 -21
  51. siliconcompiler/report/dashboard/cli/board.py +364 -179
  52. siliconcompiler/report/dashboard/web/__init__.py +90 -12
  53. siliconcompiler/report/dashboard/web/components/__init__.py +219 -240
  54. siliconcompiler/report/dashboard/web/components/flowgraph.py +49 -26
  55. siliconcompiler/report/dashboard/web/components/graph.py +139 -100
  56. siliconcompiler/report/dashboard/web/layouts/__init__.py +29 -1
  57. siliconcompiler/report/dashboard/web/layouts/_common.py +38 -2
  58. siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph.py +39 -26
  59. siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph_node_tab.py +50 -50
  60. siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph_sac_tabs.py +49 -46
  61. siliconcompiler/report/dashboard/web/state.py +141 -14
  62. siliconcompiler/report/dashboard/web/utils/__init__.py +79 -16
  63. siliconcompiler/report/dashboard/web/utils/file_utils.py +74 -11
  64. siliconcompiler/report/dashboard/web/viewer.py +25 -1
  65. siliconcompiler/report/report.py +5 -2
  66. siliconcompiler/report/summary_image.py +29 -11
  67. siliconcompiler/scheduler/__init__.py +9 -1
  68. siliconcompiler/scheduler/docker.py +81 -4
  69. siliconcompiler/scheduler/run_node.py +37 -20
  70. siliconcompiler/scheduler/scheduler.py +211 -36
  71. siliconcompiler/scheduler/schedulernode.py +394 -60
  72. siliconcompiler/scheduler/send_messages.py +77 -29
  73. siliconcompiler/scheduler/slurm.py +76 -12
  74. siliconcompiler/scheduler/taskscheduler.py +142 -21
  75. siliconcompiler/schema/__init__.py +0 -4
  76. siliconcompiler/schema/baseschema.py +338 -59
  77. siliconcompiler/schema/editableschema.py +14 -6
  78. siliconcompiler/schema/journal.py +28 -17
  79. siliconcompiler/schema/namedschema.py +22 -14
  80. siliconcompiler/schema/parameter.py +89 -28
  81. siliconcompiler/schema/parametertype.py +2 -0
  82. siliconcompiler/schema/parametervalue.py +258 -15
  83. siliconcompiler/schema/safeschema.py +25 -2
  84. siliconcompiler/schema/schema_cfg.py +23 -19
  85. siliconcompiler/schema/utils.py +2 -2
  86. siliconcompiler/schema_obj.py +24 -5
  87. siliconcompiler/tool.py +1131 -265
  88. siliconcompiler/tools/bambu/__init__.py +41 -0
  89. siliconcompiler/tools/builtin/concatenate.py +2 -2
  90. siliconcompiler/tools/builtin/minimum.py +2 -1
  91. siliconcompiler/tools/builtin/mux.py +2 -1
  92. siliconcompiler/tools/builtin/nop.py +2 -1
  93. siliconcompiler/tools/builtin/verify.py +2 -1
  94. siliconcompiler/tools/klayout/__init__.py +95 -0
  95. siliconcompiler/tools/openroad/__init__.py +289 -0
  96. siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +3 -0
  97. siliconcompiler/tools/openroad/scripts/apr/sc_detailed_route.tcl +7 -2
  98. siliconcompiler/tools/openroad/scripts/apr/sc_global_route.tcl +8 -4
  99. siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +9 -5
  100. siliconcompiler/tools/openroad/scripts/common/write_images.tcl +5 -1
  101. siliconcompiler/tools/slang/__init__.py +1 -1
  102. siliconcompiler/tools/slang/elaborate.py +2 -1
  103. siliconcompiler/tools/vivado/scripts/sc_run.tcl +1 -1
  104. siliconcompiler/tools/vivado/scripts/sc_syn_fpga.tcl +8 -1
  105. siliconcompiler/tools/vivado/syn_fpga.py +6 -0
  106. siliconcompiler/tools/vivado/vivado.py +35 -2
  107. siliconcompiler/tools/vpr/__init__.py +150 -0
  108. siliconcompiler/tools/yosys/__init__.py +369 -1
  109. siliconcompiler/tools/yosys/scripts/procs.tcl +0 -1
  110. siliconcompiler/toolscripts/_tools.json +5 -10
  111. siliconcompiler/utils/__init__.py +66 -0
  112. siliconcompiler/utils/flowgraph.py +2 -2
  113. siliconcompiler/utils/issue.py +2 -1
  114. siliconcompiler/utils/logging.py +14 -0
  115. siliconcompiler/utils/multiprocessing.py +256 -0
  116. siliconcompiler/utils/showtools.py +10 -0
  117. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/METADATA +6 -6
  118. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/RECORD +122 -115
  119. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/entry_points.txt +3 -0
  120. siliconcompiler/schema/cmdlineschema.py +0 -250
  121. siliconcompiler/schema/packageschema.py +0 -101
  122. siliconcompiler/toolscripts/rhel8/install-slang.sh +0 -40
  123. siliconcompiler/toolscripts/rhel9/install-slang.sh +0 -40
  124. siliconcompiler/toolscripts/ubuntu20/install-slang.sh +0 -47
  125. siliconcompiler/toolscripts/ubuntu22/install-slang.sh +0 -37
  126. siliconcompiler/toolscripts/ubuntu24/install-slang.sh +0 -37
  127. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/WHEEL +0 -0
  128. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/licenses/LICENSE +0 -0
  129. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/top_level.txt +0 -0
@@ -1,60 +1,89 @@
1
1
  # Copyright 2023 Silicon Compiler Authors. All Rights Reserved.
2
+ """
3
+ A 'make'-like command-line utility for executing Python functions.
4
+
5
+ This script, 'smake', provides a simple command-line interface to run Python
6
+ functions defined in a specified file (defaulting to 'make.py'). It inspects
7
+ the target file, discovers all public functions, and automatically creates a
8
+ command-line interface to execute them with their respective arguments.
9
+
10
+ This allows for creating simple, self-documenting build or task scripts in
11
+ Python without the need for complex boilerplate code.
12
+ """
2
13
  import argparse
3
- import sys
4
- import os
5
14
  import importlib
15
+ import sys
16
+ import os.path
6
17
  from inspect import getmembers, isfunction, getfullargspec
18
+
7
19
  from siliconcompiler._metadata import version
8
20
  from siliconcompiler.schema import utils
9
21
 
10
-
22
+ # The default filename to look for if none is specified.
11
23
  __default_source_file = "make.py"
12
24
 
13
25
 
14
26
  def __process_file(path):
27
+ """
28
+ Dynamically loads a Python module and inspects it for runnable targets.
29
+
30
+ This function takes a file path, imports it as a Python module, and scans
31
+ for all public functions (those not starting with an underscore). For each
32
+ function found, it extracts its signature (arguments, default values, type
33
+ annotations) and docstring to build a dictionary of "targets" that can be
34
+ called from the command line.
35
+
36
+ It also looks for a special `__scdefault` variable in the module to determine
37
+ the default target to run if none is specified.
38
+
39
+ Args:
40
+ path (str): The path to the Python file to process.
41
+
42
+ Returns:
43
+ tuple: A tuple containing:
44
+ - dict: A dictionary of discovered targets, with metadata for each.
45
+ - str or None: The name of the default target, if any.
46
+ - str or None: The docstring of the loaded module, if any.
47
+ """
15
48
  if not os.path.exists(path):
16
49
  return {}, None, None
50
+
51
+ # Dynamically load the specified file as a Python module.
17
52
  mod_name = 'scmake'
18
53
  spec = importlib.util.spec_from_file_location(mod_name, path)
19
54
  make = importlib.util.module_from_spec(spec)
20
55
  sys.modules[mod_name] = make
56
+ # Temporarily add CWD to path to allow the makefile to import local modules.
21
57
  syspath = sys.path.copy()
22
58
  sys.path.insert(0, os.getcwd())
23
59
  spec.loader.exec_module(make)
24
60
  sys.path = syspath
25
61
 
62
+ # Inspect the module for public functions to treat as targets.
26
63
  args = {}
27
64
  for name, func in getmembers(make, isfunction):
28
65
  if name.startswith('_'):
29
66
  continue
30
67
 
31
- # generate doc
68
+ # Use the function's docstring for help text.
32
69
  docstring = utils.trim(func.__doc__)
33
70
  if not docstring:
34
71
  docstring = f"run \"{name}\""
35
72
  short_help = docstring.splitlines()[0]
36
73
 
74
+ # Inspect the function's signature to build CLI arguments.
37
75
  func_spec = getfullargspec(func)
38
-
39
76
  func_args = {}
40
77
  for arg in func_spec.args:
41
- arg_type = str
42
- if arg in func_spec.annotations:
43
- arg_type = func_spec.annotations[arg]
44
- func_args[arg] = {
45
- "type": arg_type
46
- }
78
+ arg_type = func_spec.annotations.get(arg, str)
79
+ func_args[arg] = {"type": arg_type}
47
80
 
48
81
  if func_spec.defaults:
49
82
  for arg, defval in zip(reversed(func_spec.args), reversed(func_spec.defaults)):
50
83
  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)
84
+ # Infer type from default value if it's a basic type.
85
+ if defval is not None and isinstance(defval, (bool, str, float, int)):
86
+ func_args[arg]["type"] = type(defval)
58
87
 
59
88
  args[name] = {
60
89
  "function": func,
@@ -63,109 +92,108 @@ def __process_file(path):
63
92
  "args": func_args
64
93
  }
65
94
 
66
- if args:
67
- default_arg = list(args.keys())[0]
68
- else:
69
- default_arg = None
70
-
71
- default_arg = getattr(make, '__scdefault', default_arg)
72
-
95
+ # Determine the default target.
96
+ default_arg = getattr(make, '__scdefault', list(args.keys())[0] if args else None)
73
97
  module_help = utils.trim(make.__doc__)
74
98
 
75
99
  return args, default_arg, module_help
76
100
 
77
101
 
78
102
  def main(source_file=None):
103
+ """
104
+ The main entry point for the smake command-line application.
105
+
106
+ This function handles command-line argument parsing, discovers targets
107
+ from the source file, and executes the selected target function with the
108
+ provided arguments.
109
+ """
79
110
  progname = "smake"
80
111
  description = f"""-----------------------------------------------------------
81
- SC app that provides an Makefile like interface to python
112
+ SC app that provides a Makefile-like interface to Python
82
113
  configuration files. This utility app will analyze a file
83
- "{__default_source_file}" or the file specified with --file to determine
84
- the available targets.
114
+ named "{__default_source_file}" (or the file specified with --file) to
115
+ determine the available targets.
85
116
 
86
117
  To view the help, use:
87
118
  smake --help
88
119
 
89
- or view the help for a specific target:
90
- smake --help <target>
120
+ To view the help for a specific target, use:
121
+ smake <target> --help
91
122
 
92
123
  To run a target, use:
93
124
  smake <target>
94
125
 
95
- or run a target from a file other than "{__default_source_file}":
126
+ To run a target from a different file, use:
96
127
  smake --file <file> <target>
97
128
 
98
- or run a target in a different directory:
99
- smake --directory <directory> <target>
129
+ To run a target in a different directory, use:
130
+ smake -C <directory> <target>
100
131
 
101
- To run a target with supported arguments, use:
102
- smake <target> --flow asicflow
132
+ To run a target with arguments, use:
133
+ smake <target> --arg1 value1 --arg2 value2
103
134
  -----------------------------------------------------------"""
104
135
 
105
- # handle source file identification before arg parse
106
- file_args = None
136
+ # --- Pre-parsing to find --file and --directory arguments ---
137
+ # This allows us to load the correct file before setting up the full parser.
107
138
  if not source_file:
108
139
  source_file = __default_source_file
109
140
  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
141
+ if any(arg in sys.argv for arg in file_args):
142
+ for file_arg in file_args:
143
+ if file_arg in sys.argv:
144
+ try:
145
+ source_file = sys.argv[sys.argv.index(file_arg) + 1]
146
+ except IndexError:
147
+ print(f"Error: Argument for {file_arg} is missing.")
148
+ return 1
149
+ break
118
150
 
119
- # handle directory identification before arg parse
120
151
  source_dir = os.getcwd()
121
152
  dir_args = ('--directory', '-C')
122
- for file_arg in dir_args:
123
- if file_arg in sys.argv:
124
- source_dir_idx = sys.argv.index(file_arg) + 1
125
- if source_dir_idx < len(sys.argv):
126
- source_dir = sys.argv[source_dir_idx]
127
- else:
128
- source_dir = None
129
- break
130
-
131
- if source_dir:
132
- if not os.path.isdir(source_dir):
133
- print(f"Unable to change directory to {source_dir}")
134
- return 1
153
+ if any(arg in sys.argv for arg in dir_args):
154
+ for dir_arg in dir_args:
155
+ if dir_arg in sys.argv:
156
+ try:
157
+ source_dir = sys.argv[sys.argv.index(dir_arg) + 1]
158
+ except IndexError:
159
+ print(f"Error: Argument for {dir_arg} is missing.")
160
+ return 1
161
+ break
135
162
 
163
+ if source_dir and os.path.isdir(source_dir):
136
164
  os.chdir(source_dir)
165
+ elif source_dir:
166
+ print(f"Error: Unable to change directory to {source_dir}")
167
+ return 1
137
168
 
138
- make_args = {}
139
- default_arg = None
140
- module_help = None
141
- if source_file:
142
- make_args, default_arg, module_help = __process_file(source_file)
169
+ # --- Process the source file to discover targets ---
170
+ make_args, default_arg, module_help = __process_file(source_file) \
171
+ if source_file else ({}, None, None)
143
172
 
144
173
  if module_help:
145
- description += \
146
- f"\n\n{module_help}\n\n-----------------------------------------------------------"
174
+ description += f"\n\n{module_help}\n\n"
175
+ description += "-----------------------------------------------------------"
147
176
 
177
+ # --- Set up the main argument parser ---
148
178
  parser = argparse.ArgumentParser(
149
179
  progname,
150
180
  description=description,
151
181
  formatter_class=argparse.RawDescriptionHelpFormatter)
152
182
 
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}')
158
-
159
183
  parser.add_argument(
160
- *dir_args,
184
+ '--file', '-f',
185
+ metavar='<file>',
186
+ help=f'Use file as makefile, default is {__default_source_file}')
187
+ parser.add_argument(
188
+ '--directory', '-C',
161
189
  metavar='<directory>',
162
190
  help='Change to directory <directory> before reading the makefile.')
163
-
164
191
  parser.add_argument(
165
192
  '--version', '-v',
166
193
  action='version',
167
- version=version)
194
+ version=f"%(prog)s {version}")
168
195
 
196
+ # --- Create subparsers for each discovered target ---
169
197
  targetparsers = parser.add_subparsers(
170
198
  dest='target',
171
199
  metavar='<target>',
@@ -178,55 +206,63 @@ To run a target with supported arguments, use:
178
206
  help=info['help'],
179
207
  formatter_class=argparse.RawDescriptionHelpFormatter)
180
208
 
209
+ # Add arguments for each parameter of the target function.
181
210
  for subarg, subarg_info in info['args'].items():
182
- # print(subarg, subarg_info)
183
211
  add_args = {}
184
-
185
212
  if "default" not in subarg_info:
186
213
  add_args["required"] = True
187
214
  else:
188
- if type(subarg_info["default"]) is subarg_info["type"]:
189
- add_args["default"] = subarg_info["default"]
215
+ add_args["default"] = subarg_info["default"]
190
216
 
191
- if subarg_info["type"] is bool:
217
+ # Handle boolean arguments correctly.
218
+ arg_type = subarg_info["type"]
219
+ if arg_type is bool:
220
+ # Use a custom string-to-boolean converter.
192
221
  def str2bool(v):
193
- # modified from:
194
- # https://github.com/pypa/distutils/blob/8993718731b951ee36d08cb784f02aa13542ce15/distutils/util.py
195
- val = v.lower()
222
+ val = str(v).lower()
196
223
  if val in ('y', 'yes', 't', 'true', 'on', '1'):
197
224
  return True
198
225
  elif val in ('n', 'no', 'f', 'false', 'off', '0'):
199
226
  return False
200
- else:
201
- raise ValueError(f"invalid truth value {val!r}")
202
- subarg_info["type"] = str2bool
227
+ raise ValueError(f"invalid truth value {val!r}")
228
+ arg_type = str2bool
203
229
 
204
230
  subparse.add_argument(
205
231
  f'--{subarg}',
206
232
  dest=f'sub_{subarg}',
207
233
  metavar=f'<{subarg}>',
208
- type=subarg_info["type"],
234
+ type=arg_type,
209
235
  **add_args)
210
236
 
237
+ # --- Parse arguments and execute the target ---
211
238
  args = parser.parse_args()
212
- target = args.target
239
+ target = args.target or default_arg
240
+
213
241
  if not target:
214
- target = default_arg
242
+ if make_args:
243
+ print("Error: No target specified and no default target found.")
244
+ parser.print_help()
245
+ else:
246
+ print(f"Error: Unable to load makefile '{source_file}'.")
247
+ return 1
215
248
 
216
- if not os.path.isfile(source_file):
217
- print(f"Unable to load {source_file}")
249
+ if target not in make_args:
250
+ print(f"Error: Target '{target}' not found in '{source_file}'.")
218
251
  return 1
219
252
 
253
+ # Prepare arguments to pass to the target function.
220
254
  call_args = {}
221
255
  args_vars = vars(args)
222
256
  for arg in make_args[target]["args"]:
223
- if f'sub_{arg}' in args_vars and args_vars[f'sub_{arg}'] is not None:
224
- call_args[arg] = args_vars[f'sub_{arg}']
257
+ arg_key = f'sub_{arg}'
258
+ if arg_key in args_vars and args_vars[arg_key] is not None:
259
+ call_args[arg] = args_vars[arg_key]
260
+
261
+ # Call the selected function with its arguments.
225
262
  make_args[target]["function"](**call_args)
226
263
 
227
264
  return 0
228
265
 
229
266
 
230
- #########################
231
267
  if __name__ == "__main__":
232
268
  sys.exit(main())
@@ -1,10 +1,8 @@
1
1
  # Copyright 2024 Silicon Compiler Authors. All Rights Reserved.
2
-
3
- # Standard Modules
4
2
  import base64
3
+ import gzip
5
4
  import io
6
5
  import json
7
- import gzip
8
6
  import os
9
7
  import stat
10
8
  import sys
@@ -14,10 +12,9 @@ import textwrap
14
12
 
15
13
  from datetime import datetime
16
14
 
17
- import siliconcompiler
15
+ from siliconcompiler import Chip
16
+ from siliconcompiler import SiliconCompilerError, utils
18
17
  from siliconcompiler.apps._common import UNSET_DESIGN
19
- from siliconcompiler import SiliconCompilerError
20
- from siliconcompiler import utils
21
18
  from siliconcompiler.record import RecordTime
22
19
 
23
20
 
@@ -51,7 +48,7 @@ def main():
51
48
  ------------------------------------------------------------
52
49
  """
53
50
  # Create a base chip class.
54
- chip = siliconcompiler.Chip(UNSET_DESIGN)
51
+ chip = Chip(UNSET_DESIGN)
55
52
 
56
53
  # Read command-line inputs and generate Chip objects to run the flow on.
57
54
  try:
@@ -1,11 +1,9 @@
1
1
  # Copyright 2024 Silicon Compiler Authors. All Rights Reserved.
2
-
3
- # Standard Modules
4
2
  import sys
5
3
 
6
- import siliconcompiler
7
- from siliconcompiler.apps._common import UNSET_DESIGN
4
+ from siliconcompiler import Chip
8
5
  from siliconcompiler import SiliconCompilerError
6
+ from siliconcompiler.apps._common import UNSET_DESIGN
9
7
 
10
8
 
11
9
  ###########################
@@ -17,7 +15,7 @@ def main():
17
15
  ------------------------------------------------------------
18
16
  """
19
17
  # Create a base chip class.
20
- chip = siliconcompiler.Chip(UNSET_DESIGN)
18
+ chip = Chip(UNSET_DESIGN)
21
19
 
22
20
  # Read command-line inputs and generate Chip objects to run the flow on.
23
21
  try: