opencos-eda 0.3.1__tar.gz → 0.3.3__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.1/opencos_eda.egg-info → opencos_eda-0.3.3}/PKG-INFO +2 -1
  2. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/deps/deps_file.py +42 -21
  3. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/eda_base.py +37 -17
  4. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/eda_config_defaults.yml +2 -1
  5. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/helpers.py +36 -7
  6. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/test_eda.py +3 -13
  7. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/test_tools.py +6 -8
  8. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/slang.py +6 -0
  9. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/verilator.py +48 -39
  10. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/util.py +8 -6
  11. {opencos_eda-0.3.1 → opencos_eda-0.3.3/opencos_eda.egg-info}/PKG-INFO +2 -1
  12. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos_eda.egg-info/requires.txt +1 -0
  13. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/pyproject.toml +2 -1
  14. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/LICENSE +0 -0
  15. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/LICENSE.spdx +0 -0
  16. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/README.md +0 -0
  17. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/__init__.py +0 -0
  18. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/_version.py +0 -0
  19. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/_waves_pkg.sv +0 -0
  20. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/__init__.py +0 -0
  21. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/build.py +0 -0
  22. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/deps_help.py +0 -0
  23. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/elab.py +0 -0
  24. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/export.py +0 -0
  25. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/flist.py +0 -0
  26. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/lec.py +0 -0
  27. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/lint.py +0 -0
  28. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/multi.py +0 -0
  29. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/open.py +0 -0
  30. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/proj.py +0 -0
  31. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/shell.py +0 -0
  32. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/sim.py +0 -0
  33. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/sweep.py +0 -0
  34. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/synth.py +0 -0
  35. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/targets.py +0 -0
  36. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/upload.py +0 -0
  37. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/commands/waves.py +0 -0
  38. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/deps/__init__.py +0 -0
  39. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/deps/defaults.py +0 -0
  40. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/deps/deps_commands.py +0 -0
  41. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/deps/deps_processor.py +0 -0
  42. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/deps_schema.py +0 -0
  43. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/eda.py +0 -0
  44. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/eda_config.py +0 -0
  45. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/eda_config_max_verilator_waivers.yml +0 -0
  46. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/eda_config_reduced.yml +0 -0
  47. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/eda_deps_bash_completion.bash +0 -0
  48. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/eda_deps_sanitize.py +0 -0
  49. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/eda_extract_targets.py +0 -0
  50. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/eda_tool_helper.py +0 -0
  51. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/export_helper.py +0 -0
  52. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/export_json_convert.py +0 -0
  53. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/files.py +0 -0
  54. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/hw/__init__.py +0 -0
  55. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/hw/oc_cli.py +0 -0
  56. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/hw/pcie.py +0 -0
  57. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/names.py +0 -0
  58. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/peakrdl_cleanup.py +0 -0
  59. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/seed.py +0 -0
  60. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/__init__.py +0 -0
  61. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/custom_config.yml +0 -0
  62. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/deps_files/command_order/DEPS.yml +0 -0
  63. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/deps_files/error_msgs/DEPS.yml +0 -0
  64. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/deps_files/iverilog_test/DEPS.yml +0 -0
  65. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/deps_files/no_deps_here/DEPS.yml +0 -0
  66. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/deps_files/non_sv_reqs/DEPS.yml +0 -0
  67. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/deps_files/tags_with_tools/DEPS.yml +0 -0
  68. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/deps_files/test_err_fatal/DEPS.yml +0 -0
  69. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/test_build.py +0 -0
  70. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/test_deps_helpers.py +0 -0
  71. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/test_deps_schema.py +0 -0
  72. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/test_eda_elab.py +0 -0
  73. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/test_eda_synth.py +0 -0
  74. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tests/test_oc_cli.py +0 -0
  75. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/__init__.py +0 -0
  76. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/cocotb.py +0 -0
  77. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/invio.py +0 -0
  78. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/invio_helpers.py +0 -0
  79. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/invio_yosys.py +0 -0
  80. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/iverilog.py +0 -0
  81. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/modelsim_ase.py +0 -0
  82. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/quartus.py +0 -0
  83. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/questa.py +0 -0
  84. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/questa_fse.py +0 -0
  85. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/riviera.py +0 -0
  86. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/slang_yosys.py +0 -0
  87. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/surelog.py +0 -0
  88. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/tabbycad_yosys.py +0 -0
  89. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/vivado.py +0 -0
  90. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/tools/yosys.py +0 -0
  91. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/utils/__init__.py +0 -0
  92. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/utils/markup_helpers.py +0 -0
  93. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/utils/status_constants.py +0 -0
  94. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/utils/str_helpers.py +0 -0
  95. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/utils/subprocess_helpers.py +0 -0
  96. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/utils/vscode_helper.py +0 -0
  97. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos/utils/vsim_helper.py +0 -0
  98. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos_eda.egg-info/SOURCES.txt +0 -0
  99. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos_eda.egg-info/dependency_links.txt +0 -0
  100. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos_eda.egg-info/entry_points.txt +0 -0
  101. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/opencos_eda.egg-info/top_level.txt +0 -0
  102. {opencos_eda-0.3.1 → opencos_eda-0.3.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencos-eda
3
- Version: 0.3.1
3
+ Version: 0.3.3
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
@@ -17,4 +17,5 @@ Requires-Dist: toml>=0.10.2
17
17
  Requires-Dist: yamllint>=1.35.1
18
18
  Requires-Dist: PySerial>=3.5
19
19
  Requires-Dist: cocotb>=2.0
20
+ Requires-Dist: supports_color>=0.2.0
20
21
  Dynamic: license-file
@@ -249,8 +249,11 @@ class DepsFile:
249
249
  self.rel_deps_file = os.path.join(os.path.relpath(deps_path), deps_leaf)
250
250
 
251
251
  self.error = getattr(command_design_ref, 'error', None)
252
+ self.error_ifarg = getattr(command_design_ref, 'error_ifarg', None)
252
253
  if not self.error:
253
254
  self.error = util.error
255
+ if not self.error_ifarg:
256
+ self.error_ifarg = util.error
254
257
 
255
258
 
256
259
  def found(self) -> bool:
@@ -320,19 +323,28 @@ class DepsFile:
320
323
  # If we don't have caller_info, likely came from command line (or DEPS JSON data):
321
324
  if '.' in target_node:
322
325
  # Likely a filename (target_node does not include path)
323
- self.error(f'Trying to resolve command-line target={t_full} (file?):',
324
- f'File={t_node} not found in directory={t_path}',
325
- error_code=EDA_DEPS_FILE_NOT_FOUND)
326
+ self.error_ifarg(
327
+ f'Trying to resolve command-line target={t_full} (file?):',
328
+ f'File={t_node} not found in directory={t_path}',
329
+ arg='error-unknown-args',
330
+ error_code=EDA_DEPS_FILE_NOT_FOUND
331
+ )
326
332
  elif not self.rel_deps_file:
327
333
  # target, but there's no DEPS file
328
- self.error(f'Trying to resolve command-line target={t_full}:',
329
- f'but path {t_path} has no DEPS markup file (DEPS.yml)',
330
- error_code=EDA_DEPS_FILE_NOT_FOUND)
334
+ self.error_ifarg(
335
+ f'Trying to resolve command-line target={t_full}:',
336
+ f'but path {t_path} has no DEPS markup file (DEPS.yml)',
337
+ arg='error-unknown-args',
338
+ error_code=EDA_DEPS_FILE_NOT_FOUND
339
+ )
331
340
  else:
332
341
  self.warning_show_available_targets()
333
- self.error(f'Trying to resolve command-line target={t_full}:',
334
- f'was not found in deps_file={self.rel_deps_file}',
335
- error_code=EDA_DEPS_TARGET_NOT_FOUND)
342
+ self.error_ifarg(
343
+ f'Trying to resolve command-line target={t_full}:',
344
+ f'was not found in deps_file={self.rel_deps_file}',
345
+ arg='error-unknown-args',
346
+ error_code=EDA_DEPS_TARGET_NOT_FOUND
347
+ )
336
348
 
337
349
  else:
338
350
  # If we have caller_info, then this was a recursive call from another
@@ -340,22 +352,31 @@ class DepsFile:
340
352
 
341
353
  if '.' in target_node:
342
354
  # Likely a filename (target_node does not include path)
343
- self.error(f'Trying to resolve target={t_full} (file?):',
344
- f'called from {caller_info},',
345
- f'File={t_node} not found in directory={t_path}',
346
- error_code=EDA_DEPS_FILE_NOT_FOUND)
355
+ self.error_ifarg(
356
+ f'Trying to resolve target={t_full} (file?):',
357
+ f'called from {caller_info},',
358
+ f'File={t_node} not found in directory={t_path}',
359
+ arg='error-unknown-args',
360
+ error_code=EDA_DEPS_FILE_NOT_FOUND
361
+ )
347
362
  elif not self.rel_deps_file:
348
363
  # target, but there's no DEPS file
349
- self.error(f'Trying to resolve target={t_full}:',
350
- f'called from {caller_info},',
351
- f'but {t_path} has no DEPS markup file (DEPS.yml)',
352
- error_code=EDA_DEPS_FILE_NOT_FOUND)
364
+ self.error_ifarg(
365
+ f'Trying to resolve target={t_full}:',
366
+ f'called from {caller_info},',
367
+ f'but {t_path} has no DEPS markup file (DEPS.yml)',
368
+ arg='error-unknown-args',
369
+ error_code=EDA_DEPS_FILE_NOT_FOUND
370
+ )
353
371
  else:
354
372
  self.warning_show_available_targets()
355
- self.error(f'Trying to resolve target={t_full}:',
356
- f'called from {caller_info},',
357
- f'Target not found in deps_file={self.rel_deps_file}',
358
- error_code=EDA_DEPS_TARGET_NOT_FOUND)
373
+ self.error_ifarg(
374
+ f'Trying to resolve target={t_full}:',
375
+ f'called from {caller_info},',
376
+ f'Target not found in deps_file={self.rel_deps_file}',
377
+ arg='error-unknown-args',
378
+ error_code=EDA_DEPS_TARGET_NOT_FOUND
379
+ )
359
380
  else:
360
381
  debug(f'Found {target_node=} in deps_file={self.rel_deps_file}')
361
382
  found_target = True
@@ -250,7 +250,9 @@ class Command: # pylint: disable=too-many-public-methods
250
250
  ' --disable-tags has higher precedence than --enable-tags.'),
