opencos-eda 0.3.3__tar.gz → 0.3.6__tar.gz

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 (102) hide show
  1. {opencos_eda-0.3.3/opencos_eda.egg-info → opencos_eda-0.3.6}/PKG-INFO +12 -3
  2. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/sim.py +16 -6
  3. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/deps/defaults.py +1 -0
  4. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/deps/deps_processor.py +60 -24
  5. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/deps_schema.py +17 -0
  6. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/eda.py +13 -19
  7. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/eda_base.py +78 -29
  8. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/eda_config.py +86 -41
  9. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/eda_config_defaults.yml +8 -1
  10. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/eda_tool_helper.py +19 -0
  11. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/export_helper.py +89 -31
  12. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/files.py +3 -1
  13. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/helpers.py +60 -17
  14. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/test_eda.py +11 -1
  15. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/cocotb.py +94 -21
  16. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/iverilog.py +4 -0
  17. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/riviera.py +23 -12
  18. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/verilator.py +91 -2
  19. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/vivado.py +1 -0
  20. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/util.py +86 -57
  21. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/utils/str_helpers.py +6 -1
  22. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/utils/subprocess_helpers.py +66 -3
  23. {opencos_eda-0.3.3 → opencos_eda-0.3.6/opencos_eda.egg-info}/PKG-INFO +12 -3
  24. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos_eda.egg-info/requires.txt +13 -2
  25. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/pyproject.toml +17 -3
  26. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/LICENSE +0 -0
  27. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/LICENSE.spdx +0 -0
  28. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/README.md +0 -0
  29. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/__init__.py +0 -0
  30. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/_version.py +0 -0
  31. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/_waves_pkg.sv +0 -0
  32. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/__init__.py +0 -0
  33. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/build.py +0 -0
  34. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/deps_help.py +0 -0
  35. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/elab.py +0 -0
  36. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/export.py +0 -0
  37. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/flist.py +0 -0
  38. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/lec.py +0 -0
  39. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/lint.py +0 -0
  40. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/multi.py +0 -0
  41. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/open.py +0 -0
  42. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/proj.py +0 -0
  43. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/shell.py +0 -0
  44. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/sweep.py +0 -0
  45. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/synth.py +0 -0
  46. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/targets.py +0 -0
  47. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/upload.py +0 -0
  48. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/commands/waves.py +0 -0
  49. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/deps/__init__.py +0 -0
  50. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/deps/deps_commands.py +0 -0
  51. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/deps/deps_file.py +0 -0
  52. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/eda_config_max_verilator_waivers.yml +0 -0
  53. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/eda_config_reduced.yml +0 -0
  54. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/eda_deps_bash_completion.bash +0 -0
  55. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/eda_deps_sanitize.py +0 -0
  56. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/eda_extract_targets.py +0 -0
  57. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/export_json_convert.py +0 -0
  58. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/hw/__init__.py +0 -0
  59. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/hw/oc_cli.py +0 -0
  60. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/hw/pcie.py +0 -0
  61. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/names.py +0 -0
  62. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/peakrdl_cleanup.py +0 -0
  63. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/seed.py +0 -0
  64. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/__init__.py +0 -0
  65. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/custom_config.yml +0 -0
  66. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/deps_files/command_order/DEPS.yml +0 -0
  67. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/deps_files/error_msgs/DEPS.yml +0 -0
  68. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/deps_files/iverilog_test/DEPS.yml +0 -0
  69. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/deps_files/no_deps_here/DEPS.yml +0 -0
  70. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/deps_files/non_sv_reqs/DEPS.yml +0 -0
  71. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/deps_files/tags_with_tools/DEPS.yml +0 -0
  72. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/deps_files/test_err_fatal/DEPS.yml +0 -0
  73. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/test_build.py +0 -0
  74. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/test_deps_helpers.py +0 -0
  75. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/test_deps_schema.py +0 -0
  76. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/test_eda_elab.py +0 -0
  77. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/test_eda_synth.py +0 -0
  78. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/test_oc_cli.py +0 -0
  79. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tests/test_tools.py +0 -0
  80. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/__init__.py +0 -0
  81. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/invio.py +0 -0
  82. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/invio_helpers.py +0 -0
  83. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/invio_yosys.py +0 -0
  84. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/modelsim_ase.py +0 -0
  85. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/quartus.py +0 -0
  86. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/questa.py +0 -0
  87. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/questa_fse.py +0 -0
  88. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/slang.py +0 -0
  89. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/slang_yosys.py +0 -0
  90. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/surelog.py +0 -0
  91. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/tabbycad_yosys.py +0 -0
  92. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/tools/yosys.py +0 -0
  93. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/utils/__init__.py +0 -0
  94. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/utils/markup_helpers.py +0 -0
  95. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/utils/status_constants.py +0 -0
  96. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/utils/vscode_helper.py +0 -0
  97. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos/utils/vsim_helper.py +0 -0
  98. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos_eda.egg-info/SOURCES.txt +0 -0
  99. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos_eda.egg-info/dependency_links.txt +0 -0
  100. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos_eda.egg-info/entry_points.txt +0 -0
  101. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/opencos_eda.egg-info/top_level.txt +0 -0
  102. {opencos_eda-0.3.3 → opencos_eda-0.3.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencos-eda
3
- Version: 0.3.3
3
+ Version: 0.3.6
4
4
  Summary: A simple Python package for wrapping RTL simuliatons and synthesis
5
5
  Author-email: Simon Sabato <simon@cognichip.ai>, Drew Ranck <drew@cognichip.ai>
6
6
  Project-URL: Homepage, https://github.com/cognichip/opencos
@@ -9,13 +9,22 @@ License-File: LICENSE
9
9
  License-File: LICENSE.spdx
10
10
  Requires-Dist: mergedeep>=1.3.4
11
11
  Requires-Dist: peakrdl>=1.1.0
12
+ Requires-Dist: psutil>=7.0.0
12
13
  Requires-Dist: pyyaml>=6.0.2
13
- Requires-Dist: pytest>=8.3.5
14
14
  Requires-Dist: python-dotenv>=1.0.1
15
15
  Requires-Dist: schema>=0.7.7
16
16
  Requires-Dist: toml>=0.10.2
17
17
  Requires-Dist: yamllint>=1.35.1
18
18
  Requires-Dist: PySerial>=3.5
19
- Requires-Dist: cocotb>=2.0
20
19
  Requires-Dist: supports_color>=0.2.0
20
+ Requires-Dist: cocotb>=2.0
21
+ Requires-Dist: pytest>=8.3.5
22
+ Requires-Dist: coverage>=7.6.1
23
+ Provides-Extra: dev
24
+ Requires-Dist: pylint>=3.0.0; extra == "dev"
25
+ Provides-Extra: docs
26
+ Requires-Dist: mkdocs; extra == "docs"
27
+ Requires-Dist: mkdocs-material; extra == "docs"
28
+ Requires-Dist: mkdocs-wavedrom-plugin; extra == "docs"
29
+ Requires-Dist: mkdocs-plantuml; extra == "docs"
21
30
  Dynamic: license-file
@@ -145,6 +145,7 @@ class CommandSim(CommandDesign):
145
145
  self.run_dep_commands()
146
146
  self.do_it()
147
147
  self.run_post_tool_dep_commands()
148
+ self.report_pass_fail()
148
149
  return unparsed
149
150
 
150
151
 
@@ -198,6 +199,9 @@ class CommandSim(CommandDesign):
198
199
 
199
200
  clist = list(obj).copy()
200
201
  tee_fpath = getattr(obj, 'tee_fpath', None)
202
+ work_dir = getattr(obj, 'work_dir', None)
203
+ if not work_dir:
204
+ work_dir = self.args['work-dir']
201
205
 
202
206
  util.debug(f'run_commands_check_logs: {clist=}, {tee_fpath=}')
203
207
 
@@ -207,24 +211,28 @@ class CommandSim(CommandDesign):
207
211
  if log_filename:
208
212
  log_fname = log_filename
209
213
 
214
+
210
215
  _, stdout, _ = self.exec(
211
- work_dir=self.args['work-dir'], command_list=clist, tee_fpath=tee_fpath
216
+ work_dir=work_dir, command_list=clist, tee_fpath=tee_fpath
212
217
  )
213
218
 
214
219
  if check_logs and log_fname:
215
220
  # Note this call will check on stdout if not GUI, not opening the log_fname,
216
221
  # but if this is GUI we normally lose stdout and have to open the log.
217
- gui_mode = self.args.get('gui', False)
218
- file_contents_str = '' if gui_mode else stdout
222
+ if self.args.get('gui', False):
223
+ file_contents_str = ''
224
+ else:
225
+ file_contents_str = stdout
226
+
219
227
  self.check_logs_for_errors(
220
- filename=os.path.join(self.args['work-dir'], log_fname),
228
+ filename=os.path.join(work_dir, log_fname),
221
229
  file_contents_str=file_contents_str,
222
230
  bad_strings=bad_strings, must_strings=must_strings,
223
231
  use_bad_strings=use_bad_strings, use_must_strings=use_must_strings
224
232
  )
225
233
  if log_fname:
226
234
  self.artifacts_add(
227
- name=os.path.join(self.args['work-dir'], log_fname),
235
+ name=os.path.join(work_dir, log_fname),
228
236
  typ='text', description='Simulator stdout/stderr log file'
229
237
  )
230
238
 
@@ -253,6 +261,7 @@ class CommandSim(CommandDesign):
253
261
  tool = self.args.get('tool', None)
254
262
  # Certain args are allow-listed here
255
263
  deps_file_args = []
264
+ print(f'SUPER DREW DEBUG: {self.get_command_line_args()=}')
256
265
  for a in self.get_command_line_args():
257
266
  if any(a.startswith(x) for x in [
258
267
  '--compile-args',
@@ -265,7 +274,8 @@ class CommandSim(CommandDesign):
265
274
  '--stop-',
266
275
  '--lint-',
267
276
  '--verilate',
268
- '--verilator']):
277
+ '--verilator',
278
+ '--cocotb-test-']):
269
279
  deps_file_args.append(a)
