opencos-eda 0.2.51__tar.gz → 0.2.52__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 (100) hide show
  1. {opencos_eda-0.2.51/opencos_eda.egg-info → opencos_eda-0.2.52}/PKG-INFO +2 -1
  2. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/waves.py +12 -2
  3. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/eda.py +16 -3
  4. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/eda_config.py +1 -1
  5. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/eda_config_defaults.yml +34 -0
  6. opencos_eda-0.2.52/opencos/tests/test_tools.py +350 -0
  7. opencos_eda-0.2.52/opencos/tools/cocotb.py +483 -0
  8. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/verilator.py +31 -0
  9. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/util.py +2 -0
  10. opencos_eda-0.2.52/opencos/utils/vscode_helper.py +47 -0
  11. {opencos_eda-0.2.51 → opencos_eda-0.2.52/opencos_eda.egg-info}/PKG-INFO +2 -1
  12. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos_eda.egg-info/SOURCES.txt +2 -0
  13. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos_eda.egg-info/requires.txt +1 -0
  14. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/pyproject.toml +2 -1
  15. opencos_eda-0.2.51/opencos/tests/test_tools.py +0 -156
  16. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/LICENSE +0 -0
  17. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/LICENSE.spdx +0 -0
  18. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/README.md +0 -0
  19. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/__init__.py +0 -0
  20. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/_version.py +0 -0
  21. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/_waves_pkg.sv +0 -0
  22. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/__init__.py +0 -0
  23. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/build.py +0 -0
  24. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/elab.py +0 -0
  25. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/export.py +0 -0
  26. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/flist.py +0 -0
  27. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/lec.py +0 -0
  28. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/multi.py +0 -0
  29. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/open.py +0 -0
  30. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/proj.py +0 -0
  31. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/shell.py +0 -0
  32. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/sim.py +0 -0
  33. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/sweep.py +0 -0
  34. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/synth.py +0 -0
  35. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/targets.py +0 -0
  36. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/commands/upload.py +0 -0
  37. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/deps/__init__.py +0 -0
  38. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/deps/defaults.py +0 -0
  39. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/deps/deps_commands.py +0 -0
  40. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/deps/deps_file.py +0 -0
  41. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/deps/deps_processor.py +0 -0
  42. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/deps_schema.py +0 -0
  43. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/eda_base.py +0 -0
  44. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/eda_config_max_verilator_waivers.yml +0 -0
  45. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/eda_config_reduced.yml +0 -0
  46. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/eda_deps_bash_completion.bash +0 -0
  47. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/eda_deps_sanitize.py +0 -0
  48. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/eda_extract_targets.py +0 -0
  49. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/eda_tool_helper.py +0 -0
  50. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/export_helper.py +0 -0
  51. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/export_json_convert.py +0 -0
  52. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/files.py +0 -0
  53. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/hw/__init__.py +0 -0
  54. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/hw/oc_cli.py +0 -0
  55. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/hw/pcie.py +0 -0
  56. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/names.py +0 -0
  57. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/peakrdl_cleanup.py +0 -0
  58. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/seed.py +0 -0
  59. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/__init__.py +0 -0
  60. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/custom_config.yml +0 -0
  61. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/deps_files/command_order/DEPS.yml +0 -0
  62. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/deps_files/error_msgs/DEPS.yml +0 -0
  63. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/deps_files/iverilog_test/DEPS.yml +0 -0
  64. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/deps_files/no_deps_here/DEPS.yml +0 -0
  65. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/deps_files/non_sv_reqs/DEPS.yml +0 -0
  66. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/deps_files/tags_with_tools/DEPS.yml +0 -0
  67. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/deps_files/test_err_fatal/DEPS.yml +0 -0
  68. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/helpers.py +0 -0
  69. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/test_build.py +0 -0
  70. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/test_deps_helpers.py +0 -0
  71. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/test_deps_schema.py +0 -0
  72. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/test_eda.py +0 -0
  73. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/test_eda_elab.py +0 -0
  74. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/test_eda_synth.py +0 -0
  75. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tests/test_oc_cli.py +0 -0
  76. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/__init__.py +0 -0
  77. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/invio.py +0 -0
  78. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/invio_helpers.py +0 -0
  79. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/invio_yosys.py +0 -0
  80. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/iverilog.py +0 -0
  81. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/modelsim_ase.py +0 -0
  82. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/questa.py +0 -0
  83. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/questa_fse.py +0 -0
  84. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/riviera.py +0 -0
  85. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/slang.py +0 -0
  86. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/slang_yosys.py +0 -0
  87. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/surelog.py +0 -0
  88. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/tabbycad_yosys.py +0 -0
  89. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/vivado.py +0 -0
  90. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/tools/yosys.py +0 -0
  91. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/utils/__init__.py +0 -0
  92. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/utils/markup_helpers.py +0 -0
  93. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/utils/status_constants.py +0 -0
  94. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/utils/str_helpers.py +0 -0
  95. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/utils/subprocess_helpers.py +0 -0
  96. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos/utils/vsim_helper.py +0 -0
  97. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos_eda.egg-info/dependency_links.txt +0 -0
  98. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos_eda.egg-info/entry_points.txt +0 -0
  99. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/opencos_eda.egg-info/top_level.txt +0 -0
  100. {opencos_eda-0.2.51 → opencos_eda-0.2.52}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencos-eda
