opencos-eda 0.3.8__py3-none-any.whl → 0.3.10__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.
- opencos/commands/deps_help.py +40 -21
- opencos/commands/sim.py +0 -1
- opencos/deps/deps_file.py +82 -79
- opencos/eda.py +108 -17
- opencos/eda_base.py +8 -4
- opencos/eda_config.py +8 -1
- opencos/eda_config_defaults.yml +14 -5
- opencos/eda_deps_bash_completion.bash +37 -15
- opencos/tools/modelsim_ase.py +19 -378
- opencos/tools/questa.py +42 -247
- opencos/tools/questa_common.py +480 -0
- opencos/tools/questa_fe.py +84 -0
- opencos/tools/questa_fse.py +7 -8
- opencos/tools/riviera.py +27 -10
- opencos/tools/verilator.py +1 -0
- opencos/utils/str_helpers.py +7 -0
- opencos/utils/vsim_helper.py +53 -21
- {opencos_eda-0.3.8.dist-info → opencos_eda-0.3.10.dist-info}/METADATA +2 -1
- {opencos_eda-0.3.8.dist-info → opencos_eda-0.3.10.dist-info}/RECORD +24 -40
- {opencos_eda-0.3.8.dist-info → opencos_eda-0.3.10.dist-info}/entry_points.txt +1 -0
- opencos/tests/__init__.py +0 -0
- opencos/tests/custom_config.yml +0 -13
- opencos/tests/deps_files/command_order/DEPS.yml +0 -44
- opencos/tests/deps_files/error_msgs/DEPS.yml +0 -55
- opencos/tests/deps_files/iverilog_test/DEPS.yml +0 -4
- opencos/tests/deps_files/no_deps_here/DEPS.yml +0 -0
- opencos/tests/deps_files/non_sv_reqs/DEPS.yml +0 -50
- opencos/tests/deps_files/tags_with_tools/DEPS.yml +0 -54
- opencos/tests/deps_files/test_err_fatal/DEPS.yml +0 -4
- opencos/tests/helpers.py +0 -354
- opencos/tests/test_build.py +0 -12
- opencos/tests/test_deps_helpers.py +0 -207
- opencos/tests/test_deps_schema.py +0 -30
- opencos/tests/test_eda.py +0 -921
- opencos/tests/test_eda_elab.py +0 -110
- opencos/tests/test_eda_synth.py +0 -150
- opencos/tests/test_oc_cli.py +0 -25
- opencos/tests/test_tools.py +0 -404
- {opencos_eda-0.3.8.dist-info → opencos_eda-0.3.10.dist-info}/WHEEL +0 -0
- {opencos_eda-0.3.8.dist-info → opencos_eda-0.3.10.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.3.8.dist-info → opencos_eda-0.3.10.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.3.8.dist-info → opencos_eda-0.3.10.dist-info}/top_level.txt +0 -0
opencos/tests/test_eda_elab.py
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
'''pytests for: eda elab <command> [args] <target>'''
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import pytest
|
|
5
|
-
|
|
6
|
-
from opencos import eda_tool_helper
|
|
7
|
-
from opencos.tests import helpers
|
|
8
|
-
from opencos.tests.helpers import eda_wrap, eda_elab_wrap, eda_lint_wrap
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
thispath = os.path.dirname(__file__)
|
|
12
|
-
|
|
13
|
-
def chdir_remove_work_dir(relpath):
|
|
14
|
-
'''Changes dir to relpath, removes the work directories (eda.work, eda.export*)'''
|
|
15
|
-
return helpers.chdir_remove_work_dir(thispath, relpath)
|
|
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
|
-
|
|
20
|
-
# list of tools we'd like to try:
|
|
21
|
-
list_of_elab_tools = [
|
|
22
|
-
'slang',
|
|
23
|
-
'verilator',
|
|
24
|
-
'vivado',
|
|
25
|
-
'modelsim_ase'
|
|
26
|
-
'questa_fse',
|
|
27
|
-
'invio',
|
|
28
|
-
'surelog',
|
|
29
|
-
'invio_yosys',
|
|
30
|
-
]
|
|
31
|
-
|
|
32
|
-
list_of_lint_tools = [
|
|
33
|
-
'slang',
|
|
34
|
-
'verilator',
|
|
35
|
-
'vivado',
|
|
36
|
-
'modelsim_ase'
|
|
37
|
-
'questa_fse',
|
|
38
|
-
'invio',
|
|
39
|
-
'surelog',
|
|
40
|
-
]
|
|
41
|
-
|
|
42
|
-
list_of_elab_tools_cant_sim = [
|
|
43
|
-
'slang',
|
|
44
|
-
'invio',
|
|
45
|
-
'surelog',
|
|
46
|
-
'invio_yosys',
|
|
47
|
-
]
|
|
48
|
-
|
|
49
|
-
list_of_commands = [
|
|
50
|
-
'elab',
|
|
51
|
-
'lint',
|
|
52
|
-
]
|
|
53
|
-
|
|
54
|
-
def skip_it(tool) -> bool:
|
|
55
|
-
'''Returns True if this test should be skipped
|
|
56
|
-
|
|
57
|
-
For example, run in a github Action w/ container that doesn't have a tool
|
|
58
|
-
in tool_loaded.
|
|
59
|
-
'''
|
|
60
|
-
return bool( tool not in tools_loaded )
|
|
61
|
-
|
|
62
|
-
@pytest.mark.parametrize("command", list_of_commands)
|
|
63
|
-
@pytest.mark.parametrize("tool", list_of_elab_tools)
|
|
64
|
-
class Tests:
|
|
65
|
-
'''Test tools from list_of_elab_tools for 'eda elab' and 'eda multi elab'.'''
|
|
66
|
-
|
|
67
|
-
def test_args_elab(self, command, tool):
|
|
68
|
-
'''tests: eda elab --tool oclib_priarb'''
|
|
69
|
-
if command == 'lint' and tool not in list_of_lint_tools:
|
|
70
|
-
pytest.skip(f"lint skipped for {tool=} b/c it can't run lint")
|
|
71
|
-
if skip_it(tool):
|
|
72
|
-
pytest.skip(f"{tool=} skipped, {tools_loaded=}")
|
|
73
|
-
return # skip/pass
|
|
74
|
-
chdir_remove_work_dir('../../lib')
|
|
75
|
-
if command == 'elab':
|
|
76
|
-
rc = eda_elab_wrap('--tool', tool, 'oclib_priarb')
|
|
77
|
-
else:
|
|
78
|
-
rc = eda_lint_wrap('--tool', tool, 'oclib_priarb')
|
|
79
|
-
print(f'{rc=}')
|
|
80
|
-
assert rc == 0
|
|
81
|
-
|
|
82
|
-
def test_args_multi_elab(self, command, tool):
|
|
83
|
-
'''tests: eda multi elab --tool oclib_*arb'''
|
|
84
|
-
if skip_it(tool):
|
|
85
|
-
pytest.skip(f"{tool=} skipped, {tools_loaded=}")
|
|
86
|
-
return # skip/pass
|
|
87
|
-
chdir_remove_work_dir('../../lib')
|
|
88
|
-
rc = eda_wrap('multi', command, '--tool', tool, 'oclib_*arb')
|
|
89
|
-
print(f'{rc=}')
|
|
90
|
-
assert rc == 0
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@pytest.mark.parametrize("tool", list_of_elab_tools_cant_sim)
|
|
94
|
-
def test_elab_tool_cant_run_sim(tool):
|
|
95
|
-
'''Checks eda.check_command_handler_cls(...) so we don't fallback to a different tool'''
|
|
96
|
-
if skip_it(tool):
|
|
97
|
-
pytest.skip(f"{tool=}skipped, {tools_loaded=}")
|
|
98
|
-
return # skip/pass
|
|
99
|
-
chdir_remove_work_dir('../../lib')
|
|
100
|
-
|
|
101
|
-
# Calling this will have rc non-zero, but will also throw CommandSim NotImplementedError.
|
|
102
|
-
rc = 0
|
|
103
|
-
try:
|
|
104
|
-
rc = eda_wrap('sim', '--tool', tool, 'oclib_fifo')
|
|
105
|
-
print(f'{rc=}')
|
|
106
|
-
assert rc > 1
|
|
107
|
-
except NotImplementedError:
|
|
108
|
-
rc = 3
|
|
109
|
-
print(f'{rc=} (forced to 3 for NotImplementedError)')
|
|
110
|
-
assert rc > 1
|
opencos/tests/test_eda_synth.py
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
'''pytests for: eda [multi|tools-multi] synth [args] <target(s)>'''
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import shutil
|
|
5
|
-
|
|
6
|
-
import pytest
|
|
7
|
-
|
|
8
|
-
from opencos import eda, eda_tool_helper
|
|
9
|
-
from opencos.tests import helpers
|
|
10
|
-
from opencos.tests.helpers import Helpers
|
|
11
|
-
from opencos.utils.markup_helpers import yaml_safe_load
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
THISPATH = os.path.dirname(__file__)
|
|
15
|
-
|
|
16
|
-
def chdir_remove_work_dir(relpath):
|
|
17
|
-
'''Changes dir to relpath, removes the work directories (eda.work, eda.export*)'''
|
|
18
|
-
return helpers.chdir_remove_work_dir(THISPATH, relpath)
|
|
19
|
-
|
|
20
|
-
# Figure out what tools the system has available, without calling eda.main(..)
|
|
21
|
-
config, tools_loaded = eda_tool_helper.get_config_and_tools_loaded()
|
|
22
|
-
|
|
23
|
-
# list of tools we'd like to try:
|
|
24
|
-
list_of_synth_tools = [
|
|
25
|
-
'invio_yosys',
|
|
26
|
-
'tabbycad_yosys',
|
|
27
|
-
'slang_yosys'
|
|
28
|
-
]
|
|
29
|
-
|
|
30
|
-
list_of_elab_tools = [
|
|
31
|
-
'invio_yosys',
|
|
32
|
-
'slang_yosys'
|
|
33
|
-
]
|
|
34
|
-
|
|
35
|
-
def skip_it(tool, command) -> bool:
|
|
36
|
-
'''skip_it: returns True if we should skip due to lack of tool existence'''
|
|
37
|
-
return bool( tool not in tools_loaded or
|
|
38
|
-
(command == 'elab' and tool not in list_of_elab_tools) or
|
|
39
|
-
(command == 'synth' and tool not in list_of_synth_tools) )
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
@pytest.mark.parametrize("tool", list_of_synth_tools)
|
|
43
|
-
@pytest.mark.parametrize("command", ['elab', 'synth'])
|
|
44
|
-
class Tests:
|
|
45
|
-
'''skippable (via pytest parameters) class holder for pytest methods'''
|
|
46
|
-
|
|
47
|
-
def test_args_multi_synth_bad_target_should_fail(self, tool, command):
|
|
48
|
-
'''Tests: eda mulit <elab|synth>, and this test should fail.'''
|
|
49
|
-
if skip_it(tool, command):
|
|
50
|
-
pytest.skip(f"{tool=} {command=} skipped, {tools_loaded=}")
|
|
51
|
-
return # skip/pass
|
|
52
|
-
chdir_remove_work_dir('../../lib')
|
|
53
|
-
cmdlist = (f'multi {command} --debug --fail-if-no-targets --tool {tool}'
|
|
54
|
-
' target_doesnt_exist*').split()
|
|
55
|
-
rc = eda.main(*cmdlist)
|
|
56
|
-
print(f'{rc=}')
|
|
57
|
-
assert rc > 1
|
|
58
|
-
|
|
59
|
-
def test_args_multi_synth_oclib_fifos(self, tool, command):
|
|
60
|
-
'''This should be 4 jobs and takes ~15 seconds for synth.'''
|
|
61
|
-
if skip_it(tool, command):
|
|
62
|
-
pytest.skip(f"{tool=} {command=} skipped, {tools_loaded=}")
|
|
63
|
-
return # skip/pass
|
|
64
|
-
chdir_remove_work_dir('../../lib')
|
|
65
|
-
cmdlist = (f'multi {command} --debug --fail-if-no-targets --tool {tool}'
|
|
66
|
-
' --yosys-synth=synth_xilinx oclib_fifo*').split()
|
|
67
|
-
rc = eda.main(*cmdlist)
|
|
68
|
-
print(f'{rc=}')
|
|
69
|
-
assert rc == 0
|
|
70
|
-
|
|
71
|
-
def test_args_multi_synth_oclib_rams(self, tool, command):
|
|
72
|
-
'''This should be 4 jobs and takes ~15 seconds for synth.'''
|
|
73
|
-
if skip_it(tool, command):
|
|
74
|
-
pytest.skip(f"{tool=} {command=} skipped, {tools_loaded=}")
|
|
75
|
-
return # skip/pass
|
|
76
|
-
chdir_remove_work_dir('../../lib')
|
|
77
|
-
cmdlist = (f'multi {command} --debug --fail-if-no-targets --tool {tool}'
|
|
78
|
-
' --yosys-synth=synth_xilinx rams/oclib_ram*').split()
|
|
79
|
-
rc = eda.main(*cmdlist)
|
|
80
|
-
print(f'{rc=}')
|
|
81
|
-
assert rc == 0
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def vivado_has_xpms() -> bool:
|
|
85
|
-
'''Returns True if Vivado is installed and has visibility to XPMs'''
|
|
86
|
-
if 'vivado' not in tools_loaded:
|
|
87
|
-
return False
|
|
88
|
-
vivado_exe = shutil.which('vivado')
|
|
89
|
-
vivado_bin_path, _ = os.path.split(vivado_exe)
|
|
90
|
-
vivado_base_path, _ = os.path.split(vivado_bin_path) # strip bin/vivado
|
|
91
|
-
|
|
92
|
-
return os.path.exists(os.path.join(vivado_base_path, 'data', 'ip', 'xpm'))
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
@pytest.mark.skipif(
|
|
96
|
-
'slang_yosys' not in tools_loaded, reason="requires slang_yosys for synth"
|
|
97
|
-
)
|
|
98
|
-
class TestsSlangYosys(Helpers):
|
|
99
|
-
'''Tests that require tool=slang_yosys to be available'''
|
|
100
|
-
|
|
101
|
-
def test_sdc_file(self):
|
|
102
|
-
'''Test for 'eda synth' on oclib_fifo_with_sdc
|
|
103
|
-
|
|
104
|
-
This does not use the actual .sdc file, but it also shouldn't fail with
|
|
105
|
-
that file in the 'deps' list (CommandDesign should track it correctly)
|
|
106
|
-
'''
|
|
107
|
-
chdir_remove_work_dir('deps_files/test_sdc_files')
|
|
108
|
-
cmd_str = 'synth --tool=slang_yosys oclib_fifo_with_sdc'
|
|
109
|
-
rc = self.log_it(cmd_str, use_eda_wrap=False)
|
|
110
|
-
assert rc == 0
|
|
111
|
-
|
|
112
|
-
# Since vanilla yosys won't use the SDC file, let's at least confirm
|
|
113
|
-
# that EDA used it and tracked it:
|
|
114
|
-
eda_config_yml_path = os.path.join(
|
|
115
|
-
os.getcwd(), 'eda.work', 'oclib_fifo_with_sdc.synth', 'eda_output_config.yml'
|
|
116
|
-
)
|
|
117
|
-
data = yaml_safe_load(eda_config_yml_path)
|
|
118
|
-
assert 'files_sdc' in data
|
|
119
|
-
assert data['files_sdc']
|
|
120
|
-
assert data['files_sdc'][0].endswith('oclib_fifo_yosys.sdc')
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
@pytest.mark.skipif('vivado' not in tools_loaded, reason="requires vivado")
|
|
124
|
-
@pytest.mark.skipif(not vivado_has_xpms(), reason="requires install to have XPMs")
|
|
125
|
-
class TestsVivado(Helpers):
|
|
126
|
-
'''Tests that require tool=vivado with XPMs available for synthesis'''
|
|
127
|
-
|
|
128
|
-
def test_sdc_file(self):
|
|
129
|
-
'''Test for 'eda synth' on oclib_fifo_with_sdc
|
|
130
|
-
|
|
131
|
-
And check that the .sdc file was used and not the default generated .xdc
|
|
132
|
-
file
|
|
133
|
-
'''
|
|
134
|
-
chdir_remove_work_dir('deps_files/test_sdc_files')
|
|
135
|
-
cmd_str = 'synth --tool=vivado oclib_fifo_with_sdc'
|
|
136
|
-
rc = self.log_it(cmd_str, use_eda_wrap=False)
|
|
137
|
-
assert rc == 0
|
|
138
|
-
|
|
139
|
-
# apparently this doesn't get saved in the eda.log. That's not great,
|
|
140
|
-
# but we can check the <target>.synth.log file.
|
|
141
|
-
synth_log = os.path.join(
|
|
142
|
-
THISPATH, 'deps_files', 'test_sdc_files',
|
|
143
|
-
'eda.work', 'oclib_fifo_with_sdc.synth', 'oclib_fifo.synth.log'
|
|
144
|
-
)
|
|
145
|
-
sdc_lines = self.get_log_lines_with('.sdc', logfile=synth_log)
|
|
146
|
-
assert sdc_lines
|
|
147
|
-
for sdc_line in sdc_lines:
|
|
148
|
-
assert 'oclib_fifo_vivado.sdc' in sdc_line
|
|
149
|
-
assert 'test_sdc_files' in sdc_line
|
|
150
|
-
assert 'eda.work' not in sdc_line
|
opencos/tests/test_oc_cli.py
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
'''pytests for: ocli
|
|
2
|
-
|
|
3
|
-
If you want to run this, consider running from the root of opencos repo:
|
|
4
|
-
> pytest --verbose opencos/*/*.py
|
|
5
|
-
> python3 -m pytest --verbose opencos/*/*.py
|
|
6
|
-
which avoids using any pip installed opencos.eda
|
|
7
|
-
'''
|
|
8
|
-
|
|
9
|
-
from opencos.hw import oc_cli
|
|
10
|
-
|
|
11
|
-
def test_args_help():
|
|
12
|
-
'''simple test for: oc_cli --help'''
|
|
13
|
-
rc = oc_cli.main('--help')
|
|
14
|
-
print(f'{rc=}')
|
|
15
|
-
assert not rc
|
|
16
|
-
|
|
17
|
-
def test_parse_names():
|
|
18
|
-
'''simple test for: oc_cli.parse_names()'''
|
|
19
|
-
oc_cli.parse_names()
|
|
20
|
-
t = getattr(oc_cli, 'name_tables', None)
|
|
21
|
-
assert t is not None
|
|
22
|
-
assert len(t.keys()) == 7, f'Expect exactly 7 keys in t, {t=}'
|
|
23
|
-
entry = t.get('OC_VENDOR', None)
|
|
24
|
-
assert entry is not None
|
|
25
|
-
assert len(entry.keys()) >= 1
|
opencos/tests/test_tools.py
DELETED
|
@@ -1,404 +0,0 @@
|
|
|
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 shutil
|
|
7
|
-
import sys
|
|
8
|
-
import pytest
|
|
9
|
-
|
|
10
|
-
from opencos import eda_base
|
|
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 Helpers, eda_wrap, eda_wrap_is_sim_fail, config, tools_loaded
|
|
16
|
-
from opencos.utils.markup_helpers import yaml_safe_load
|
|
17
|
-
from opencos.utils import status_constants
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
THISPATH = os.path.dirname(__file__)
|
|
21
|
-
|
|
22
|
-
def chdir_remove_work_dir(relpath):
|
|
23
|
-
'''Changes dir to relpath, removes the work directories (eda.work, eda.export*)'''
|
|
24
|
-
return helpers.chdir_remove_work_dir(THISPATH, relpath)
|
|
25
|
-
|
|
26
|
-
def filter_tools(tools: list) -> list:
|
|
27
|
-
'''Given a list of tool l, filters to return a list of tools that are loaded'''
|
|
28
|
-
return [x for x in tools if x in tools_loaded]
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def test_tools_loaded():
|
|
32
|
-
'''Does not directly call 'eda.main' instead create a few Tool
|
|
33
|
-
|
|
34
|
-
class objects and confirm the versioning methods work.
|
|
35
|
-
'''
|
|
36
|
-
assert config
|
|
37
|
-
assert len(config.keys()) > 0
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
# It's possible we're running in some container or install that has no tools, for example,
|
|
41
|
-
# Windows.
|
|
42
|
-
if sys.platform.startswith('win') and \
|
|
43
|
-
not helpers.can_run_eda_command('elab', 'sim', cfg=config):
|
|
44
|
-
# Windows, no handlers for elab or sim:
|
|
45
|
-
pass
|
|
46
|
-
else:
|
|
47
|
-
basic_tools_available_via_path = any(shutil.which(x) for x in (
|
|
48
|
-
'verilator', 'iverilog', 'xsim', 'vsim', 'slang', 'yosys'
|
|
49
|
-
))
|
|
50
|
-
if basic_tools_available_via_path:
|
|
51
|
-
assert len(tools_loaded) > 0
|
|
52
|
-
|
|
53
|
-
def version_checker(
|
|
54
|
-
obj: eda_base.Tool, chk_str: str
|
|
55
|
-
) -> None:
|
|
56
|
-
assert obj.get_versions()
|
|
57
|
-
full_ver = obj.get_full_tool_and_versions()
|
|
58
|
-
assert chk_str in full_ver, f'{chk_str=} not in {full_ver=}'
|
|
59
|
-
ver_num = full_ver.rsplit(':', maxsplit=1)[-1]
|
|
60
|
-
if 'b' in ver_num:
|
|
61
|
-
ver_num = ver_num.split('b')[0]
|
|
62
|
-
if '.' in ver_num:
|
|
63
|
-
major_ver = ver_num.split('.')[0]
|
|
64
|
-
assert major_ver.isdigit(), (
|
|
65
|
-
f'Major version {major_ver=} is not a digit, from {full_ver=}'
|
|
66
|
-
)
|
|
67
|
-
assert float(major_ver) >= 0, (
|
|
68
|
-
f'{major_ver=} is not a valid version number, from {full_ver=}'
|
|
69
|
-
)
|
|
70
|
-
else:
|
|
71
|
-
assert float(ver_num), f'{ver_num=} is not a float, from {full_ver=}'
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
# Do some very crude checks on the eda.Tool methods, and make
|
|
75
|
-
# sure versions work for Verilator and Vivado:
|
|
76
|
-
if 'verilator' in tools_loaded:
|
|
77
|
-
my_tool = ToolVerilator(config={})
|
|
78
|
-
version_checker(obj=my_tool, chk_str='verilator:')
|
|
79
|
-
|
|
80
|
-
if 'vivado' in tools_loaded:
|
|
81
|
-
my_tool = ToolVivado(config={})
|
|
82
|
-
version_checker(obj=my_tool, chk_str='vivado:')
|
|
83
|
-
|
|
84
|
-
if 'cocotb' in tools_loaded:
|
|
85
|
-
my_tool = ToolCocotb(config={})
|
|
86
|
-
version_checker(obj=my_tool, chk_str='cocotb:')
|
|
87
|
-
|
|
88
|
-
# Run these on simulation tools.
|
|
89
|
-
list_of_commands = [
|
|
90
|
-
'sim',
|
|
91
|
-
'elab'
|
|
92
|
-
]
|
|
93
|
-
|
|
94
|
-
list_of_tools = [
|
|
95
|
-
'iverilog',
|
|
96
|
-
'verilator',
|
|
97
|
-
'vivado',
|
|
98
|
-
'modelsim_ase',
|
|
99
|
-
'questa_fse',
|
|
100
|
-
]
|
|
101
|
-
|
|
102
|
-
list_of_deps_targets = [
|
|
103
|
-
('tb_no_errs', True), # target:str, sim_expect_pass:bool (sim only, all elab should pass)
|
|
104
|
-
('tb_dollar_fatal', False),
|
|
105
|
-
('tb_dollar_err', False),
|
|
106
|
-
]
|
|
107
|
-
|
|
108
|
-
list_of_added_sim_args = [
|
|
109
|
-
'',
|
|
110
|
-
'--gui --test-mode',
|
|
111
|
-
]
|
|
112
|
-
|
|
113
|
-
list_of_loaded_tools = filter_tools(list_of_tools)
|
|
114
|
-
|
|
115
|
-
cannot_use_cocotb = 'cocotb' not in tools_loaded or \
|
|
116
|
-
('iverilog' not in tools_loaded and \
|
|
117
|
-
'verilator' not in tools_loaded)
|
|
118
|
-
CANNOT_USE_COCOTB_REASON = 'requires cocotb in tools_loaded, and one of (iverilog, verilator) too'
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
class TestSimElabTools(Helpers):
|
|
122
|
-
'''Tests for eda sim|elab for various tools with various args'''
|
|
123
|
-
|
|
124
|
-
DEFAULT_DIR = os.path.join(THISPATH, 'deps_files', 'test_err_fatal')
|
|
125
|
-
|
|
126
|
-
@pytest.mark.parametrize("command", list_of_commands)
|
|
127
|
-
@pytest.mark.parametrize("tool", list_of_loaded_tools)
|
|
128
|
-
@pytest.mark.parametrize("target,sim_expect_pass", list_of_deps_targets)
|
|
129
|
-
@pytest.mark.parametrize("added_sim_args_str", list_of_added_sim_args)
|
|
130
|
-
def test_pass_or_fail(
|
|
131
|
-
self, command, tool, target, sim_expect_pass, added_sim_args_str
|
|
132
|
-
):
|
|
133
|
-
'''tests that: eda <sim|elab> --tool <parameter-tool> <parameter-args> <parameter-target>
|
|
134
|
-
|
|
135
|
-
will correctly pass or fail depending on if it is supported or not.
|
|
136
|
-
|
|
137
|
-
Also tests for: non-gui, or --gui --test-mode (runs non-gui, but most python args will
|
|
138
|
-
be for --gui mode, signal logging, etc).
|
|
139
|
-
'''
|
|
140
|
-
added_args_str = ''
|
|
141
|
-
if command == 'sim':
|
|
142
|
-
added_args_str = added_sim_args_str
|
|
143
|
-
|
|
144
|
-
rc = self.log_it(f'{command} --tool {tool} {added_args_str} {target}')
|
|
145
|
-
print(f'{rc=}')
|
|
146
|
-
tool_error_count_lines = self.get_log_lines_with('tool errors')
|
|
147
|
-
if command != 'sim' or sim_expect_pass:
|
|
148
|
-
# command='elab' should pass.
|
|
149
|
-
assert rc == 0
|
|
150
|
-
assert tool_error_count_lines
|
|
151
|
-
assert all('tool warnings' in line for line in tool_error_count_lines)
|
|
152
|
-
assert all(' 0 tool errors' in line for line in tool_error_count_lines)
|
|
153
|
-
|
|
154
|
-
else:
|
|
155
|
-
assert eda_wrap_is_sim_fail(rc)
|
|
156
|
-
assert tool_error_count_lines
|
|
157
|
-
assert all('tool warnings' in line for line in tool_error_count_lines)
|
|
158
|
-
# May or may not have reported tool errors.
|
|
159
|
-
assert all('tool errors' in line for line in tool_error_count_lines)
|
|
160
|
-
# The final line of tool warnings/errors should have > 0 tool errors,
|
|
161
|
-
# since we were checking SV $error and $fatal
|
|
162
|
-
assert ' 0 tool errors' not in tool_error_count_lines[-1]
|
|
163
|
-
# The line should end with ' X tool errors'
|
|
164
|
-
parts = tool_error_count_lines[-1].split()
|
|
165
|
-
assert parts[-3].isdigit()
|
|
166
|
-
assert int(parts[-3]) in (1, 2, 3) # we should have at least 1, but some tools dup.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
@pytest.mark.skipif('vivado' not in tools_loaded, reason="requires vivado")
|
|
170
|
-
def test_vivado_tool_defines():
|
|
171
|
-
'''This test attempts to confirm that the following class inheritance works:
|
|
172
|
-
|
|
173
|
-
Command <- CommandDesign <- CommandSim <- CommandSimVivado <- CommandElabVivado
|
|
174
|
-
|
|
175
|
-
in particular that CommandElabVivado(CommandSimVivado, ToolVivado) has the
|
|
176
|
-
correct ToolVivado.set_tool_defines() method, and that no other parent Command
|
|
177
|
-
class has overriden it to defeat the defines that should be set.
|
|
178
|
-
|
|
179
|
-
We also run with an added dependency (lib_ultrascale_plus_defines) to check that
|
|
180
|
-
defines are set as expected.
|
|
181
|
-
'''
|
|
182
|
-
|
|
183
|
-
chdir_remove_work_dir('../../lib')
|
|
184
|
-
rc = eda_wrap(
|
|
185
|
-
'elab', '--tool', 'vivado', 'third_party/vendors/xilinx/lib_ultrascale_plus_defines',
|
|
186
|
-
'oclib_fifo'
|
|
187
|
-
)
|
|
188
|
-
assert rc == 0
|
|
189
|
-
|
|
190
|
-
# Confirm that args and defines we expected to be set are set.
|
|
191
|
-
eda_config_yml_path = os.path.join(
|
|
192
|
-
os.getcwd(), 'eda.work', 'oclib_fifo.elab', 'eda_output_config.yml'
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
data = yaml_safe_load(eda_config_yml_path)
|
|
196
|
-
assert 'args' in data
|
|
197
|
-
assert data['args'].get('top', '') == 'oclib_fifo'
|
|
198
|
-
assert 'config' in data
|
|
199
|
-
assert 'eda_original_args' in data['config']
|
|
200
|
-
assert 'oclib_fifo' in data['config']['eda_original_args']
|
|
201
|
-
assert data.get('target', '') == 'oclib_fifo'
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
# This checks opencos.tools.vivado.ToolVivado.set_tool_defines():
|
|
205
|
-
# We ran with --xilinx, so we expect certain defines to be set, others not to be set.
|
|
206
|
-
assert 'defines' in data
|
|
207
|
-
|
|
208
|
-
assert 'OC_TOOL_VIVADO' in data['defines']
|
|
209
|
-
assert 'OC_LIBRARY' in data['defines']
|
|
210
|
-
assert 'OC_LIBRARY_ULTRASCALE_PLUS' in data['defines']
|
|
211
|
-
|
|
212
|
-
assert 'OC_LIBRARY_BEHAVIORAL' not in data['defines']
|
|
213
|
-
assert 'VERILATOR' not in data['defines']
|
|
214
|
-
assert 'SYNTHESIS' not in data['defines']
|
|
215
|
-
|
|
216
|
-
assert data['defines']['OC_LIBRARY'] == '1'
|
|
217
|
-
assert data['defines']['OC_LIBRARY_ULTRASCALE_PLUS'] is None # key present, no value
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
class TestCocotb:
|
|
221
|
-
'''Namespace class for cocotb tests'''
|
|
222
|
-
|
|
223
|
-
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
224
|
-
def test_cocotb_tool_defines(self):
|
|
225
|
-
'''Test cocotb tool defines, configs, and integration.'''
|
|
226
|
-
|
|
227
|
-
chdir_remove_work_dir('../../examples/cocotb')
|
|
228
|
-
|
|
229
|
-
# Test 0: Using eda multi:
|
|
230
|
-
rc = eda_wrap('multi', 'sim', '--tool=cocotb', '*test')
|
|
231
|
-
assert rc == 0
|
|
232
|
-
|
|
233
|
-
# Test 1: basic cocotb sim command with Python runner (default)
|
|
234
|
-
rc = eda_wrap('sim', '--tool', 'cocotb', 'cocotb_counter_test')
|
|
235
|
-
assert rc == 0
|
|
236
|
-
|
|
237
|
-
# Test 2: cocotb works with different simulators/configurations
|
|
238
|
-
rc = eda_wrap('sim', '--tool', 'cocotb', 'cocotb_counter_waves_test')
|
|
239
|
-
assert rc == 0
|
|
240
|
-
|
|
241
|
-
# Test 3: Makefile approach
|
|
242
|
-
rc = eda_wrap('sim', '--tool', 'cocotb', 'cocotb_counter_makefile_test')
|
|
243
|
-
assert rc == 0
|
|
244
|
-
|
|
245
|
-
# Test 4: cocotb-specific defines are set correctly
|
|
246
|
-
eda_config_yml_path = os.path.join(
|
|
247
|
-
os.getcwd(), 'eda.work', 'cocotb_counter_test.sim', 'eda_output_config.yml'
|
|
248
|
-
)
|
|
249
|
-
|
|
250
|
-
data = yaml_safe_load(eda_config_yml_path)
|
|
251
|
-
assert 'args' in data
|
|
252
|
-
assert data['args'].get('top', '') == 'counter'
|
|
253
|
-
assert 'config' in data
|
|
254
|
-
assert 'eda_original_args' in data['config']
|
|
255
|
-
assert 'cocotb_counter_test' in data['config']['eda_original_args'] or \
|
|
256
|
-
'./cocotb_counter_test' in data['config']['eda_original_args']
|
|
257
|
-
assert data.get('target', '') == 'cocotb_counter_test'
|
|
258
|
-
|
|
259
|
-
assert 'defines' in data
|
|
260
|
-
assert 'OC_TOOL_COCOTB' in data['defines']
|
|
261
|
-
assert 'SIMULATION' in data['defines']
|
|
262
|
-
assert 'COCOTB' in data['defines']
|
|
263
|
-
|
|
264
|
-
assert data['defines']['SIMULATION'] == 1
|
|
265
|
-
assert data['defines']['COCOTB'] == 1
|
|
266
|
-
assert data['defines']['OC_TOOL_COCOTB'] is None # key present, no value
|
|
267
|
-
|
|
268
|
-
assert 'VERILATOR' not in data['defines']
|
|
269
|
-
assert 'SYNTHESIS' not in data['defines']
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
@pytest.mark.parametrize("cocotb_simulator", ['verilator', 'iverilog'])
|
|
274
|
-
@pytest.mark.parametrize("waves_arg", ["", "--waves"])
|
|
275
|
-
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
276
|
-
def test_cocotb_different_simulators(self, cocotb_simulator, waves_arg):
|
|
277
|
-
'''Test cocotb with different simulator configurations.'''
|
|
278
|
-
|
|
279
|
-
if cocotb_simulator not in tools_loaded:
|
|
280
|
-
pytest.skip(f"{cocotb_simulator=} skipped, {tools_loaded=}")
|
|
281
|
-
return #skip/bypass
|
|
282
|
-
|
|
283
|
-
chdir_remove_work_dir('../../examples/cocotb')
|
|
284
|
-
|
|
285
|
-
rc = eda_wrap(
|
|
286
|
-
'sim', '--tool', 'cocotb',
|
|
287
|
-
f'--cocotb-simulator={cocotb_simulator}',
|
|
288
|
-
waves_arg,
|
|
289
|
-
'cocotb_counter_test',
|
|
290
|
-
)
|
|
291
|
-
assert rc == 0
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
296
|
-
def test_cocotb_tool_instantiation(self):
|
|
297
|
-
'''Test that ToolCocotb can be instantiated and has correct properties.'''
|
|
298
|
-
|
|
299
|
-
tool = ToolCocotb(config={})
|
|
300
|
-
|
|
301
|
-
# version detection works
|
|
302
|
-
version = tool.get_versions()
|
|
303
|
-
assert version, "Should return a non-empty version string"
|
|
304
|
-
assert isinstance(version, str)
|
|
305
|
-
|
|
306
|
-
# tool defines
|
|
307
|
-
tool.set_tool_defines()
|
|
308
|
-
defines = tool.defines
|
|
309
|
-
assert 'SIMULATION' in defines
|
|
310
|
-
assert 'COCOTB' in defines
|
|
311
|
-
assert 'OC_TOOL_COCOTB' in defines
|
|
312
|
-
assert defines['SIMULATION'] == 1
|
|
313
|
-
assert defines['COCOTB'] == 1
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
318
|
-
def test_cocotb_failure_cases(self):
|
|
319
|
-
'''Test cocotb failure scenarios to ensure proper error handling.'''
|
|
320
|
-
|
|
321
|
-
chdir_remove_work_dir('../../examples/cocotb')
|
|
322
|
-
|
|
323
|
-
# Test 1: missing test files should fail gracefully
|
|
324
|
-
rc = eda_wrap('sim', '--tool', 'cocotb', 'counter') # Just HDL, no test files
|
|
325
|
-
assert rc == status_constants.EDA_DEPS_TARGET_NOT_FOUND, \
|
|
326
|
-
"Should fail when no cocotb test files are found"
|
|
327
|
-
|
|
328
|
-
# Test 2: non-existent target should fail
|
|
329
|
-
rc = eda_wrap('sim', '--tool', 'cocotb', 'nonexistent_target')
|
|
330
|
-
assert rc in (
|
|
331
|
-
status_constants.EDA_DEPS_TARGET_NOT_FOUND,
|
|
332
|
-
# b/c we run eda_wrap, eda.main will continue to run after first error.
|
|
333
|
-
status_constants.EDA_COMMAND_MISSING_TOP
|
|
334
|
-
), "Should fail for non-existent target"
|
|
335
|
-
|
|
336
|
-
# Test 3: invalid cocotb test module should fail
|
|
337
|
-
rc = eda_wrap(
|
|
338
|
-
'sim', '--tool', 'cocotb',
|
|
339
|
-
'--cocotb-test-module=nonexistent_test',
|
|
340
|
-
'cocotb_counter_test',
|
|
341
|
-
)
|
|
342
|
-
assert eda_wrap_is_sim_fail(rc), \
|
|
343
|
-
f"Should fail with invalid test module {rc=}"
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
347
|
-
def test_cocotb_missing_dependencies(self):
|
|
348
|
-
'''Test cocotb behavior when dependencies are missing.'''
|
|
349
|
-
|
|
350
|
-
# Test missing cocotb installation (simulate by checking error handling)
|
|
351
|
-
tool = ToolCocotb(config={})
|
|
352
|
-
version = tool.get_versions()
|
|
353
|
-
assert version, "Should return version when cocotb is properly installed"
|
|
354
|
-
|
|
355
|
-
# Test tool defines are properly set even with minimal config
|
|
356
|
-
tool.set_tool_defines()
|
|
357
|
-
defines = tool.defines
|
|
358
|
-
assert 'SIMULATION' in defines
|
|
359
|
-
assert 'COCOTB' in defines
|
|
360
|
-
assert 'OC_TOOL_COCOTB' in defines
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
364
|
-
def test_cocotb_invalid_simulator(self):
|
|
365
|
-
'''Test cocotb with invalid simulator configuration.'''
|
|
366
|
-
|
|
367
|
-
chdir_remove_work_dir('../../examples/cocotb')
|
|
368
|
-
|
|
369
|
-
rc = eda_wrap(
|
|
370
|
-
'sim', '--tool', 'cocotb',
|
|
371
|
-
'--cocotb-simulator=invalid_sim',
|
|
372
|
-
'cocotb_counter_test',
|
|
373
|
-
)
|
|
374
|
-
assert eda_wrap_is_sim_fail(rc), \
|
|
375
|
-
f"Should fail with invalid simulator {rc=}"
|
|
376
|
-
|
|
377
|
-
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
378
|
-
def test_cocotb_malformed_hdl(self):
|
|
379
|
-
'''Test cocotb with malformed HDL files.'''
|
|
380
|
-
|
|
381
|
-
chdir_remove_work_dir('../../lib/tests')
|
|
382
|
-
|
|
383
|
-
# Test with a target that has syntax errors - should fail during compilation
|
|
384
|
-
rc = eda_wrap(
|
|
385
|
-
'sim', '--tool', 'cocotb',
|
|
386
|
-
'--cocotb-test-module=test_counter',
|
|
387
|
-
'tb_dollar_fatal',
|
|
388
|
-
)
|
|
389
|
-
|
|
390
|
-
# eda_wrap may continue to errors beyond normal sim fails:
|
|
391
|
-
assert eda_wrap_is_sim_fail(rc) or \
|
|
392
|
-
f"Should fail with malformed HDL or failing test assertions {rc=}"
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
396
|
-
def test_cocotb_test_failures(self):
|
|
397
|
-
'''Test that cocotb properly reports test failures.'''
|
|
398
|
-
|
|
399
|
-
chdir_remove_work_dir('../../examples/cocotb')
|
|
400
|
-
|
|
401
|
-
# Intentionally failing cocotb tests
|
|
402
|
-
rc = eda_wrap('sim', '--tool', 'cocotb', 'cocotb_failure_test')
|
|
403
|
-
assert eda_wrap_is_sim_fail(rc), \
|
|
404
|
-
f"Should fail when cocotb tests contain assertion failures {rc=}"
|
|
File without changes
|
|
File without changes
|