270
280
 
271
281
  export_obj.run(
@@ -33,6 +33,7 @@ SUPPORTED_TARGET_TABLE_KEYS = set([
33
33
  'defines',
34
34
  'parameters',
35
35
  'incdirs',
36
+ 'plusargs',
36
37
  'top',
37
38
  'deps',
38
39
  'reqs',
@@ -10,7 +10,7 @@ import os
10
10
  from opencos import files
11
11
  from opencos import eda_config
12
12
  from opencos.util import debug, info, warning, error, read_tokens_from_dot_f, \
13
- patch_args_for_dir
13
+ patch_args_for_dir, load_env_file
14
14
  from opencos.utils.str_helpers import dep_str2list
15
15
  from opencos.deps.deps_file import deps_target_get_deps_list
16
16
  from opencos.deps.deps_commands import deps_commands_handler
@@ -77,7 +77,7 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
77
77
  ).get('command_handler', {}).keys()
78
78
 
79
79
 
80
- def apply_defines(self, defines_dict: dict):
80
+ def apply_defines(self, defines_dict: dict) -> None:
81
81
  '''Given defines_dict, applies them to our self.command_design_ref obj'''
82
82
  if not isinstance(defines_dict, dict):
83
83
  self.error(f"{defines_dict=} is not type dict, can't apply defines,",
@@ -95,7 +95,19 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
95
95
  self.command_design_ref.process_plusarg(f'+define+{k}={v}')
96
96
 
97
97
 
98
- def apply_parameters(self, parameters_dict: dict):
98
+ def apply_plusargs(self, plusargs_dict: dict) -> None:
99
+ '''Given plusarsg_dict, applies them to our self.command_design_ref obj'''
100
+ if not isinstance(plusargs_dict, dict):
101
+ self.error(f"{plusargs_dict=} is not type dict, can't apply plusargs,",
102
+ f"in {self.caller_info}")
103
+ for k,v in plusargs_dict.items():
104
+ if v is None or v == '':
105
+ self.command_design_ref.process_plusarg(f'+{k}')
106
+ else:
107
+ self.command_design_ref.process_plusarg(f'+{k}={v}')
108
+
109
+
110
+ def apply_parameters(self, parameters_dict: dict) -> None:
99
111
  '''Given parameters_dict, applies them to our self.command_design_ref obj'''
100
112
  if not isinstance(parameters_dict, dict):
101
113
  self.error(f"{parameters_dict=} is not type dict, can't apply defines,",
@@ -110,7 +122,7 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
110
122
  )
111
123
 
112
124
 
113
- def apply_incdirs(self, incdirs_list:list):
125
+ def apply_incdirs(self, incdirs_list:list) -> None:
114
126
  '''Given incdirs_list, applies them to our self.command_design_ref obj'''
115
127
  if not isinstance(incdirs_list, (str, list)):
116
128
  self.error(f"{incdirs_list=} is not type str/list, can't apply incdirs",
@@ -180,9 +192,15 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
180
192
  # Since some args (util.py, eda_config.py, eda.py) can only be handled from command
181
193
  # line, it would be nice if -f or --input-file is handled from DEPS, so we'll special
182
194
  # case that now. Recursively resolve -f / --input-file.
195
+ # Do similary for --env-file (also only supported in util.py)
183
196
  parser = argparse.ArgumentParser(
184
197
  prog='deps_processor -f/--input-file', add_help=False, allow_abbrev=False
185
198
  )
199
+ parser.add_argument('--env-file', default=[], action='append',
200
+ help=(
201
+ "dotenv file(s) to pass ENV vars, (default: .env loaded first,"
202
+ " subsequent files' vars override .env"
203
+ ))
186
204
  parser.add_argument('-f', '--input-file', default=[], action='append',
187
205
  help=(
188
206
  'Input .f file to be expanded as eda args, defines, incdirs,'
@@ -213,7 +231,12 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
213
231
  # recurse until we've resolved nested .f files.
214
232
  return self.apply_args(args_list=tokens2)
215
233
 
216
- tokens = tokens2 # if no --input-file values, keep parsing the remaining tokens2
234
+ if parsed.env_file:
235
+ for env_file in parsed.env_file:
236
+ load_env_file(env_file)
237
+
238
+ # if no --input-file/--env-file values, keep parsing the remaining tokens2:
239
+ tokens = tokens2
217
240
 
218
241
  # We have to special-case anything with --tool[=value] in tokens, otherwise
219
242
  # the user may think they were allowed to set --tool, but in our flow the Command handler
@@ -290,7 +313,9 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
290
313
  caller_info=self.caller_info
291
314
  )
292
315
 
293
- def process_deps_entry(self):
316
+ def process_deps_entry( # pylint: disable=too-many-branches
317
+ self
318
+ ) -> list:
294
319
  '''Main entry point (after creating DepsProcessor obj) to resolve a deps target
295
320
 
296
321
  Example usage:
@@ -303,22 +328,6 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
303
328
  This method will apply all target features to the CommandDesign ref object as
304
329
  we traverse.
305
330
 
306
- Supported target keys:
307
- -- tags (or equivalent, to support multiple define/incdir/deps for a target)
308
- -- supports tag-name, with-tools, with-args, args, defines, incdirs, deps
309
- ** to be applied if a tool matches.
310
- -- TODO(drew): other features in docs/DEPS.md not yet implemented.
311
- -- multi: ignore-this-target: - commands (handled in eda.py CommandMulti.resolve_target)
312
- -- Named eda commands
313
- -- (partially done) sim or other eda commands (eda.py command specific things)
314
- basically, check the command, and apply/merge values to 'entry'?
315
- -- args
316
- -- defines
317
- -- incdirs
318
- -- top.
319
- -- commands (not in deps)
320
- -- deps
321
-
322
331
  TODO(drew): This does not yet support conditional inclusions based on defines,
323
332
  like the old DEPS files did with pattern:
324
333
  SOME_DEFINE ? dep_if_define_present : dep_if_define_not_present
@@ -344,6 +353,8 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
344
353
  remaining_deps_list += self.process_tags()
345
354
  elif key == 'defines':
346
355
  self.process_defines()
356
+ elif key == 'plusargs':
357
+ self.process_plusargs()
347
358
  elif key == 'parameters':
348
359
  self.process_parameters()
349
360
  elif key == 'incdirs':
@@ -520,6 +531,10 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
520
531
  # apply defines:
521
532
  self.apply_defines(value.get('defines', {}))
522
533
 
534
+ if key == 'plusargs':
535
+ # apply plusargs:
536
+ self.apply_plusargs(value.get('plusargs', {}))
537
+
523
538
  elif key == 'parameters':
524
539
  self.apply_parameters(value.get('parameters', {}))
525
540
 
@@ -598,7 +613,7 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
598
613
  return ret_deps_added_from_tags
599
614
 
600
615
 
601
- def process_defines(self):
616
+ def process_defines(self) -> None:
602
617
  '''Returns None, applies defines (dict, if any) from self.deps_entry to
603
618
  self.command_design_ref.'''
604
619
 
@@ -614,7 +629,28 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
614
629
 
615
630
  self.apply_defines(entry_defines)
616
631
 
617
- def process_parameters(self):
632
+
633
+ def process_plusargs(self) -> None:
634
+ '''Returns None, applies plusargs (dict, if any) from self.deps_entry to
635
+ self.command_design_ref.
636
+
637
+ These work w/ the same rules as defines (no value, or value int/str)
638
+ '''
639
+
640
+ # Plusargs:
641
+ # apply command specific plusargs, with higher priority than the a
642
+ # deps_entry['sim']['plusargs'] entry,
643
+ # do this with dict1.update(dict2):
644
+ entry_plusargs = {}
645
+ entry_plusargs.update(self.deps_entry.get('plusargs', {}))
646
+ entry_plusargs.update(self.entry_eda_command.get('plusargs', {}))
647
+ assert isinstance(entry_plusargs, dict), \
648
+ f'{entry_plusargs=} for in {self.caller_info} must be a dict'
649
+
650
+ self.apply_plusargs(entry_plusargs)
651
+
652
+
653
+ def process_parameters(self) -> None:
618
654
  '''Returns None, applies parameters (dict, if any) from self.deps_entry to
619
655
  self.command_design_ref.'''
620
656
 
@@ -17,6 +17,9 @@ my_target_name:
17
17
  incdirs: <---- incdirs, optional array (or string)
18
18
  - ./
19
19
 
20
+ plusargs: <---- plusargs, optional table
21
+ some_plusarg: 32
22
+
20
23
  top: tb <---- top, optional string
21
24
 
22
25
  deps:
@@ -63,6 +66,7 @@ my_target_name:
63
66
  defines: <---- defines, optional table
64
67
  parameters: <---- parameters, optional table
65
68
  incdirs: <---- incdirs, optional array (or string)
69
+ plusargs: <---- plusargs, optional table
66
70
  top: tb <---- top, optional string
67
71
  deps: <---- TARGET_DEPS_CONTENTS schema
68
72
  - some_file.sv <---- string file name
@@ -216,6 +220,9 @@ TARGET_EDA_COMMAND_ENTRY_TABLE = {
216
220
  Optional('defines'): {
217
221
  Optional(str): Or(str, int, type(None)),
218
222
  },
223
+ Optional('plusargs'): {
224
+ Optional(str): Or(str, int, type(None)),
225
+ },
219
226
  Optional('parameters'): {
220
227
  Optional(str): Or(str, int),
221
228
  },
@@ -241,6 +248,9 @@ TARGET_TAGS_TABLE = {
241
248
  Optional('defines'): {
242
249
  Optional(str): Or(str, int, type(None)),
243
250
  },
251
+ Optional('plusargs'): {
252
+ Optional(str): Or(str, int, type(None)),
253
+ },
244
254
  Optional('parameters'): {
245
255
  Optional(str): Or(str, int),
246
256
  },
@@ -262,6 +272,10 @@ TARGET_CONTENTS = Or(
262
272
  Optional('defines'): {
263
273
  Optional(str): Or(str, int, type(None)),
264
274
  },
275
+ # plusargs: table of key-value; value null or string
276
+ Optional('plusargs'): {
277
+ Optional(str): Or(str, int, type(None)),
278
+ },
265
279
  # parameters: table of key-value
266
280
  Optional('parameters'): {
267
281
  Optional(str): Or(str, int),
@@ -324,6 +338,9 @@ FILE_SIMPLIFIED = Schema(
324
338
  Optional('defines'): {
325
339
  Optional(str): Or(type(None), str),
326
340
  },
341
+ Optional('plusargs'): {
342
+ Optional(str): Or(type(None), str),
343
+ },
327
344
  Optional('parameters'): {
328
345
  Optional(str): str,
329
346
  },
@@ -20,10 +20,11 @@ from pathlib import Path
20
20
 
21
21
  import opencos
22
22
  from opencos import util, eda_config, eda_base
23
+ from opencos.util import safe_emoji
23
24
  from opencos.eda_base import Tool, which_tool, get_eda_exec
24
25
  from opencos.utils import vsim_helper, vscode_helper
25
26
  from opencos.utils.subprocess_helpers import subprocess_run_background
26
- from opencos.utils import status_constants, str_helpers
27
+ from opencos.utils import status_constants, str_helpers, subprocess_helpers
27
28
 
28
29
  # Configure util:
29
30
  util.progname = "EDA"
@@ -50,7 +51,7 @@ def init_config(
50
51
  # For key DEFAULT_HANDLERS, we'll update config['command_handler'] with
51
52
  # the actual class using importlib (via opencos.util)
52
53
 
53
- eda_config.tool_try_add_to_path(tool)
54
+ eda_config.update_config_auto_tool_order_for_tool(tool=tool, config=config)
54
55
 
55
56
  config['command_handler'] = {}
56
57
  for _cmd, str_class in config['DEFAULT_HANDLERS'].items():
@@ -95,15 +96,15 @@ def usage(tokens: list, config: dict, command: str = "", tool: str = "") -> int:
95
96
 
96
97
  if command == "":
97
98
  print(
98
- """
99
- Usage:
99
+ f"""
100
+ {safe_emoji("🔦 ")}Usage:
100
101
  eda [<options>] <command> [options] <files|targets, ...>
101
102
  """
102
103
  )
103
104
  print(get_all_commands_help_str(config=config))
104
105
  print(
105
- """
106
- And <files|targets, ...> is one or more source file or DEPS markup file target,
106
+ f"""
107
+ {safe_emoji("❕ ")}where <files|targets, ...> is one or more source file or DEPS markup file target,
107
108
  such as .v, .sv, .vhd[l], .cpp files, or a target key in a DEPS.[yml|yaml|toml|json].
108
109
  Note that you can prefix source files with `sv@`, `v@`, `vhdl@` or `cpp@` to
109
110
  force use that file as systemverilog, verilog, vhdl, or C++, respectively.
@@ -163,10 +164,7 @@ def auto_tool_setup( # pylint: disable=too-many-locals,too-many-branches,too-man
163
164
  If so, updates config['auto_tools_order'][tool]['exe']
164
165
  '''
165
166
 
166
-
167
- tool = eda_config.update_config_auto_tool_order_for_tool(
168
- tool=tool, config=config
169
- )
167
+ tool = eda_config.tool_arg_remove_path_information(tool)
170
168
 
171
169
  assert 'auto_tools_order' in config
172
170
  assert isinstance(config['auto_tools_order'], list)
@@ -275,9 +273,7 @@ def tool_setup(tool: str, config: dict, quiet: bool = False, auto_setup: bool =
275
273
 
276
274
  '''
277
275
 
278
- tool = eda_config.update_config_auto_tool_order_for_tool(
279
- tool=tool, config=config
280
- )
276
+ tool = eda_config.tool_arg_remove_path_information(tool)
281
277
 
282
278
  if not quiet and not auto_setup:
283
279
  util.info(f"Setup for tool: '{tool}'")
@@ -389,6 +385,8 @@ def process_tokens( # pylint: disable=too-many-branches,too-many-statements,too-
389
385
  if not is_interactive:
390
386
  # Run init_config() now, we deferred it in main(), but only run it
391
387
  # for this tool (or tool=None to figure it out)
388
+ # This will handle any --tool=<name>=/path/to/bin also, so don't have to
389
+ # run tool_setup(..) on its own.
392
390
  config = init_config(
393
391
  config, tool=parsed.tool,
394
392
  run_auto_tool_setup=run_auto_tool_setup
@@ -406,13 +404,8 @@ def process_tokens( # pylint: disable=too-many-branches,too-many-statements,too-
406
404
  for arg in unparsed:
407
405
  if not arg.startswith('-'):
408
406
  command = arg
409
- if parsed.tool:
410
- tool_setup(parsed.tool, config=config)
411
407
  return usage(tokens=unparsed, config=config, command=command, tool=parsed.tool)
412
408
 
413
- if parsed.tool:
414
- tool_setup(parsed.tool, config=config)
415
-
416
409
  deferred_tokens = unparsed
417
410
  if not command:
418
411
  util.error("Didn't get a command!")
@@ -503,7 +496,8 @@ def check_command_handler_cls(command_obj:object, command:str, parsed_args) -> i
503
496
  def signal_handler(sig, frame) -> None: # pylint: disable=unused-argument
504
497
  '''Handles Ctrl-C, called by main_cli() if running from command line'''
505
498
  util.fancy_stop()
506
- util.info('Received Ctrl+C...', start='\nINFO: [EDA] ')
499
+ util.error(f'{safe_emoji("❌ ")}Received Ctrl+C...', start='\nINFO: [EDA] ')
500
+ subprocess_helpers.cleanup_all()
507
501
  util.exit(-1)
508
502
 
509
503
  # **************************************************************