3
- Version: 0.2.51
3
+ Version: 0.2.52
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
@@ -15,4 +15,5 @@ Requires-Dist: schema>=0.7.7
15
15
  Requires-Dist: toml>=0.10.2
16
16
  Requires-Dist: yamllint>=1.35.1
17
17
  Requires-Dist: PySerial>=3.5
18
+ Requires-Dist: cocotb>=2.0.0b1
18
19
  Dynamic: license-file
@@ -32,6 +32,8 @@ class CommandWaves(CommandDesign):
32
32
 
33
33
  VSIM_TOOLS = set([
34
34
  'questa',
35
+ 'questa_fse',
36
+ 'riviera',
35
37
  'modelsim_ase',
36
38
  ])
37
39
 
@@ -137,13 +139,21 @@ class CommandWaves(CommandDesign):
137
139
  self.error(f"Don't know how to open {wave_file} without one of",
138
140
  f"{self.VSIM_TOOLS} in PATH")
139
141
  elif wave_file.endswith('.fst'):
140
- if 'gtkwave' in self.config['tools_loaded'] and shutil.which('gtkwave'):
142
+ if ('vaporview' in self.config['tools_loaded'] or \
143
+ 'surfer' in self.config['tools_loaded']) and shutil.which('code'):
144
+ command_list = ['code', '-n', '.', wave_file]
145
+ self.exec(os.path.dirname(wave_file), command_list)
146
+ elif 'gtkwave' in self.config['tools_loaded'] and shutil.which('gtkwave'):
141
147
  command_list = ['gtkwave', wave_file]
142
148
  self.exec(os.path.dirname(wave_file), command_list)
143
149
  else:
144
150
  self.error(f"Don't know how to open {wave_file} without GtkWave in PATH")
145
151
  elif wave_file.endswith('.vcd'):
146
- if 'gtkwave' in self.config['tools_loaded'] and shutil.which('gtkwave'):
152
+ if ('vaporview' in self.config['tools_loaded'] or \
153
+ 'surfer' in self.config['tools_loaded']) and shutil.which('code'):
154
+ command_list = ['code', '-n', '.', wave_file]
155
+ self.exec(os.path.dirname(wave_file), command_list)
156
+ elif 'gtkwave' in self.config['tools_loaded'] and shutil.which('gtkwave'):
147
157
  command_list = ['gtkwave', wave_file]
148
158
  self.exec(os.path.dirname(wave_file), command_list)
149
159
  elif self._vsim_available(from_tools=self.VSIM_VCD_TOOLS):
@@ -21,7 +21,7 @@ from pathlib import Path
21
21
  import opencos
