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.
Files changed (44) hide show
  1. opencos/commands/__init__.py +2 -0
  2. opencos/commands/build.py +1 -1
  3. opencos/commands/deps_help.py +259 -0
  4. opencos/commands/export.py +1 -1
  5. opencos/commands/flist.py +4 -1
  6. opencos/commands/lec.py +1 -1
  7. opencos/commands/open.py +2 -0
  8. opencos/commands/proj.py +1 -1
  9. opencos/commands/shell.py +1 -1
  10. opencos/commands/sim.py +76 -8
  11. opencos/commands/synth.py +1 -1
  12. opencos/commands/upload.py +3 -0
  13. opencos/commands/waves.py +1 -0
  14. opencos/deps/defaults.py +1 -0
  15. opencos/deps/deps_file.py +30 -4
  16. opencos/deps/deps_processor.py +72 -2
  17. opencos/deps_schema.py +3 -0
  18. opencos/eda.py +50 -26
  19. opencos/eda_base.py +177 -33
  20. opencos/eda_config.py +1 -1
  21. opencos/eda_config_defaults.yml +49 -3
  22. opencos/eda_extract_targets.py +1 -58
  23. opencos/tests/helpers.py +16 -0
  24. opencos/tests/test_eda.py +14 -3
  25. opencos/tests/test_tools.py +159 -132
  26. opencos/tools/cocotb.py +15 -14
  27. opencos/tools/iverilog.py +4 -24
  28. opencos/tools/modelsim_ase.py +70 -57
  29. opencos/tools/quartus.py +680 -0
  30. opencos/tools/questa.py +158 -90
  31. opencos/tools/questa_fse.py +10 -0
  32. opencos/tools/riviera.py +1 -0
  33. opencos/tools/verilator.py +9 -15
  34. opencos/tools/vivado.py +30 -23
  35. opencos/util.py +89 -15
  36. opencos/utils/status_constants.py +1 -0
  37. opencos/utils/str_helpers.py +85 -0
  38. {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/METADATA +1 -1
  39. {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/RECORD +44 -42
  40. {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/WHEEL +0 -0
  41. {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/entry_points.txt +0 -0
  42. {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/licenses/LICENSE +0 -0
  43. {opencos_eda-0.2.52.dist-info → opencos_eda-0.2.54.dist-info}/licenses/LICENSE.spdx +0 -0
  44. {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
- [ './simulate_only.sh' ], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
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, possible targets in deps file = ['foo'",
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, possible targets in deps file = ['foo'",
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'''
@@ -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
- def test_err_fatal(command, tool, target, sim_expect_pass):
109
- '''tests that: eda <sim|elab> --tool <parameter-tool> <parameter-target>
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 > 0
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
- @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.'''
193
+ class TestCocotb:
194
+ '''Namespace class for cocotb tests'''
182
195
 
183
- chdir_remove_work_dir('../../examples/cocotb')
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
- # Test 0: Using eda multi:
186
- rc = eda_wrap('multi', 'sim', '--tool=cocotb', '*test')
187
- assert rc == 0
200
+ chdir_remove_work_dir('../../examples/cocotb')
188
201
 
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
202
+ # Test 0: Using eda multi:
203
+ rc = eda_wrap('multi', 'sim', '--tool=cocotb', '*test')
204
+ assert rc == 0
192
205
 
193
- # Test 2: cocotb works with different simulators/configurations
194
- rc = eda_wrap('sim', '--tool', 'cocotb', 'cocotb_counter_waves_test')
195
- assert rc == 0
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
- # Test 3: Makefile approach
198
- rc = eda_wrap('sim', '--tool', 'cocotb', 'cocotb_counter_makefile_test')
199
- assert rc == 0
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
- # 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
- )
214
+ # Test 3: Makefile approach
215
+ rc = eda_wrap('sim', '--tool', 'cocotb', 'cocotb_counter_makefile_test')
216
+ assert rc == 0
205
217
 
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'
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
- assert 'defines' in data
216
- assert 'OC_TOOL_COCOTB' in data['defines']
217
- assert 'SIMULATION' in data['defines']
218
- assert 'COCOTB' in data['defines']
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
- assert data['defines']['SIMULATION'] == 1
221
- assert data['defines']['COCOTB'] == 1
222
- assert data['defines']['OC_TOOL_COCOTB'] is None # key present, no value
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
- assert 'VERILATOR' not in data['defines']
225
- assert 'SYNTHESIS' not in data['defines']
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
- if cocotb_simulator not in tools_loaded:
236
- pytest.skip(f"{cocotb_simulator=} skipped, {tools_loaded=}")
237
- return #skip/bypass
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
- chdir_remove_work_dir('../../examples/cocotb')
252
+ if cocotb_simulator not in tools_loaded:
253
+ pytest.skip(f"{cocotb_simulator=} skipped, {tools_loaded=}")
254
+ return #skip/bypass
240
255
 
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
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
- tool = ToolCocotb(config={})
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
- # version detection works
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
- # 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
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
- chdir_remove_work_dir('../../examples/cocotb')
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
- # 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"
294
+ chdir_remove_work_dir('../../examples/cocotb')
282
295
 
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"
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
- # 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"
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
- # 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"
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
- # 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
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
- chdir_remove_work_dir('../../examples/cocotb')
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
- 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"
340
+ chdir_remove_work_dir('../../examples/cocotb')
325
341
 
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.'''
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
- chdir_remove_work_dir('../../lib/tests')
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
- # 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
- )
354
+ chdir_remove_work_dir('../../lib/tests')
338
355
 
339
- assert rc > 1, "Should fail with malformed HDL or failing test assertions"
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
- chdir_remove_work_dir('../../examples/cocotb')
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
- # 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"
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
- util.write_shell_command_file(
126
- dirpath=self.args['work-dir'],
127
- filename='cocotb_test.sh',
128
- command_lists=self.cocotb_command_lists,
129
- line_breaks=True
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
- util.write_shell_command_file(
89
- dirpath=self.args['work-dir'],
90
- filename='compile_only.sh',
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