opencos-eda 0.2.52__py3-none-any.whl → 0.2.54__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/__init__.py +2 -0
- opencos/commands/build.py +1 -1
- opencos/commands/deps_help.py +259 -0
- opencos/commands/export.py +1 -1
- opencos/commands/flist.py +4 -1
- opencos/commands/lec.py +1 -1
- opencos/commands/open.py +2 -0
- opencos/commands/proj.py +1 -1
- opencos/commands/shell.py +1 -1
- opencos/commands/sim.py +76 -8
- opencos/commands/synth.py +1 -1
- opencos/commands/upload.py +3 -0
- opencos/commands/waves.py +1 -0
- opencos/deps/defaults.py +1 -0
- opencos/deps/deps_file.py +30 -4
- opencos/deps/deps_processor.py +72 -2
- opencos/deps_schema.py +3 -0
- opencos/eda.py +50 -26
- opencos/eda_base.py +177 -33
- opencos/eda_config.py +1 -1
- opencos/eda_config_defaults.yml +49 -3
- opencos/eda_extract_targets.py +1 -58
- opencos/tests/helpers.py +16 -0
- opencos/tests/test_eda.py +14 -3
- opencos/tests/test_tools.py +159 -132
- opencos/tools/cocotb.py +15 -14
- opencos/tools/iverilog.py +4 -24
- opencos/tools/modelsim_ase.py +70 -57
- opencos/tools/quartus.py +680 -0
- opencos/tools/questa.py +158 -90
- opencos/tools/questa_fse.py +10 -0
- opencos/tools/riviera.py +1 -0
- opencos/tools/verilator.py +9 -15
- opencos/tools/vivado.py +30 -23
- opencos/util.py +89 -15
- opencos/utils/status_constants.py +1 -0
- opencos/utils/str_helpers.py +85 -0
- {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/METADATA +1 -1
- {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/RECORD +44 -42
- {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/WHEEL +0 -0
- {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/top_level.txt +0 -0
opencos/tests/test_eda.py
CHANGED
|
@@ -170,7 +170,7 @@ class TestsRequiresVerilator( # pylint: disable=too-many-public-methods
|
|
|
170
170
|
assert res.stderr == b''
|
|
171
171
|
|
|
172
172
|
res = subprocess.run(
|
|
173
|
-
[ './
|
|
173
|
+
[ './simulate.sh' ], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
174
174
|
check=True
|
|
175
175
|
)
|
|
176
176
|
rc = res.returncode
|
|
@@ -589,9 +589,15 @@ class TestDepsResolveErrorMessages(Helpers):
|
|
|
589
589
|
assert rc > 1
|
|
590
590
|
assert self.is_in_log(
|
|
591
591
|
"Trying to resolve command-line target=./nope_target0: was not",
|
|
592
|
-
"found in deps_file=./DEPS.yml
|
|
592
|
+
"found in deps_file=./DEPS.yml",
|
|
593
593
|
windows_path_support=True
|
|
594
594
|
)
|
|
595
|
+
assert self.is_in_log(
|
|
596
|
+
"Targets available in deps_file=./DEPS.yml:",
|
|
597
|
+
windows_path_support=True
|
|
598
|
+
)
|
|
599
|
+
assert self.is_in_log(" foo")
|
|
600
|
+
|
|
595
601
|
|
|
596
602
|
def test_cmd_line_bad1(self):
|
|
597
603
|
'''EDA calling a non-existent target in DEPS file, with file that exists.'''
|
|
@@ -600,9 +606,14 @@ class TestDepsResolveErrorMessages(Helpers):
|
|
|
600
606
|
assert rc > 1
|
|
601
607
|
assert self.is_in_log(
|
|
602
608
|
"Trying to resolve command-line target=./nope_target1: was not",
|
|
603
|
-
"found in deps_file=./DEPS.yml
|
|
609
|
+
"found in deps_file=./DEPS.yml",
|
|
610
|
+
windows_path_support=True
|
|
611
|
+
)
|
|
612
|
+
assert self.is_in_log(
|
|
613
|
+
"Targets available in deps_file=./DEPS.yml:",
|
|
604
614
|
windows_path_support=True
|
|
605
615
|
)
|
|
616
|
+
assert self.is_in_log(" foo")
|
|
606
617
|
|
|
607
618
|
def test_cmd_line_bad2(self):
|
|
608
619
|
'''EDA calling a non-existent file w/out DEPS'''
|
opencos/tests/test_tools.py
CHANGED
|
@@ -12,8 +12,9 @@ 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
|
|
15
|
+
from opencos.tests.helpers import eda_wrap, eda_wrap_is_sim_fail
|
|
16
16
|
from opencos.utils.markup_helpers import yaml_safe_load
|
|
17
|
+
from opencos.utils import status_constants
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
thispath = os.path.dirname(__file__)
|
|
@@ -97,6 +98,11 @@ list_of_deps_targets = [
|
|
|
97
98
|
('tb_dollar_err', False),
|
|
98
99
|
]
|
|
99
100
|
|
|
101
|
+
list_of_added_sim_args = [
|
|
102
|
+
'',
|
|
103
|
+
'--gui --test-mode',
|
|
104
|
+
]
|
|
105
|
+
|
|
100
106
|
cannot_use_cocotb = 'cocotb' not in tools_loaded or \
|
|
101
107
|
('iverilog' not in tools_loaded and \
|
|
102
108
|
'verilator' not in tools_loaded)
|
|
@@ -105,24 +111,32 @@ CANNOT_USE_COCOTB_REASON = 'requires cocotb in tools_loaded, and one of (iverilo
|
|
|
105
111
|
@pytest.mark.parametrize("command", list_of_commands)
|
|
106
112
|
@pytest.mark.parametrize("tool", list_of_tools)
|
|
107
113
|
@pytest.mark.parametrize("target,sim_expect_pass", list_of_deps_targets)
|
|
108
|
-
|
|
109
|
-
|
|
114
|
+
@pytest.mark.parametrize("added_sim_args_str", list_of_added_sim_args)
|
|
115
|
+
def test_sim_elab_tools_pass_or_fail(command, tool, target, sim_expect_pass, added_sim_args_str):
|
|
116
|
+
'''tests that: eda <sim|elab> --tool <parameter-tool> <parameter-args> <parameter-target>
|
|
110
117
|
|
|
111
118
|
will correctly pass or fail depending on if it is supported or not.
|
|
119
|
+
|
|
120
|
+
Also tests for: non-gui, or --gui --test-mode (runs non-gui, but most python args will
|
|
121
|
+
be for --gui mode, signal logging, etc).
|
|
112
122
|
'''
|
|
113
123
|
if tool not in tools_loaded:
|
|
114
124
|
pytest.skip(f"{tool=} skipped, {tools_loaded=}")
|
|
115
125
|
return # skip/pass
|
|
116
126
|
|
|
127
|
+
added_args = []
|
|
128
|
+
if command == 'sim':
|
|
129
|
+
added_args = added_sim_args_str.split()
|
|
130
|
+
|
|
117
131
|
relative_dir = "deps_files/test_err_fatal"
|
|
118
132
|
os.chdir(os.path.join(thispath, relative_dir))
|
|
119
|
-
rc = eda.main(command, '--tool', tool, target)
|
|
133
|
+
rc = eda.main(command, '--tool', tool, *(added_args), target)
|
|
120
134
|
print(f'{rc=}')
|
|
121
135
|
if command != 'sim' or sim_expect_pass:
|
|
122
136
|
# command='elab' should pass.
|
|
123
137
|
assert rc == 0
|
|
124
138
|
else:
|
|
125
|
-
assert rc
|
|
139
|
+
assert eda_wrap_is_sim_fail(rc)
|
|
126
140
|
|
|
127
141
|
|
|
128
142
|
@pytest.mark.skipif('vivado' not in tools_loaded, reason="requires vivado")
|
|
@@ -176,175 +190,188 @@ def test_vivado_tool_defines():
|
|
|
176
190
|
assert data['defines']['OC_LIBRARY_ULTRASCALE_PLUS'] is None # key present, no value
|
|
177
191
|
|
|
178
192
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
'''Test cocotb tool defines, configs, and integration.'''
|
|
193
|
+
class TestCocotb:
|
|
194
|
+
'''Namespace class for cocotb tests'''
|
|
182
195
|
|
|
183
|
-
|
|
196
|
+
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
197
|
+
def test_cocotb_tool_defines(self):
|
|
198
|
+
'''Test cocotb tool defines, configs, and integration.'''
|
|
184
199
|
|
|
185
|
-
|
|
186
|
-
rc = eda_wrap('multi', 'sim', '--tool=cocotb', '*test')
|
|
187
|
-
assert rc == 0
|
|
200
|
+
chdir_remove_work_dir('../../examples/cocotb')
|
|
188
201
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
202
|
+
# Test 0: Using eda multi:
|
|
203
|
+
rc = eda_wrap('multi', 'sim', '--tool=cocotb', '*test')
|
|
204
|
+
assert rc == 0
|
|
192
205
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
206
|
+
# Test 1: basic cocotb sim command with Python runner (default)
|
|
207
|
+
rc = eda_wrap('sim', '--tool', 'cocotb', 'cocotb_counter_test')
|
|
208
|
+
assert rc == 0
|
|
196
209
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
210
|
+
# Test 2: cocotb works with different simulators/configurations
|
|
211
|
+
rc = eda_wrap('sim', '--tool', 'cocotb', 'cocotb_counter_waves_test')
|
|
212
|
+
assert rc == 0
|
|
200
213
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
)
|
|
214
|
+
# Test 3: Makefile approach
|
|
215
|
+
rc = eda_wrap('sim', '--tool', 'cocotb', 'cocotb_counter_makefile_test')
|
|
216
|
+
assert rc == 0
|
|
205
217
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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'
|
|
218
|
+
# Test 4: cocotb-specific defines are set correctly
|
|
219
|
+
eda_config_yml_path = os.path.join(
|
|
220
|
+
os.getcwd(), 'eda.work', 'cocotb_counter_test.sim', 'eda_output_config.yml'
|
|
221
|
+
)
|
|
214
222
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
223
|
+
data = yaml_safe_load(eda_config_yml_path)
|
|
224
|
+
assert 'args' in data
|
|
225
|
+
assert data['args'].get('top', '') == 'counter'
|
|
226
|
+
assert 'config' in data
|
|
227
|
+
assert 'eda_original_args' in data['config']
|
|
228
|
+
assert 'cocotb_counter_test' in data['config']['eda_original_args'] or \
|
|
229
|
+
'./cocotb_counter_test' in data['config']['eda_original_args']
|
|
230
|
+
assert data.get('target', '') == 'cocotb_counter_test'
|
|
219
231
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
232
|
+
assert 'defines' in data
|
|
233
|
+
assert 'OC_TOOL_COCOTB' in data['defines']
|
|
234
|
+
assert 'SIMULATION' in data['defines']
|
|
235
|
+
assert 'COCOTB' in data['defines']
|
|
223
236
|
|
|
224
|
-
|
|
225
|
-
|
|
237
|
+
assert data['defines']['SIMULATION'] == 1
|
|
238
|
+
assert data['defines']['COCOTB'] == 1
|
|
239
|
+
assert data['defines']['OC_TOOL_COCOTB'] is None # key present, no value
|
|
226
240
|
|
|
241
|
+
assert 'VERILATOR' not in data['defines']
|
|
242
|
+
assert 'SYNTHESIS' not in data['defines']
|
|
227
243
|
|
|
228
244
|
|
|
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
245
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
246
|
+
@pytest.mark.parametrize("cocotb_simulator", ['verilator', 'iverilog'])
|
|
247
|
+
@pytest.mark.parametrize("waves_arg", ["", "--waves"])
|
|
248
|
+
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
249
|
+
def test_cocotb_different_simulators(self, cocotb_simulator, waves_arg):
|
|
250
|
+
'''Test cocotb with different simulator configurations.'''
|
|
238
251
|
|
|
239
|
-
|
|
252
|
+
if cocotb_simulator not in tools_loaded:
|
|
253
|
+
pytest.skip(f"{cocotb_simulator=} skipped, {tools_loaded=}")
|
|
254
|
+
return #skip/bypass
|
|
240
255
|
|
|
241
|
-
|
|
242
|
-
'sim', '--tool', 'cocotb',
|
|
243
|
-
f'--cocotb-simulator={cocotb_simulator}',
|
|
244
|
-
waves_arg,
|
|
245
|
-
'cocotb_counter_test',
|
|
246
|
-
)
|
|
247
|
-
assert rc == 0
|
|
256
|
+
chdir_remove_work_dir('../../examples/cocotb')
|
|
248
257
|
|
|
258
|
+
rc = eda_wrap(
|
|
259
|
+
'sim', '--tool', 'cocotb',
|
|
260
|
+
f'--cocotb-simulator={cocotb_simulator}',
|
|
261
|
+
waves_arg,
|
|
262
|
+
'cocotb_counter_test',
|
|
263
|
+
)
|
|
264
|
+
assert rc == 0
|
|
249
265
|
|
|
250
266
|
|
|
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
267
|
|
|
255
|
-
|
|
268
|
+
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
269
|
+
def test_cocotb_tool_instantiation(self):
|
|
270
|
+
'''Test that ToolCocotb can be instantiated and has correct properties.'''
|
|
256
271
|
|
|
257
|
-
|
|
258
|
-
version = tool.get_versions()
|
|
259
|
-
assert version, "Should return a non-empty version string"
|
|
260
|
-
assert isinstance(version, str)
|
|
272
|
+
tool = ToolCocotb(config={})
|
|
261
273
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
assert 'COCOTB' in defines
|
|
267
|
-
assert 'OC_TOOL_COCOTB' in defines
|
|
268
|
-
assert defines['SIMULATION'] == 1
|
|
269
|
-
assert defines['COCOTB'] == 1
|
|
274
|
+
# version detection works
|
|
275
|
+
version = tool.get_versions()
|
|
276
|
+
assert version, "Should return a non-empty version string"
|
|
277
|
+
assert isinstance(version, str)
|
|
270
278
|
|
|
279
|
+
# tool defines
|
|
280
|
+
tool.set_tool_defines()
|
|
281
|
+
defines = tool.defines
|
|
282
|
+
assert 'SIMULATION' in defines
|
|
283
|
+
assert 'COCOTB' in defines
|
|
284
|
+
assert 'OC_TOOL_COCOTB' in defines
|
|
285
|
+
assert defines['SIMULATION'] == 1
|
|
286
|
+
assert defines['COCOTB'] == 1
|
|
271
287
|
|
|
272
288
|
|
|
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
289
|
|
|
277
|
-
|
|
290
|
+
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
291
|
+
def test_cocotb_failure_cases(self):
|
|
292
|
+
'''Test cocotb failure scenarios to ensure proper error handling.'''
|
|
278
293
|
|
|
279
|
-
|
|
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"
|
|
294
|
+
chdir_remove_work_dir('../../examples/cocotb')
|
|
282
295
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
296
|
+
# Test 1: missing test files should fail gracefully
|
|
297
|
+
rc = eda_wrap('sim', '--tool', 'cocotb', 'counter') # Just HDL, no test files
|
|
298
|
+
assert rc == status_constants.EDA_DEPS_TARGET_NOT_FOUND, \
|
|
299
|
+
"Should fail when no cocotb test files are found"
|
|
286
300
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
301
|
+
# Test 2: non-existent target should fail
|
|
302
|
+
rc = eda_wrap('sim', '--tool', 'cocotb', 'nonexistent_target')
|
|
303
|
+
assert rc in (
|
|
304
|
+
status_constants.EDA_DEPS_TARGET_NOT_FOUND,
|
|
305
|
+
# b/c we run eda_wrap, eda.main will continue to run after first error.
|
|
306
|
+
status_constants.EDA_COMMAND_MISSING_TOP
|
|
307
|
+
), "Should fail for non-existent target"
|
|
294
308
|
|
|
309
|
+
# Test 3: invalid cocotb test module should fail
|
|
310
|
+
rc = eda_wrap(
|
|
311
|
+
'sim', '--tool', 'cocotb',
|
|
312
|
+
'--cocotb-test-module=nonexistent_test',
|
|
313
|
+
'cocotb_counter_test',
|
|
314
|
+
)
|
|
315
|
+
assert eda_wrap_is_sim_fail(rc), \
|
|
316
|
+
f"Should fail with invalid test module {rc=}"
|
|
295
317
|
|
|
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
318
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
assert version, "Should return version when cocotb is properly installed"
|
|
319
|
+
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
320
|
+
def test_cocotb_missing_dependencies(self):
|
|
321
|
+
'''Test cocotb behavior when dependencies are missing.'''
|
|
304
322
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
assert 'COCOTB' in defines
|
|
310
|
-
assert 'OC_TOOL_COCOTB' in defines
|
|
323
|
+
# Test missing cocotb installation (simulate by checking error handling)
|
|
324
|
+
tool = ToolCocotb(config={})
|
|
325
|
+
version = tool.get_versions()
|
|
326
|
+
assert version, "Should return version when cocotb is properly installed"
|
|
311
327
|
|
|
328
|
+
# Test tool defines are properly set even with minimal config
|
|
329
|
+
tool.set_tool_defines()
|
|
330
|
+
defines = tool.defines
|
|
331
|
+
assert 'SIMULATION' in defines
|
|
332
|
+
assert 'COCOTB' in defines
|
|
333
|
+
assert 'OC_TOOL_COCOTB' in defines
|
|
312
334
|
|
|
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
335
|
|
|
317
|
-
|
|
336
|
+
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
337
|
+
def test_cocotb_invalid_simulator(self):
|
|
338
|
+
'''Test cocotb with invalid simulator configuration.'''
|
|
318
339
|
|
|
319
|
-
|
|
320
|
-
'sim', '--tool', 'cocotb',
|
|
321
|
-
'--cocotb-simulator=invalid_sim',
|
|
322
|
-
'cocotb_counter_test',
|
|
323
|
-
)
|
|
324
|
-
assert rc > 1, "Should fail with invalid simulator"
|
|
340
|
+
chdir_remove_work_dir('../../examples/cocotb')
|
|
325
341
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
342
|
+
rc = eda_wrap(
|
|
343
|
+
'sim', '--tool', 'cocotb',
|
|
344
|
+
'--cocotb-simulator=invalid_sim',
|
|
345
|
+
'cocotb_counter_test',
|
|
346
|
+
)
|
|
347
|
+
assert eda_wrap_is_sim_fail(rc), \
|
|
348
|
+
f"Should fail with invalid simulator {rc=}"
|
|
329
349
|
|
|
330
|
-
|
|
350
|
+
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
351
|
+
def test_cocotb_malformed_hdl(self):
|
|
352
|
+
'''Test cocotb with malformed HDL files.'''
|
|
331
353
|
|
|
332
|
-
|
|
333
|
-
rc = eda_wrap(
|
|
334
|
-
'sim', '--tool', 'cocotb',
|
|
335
|
-
'--cocotb-test-module=test_counter',
|
|
336
|
-
'tb_dollar_fatal',
|
|
337
|
-
)
|
|
354
|
+
chdir_remove_work_dir('../../lib/tests')
|
|
338
355
|
|
|
339
|
-
|
|
356
|
+
# Test with a target that has syntax errors - should fail during compilation
|
|
357
|
+
rc = eda_wrap(
|
|
358
|
+
'sim', '--tool', 'cocotb',
|
|
359
|
+
'--cocotb-test-module=test_counter',
|
|
360
|
+
'tb_dollar_fatal',
|
|
361
|
+
)
|
|
340
362
|
|
|
363
|
+
# eda_wrap may continue to errors beyond normal sim fails:
|
|
364
|
+
assert eda_wrap_is_sim_fail(rc) or \
|
|
365
|
+
f"Should fail with malformed HDL or failing test assertions {rc=}"
|
|
341
366
|
|
|
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
367
|
|
|
346
|
-
|
|
368
|
+
@pytest.mark.skipif(cannot_use_cocotb, reason=CANNOT_USE_COCOTB_REASON)
|
|
369
|
+
def test_cocotb_test_failures(self):
|
|
370
|
+
'''Test that cocotb properly reports test failures.'''
|
|
347
371
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
372
|
+
chdir_remove_work_dir('../../examples/cocotb')
|
|
373
|
+
|
|
374
|
+
# Intentionally failing cocotb tests
|
|
375
|
+
rc = eda_wrap('sim', '--tool', 'cocotb', 'cocotb_failure_test')
|
|
376
|
+
assert eda_wrap_is_sim_fail(rc), \
|
|
377
|
+
f"Should fail when cocotb tests contain assertion failures {rc=}"
|
opencos/tools/cocotb.py
CHANGED
|
@@ -122,20 +122,12 @@ class CommandSimCocotb(CommandSim, ToolCocotb):
|
|
|
122
122
|
util.safe_mkdirs(base=self.args['work-dir'], new_dirs=paths)
|
|
123
123
|
|
|
124
124
|
# Write shell scripts
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
util.write_shell_command_file(
|
|
133
|
-
dirpath=self.args['work-dir'],
|
|
134
|
-
filename='all.sh',
|
|
135
|
-
command_lists=[
|
|
136
|
-
['./pre_compile_dep_shell_commands.sh'],
|
|
137
|
-
['./cocotb_test.sh'],
|
|
138
|
-
]
|
|
125
|
+
self.write_sh_scripts_to_work_dir(
|
|
126
|
+
compile_lists=[],
|
|
127
|
+
elaborate_lists=[],
|
|
128
|
+
simulate_lists=self.cocotb_command_lists,
|
|
129
|
+
simulate_line_breaks=True,
|
|
130
|
+
simulate_sh_fname='cocotb_test.sh'
|
|
139
131
|
)
|
|
140
132
|
|
|
141
133
|
def _find_cocotb_test_files(self):
|
|
@@ -316,6 +308,11 @@ def run_cocotb_test():
|
|
|
316
308
|
# Get the runner for the specified simulator
|
|
317
309
|
runner = get_runner(simulator)
|
|
318
310
|
|
|
311
|
+
build_args = []
|
|
312
|
+
|
|
313
|
+
if simulator == "verilator":
|
|
314
|
+
build_args.extend({list(self.args.get('verilate-args', []))!r})
|
|
315
|
+
|
|
319
316
|
# Build the design
|
|
320
317
|
runner.build(
|
|
321
318
|
sources=sources,
|
|
@@ -324,6 +321,7 @@ def run_cocotb_test():
|
|
|
324
321
|
defines=defines,
|
|
325
322
|
parameters=parameters,
|
|
326
323
|
build_dir="sim_build",
|
|
324
|
+
build_args=build_args,
|
|
327
325
|
)
|
|
328
326
|
|
|
329
327
|
# Run the test
|
|
@@ -398,6 +396,9 @@ MODULE = {test_module}
|
|
|
398
396
|
define_args.append(f'-D{k}={sanitize_defines_for_sh(v)}')
|
|
399
397
|
makefile_content += 'COMPILE_ARGS += ' + ' '.join(define_args) + '\n'
|
|
400
398
|
|
|
399
|
+
if self.args['cocotb-simulator'] == 'verilator' and self.args.get('verilate-args'):
|
|
400
|
+
makefile_content += 'COMPILE_ARGS += ' + ' '.join(self.args['verilate-args']) + '\n'
|
|
401
|
+
|
|
401
402
|
makefile_content += '''
|
|
402
403
|
# Waves support
|
|
403
404
|
ifeq ($(WAVES),1)
|
opencos/tools/iverilog.py
CHANGED
|
@@ -84,32 +84,12 @@ class CommandSimIverilog(CommandSim, ToolIverilog):
|
|
|
84
84
|
|
|
85
85
|
paths = ['logs']
|
|
86
86
|
util.safe_mkdirs(base=self.args['work-dir'], new_dirs=paths)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
command_lists=self.iverilog_command_lists,
|
|
92
|
-
line_breaks=True
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
util.write_shell_command_file(
|
|
96
|
-
dirpath=self.args['work-dir'],
|
|
97
|
-
filename='simulate_only.sh',
|
|
98
|
-
command_lists=self.iverilog_exec_command_lists
|
|
87
|
+
self.write_sh_scripts_to_work_dir(
|
|
88
|
+
compile_lists=self.iverilog_command_lists,
|
|
89
|
+
elaborate_lists=[],
|
|
90
|
+
simulate_lists=self.iverilog_exec_command_lists
|
|
99
91
|
)
|
|
100
92
|
|
|
101
|
-
util.write_shell_command_file(
|
|
102
|
-
dirpath=self.args['work-dir'],
|
|
103
|
-
filename='all.sh',
|
|
104
|
-
command_lists = [
|
|
105
|
-
['./pre_compile_dep_shell_commands.sh'],
|
|
106
|
-
['./compile_only.sh'],
|
|
107
|
-
['./simulate_only.sh'],
|
|
108
|
-
]
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
self.write_eda_config_and_args()
|
|
112
|
-
|
|
113
93
|
def compile(self):
|
|
114
94
|
if self.args['stop-before-compile']:
|
|
115
95
|
return
|