22
22
  from opencos import util, eda_config, eda_base
23
23
  from opencos.eda_base import Tool, which_tool
24
- from opencos.utils import vsim_helper
24
+ from opencos.utils import vsim_helper, vscode_helper
25
25
 
26
26
  # Configure util:
27
27
  util.progname = "EDA"
@@ -213,6 +213,19 @@ def auto_tool_setup( # pylint: disable=too-many-locals,too-many-branches,too-man
213
213
  vsim_helper.init() # only runs checks once internally
214
214
  has_vsim_helper = vsim_helper.TOOL_IS.get(name, False)
215
215
 
216
+ has_vscode_helper = True
217
+ needs_vscode_extensions = value.get('requires_vscode_extension', None)
218
+ if needs_vscode_extensions:
219
+ if not isinstance(needs_vscode_extensions, list):
220
+ util.error(
221
+ f'eda config issue, tool {name}: requires_vscode_extension must be a list'
222
+ )
223
+ else:
224
+ vscode_helper.init() # only runs checks once internally
225
+ has_vscode_helper = all(
226
+ x in vscode_helper.EXTENSIONS for x in needs_vscode_extensions
227
+ )
228
+
216
229
  if has_all_exe:
217
230
  requires_cmd_list = value.get('requires_cmd', [])
218
231
  for cmd in requires_cmd_list:
@@ -230,8 +243,8 @@ def auto_tool_setup( # pylint: disable=too-many-locals,too-many-branches,too-man
230
243
  util.debug(f"... No, exception {e} running {cmd_list}")
231
244
 
232
245
 
233
- if all([has_all_py, has_all_env, has_all_exe, has_all_in_exe_path,
234
- has_vsim_helper]):
246
+ if all((has_all_py, has_all_env, has_all_exe, has_all_in_exe_path,
247
+ has_vsim_helper, has_vscode_helper)):
235
248
  exe = exe_list[0]
236
249
  p = shutil.which(exe)
237
250
  config['auto_tools_found'][name] = exe # populate key-value pairs w/ first exe in list
@@ -46,7 +46,7 @@ class Defaults:
46
46
  supported_config_auto_tools_order_keys = set([
47
47
  'exe', 'handlers',
48
48
  'requires_env', 'requires_py', 'requires_cmd', 'requires_in_exe_path',
49
- 'requires_vsim_helper',
49
+ 'requires_vsim_helper', 'requires_vscode_extension',
50
50
  'disable-tools-multi',
51
51
  ])
52
52
  supported_config_tool_keys = set([
@@ -280,6 +280,20 @@ tools:
280
280
  simulate-waves-args: |
281
281
  +trace
282
282
 
283
+ cocotb:
284
+ defines:
285
+ OC_TOOL_COCOTB: null
286
+ log-bad-strings:
287
+ - "ERROR"
288
+ - "FAILED"
289
+ - "AssertionError"
290
+ - "Exception"
291
+ - "Traceback"
292
+ - "COCOTB_TEST_FAILED"
293
+ log-must-strings:
294
+ - "passed"
295
+ - "Cocotb test completed successfully!"
296
+
283
297
 
284
298
  vivado:
285
299
  sim-libraries:
@@ -345,6 +359,17 @@ auto_tools_order:
345
359
  handlers:
346
360
  elab: opencos.tools.invio.CommandElabInvio
347
361
 
362
+ vaporview:
363
+ exe: code
364
+ requires_vscode_extension:
365
+ - lramseyer.vaporview
366
+ handlers: { }
367
+
368
+ surfer:
369
+ exe: code
370
+ requires_vscode_extension:
371
+ - surfer-project.surfer
372
+ handlers: { }
348
373
 
349
374
  gtkwave:
350
375
  exe: gtkwave
@@ -431,3 +456,12 @@ auto_tools_order:
431
456
  handlers:
432
457
  elab: opencos.tools.iverilog.CommandElabIverilog
433
458
  sim: opencos.tools.iverilog.CommandSimIverilog
459
+
460
+ cocotb:
461
+ exe: python
462
+ requires_cmd:
463
+ - python -c "import cocotb; print(cocotb.__version__)"
464
+ requires_py:
465
+ - cocotb
466
+ handlers:
467
+ sim: opencos.tools.cocotb.CommandSimCocotb
@@ -0,0 +1,350 @@
1
+ '''pytests for testing a few different tools within opencos.eda'''
2
+
3
+ # pylint: disable=R0801 # (similar lines in 2+ files)
4
+
5
+ import os
6
+ import sys
7
+ import pytest
8
+
9
+ from opencos import eda, eda_tool_helper, eda_base
10
+
11
+ from opencos.tools.verilator import ToolVerilator
12
+ from opencos.tools.vivado import ToolVivado
13
+ from opencos.tools.cocotb import ToolCocotb
14
+ from opencos.tests import helpers
15
+ from opencos.tests.helpers import eda_wrap
16
+ from opencos.utils.markup_helpers import yaml_safe_load
17
+
18
+
19
+ thispath = os.path.dirname(__file__)
20
+
21
+ def chdir_remove_work_dir(relpath):
22
+ '''Changes dir to relpath, removes the work directories (eda.work, eda.export*)'''
23
+ return helpers.chdir_remove_work_dir(thispath, relpath)
24
+
25
+ # Figure out what tools the system has available, without calling eda.main(..)
26
+ config, tools_loaded = eda_tool_helper.get_config_and_tools_loaded()
27
+
28
+ def test_tools_loaded():
29
+ '''Does not directly call 'eda.main' instead create a few Tool
30
+
31
+ class objects and confirm the versioning methods work.
32
+ '''
33
+ assert config
34
+ assert len(config.keys()) > 0
35
+
36
+ # It's possible we're running in some container or install that has no tools, for example,
37
+ # Windows.
38
+ if sys.platform.startswith('win') and \
39
+ not helpers.can_run_eda_command('elab', 'sim', config=config):
40
+ # Windows, not handlers for elab or sim:
41
+ pass
42
+ else:
43
+ assert len(tools_loaded) > 0
44
+
45
+ def version_checker(
46
+ obj: eda_base.Tool, chk_str: str
47
+ ) -> None:
48
+ assert obj.get_versions()
49
+ full_ver = obj.get_full_tool_and_versions()
50
+ assert chk_str in full_ver, f'{chk_str=} not in {full_ver=}'
51
+ ver_num = full_ver.rsplit(':', maxsplit=1)[-1]
52
+ if 'b' in ver_num:
53
+ ver_num = ver_num.split('b')[0] # TODO(chaitanya): remove once cocotb 2.0 is released
54
+ if '.' in ver_num:
55
+ major_ver = ver_num.split('.')[0]
56
+ assert major_ver.isdigit(), (
57
+ f'Major version {major_ver=} is not a digit, from {full_ver=}'
58
+ )
59
+ assert float(major_ver) >= 0, (
60
+ f'{major_ver=} is not a valid version number, from {full_ver=}'
61
+ )
62
+ else:
63
+ assert float(ver_num), f'{ver_num=} is not a float, from {full_ver=}'
64
+
65
+
66
+ # Do some very crude checks on the eda.Tool methods, and make
67
+ # sure versions work for Verilator and Vivado:
68
+ if 'verilator' in tools_loaded:
69
+ my_tool = ToolVerilator(config={})
70
+ version_checker(obj=my_tool, chk_str='verilator:')
71
+
72
+ if 'vivado' in tools_loaded:
73
+ my_tool = ToolVivado(config={})
74
+ version_checker(obj=my_tool, chk_str='vivado:')
75
+
76
+ if 'cocotb' in tools_loaded:
77
+ my_tool = ToolCocotb(config={})
78
+ version_checker(obj=my_tool, chk_str='cocotb:')
79
+
80
+ # Run these on simulation tools.
81
+ list_of_commands = [
82
+ 'sim',
83
+ 'elab'
84
+ ]
85
+
86
+ list_of_tools = [
87
+ 'iverilog',
88
+ 'verilator',
89
+ 'vivado',
90
+ 'modelsim_ase',
91
+ 'questa_fse',
92
+ ]
93
+
94
+ list_of_deps_targets = [
95
+ ('tb_no_errs', True), # target:str, sim_expect_pass:bool (sim only, all elab should pass)
96
+ ('tb_dollar_fatal', False),
97
+ ('tb_dollar_err', False),
98
+ ]
99
+
100
+ cannot_use_cocotb = 'cocotb' not in tools_loaded or \
101
+ ('iverilog' not in tools_loaded and \
102
+ 'verilator' not in tools_loaded)
103
+ CANNOT_USE_COCOTB_REASON = 'requires cocotb in tools_loaded, and one of (iverilog, verilator) too'
104
+
105
+ @pytest.mark.parametrize("command", list_of_commands)
106
+ @pytest.mark.parametrize("tool", list_of_tools)
107
+ @pytest.mark.parametrize("target,sim_expect_pass", list_of_deps_targets)
108
+ def test_err_fatal(command, tool, target, sim_expect_pass):
109
+ '''tests that: eda <sim|elab> --tool <parameter-tool> <parameter-target>
110
+
111
+ will correctly pass or fail depending on if it is supported or not.
112
+ '''
113
+ if tool not in tools_loaded:
114
+ pytest.skip(f"{tool=} skipped, {tools_loaded=}")
115
+ return # skip/pass
116
+
117
+ relative_dir = "deps_files/test_err_fatal"
118
+ os.chdir(os.path.join(thispath, relative_dir))
119
+ rc = eda.main(command, '--tool', tool, target)
120
+ print(f'{rc=}')
121
+ if command != 'sim' or sim_expect_pass:
122
+ # command='elab' should pass.
123
+ assert rc == 0
124
+ else:
125
+ assert rc > 0
126
+
127
+
128
+ @pytest.mark.skipif('vivado' not in tools_loaded, reason="requires vivado")
129
+ def test_vivado_tool_defines():
130
+ '''This test attempts to confirm that the following class inheritance works:
131
+
132
+ Command <- CommandDesign <- CommandSim <- CommandSimVivado <- CommandElabVivado
133
+
134
+ in particular that CommandElabVivado(CommandSimVivado, ToolVivado) has the
135
+ correct ToolVivado.set_tool_defines() method, and that no other parent Command
136
+ class has overriden it to defeat the defines that should be set.
137
+
138
+ We also run with an added dependency (lib_ultrascale_plus_defines) to check that
139
+ defines are set as expected.
140
+ '''
141
+
142
+ chdir_remove_work_dir('../../lib')
143
+ rc = eda_wrap(
144
+ 'elab', '--tool', 'vivado', 'third_party/vendors/xilinx/lib_ultrascale_plus_defines',
145
+ 'oclib_fifo'
146
+ )
147
+ assert rc == 0
148
+
149
+ # Confirm that args and defines we expected to be set are set.
150
+ eda_config_yml_path = os.path.join(
151
+ os.getcwd(), 'eda.work', 'oclib_fifo.elab', 'eda_output_config.yml'
152
+ )
153
+
154
+ data = yaml_safe_load(eda_config_yml_path)
155
+ assert 'args' in data
156
+ assert data['args'].get('top', '') == 'oclib_fifo'
157
+ assert 'config' in data
158
+ assert 'eda_original_args' in data['config']
159
+ assert 'oclib_fifo' in data['config']['eda_original_args']
160
+ assert data.get('target', '') == 'oclib_fifo'
161
+
162
+
163
+ # This checks opencos.tools.vivado.ToolVivado.set_tool_defines():
164
+ # We ran with --xilinx, so we expect certain defines to be set, others not to be set.
165
+ assert 'defines' in data
166
+
167
+ assert 'OC_TOOL_VIVADO' in data['defines']
168
+ assert 'OC_LIBRARY' in data['defines']
169
+ assert 'OC_LIBRARY_ULTRASCALE_PLUS' in data['defines']
170
+
171
+ assert 'OC_LIBRARY_BEHAVIORAL' not in data['defines']
172
+ assert 'VERILATOR' not in data['defines']
173
+ assert 'SYNTHESIS' not in data['defines']
174
+
175
+ assert data['defines']['OC_LIBRARY'] == '1'
176
+ assert data['defines']['OC_LIBRARY_ULTRASCALE_PLUS'] is None # key present, no value
177
+
178
+
179
+ @pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
180
+ def test_cocotb_tool_defines():
181
+ '''Test cocotb tool defines, configs, and integration.'''
182
+
183
+ chdir_remove_work_dir('../../examples/cocotb')
184
+
185
+ # Test 0: Using eda multi:
186
+ rc = eda_wrap('multi', 'sim', '--tool=cocotb', '*test')
187
+ assert rc == 0
188
+
189
+ # Test 1: basic cocotb sim command with Python runner (default)
190
+ rc = eda_wrap('sim', '--tool', 'cocotb', 'cocotb_counter_test')
191
+ assert rc == 0
192
+
193
+ # Test 2: cocotb works with different simulators/configurations
194
+ rc = eda_wrap('sim', '--tool', 'cocotb', 'cocotb_counter_waves_test')
195
+ assert rc == 0
196
+
197
+ # Test 3: Makefile approach
198
+ rc = eda_wrap('sim', '--tool', 'cocotb', 'cocotb_counter_makefile_test')
199
+ assert rc == 0
200
+
201
+ # Test 4: cocotb-specific defines are set correctly
202
+ eda_config_yml_path = os.path.join(
203
+ os.getcwd(), 'eda.work', 'cocotb_counter_test.sim', 'eda_output_config.yml'
204
+ )
205
+
206
+ data = yaml_safe_load(eda_config_yml_path)
207
+ assert 'args' in data
208
+ assert data['args'].get('top', '') == 'counter'
209
+ assert 'config' in data
210
+ assert 'eda_original_args' in data['config']
211
+ assert 'cocotb_counter_test' in data['config']['eda_original_args'] or \
212
+ './cocotb_counter_test' in data['config']['eda_original_args']
213
+ assert data.get('target', '') == 'cocotb_counter_test'
214
+
215
+ assert 'defines' in data
216
+ assert 'OC_TOOL_COCOTB' in data['defines']
217
+ assert 'SIMULATION' in data['defines']
218
+ assert 'COCOTB' in data['defines']
219
+
220
+ assert data['defines']['SIMULATION'] == 1
221
+ assert data['defines']['COCOTB'] == 1
222
+ assert data['defines']['OC_TOOL_COCOTB'] is None # key present, no value
223
+
224
+ assert 'VERILATOR' not in data['defines']
225
+ assert 'SYNTHESIS' not in data['defines']
226
+
227
+
228
+
229
+ @pytest.mark.parametrize("cocotb_simulator", ['verilator', 'iverilog'])
230
+ @pytest.mark.parametrize("waves_arg", ["", "--waves"])
231
+ @pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
232
+ def test_cocotb_different_simulators(cocotb_simulator, waves_arg):
233
+ '''Test cocotb with different simulator configurations.'''
234
+
235
+ if cocotb_simulator not in tools_loaded:
236
+ pytest.skip(f"{cocotb_simulator=} skipped, {tools_loaded=}")
237
+ return #skip/bypass
238
+
239
+ chdir_remove_work_dir('../../examples/cocotb')
240
+
241
+ rc = eda_wrap(
242
+ 'sim', '--tool', 'cocotb',
243
+ f'--cocotb-simulator={cocotb_simulator}',
244
+ waves_arg,
245
+ 'cocotb_counter_test',
246
+ )
247
+ assert rc == 0
248
+
249
+
250
+
251
+ @pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
252
+ def test_cocotb_tool_instantiation():
253
+ '''Test that ToolCocotb can be instantiated and has correct properties.'''
254
+
255
+ tool = ToolCocotb(config={})
256
+
257
+ # version detection works
258
+ version = tool.get_versions()
259
+ assert version, "Should return a non-empty version string"
260
+ assert isinstance(version, str)
261
+
262
+ # tool defines
263
+ tool.set_tool_defines()
264
+ defines = tool.defines
265
+ assert 'SIMULATION' in defines
266
+ assert 'COCOTB' in defines
267
+ assert 'OC_TOOL_COCOTB' in defines
268
+ assert defines['SIMULATION'] == 1
269
+ assert defines['COCOTB'] == 1
270
+
271
+
272
+
273
+ @pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
274
+ def test_cocotb_failure_cases():
275
+ '''Test cocotb failure scenarios to ensure proper error handling.'''
276
+
277
+ chdir_remove_work_dir('../../examples/cocotb')
278
+
279
+ # Test 1: missing test files should fail gracefully
280
+ rc = eda_wrap('sim', '--tool', 'cocotb', 'counter') # Just HDL, no test files
281
+ assert rc > 1, "Should fail when no cocotb test files are found"
282
+
283
+ # Test 2: non-existent target should fail
284
+ rc = eda_wrap('sim', '--tool', 'cocotb', 'nonexistent_target')
285
+ assert rc > 1, "Should fail for non-existent target"
286
+
287
+ # Test 3: invalid cocotb test module should fail
288
+ rc = eda_wrap(
289
+ 'sim', '--tool', 'cocotb',
290
+ '--cocotb-test-module=nonexistent_test',
291
+ 'cocotb_counter_test',
292
+ )
293
+ assert rc > 1, "Should fail with invalid test module"
294
+
295
+
296
+ @pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
297
+ def test_cocotb_missing_dependencies():
298
+ '''Test cocotb behavior when dependencies are missing.'''
299
+
300
+ # Test missing cocotb installation (simulate by checking error handling)
301
+ tool = ToolCocotb(config={})
302
+ version = tool.get_versions()
303
+ assert version, "Should return version when cocotb is properly installed"
304
+
305
+ # Test tool defines are properly set even with minimal config
306
+ tool.set_tool_defines()
307
+ defines = tool.defines
308
+ assert 'SIMULATION' in defines
309
+ assert 'COCOTB' in defines
310
+ assert 'OC_TOOL_COCOTB' in defines
311
+
312
+
313
+ @pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
314
+ def test_cocotb_invalid_simulator():
315
+ '''Test cocotb with invalid simulator configuration.'''
316
+
317
+ chdir_remove_work_dir('../../examples/cocotb')
318
+
319
+ rc = eda_wrap(
320
+ 'sim', '--tool', 'cocotb',
321
+ '--cocotb-simulator=invalid_sim',
322
+ 'cocotb_counter_test',
323
+ )
324
+ assert rc > 1, "Should fail with invalid simulator"
325
+
326
+ @pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
327
+ def test_cocotb_malformed_hdl():
328
+ '''Test cocotb with malformed HDL files.'''
329
+
330
+ chdir_remove_work_dir('../../lib/tests')
331
+
332
+ # Test with a target that has syntax errors - should fail during compilation
333
+ rc = eda_wrap(
334
+ 'sim', '--tool', 'cocotb',
335
+ '--cocotb-test-module=test_counter',
336
+ 'tb_dollar_fatal',
337
+ )
338
+
339
+ assert rc > 1, "Should fail with malformed HDL or failing test assertions"
340
+
341
+
342
+ @pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
343
+ def test_cocotb_test_failures():
344
+ '''Test that cocotb properly reports test failures.'''
345
+
346
+ chdir_remove_work_dir('../../examples/cocotb')
347
+
348
+ # Intentionally failing cocotb tests
349
+ rc = eda_wrap('sim', '--tool', 'cocotb', 'cocotb_failure_test')
350
+ assert rc > 1, "Should fail when cocotb tests contain assertion failures"