251
251
  'test-mode': ('command and tool dependent, usually stops the command early without'
252
252
  ' executing.'),
253
- 'error-unknown-args': 'Enable errors on unknown/unparsable args',
253
+ 'error-unknown-args': (
254
+ 'Enable errors on unknown/unparsable args, or unknown/nonexistent files, or targets'
255
+ ),
254
256
  })
255
257
  self.modified_args = {}
256
258
  self.config = copy.deepcopy(config) # avoid external modifications.
@@ -497,9 +499,11 @@ class Command: # pylint: disable=too-many-public-methods
497
499
 
498
500
  # Do some minimal type handling, preserving the type(self.args[key])
499
501
  if key not in self.args:
500
- self.error_unknown_arg(
502
+ self.error_ifarg(
501
503
  f'set_arg, {key=} not in self.args {value=}',
502
- f'({self.command_name=}, {self.__class__.__name__=})'
504
+ f'({self.command_name=}, {self.__class__.__name__=})',
505
+ arg='error-unknown-args',
506
+ error_code=status_constants.EDA_COMMAND_OR_ARGS_ERROR
503
507
  )
504
508
 
505
509
  cur_value = self.args[key]
@@ -695,9 +699,11 @@ class Command: # pylint: disable=too-many-public-methods
695
699
  _, unparsed = self.run_argparser_on_list(tokens)
696
700
  if process_all and unparsed:
697
701
  self.warning_show_known_args()
698
- self.error_unknown_arg(
702
+ self.error_ifarg(
699
703
  f"Didn't understand argument: '{unparsed=}' in",
700
- f"{self.command_name=} context, {pwd=}"
704
+ f"{self.command_name=} context, {pwd=}",
705
+ arg='error-unknown-args',
706
+ error_code=status_constants.EDA_COMMAND_OR_ARGS_ERROR
701
707
  )
702
708
 
703
709
  return unparsed
@@ -914,13 +920,17 @@ class Command: # pylint: disable=too-many-public-methods
914
920
  lines.append(self.pretty_str_known_args(command=commands[-1])) # use last command if > 1
915
921
  util.warning("\n".join(lines))
916
922
 
917
- def error_unknown_arg(self, *msg) -> None:
923
+ def error_ifarg(
924
+ self, *msg, arg: str, error_code: int = status_constants.EDA_COMMAND_OR_ARGS_ERROR
925
+ ) -> None:
918
926
  '''For errors involving an unknown --arg, they can be optionally disabled
919
927
 
920
- using --no-error-unknown-args
928
+ using CLI: --no-error-unknown-args, and this method arg='error-uknown-arg'
929
+
930
+ Note if arg is not present in self.args, the error is enabled.
921
931
  '''
922
- if self.args['error-unknown-args']:
923
- self.error(*msg, error_code=status_constants.EDA_COMMAND_OR_ARGS_ERROR)
932
+ if self.args.get(arg, True):
933
+ self.error(*msg, error_code=error_code)
924
934
  else:
925
935
  util.warning(*msg)
926
936
 
@@ -1497,8 +1507,12 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
1497
1507
  found_target = True
1498
1508
  break # move on to the next target
1499
1509
  if not found_target and error_on_not_found: # if STILL not found_this_target...
1500
- self.error(f"Unable to resolve {target=}",
1501
- error_code=status_constants.EDA_DEPS_TARGET_NOT_FOUND)
1510
+ # allow this if --no-error-unknown-args:
1511
+ self.error_ifarg(
1512
+ f"Unable to resolve {target=}",
1513
+ arg='error-unknown-args',
1514
+ error_code=status_constants.EDA_DEPS_TARGET_NOT_FOUND
1515
+ )
1502
1516
 
1503
1517
  # if we've found any target since being called, it means we found the one we were called for
1504
1518
  return found_target
@@ -1660,9 +1674,11 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
1660
1674
  if process_all and possible_unparsed_args:
1661
1675
  _tool = self.safe_which_tool()
1662
1676
  self.warning_show_known_args()
1663
- self.error_unknown_arg(
1677
+ self.error_ifarg(
1664
1678
  f"Didn't understand unparsed args: {possible_unparsed_args}, for command",
1665
- f"'{self.command_name}', tool '{_tool}'"
1679
+ f"'{self.command_name}', tool '{_tool}'",
1680
+ arg='error-unknown-args',
1681
+ error_code=status_constants.EDA_COMMAND_OR_ARGS_ERROR
1666
1682
  )
1667
1683
 
1668
1684
  remove_list = []
@@ -1721,9 +1737,11 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
1721
1737
  # we were unable to figure out what this command line token is for...
1722
1738
  if process_all and unparsed:
1723
1739
  self.warning_show_known_args()
1724
- self.error_unknown_arg(
1740
+ self.error_ifarg(
1725
1741
  f"Didn't understand remaining args or targets {unparsed=} for command",
1726
- f"'{self.command_name}'"
1742
+ f"'{self.command_name}'",
1743
+ arg='error-unknown-args',
1744
+ error_code=status_constants.EDA_COMMAND_OR_ARGS_ERROR
1727
1745
  )
1728
1746
 
1729
1747
  # handle a missing self.args['top'] with last filepath or last target:
@@ -2269,9 +2287,11 @@ class CommandParallel(Command):
2269
2287
  bad_remaining_args = [x for x in single_cmd_unparsed if x.startswith('-')]
2270
2288
  if bad_remaining_args:
2271
2289
  self.warning_show_known_args(command=f'{self.command_name} {command}')
2272
- self.error_unknown_arg(
2290
+ self.error_ifarg(
2273
2291
  f'for {self.command_name} {command=} the following args are unknown',
2274
- f'{bad_remaining_args}'
2292
+ f'{bad_remaining_args}',
2293
+ arg='error-unknown-args',
2294
+ error_code=status_constants.EDA_COMMAND_OR_ARGS_ERROR
2275
2295
  )
2276
2296
 
2277
2297
  # Remove unparsed args starting with '+', since those are commonly sent downstream to
@@ -145,6 +145,7 @@ tools:
145
145
  --timescale=1ns/1ns
146
146
  --allow-dup-initial-drivers
147
147
  -Wno-missing-top
148
+ compile-waivers: []
148
149
 
149
150
  verilator:
150
151
  defines: { }
@@ -153,11 +154,11 @@ tools:
153
154
  - "%Fatal"
154
155
  log-must-strings:
155
156
  - "R e p o r t: Verilator" # These come at end of compile or simulation, since we don't suppress it.
157
+ # Note: -j $(nproc) is handled in verilator.py, but you can override it in compile-args
156
158
  compile-args: |
157
159
  --timing
158
160
  --assert
159
161
  --autoflush
160
- -j 2
161
162
  -sv
162
163
  compile-coverage-args: |
163
164
  --coverage
@@ -9,12 +9,14 @@ from pathlib import Path
9
9
 
10
10
  from contextlib import redirect_stdout, redirect_stderr
11
11
 
12
- from opencos import eda
13
- from opencos import deps_schema
12
+ from opencos import eda, eda_tool_helper, deps_schema
14
13
  from opencos.utils.markup_helpers import yaml_safe_load
15
14
  from opencos.utils import status_constants
16
15
  from opencos.utils.subprocess_helpers import subprocess_run_background
17
16
 
17
+ # Figure out what tools the system has available, without calling eda.main(..)
18
+ config, tools_loaded = eda_tool_helper.get_config_and_tools_loaded()
19
+
18
20
 
19
21
  def eda_wrap_is_sim_fail(rc: int, quiet: bool = False) -> bool:
20
22
  '''Because eda_wrap calls eda_main(..) and will continue running
@@ -30,11 +32,11 @@ def eda_wrap_is_sim_fail(rc: int, quiet: bool = False) -> bool:
30
32
  status_constants.EDA_DEFAULT_ERROR
31
33
  )
32
34
 
33
- def can_run_eda_command(*commands, config: dict) -> bool:
35
+ def can_run_eda_command(*commands, cfg: dict = config) -> bool:
34
36
  '''Returns True if we have any installed tool that can run: eda <command>'''
35
37
  runnable = []
36
38
  for command in list(commands):
37
- handler = config['command_handler'].get(command, None)
39
+ handler = cfg['command_handler'].get(command, None)
38
40
  if not handler:
39
41
  return False
40
42
  if handler and getattr(handler, 'CHECK_REQUIRES', []):
@@ -44,7 +46,7 @@ def can_run_eda_command(*commands, config: dict) -> bool:
44
46
  # We cannot run tools that have disable-auto set:
45
47
  tool = getattr(handler, '_TOOL', '')
46
48
  if handler and tool:
47
- entry = config['auto_tools_order'][0].get(tool, {})
49
+ entry = cfg['auto_tools_order'][0].get(tool, {})
48
50
  if entry and entry.get('disable-auto', False):
49
51
  # This tool cannot automatically run our command.
50
52
  return False
@@ -52,6 +54,14 @@ def can_run_eda_command(*commands, config: dict) -> bool:
52
54
  runnable.append(True)
53
55
  return runnable and all(runnable)
54
56
 
57
+ def can_run_eda_sim(cfg: dict = config) -> bool:
58
+ '''Returns True if we have any installed tool that can run: eda sim'''
59
+ return can_run_eda_command('sim', cfg=cfg)
60
+
61
+ def can_run_eda_elab(cfg: dict = config) -> bool:
62
+ '''Returns True if we have any installed tool that can run: eda elab'''
63
+ return can_run_eda_command('elab', cfg=cfg)
64
+
55
65
  def chdir_remove_work_dir(startpath, relpath):
56
66
  '''Changes dir to startpath/relpath, removes the work directories (eda.work, eda.export*)'''
57
67
  os.chdir(os.path.join(str(Path(startpath)), str(Path(relpath))))
@@ -232,7 +242,9 @@ class Helpers:
232
242
 
233
243
  return rc
234
244
 
235
- def is_in_log(self, *want_str, logfile=None, windows_path_support=False):
245
+ def is_in_log(
246
+ self, *want_str, logfile=None, windows_path_support: bool = False
247
+ ) -> bool:
236
248
  '''Check if want_str (joined) is in the logfile, or self.DEFAULT_LOG'''
237
249
  logfile = self._resolve_logfile(logfile)
238
250
  want_str0 = ' '.join(list(want_str))
@@ -244,7 +256,9 @@ class Helpers:
244
256
  return True
245
257
  return False
246
258
 
247
- def get_log_lines_with(self, *want_str, logfile=None, windows_path_support=False):
259
+ def get_log_lines_with(
260
+ self, *want_str, logfile=None, windows_path_support: bool = False
261
+ ) -> list:
248
262
  '''gets all log lines with any of want_str args are in the logfile, or self.DEFAULT_LOG'''
249
263
  logfile = self._resolve_logfile(logfile)
250
264
  ret_list = []
@@ -257,6 +271,21 @@ class Helpers:
257
271
  ret_list.append(line)
258
272
  return ret_list
259
273
 
274
+ def get_log_lines_with_all(
275
+ self, *want_str, logfile=None, windows_path_support: bool = False
276
+ ) -> list:
277
+ '''gets all log lines with ALL of want_str args are in the logfile, or self.DEFAULT_LOG'''
278
+ logfile = self._resolve_logfile(logfile)
279
+ ret_list = []
280
+ with open(logfile, encoding='utf-8') as f:
281
+ for line in f.readlines():
282
+ if all(x in line for x in list(want_str)):
283
+ ret_list.append(line)
284
+ elif windows_path_support and \
285
+ all(x.replace('/', '\\') in line for x in list(want_str)):
286
+ ret_list.append(line)
287
+ return ret_list
288
+
260
289
  def get_log_words_with(self, *want_str, logfile=None, windows_path_support=False):
261
290
  '''gets all log words with any of *want_str within a single word
262
291
  in the logfile or self.DEFAULT_LOG
@@ -23,11 +23,12 @@ import subprocess
23
23
 
24
24
  import pytest
25
25
 
26
- from opencos import eda, eda_tool_helper
26
+ from opencos import eda
27
27
  from opencos.utils.markup_helpers import yaml_safe_load
28
28
  from opencos.tests import helpers
29
29
  from opencos.tests.helpers import eda_wrap, eda_sim_wrap, eda_elab_wrap, \
30
- Helpers
30
+ Helpers, tools_loaded, can_run_eda_sim
31
+
31
32
 
32
33
 
33
34
  THISPATH = os.path.dirname(__file__)
@@ -36,17 +37,6 @@ def chdir_remove_work_dir(relpath):
36
37
  '''Changes dir to relpath, removes the work directories (eda.work, eda.export*)'''
37
38
  return helpers.chdir_remove_work_dir(THISPATH, relpath)
38
39
 
39
- # Figure out what tools the system has available, without calling eda.main(..)
40
- config, tools_loaded = eda_tool_helper.get_config_and_tools_loaded()
41
-
42
- def can_run_eda_sim() -> bool:
43
- '''Returns True if we have any installed tool that can run: eda sim'''
44
- return helpers.can_run_eda_command('sim', config=config)
45
-
46
- def can_run_eda_elab() -> bool:
47
- '''Returns True if we have any installed tool that can run: eda elab'''
48
- return helpers.can_run_eda_command('elab', config=config)
49
-
50
40
  @pytest.mark.skipif(
51
41
  'verilator' not in tools_loaded and 'vivado' not in tools_loaded,
52
42
  reason="requires verilator OR vivado"
@@ -6,25 +6,23 @@ import os
6
6
  import sys
7
7
  import pytest
8
8
 
9
- from opencos import eda, eda_tool_helper, eda_base
9
+ from opencos import eda, eda_base
10
10
 
11
11
  from opencos.tools.verilator import ToolVerilator
12
12
  from opencos.tools.vivado import ToolVivado
13
13
  from opencos.tools.cocotb import ToolCocotb
14
14
  from opencos.tests import helpers
15
- from opencos.tests.helpers import eda_wrap, eda_wrap_is_sim_fail
15
+ from opencos.tests.helpers import eda_wrap, eda_wrap_is_sim_fail, config, tools_loaded
16
16
  from opencos.utils.markup_helpers import yaml_safe_load
17
17
  from opencos.utils import status_constants
18
18
 
19
19
 
20
- thispath = os.path.dirname(__file__)
20
+ THISPATH = os.path.dirname(__file__)
21
21
 
22
22
  def chdir_remove_work_dir(relpath):
23
23
  '''Changes dir to relpath, removes the work directories (eda.work, eda.export*)'''
24
- return helpers.chdir_remove_work_dir(thispath, relpath)
24
+ return helpers.chdir_remove_work_dir(THISPATH, relpath)
25
25
 
26
- # Figure out what tools the system has available, without calling eda.main(..)
27
- config, tools_loaded = eda_tool_helper.get_config_and_tools_loaded()
28
26
 
29
27
  def test_tools_loaded():
30
28
  '''Does not directly call 'eda.main' instead create a few Tool
@@ -37,7 +35,7 @@ def test_tools_loaded():
37
35
  # It's possible we're running in some container or install that has no tools, for example,
38
36
  # Windows.
39
37
  if sys.platform.startswith('win') and \
40
- not helpers.can_run_eda_command('elab', 'sim', config=config):
38
+ not helpers.can_run_eda_command('elab', 'sim', cfg=config):
41
39
  # Windows, not handlers for elab or sim:
42
40
  pass
43
41
  else:
@@ -129,7 +127,7 @@ def test_sim_elab_tools_pass_or_fail(command, tool, target, sim_expect_pass, add
129
127
  added_args = added_sim_args_str.split()
130
128
 
131
129
  relative_dir = "deps_files/test_err_fatal"
132
- os.chdir(os.path.join(thispath, relative_dir))
130
+ os.chdir(os.path.join(THISPATH, relative_dir))
133
131
  rc = eda.main(command, '--tool', tool, *(added_args), target)
134
132
  print(f'{rc=}')
135
133
  if command != 'sim' or sim_expect_pass:
@@ -128,6 +128,7 @@ class CommandElabSlang(CommandElab, ToolSlang):
128
128
  command_list += self.tool_config.get('compile-args', '--single-unit').split()
129
129
  command_list += self.args['slang-args'] # add user args.
130
130
  command_list += self._get_slang_json_args(command_exe=command_list[0])
131
+ command_list += self._get_slang_tool_config_waivers()
131
132
 
132
133
  # incdirs
133
134
  for value in self.incdirs:
@@ -214,6 +215,11 @@ class CommandElabSlang(CommandElab, ToolSlang):
214
215
 
215
216
  return command_list
216
217
 
218
+ def _get_slang_tool_config_waivers(self) -> list:
219
+ # Add compile waivers from config and command-line args
220
+ return [f'-Wno-{waiver}' for waiver in
221
+ self.tool_config.get('compile-waivers', []) + self.args['compile-waivers']]
222
+
217
223
 
218
224
  class CommandLintSlang(CommandElabSlang):
219
225
  '''CommandLintSlang is a command handler for: eda lint --tool=slang.'''
@@ -5,10 +5,12 @@ Contains classes for ToolVerilator and VerilatorSim, VerilatorElab.
5
5
 
6
6
  # pylint: disable=R0801 # (calling functions with same arguments)
7
7
 
8
+ import multiprocessing
8
9
  import os
9
10
  import shutil
10
11
  import subprocess
11
12
 
13
+
12
14
  from opencos import util
13
15
  from opencos.eda_base import Tool
14
16
  from opencos.commands import CommandSim
@@ -210,15 +212,9 @@ class VerilatorSim(CommandSim, ToolVerilator):
210
212
 
211
213
  verilate_command_list = self._get_start_verilator_command_list(lint_only=lint_only)
212
214
 
213
- # Add compile args from our self.config (tools.verilator.compile-args str)
214
- config_compile_args = self.tool_config.get(
215
- 'compile-args',
216
- '--timing --assert --autoflush -sv').split()
217
- verilate_command_list += config_compile_args
218
-
219
215
  verilate_command_list += self._get_verilator_tool_config_waivers()
220
216
 
221
- verilate_command_list += self._verilator_args_deal_with_cflags()
217
+ verilate_command_list += self._verilator_args_defaults_cflags_nproc()
222
218
 
223
219
  verilate_command_list += self._get_verilator_waves_args(lint_only=lint_only)
224
220
 
@@ -425,45 +421,51 @@ class VerilatorSim(CommandSim, ToolVerilator):
425
421
  return ret
426
422
 
427
423
 
428
- def _verilator_args_deal_with_cflags(self) -> list:
424
+ def _verilator_args_defaults_cflags_nproc(self) -> list:
429
425
  '''Returns list of args to be added to verilator (compile) step
430
426
 
431
- Uses self.args['verilate-args'] and self.args['compile-args']
427
+ Uses self.args['verilate-args'], self.args['compile-args'], and self.tool_config
428
+
429
+ Sets -j <value> and -CFLAGS -O<value> if not present in --config-yml, --compile-args,
430
+ or --verilate-args. If present, chooses the first instance (does not present duplicates
431
+ to verilator call).
432
432
  '''
433
433
 
434
- # We can only support one -CFLAGS followed by one -O[0-9] arg in self.args['verilate-args']:
435
- verilate_cflags_args_dict = {}
436
- verilate_args = [] # will be combined verilate_args + compile-args
437
- prev_arg_is_cflags = False
434
+ # We can only support one -CFLAGS followed by one -O[0-9] arg in
435
+ # --verilate-args or --compile-args.
436
+
437
+ # Add compile args from our self.config (tools.verilator.compile-args str)
438
+ verilate_args = self.args['verilate-args'] + \
439
+ self.args['compile-args'] + \
440
+ self.tool_config.get(
441
+ 'compile-args',
442
+ '--timing --assert --autoflush -sv').split()
443
+
438
444
  util.debug(f"{self.args['verilate-args']=}")
439
445
  util.debug(f"{self.args['compile-args']=}")
440
- for arg in self.args['verilate-args'] + self.args['compile-args']:
441
- # pick the first ones we see of these:
442
- if arg == '-CFLAGS':
443
- prev_arg_is_cflags = True
444
- if arg not in verilate_cflags_args_dict:
445
- # We can only have 1
446
- verilate_cflags_args_dict[arg] = True
447
- verilate_args.append(arg)
448
- else:
449
- util.debug(f'Previous saw -CFLAGS args {verilate_cflags_args_dict=},',
450
- f'skipping new {arg=}')
451
-
452
- elif arg.startswith('-O') and len(arg) == 3:
453
- if '-O' not in verilate_cflags_args_dict and prev_arg_is_cflags:
454
- # We can only have 1
455
- verilate_cflags_args_dict['-O'] = arg[-1]
456
- verilate_args.append(arg)
457
- else:
458
- util.debug(f'Previous saw -CFLAGS args {verilate_cflags_args_dict=},',
459
- f'skipping new {arg=}')
460
- prev_arg_is_cflags = False
461
-
462
- else:
463
- prev_arg_is_cflags = False
464
- verilate_args.append(arg)
465
446
 
466
- if '-CFLAGS' in verilate_args:
447
+ dash_j_arg_indices = []
448
+ cflags_dasho_args_indices = []
449
+ for i, arg in enumerate(list(verilate_args)):
450
+ # There can only be one of these: -j <value>, similarly can only be one of
451
+ # -CFLAGS -O<value>
452
+ if (i + 1) < len(verilate_args):
453
+ if arg == '-j':
454
+ dash_j_arg_indices.extend([i, i + 1])
455
+ if arg == '-CFLAGS':
456
+ next_arg = verilate_args[i + 1]
457
+ if next_arg.startswith('-O') and len(next_arg) == 3:
458
+ cflags_dasho_args_indices.extend([i, i + 1])
459
+
460
+ # For -j <value> we'll pick the first one, remove the rest.
461
+ # Same goes for -CFLAGS -O<value>
462
+ for index in dash_j_arg_indices[2:] + cflags_dasho_args_indices[2:]:
463
+ verilate_args[index] = ''
464
+
465
+ verilate_args = [x for x in verilate_args if x != ''] # strip empty str.
466
+
467
+ # Support for --optimize which will use -CFLAGS -O3, if -CFLAGS is not present at all.
468
+ if cflags_dasho_args_indices:
467
469
  # add whatever args were passed via 'compile-args' or 'verilate_args'. Note these will
468
470
  # take precedence over the --optimize arg.
469
471
  pass
@@ -472,8 +474,15 @@ class VerilatorSim(CommandSim, ToolVerilator):
472
474
  # (slower compile, better runtime)
473
475
  verilate_args += '-CFLAGS', '-O3'
474
476
  else:
477
+ # Default to -O1:
475
478
  verilate_args += '-CFLAGS', '-O1'
476
479
 
480
+ # If there was no -j setting, then use max(2, $(nproc) - 1)
481
+ if not dash_j_arg_indices:
482
+ nproc = max(2, multiprocessing.cpu_count() - 1)
483
+ verilate_args += '-j', f'{nproc}'
484
+
485
+
477
486
  return verilate_args
478
487
 
479
488
 
@@ -18,6 +18,7 @@ from enum import Enum
18
18
  from pathlib import Path
19
19
  from importlib import import_module
20
20
  from dotenv import load_dotenv
21
+ from supports_color import supportsColor
21
22
 
22
23
  from opencos.utils import status_constants
23
24
 
@@ -29,7 +30,7 @@ dot_f_files_expanded = set() # pylint: disable=invalid-name
29
30
  env_files_loaded = set() # pylint: disable=invalid-name
30
31
 
31
32
  args = { # pylint: disable=invalid-name
32
- 'color' : False,
33
+ 'color' : bool(supportsColor.stdout),
33
34
  'quiet' : False,
34
35
  'verbose' : False,
35
36
  'debug' : False,
@@ -351,13 +352,14 @@ def get_argparser() -> argparse.ArgumentParser:
351
352
  bool_action_kwargs = get_argparse_bool_action_kwargs()
352
353
 
353
354
  parser.add_argument('--version', default=False, action='store_true')
354
- parser.add_argument('--color', **bool_action_kwargs, default=True,
355
+ parser.add_argument('--color', **bool_action_kwargs, default=bool(supportsColor.stdout),
355
356
  help='Use shell colors for info/warning/error messaging')
356
- parser.add_argument('--quiet', **bool_action_kwargs, help='Do not display info messaging')
357
- parser.add_argument('--verbose', **bool_action_kwargs,
357
+ parser.add_argument('--quiet', **bool_action_kwargs, default=args['quiet'],
358
+ help='Do not display info messaging')
359
+ parser.add_argument('--verbose', **bool_action_kwargs, default=args['verbose'],
358
360
  help='Display additional messaging level 2 or higher')
359
- parser.add_argument('--fancy', **bool_action_kwargs)
360
- parser.add_argument('--debug', **bool_action_kwargs,
361
+ parser.add_argument('--fancy', **bool_action_kwargs, default=args['fancy'])
362
+ parser.add_argument('--debug', **bool_action_kwargs, default=args['debug'],
361
363
  help='Display additional debug messaging level 1 or higher')
362
364
  parser.add_argument('--debug-level', type=int, default=0,
363
365
  help='Set debug level messaging (default: 0)')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencos-eda
3
- Version: 0.3.1
3
+ Version: 0.3.3
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
@@ -17,4 +17,5 @@ Requires-Dist: toml>=0.10.2
17
17
  Requires-Dist: yamllint>=1.35.1
18
18
  Requires-Dist: PySerial>=3.5
19
19
  Requires-Dist: cocotb>=2.0
20
+ Requires-Dist: supports_color>=0.2.0
20
21
  Dynamic: license-file
@@ -8,3 +8,4 @@ toml>=0.10.2
8
8
  yamllint>=1.35.1
9
9
  PySerial>=3.5
10
10
  cocotb>=2.0
11
+ supports_color>=0.2.0
@@ -2,7 +2,7 @@
2
2
 
3
3
  [project]
4
4
  name = "opencos-eda"
5
- version = "0.3.1"
5
+ version = "0.3.3"
6
6
  dependencies = [
7
7
  # opencos/eda.py dependencies
8
8
  "mergedeep >= 1.3.4",
@@ -16,6 +16,7 @@ dependencies = [
16
16
  # opencos/oc_cli.py dependencies
17
17
  "PySerial >= 3.5",
18
18
  "cocotb >= 2.0",
19
+ "supports_color >= 0.2.0",
19
20
  ]
20
21
  requires-python = ">= 3.8"
21
22
  authors = [
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes