opencos-eda 0.3.2__tar.gz → 0.3.5__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.
- {opencos_eda-0.3.2/opencos_eda.egg-info → opencos_eda-0.3.5}/PKG-INFO +11 -2
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/deps/defaults.py +1 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/deps/deps_processor.py +47 -22
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/deps_schema.py +17 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/eda.py +7 -14
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/eda_base.py +1 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/eda_config.py +84 -40
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/eda_config_defaults.yml +5 -1
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/eda_tool_helper.py +19 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/helpers.py +58 -2
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/test_eda.py +11 -1
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/iverilog.py +4 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/riviera.py +23 -12
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/slang.py +6 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/verilator.py +133 -38
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/vivado.py +1 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/util.py +22 -14
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/utils/str_helpers.py +6 -1
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/utils/subprocess_helpers.py +66 -3
- {opencos_eda-0.3.2 → opencos_eda-0.3.5/opencos_eda.egg-info}/PKG-INFO +11 -2
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos_eda.egg-info/requires.txt +12 -1
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/pyproject.toml +15 -2
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/LICENSE +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/LICENSE.spdx +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/README.md +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/__init__.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/_version.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/_waves_pkg.sv +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/__init__.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/build.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/deps_help.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/elab.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/export.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/flist.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/lec.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/lint.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/multi.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/open.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/proj.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/shell.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/sim.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/sweep.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/synth.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/targets.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/upload.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/commands/waves.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/deps/__init__.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/deps/deps_commands.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/deps/deps_file.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/eda_config_max_verilator_waivers.yml +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/eda_config_reduced.yml +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/eda_deps_bash_completion.bash +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/eda_deps_sanitize.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/eda_extract_targets.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/export_helper.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/export_json_convert.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/files.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/hw/__init__.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/hw/oc_cli.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/hw/pcie.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/names.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/peakrdl_cleanup.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/seed.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/__init__.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/custom_config.yml +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/deps_files/command_order/DEPS.yml +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/deps_files/error_msgs/DEPS.yml +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/deps_files/iverilog_test/DEPS.yml +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/deps_files/no_deps_here/DEPS.yml +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/deps_files/non_sv_reqs/DEPS.yml +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/deps_files/tags_with_tools/DEPS.yml +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/deps_files/test_err_fatal/DEPS.yml +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/test_build.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/test_deps_helpers.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/test_deps_schema.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/test_eda_elab.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/test_eda_synth.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/test_oc_cli.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tests/test_tools.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/__init__.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/cocotb.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/invio.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/invio_helpers.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/invio_yosys.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/modelsim_ase.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/quartus.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/questa.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/questa_fse.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/slang_yosys.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/surelog.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/tabbycad_yosys.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/tools/yosys.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/utils/__init__.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/utils/markup_helpers.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/utils/status_constants.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/utils/vscode_helper.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos/utils/vsim_helper.py +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos_eda.egg-info/SOURCES.txt +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos_eda.egg-info/dependency_links.txt +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos_eda.egg-info/entry_points.txt +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/opencos_eda.egg-info/top_level.txt +0 -0
- {opencos_eda-0.3.2 → opencos_eda-0.3.5}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencos-eda
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.5
|
|
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
|
|
@@ -9,12 +9,21 @@ License-File: LICENSE
|
|
|
9
9
|
License-File: LICENSE.spdx
|
|
10
10
|
Requires-Dist: mergedeep>=1.3.4
|
|
11
11
|
Requires-Dist: peakrdl>=1.1.0
|
|
12
|
+
Requires-Dist: psutil>=7.0.0
|
|
12
13
|
Requires-Dist: pyyaml>=6.0.2
|
|
13
|
-
Requires-Dist: pytest>=8.3.5
|
|
14
14
|
Requires-Dist: python-dotenv>=1.0.1
|
|
15
15
|
Requires-Dist: schema>=0.7.7
|
|
16
16
|
Requires-Dist: toml>=0.10.2
|
|
17
17
|
Requires-Dist: yamllint>=1.35.1
|
|
18
18
|
Requires-Dist: PySerial>=3.5
|
|
19
19
|
Requires-Dist: cocotb>=2.0
|
|
20
|
+
Requires-Dist: supports_color>=0.2.0
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pylint>=3.0.0; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest>=8.3.5; extra == "dev"
|
|
24
|
+
Provides-Extra: docs
|
|
25
|
+
Requires-Dist: mkdocs; extra == "docs"
|
|
26
|
+
Requires-Dist: mkdocs-material; extra == "docs"
|
|
27
|
+
Requires-Dist: mkdocs-wavedrom-plugin; extra == "docs"
|
|
28
|
+
Requires-Dist: mkdocs-plantuml; extra == "docs"
|
|
20
29
|
Dynamic: license-file
|
|
@@ -77,7 +77,7 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
77
77
|
).get('command_handler', {}).keys()
|
|
78
78
|
|
|
79
79
|
|
|
80
|
-
def apply_defines(self, defines_dict: dict):
|
|
80
|
+
def apply_defines(self, defines_dict: dict) -> None:
|
|
81
81
|
'''Given defines_dict, applies them to our self.command_design_ref obj'''
|
|
82
82
|
if not isinstance(defines_dict, dict):
|
|
83
83
|
self.error(f"{defines_dict=} is not type dict, can't apply defines,",
|
|
@@ -95,7 +95,19 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
95
95
|
self.command_design_ref.process_plusarg(f'+define+{k}={v}')
|
|
96
96
|
|
|
97
97
|
|
|
98
|
-
def
|
|
98
|
+
def apply_plusargs(self, plusargs_dict: dict) -> None:
|
|
99
|
+
'''Given plusarsg_dict, applies them to our self.command_design_ref obj'''
|
|
100
|
+
if not isinstance(plusargs_dict, dict):
|
|
101
|
+
self.error(f"{plusargs_dict=} is not type dict, can't apply plusargs,",
|
|
102
|
+
f"in {self.caller_info}")
|
|
103
|
+
for k,v in plusargs_dict.items():
|
|
104
|
+
if v is None or v == '':
|
|
105
|
+
self.command_design_ref.process_plusarg(f'+{k}')
|
|
106
|
+
else:
|
|
107
|
+
self.command_design_ref.process_plusarg(f'+{k}={v}')
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def apply_parameters(self, parameters_dict: dict) -> None:
|
|
99
111
|
'''Given parameters_dict, applies them to our self.command_design_ref obj'''
|
|
100
112
|
if not isinstance(parameters_dict, dict):
|
|
101
113
|
self.error(f"{parameters_dict=} is not type dict, can't apply defines,",
|
|
@@ -110,7 +122,7 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
110
122
|
)
|
|
111
123
|
|
|
112
124
|
|
|
113
|
-
def apply_incdirs(self, incdirs_list:list):
|
|
125
|
+
def apply_incdirs(self, incdirs_list:list) -> None:
|
|
114
126
|
'''Given incdirs_list, applies them to our self.command_design_ref obj'''
|
|
115
127
|
if not isinstance(incdirs_list, (str, list)):
|
|
116
128
|
self.error(f"{incdirs_list=} is not type str/list, can't apply incdirs",
|
|
@@ -290,7 +302,9 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
290
302
|
caller_info=self.caller_info
|
|
291
303
|
)
|
|
292
304
|
|
|
293
|
-
def process_deps_entry(
|
|
305
|
+
def process_deps_entry( # pylint: disable=too-many-branches
|
|
306
|
+
self
|
|
307
|
+
) -> list:
|
|
294
308
|
'''Main entry point (after creating DepsProcessor obj) to resolve a deps target
|
|
295
309
|
|
|
296
310
|
Example usage:
|
|
@@ -303,22 +317,6 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
303
317
|
This method will apply all target features to the CommandDesign ref object as
|
|
304
318
|
we traverse.
|
|
305
319
|
|
|
306
|
-
Supported target keys:
|
|
307
|
-
-- tags (or equivalent, to support multiple define/incdir/deps for a target)
|
|
308
|
-
-- supports tag-name, with-tools, with-args, args, defines, incdirs, deps
|
|
309
|
-
** to be applied if a tool matches.
|
|
310
|
-
-- TODO(drew): other features in docs/DEPS.md not yet implemented.
|
|
311
|
-
-- multi: ignore-this-target: - commands (handled in eda.py CommandMulti.resolve_target)
|
|
312
|
-
-- Named eda commands
|
|
313
|
-
-- (partially done) sim or other eda commands (eda.py command specific things)
|
|
314
|
-
basically, check the command, and apply/merge values to 'entry'?
|
|
315
|
-
-- args
|
|
316
|
-
-- defines
|
|
317
|
-
-- incdirs
|
|
318
|
-
-- top.
|
|
319
|
-
-- commands (not in deps)
|
|
320
|
-
-- deps
|
|
321
|
-
|
|
322
320
|
TODO(drew): This does not yet support conditional inclusions based on defines,
|
|
323
321
|
like the old DEPS files did with pattern:
|
|
324
322
|
SOME_DEFINE ? dep_if_define_present : dep_if_define_not_present
|
|
@@ -344,6 +342,8 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
344
342
|
remaining_deps_list += self.process_tags()
|
|
345
343
|
elif key == 'defines':
|
|
346
344
|
self.process_defines()
|
|
345
|
+
elif key == 'plusargs':
|
|
346
|
+
self.process_plusargs()
|
|
347
347
|
elif key == 'parameters':
|
|
348
348
|
self.process_parameters()
|
|
349
349
|
elif key == 'incdirs':
|
|
@@ -520,6 +520,10 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
520
520
|
# apply defines:
|
|
521
521
|
self.apply_defines(value.get('defines', {}))
|
|
522
522
|
|
|
523
|
+
if key == 'plusargs':
|
|
524
|
+
# apply plusargs:
|
|
525
|
+
self.apply_plusargs(value.get('plusargs', {}))
|
|
526
|
+
|
|
523
527
|
elif key == 'parameters':
|
|
524
528
|
self.apply_parameters(value.get('parameters', {}))
|
|
525
529
|
|
|
@@ -598,7 +602,7 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
598
602
|
return ret_deps_added_from_tags
|
|
599
603
|
|
|
600
604
|
|
|
601
|
-
def process_defines(self):
|
|
605
|
+
def process_defines(self) -> None:
|
|
602
606
|
'''Returns None, applies defines (dict, if any) from self.deps_entry to
|
|
603
607
|
self.command_design_ref.'''
|
|
604
608
|
|
|
@@ -614,7 +618,28 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
614
618
|
|
|
615
619
|
self.apply_defines(entry_defines)
|
|
616
620
|
|
|
617
|
-
|
|
621
|
+
|
|
622
|
+
def process_plusargs(self) -> None:
|
|
623
|
+
'''Returns None, applies plusargs (dict, if any) from self.deps_entry to
|
|
624
|
+
self.command_design_ref.
|
|
625
|
+
|
|
626
|
+
These work w/ the same rules as defines (no value, or value int/str)
|
|
627
|
+
'''
|
|
628
|
+
|
|
629
|
+
# Plusargs:
|
|
630
|
+
# apply command specific plusargs, with higher priority than the a
|
|
631
|
+
# deps_entry['sim']['plusargs'] entry,
|
|
632
|
+
# do this with dict1.update(dict2):
|
|
633
|
+
entry_plusargs = {}
|
|
634
|
+
entry_plusargs.update(self.deps_entry.get('plusargs', {}))
|
|
635
|
+
entry_plusargs.update(self.entry_eda_command.get('plusargs', {}))
|
|
636
|
+
assert isinstance(entry_plusargs, dict), \
|
|
637
|
+
f'{entry_plusargs=} for in {self.caller_info} must be a dict'
|
|
638
|
+
|
|
639
|
+
self.apply_plusargs(entry_plusargs)
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
def process_parameters(self) -> None:
|
|
618
643
|
'''Returns None, applies parameters (dict, if any) from self.deps_entry to
|
|
619
644
|
self.command_design_ref.'''
|
|
620
645
|
|
|
@@ -17,6 +17,9 @@ my_target_name:
|
|
|
17
17
|
incdirs: <---- incdirs, optional array (or string)
|
|
18
18
|
- ./
|
|
19
19
|
|
|
20
|
+
plusargs: <---- plusargs, optional table
|
|
21
|
+
some_plusarg: 32
|
|
22
|
+
|
|
20
23
|
top: tb <---- top, optional string
|
|
21
24
|
|
|
22
25
|
deps:
|
|
@@ -63,6 +66,7 @@ my_target_name:
|
|
|
63
66
|
defines: <---- defines, optional table
|
|
64
67
|
parameters: <---- parameters, optional table
|
|
65
68
|
incdirs: <---- incdirs, optional array (or string)
|
|
69
|
+
plusargs: <---- plusargs, optional table
|
|
66
70
|
top: tb <---- top, optional string
|
|
67
71
|
deps: <---- TARGET_DEPS_CONTENTS schema
|
|
68
72
|
- some_file.sv <---- string file name
|
|
@@ -216,6 +220,9 @@ TARGET_EDA_COMMAND_ENTRY_TABLE = {
|
|
|
216
220
|
Optional('defines'): {
|
|
217
221
|
Optional(str): Or(str, int, type(None)),
|
|
218
222
|
},
|
|
223
|
+
Optional('plusargs'): {
|
|
224
|
+
Optional(str): Or(str, int, type(None)),
|
|
225
|
+
},
|
|
219
226
|
Optional('parameters'): {
|
|
220
227
|
Optional(str): Or(str, int),
|
|
221
228
|
},
|
|
@@ -241,6 +248,9 @@ TARGET_TAGS_TABLE = {
|
|
|
241
248
|
Optional('defines'): {
|
|
242
249
|
Optional(str): Or(str, int, type(None)),
|
|
243
250
|
},
|
|
251
|
+
Optional('plusargs'): {
|
|
252
|
+
Optional(str): Or(str, int, type(None)),
|
|
253
|
+
},
|
|
244
254
|
Optional('parameters'): {
|
|
245
255
|
Optional(str): Or(str, int),
|
|
246
256
|
},
|
|
@@ -262,6 +272,10 @@ TARGET_CONTENTS = Or(
|
|
|
262
272
|
Optional('defines'): {
|
|
263
273
|
Optional(str): Or(str, int, type(None)),
|
|
264
274
|
},
|
|
275
|
+
# plusargs: table of key-value; value null or string
|
|
276
|
+
Optional('plusargs'): {
|
|
277
|
+
Optional(str): Or(str, int, type(None)),
|
|
278
|
+
},
|
|
265
279
|
# parameters: table of key-value
|
|
266
280
|
Optional('parameters'): {
|
|
267
281
|
Optional(str): Or(str, int),
|
|
@@ -324,6 +338,9 @@ FILE_SIMPLIFIED = Schema(
|
|
|
324
338
|
Optional('defines'): {
|
|
325
339
|
Optional(str): Or(type(None), str),
|
|
326
340
|
},
|
|
341
|
+
Optional('plusargs'): {
|
|
342
|
+
Optional(str): Or(type(None), str),
|
|
343
|
+
},
|
|
327
344
|
Optional('parameters'): {
|
|
328
345
|
Optional(str): str,
|
|
329
346
|
},
|
|
@@ -23,7 +23,7 @@ from opencos import util, eda_config, eda_base
|
|
|
23
23
|
from opencos.eda_base import Tool, which_tool, get_eda_exec
|
|
24
24
|
from opencos.utils import vsim_helper, vscode_helper
|
|
25
25
|
from opencos.utils.subprocess_helpers import subprocess_run_background
|
|
26
|
-
from opencos.utils import status_constants, str_helpers
|
|
26
|
+
from opencos.utils import status_constants, str_helpers, subprocess_helpers
|
|
27
27
|
|
|
28
28
|
# Configure util:
|
|
29
29
|
util.progname = "EDA"
|
|
@@ -50,7 +50,7 @@ def init_config(
|
|
|
50
50
|
# For key DEFAULT_HANDLERS, we'll update config['command_handler'] with
|
|
51
51
|
# the actual class using importlib (via opencos.util)
|
|
52
52
|
|
|
53
|
-
eda_config.
|
|
53
|
+
eda_config.update_config_auto_tool_order_for_tool(tool=tool, config=config)
|
|
54
54
|
|
|
55
55
|
config['command_handler'] = {}
|
|
56
56
|
for _cmd, str_class in config['DEFAULT_HANDLERS'].items():
|
|
@@ -163,10 +163,7 @@ def auto_tool_setup( # pylint: disable=too-many-locals,too-many-branches,too-man
|
|
|
163
163
|
If so, updates config['auto_tools_order'][tool]['exe']
|
|
164
164
|
'''
|
|
165
165
|
|
|
166
|
-
|
|
167
|
-
tool = eda_config.update_config_auto_tool_order_for_tool(
|
|
168
|
-
tool=tool, config=config
|
|
169
|
-
)
|
|
166
|
+
tool = eda_config.tool_arg_remove_path_information(tool)
|
|
170
167
|
|
|
171
168
|
assert 'auto_tools_order' in config
|
|
172
169
|
assert isinstance(config['auto_tools_order'], list)
|
|
@@ -275,9 +272,7 @@ def tool_setup(tool: str, config: dict, quiet: bool = False, auto_setup: bool =
|
|
|
275
272
|
|
|
276
273
|
'''
|
|
277
274
|
|
|
278
|
-
tool = eda_config.
|
|
279
|
-
tool=tool, config=config
|
|
280
|
-
)
|
|
275
|
+
tool = eda_config.tool_arg_remove_path_information(tool)
|
|
281
276
|
|
|
282
277
|
if not quiet and not auto_setup:
|
|
283
278
|
util.info(f"Setup for tool: '{tool}'")
|
|
@@ -389,6 +384,8 @@ def process_tokens( # pylint: disable=too-many-branches,too-many-statements,too-
|
|
|
389
384
|
if not is_interactive:
|
|
390
385
|
# Run init_config() now, we deferred it in main(), but only run it
|
|
391
386
|
# for this tool (or tool=None to figure it out)
|
|
387
|
+
# This will handle any --tool=<name>=/path/to/bin also, so don't have to
|
|
388
|
+
# run tool_setup(..) on its own.
|
|
392
389
|
config = init_config(
|
|
393
390
|
config, tool=parsed.tool,
|
|
394
391
|
run_auto_tool_setup=run_auto_tool_setup
|
|
@@ -406,13 +403,8 @@ def process_tokens( # pylint: disable=too-many-branches,too-many-statements,too-
|
|
|
406
403
|
for arg in unparsed:
|
|
407
404
|
if not arg.startswith('-'):
|
|
408
405
|
command = arg
|
|
409
|
-
if parsed.tool:
|
|
410
|
-
tool_setup(parsed.tool, config=config)
|
|
411
406
|
return usage(tokens=unparsed, config=config, command=command, tool=parsed.tool)
|
|
412
407
|
|
|
413
|
-
if parsed.tool:
|
|
414
|
-
tool_setup(parsed.tool, config=config)
|
|
415
|
-
|
|
416
408
|
deferred_tokens = unparsed
|
|
417
409
|
if not command:
|
|
418
410
|
util.error("Didn't get a command!")
|
|
@@ -504,6 +496,7 @@ def signal_handler(sig, frame) -> None: # pylint: disable=unused-argument
|
|
|
504
496
|
'''Handles Ctrl-C, called by main_cli() if running from command line'''
|
|
505
497
|
util.fancy_stop()
|
|
506
498
|
util.info('Received Ctrl+C...', start='\nINFO: [EDA] ')
|
|
499
|
+
subprocess_helpers.cleanup_all()
|
|
507
500
|
util.exit(-1)
|
|
508
501
|
|
|
509
502
|
# **************************************************************
|
|
@@ -594,6 +594,7 @@ class Command: # pylint: disable=too-many-public-methods
|
|
|
594
594
|
help_kwargs = {'help': f'default={value}'}
|
|
595
595
|
else:
|
|
596
596
|
help_kwargs = {'help': f'{type(value).__name__} default={value}'}
|
|
597
|
+
help_kwargs['help'] = help_kwargs['help'].replace('%', '%%')
|
|
597
598
|
|
|
598
599
|
|
|
599
600
|
# It's important to set the default=None on these, except for list types where default
|
|
@@ -18,7 +18,10 @@ from opencos import util
|
|
|
18
18
|
from opencos.utils.markup_helpers import yaml_safe_load, yaml_safe_writer
|
|
19
19
|
|
|
20
20
|
class Defaults:
|
|
21
|
-
'''Defaults is a global
|
|
21
|
+
'''Defaults is a global namespace for constants and supported features.
|
|
22
|
+
|
|
23
|
+
Defaults.config_yml is set depending on search order for default eda_config[_defaults].yml
|
|
24
|
+
'''
|
|
22
25
|
|
|
23
26
|
environ_override_config_yml = os.environ.get('EDA_CONFIG_YML', '')
|
|
24
27
|
home_override_config_yml = os.path.join(
|
|
@@ -63,14 +66,15 @@ class Defaults:
|
|
|
63
66
|
'simulate-args',
|
|
64
67
|
'simulate-waves-args',
|
|
65
68
|
'simulate-waivers',
|
|
69
|
+
'simulate-coverage-tcl',
|
|
66
70
|
'coverage-args',
|
|
67
71
|
])
|
|
68
72
|
|
|
69
73
|
EDA_OUTPUT_CONFIG_FNAME = 'eda_output_config.yml'
|
|
70
74
|
|
|
71
|
-
if os.path.
|
|
75
|
+
if os.path.isfile(Defaults.environ_override_config_yml):
|
|
72
76
|
Defaults.config_yml = Defaults.environ_override_config_yml
|
|
73
|
-
elif os.path.
|
|
77
|
+
elif os.path.isfile(Defaults.home_override_config_yml):
|
|
74
78
|
Defaults.config_yml = Defaults.home_override_config_yml
|
|
75
79
|
else:
|
|
76
80
|
Defaults.config_yml = Defaults.opencos_config_yml
|
|
@@ -149,29 +153,9 @@ def update_config_auto_tool_order_for_tool(tool: str, config: dict) -> str:
|
|
|
149
153
|
Input arg tool can be in the form (for example):
|
|
150
154
|
tool='verlator', tool='verilator=/path/to/verilator.exe'
|
|
151
155
|
|
|
152
|
-
Performs no update if tool has no = in it. Returns tool (str) w/out = in it
|
|
156
|
+
Performs no update if tool has no = or : in it. Returns tool (str) w/out = in it
|
|
153
157
|
'''
|
|
154
|
-
|
|
155
|
-
return tool
|
|
156
|
-
|
|
157
|
-
tool, user_exe = tool.split('=')[0:2]
|
|
158
|
-
|
|
159
|
-
user_exe = shutil.which(user_exe)
|
|
160
|
-
|
|
161
|
-
# try adding to $PATH if in form --tool=/path/to/exe
|
|
162
|
-
tool_try_add_to_path(tool)
|
|
163
|
-
|
|
164
|
-
if tool not in config['auto_tools_order'][0]:
|
|
165
|
-
return tool
|
|
166
|
-
if not user_exe:
|
|
167
|
-
return tool
|
|
168
|
-
|
|
169
|
-
old_exe = config['auto_tools_order'][0][tool].get('exe', str())
|
|
170
|
-
if isinstance(old_exe, list):
|
|
171
|
-
config['auto_tools_order'][0][tool]['exe'][0] = user_exe
|
|
172
|
-
else:
|
|
173
|
-
config['auto_tools_order'][0][tool]['exe'] = user_exe
|
|
174
|
-
return tool
|
|
158
|
+
return tool_try_add_to_path(tool=tool, config=config, update_config=True)
|
|
175
159
|
|
|
176
160
|
|
|
177
161
|
def update_config_auto_tool_order_for_tools(tools: list, config: dict) -> list:
|
|
@@ -327,32 +311,92 @@ def write_eda_config_and_args(
|
|
|
327
311
|
yaml_safe_writer(data=data, filepath=fullpath)
|
|
328
312
|
|
|
329
313
|
|
|
330
|
-
def
|
|
331
|
-
'''
|
|
314
|
+
def tool_arg_get_parts(tool: str) -> list:
|
|
315
|
+
'''Given a tool (str or None) that may be in form <name>=/path/to/something
|
|
316
|
+
|
|
317
|
+
Return the parts [<name>, <path>, ..]
|
|
318
|
+
'''
|
|
319
|
+
if not tool or ('=' not in tool and ':' not in tool):
|
|
320
|
+
return [tool]
|
|
321
|
+
|
|
322
|
+
if '=' in tool:
|
|
323
|
+
parts = tool.split('=')
|
|
324
|
+
else:
|
|
325
|
+
parts = tool.split(':')
|
|
326
|
+
|
|
327
|
+
return parts
|
|
328
|
+
|
|
329
|
+
def tool_arg_remove_path_information(tool: str) -> str:
|
|
330
|
+
'''Given a tool (str or None) that may be in form <name>=/path/to/something
|
|
331
|
+
|
|
332
|
+
Return the <name> only
|
|
333
|
+
'''
|
|
334
|
+
if not tool:
|
|
335
|
+
return tool
|
|
336
|
+
return tool_arg_get_parts(tool)[0]
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def tool_try_add_to_path( # pylint: disable=too-many-branches
|
|
340
|
+
tool: str, config: dict, update_config: bool
|
|
341
|
+
) -> str:
|
|
342
|
+
'''Since we support --tool=<name>=/path/to/bin[/exe], attempt to prepend $PATH
|
|
343
|
+
|
|
344
|
+
(also works for --tool=<name>:/path/to/bin[/exe] )
|
|
332
345
|
|
|
333
346
|
with this information for this tool (which will nicely affect all subprocesses,
|
|
334
347
|
but not wreck our original shell).'''
|
|
335
348
|
|
|
336
|
-
|
|
337
|
-
|
|
349
|
+
name_path_parts = tool_arg_get_parts(tool)
|
|
350
|
+
if len(name_path_parts) == 1:
|
|
351
|
+
return name_path_parts[0]
|
|
352
|
+
|
|
353
|
+
name, path_arg = name_path_parts[0:2]
|
|
354
|
+
|
|
355
|
+
if name not in config['auto_tools_order'][0]:
|
|
356
|
+
return name
|
|
357
|
+
|
|
358
|
+
config_exe = config['auto_tools_order'][0][name].get('exe', str())
|
|
359
|
+
if isinstance(config_exe, list):
|
|
360
|
+
orig_exe = config_exe[0]
|
|
361
|
+
else:
|
|
362
|
+
orig_exe = config_exe
|
|
338
363
|
|
|
339
|
-
|
|
340
|
-
|
|
364
|
+
if path_arg and os.path.isfile(path_arg):
|
|
365
|
+
# Someone passes us --tool=<name>=/path/to/bin/exe, remove the exe from path:
|
|
366
|
+
path, exe = os.path.split(path_arg)
|
|
367
|
+
elif path_arg and os.path.isdir(path_arg):
|
|
341
368
|
# Someone passes us --tool=<name>=/path/to/bin/ (did not have exe)
|
|
342
|
-
path =
|
|
369
|
+
path, exe = path_arg, orig_exe
|
|
343
370
|
else:
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
if not path:
|
|
347
|
-
|
|
371
|
+
path, exe = '', ''
|
|
372
|
+
|
|
373
|
+
if not path or not exe:
|
|
374
|
+
util.error(f'Can not find path or exe for --tool={tool}: {name=} path={path_arg}')
|
|
375
|
+
return name
|
|
348
376
|
|
|
349
377
|
path = os.path.abspath(path)
|
|
350
378
|
if os.path.isdir(path):
|
|
351
|
-
paths = os.environ
|
|
379
|
+
paths = os.environ.get('PATH', '').split(':')
|
|
352
380
|
if path not in paths:
|
|
353
|
-
os.environ['PATH'] = path + ':' + os.environ['PATH']
|
|
354
381
|
util.info(f'--tool={tool} has path information, prepending PATH with: {path}')
|
|
382
|
+
os.environ['PATH'] = path + ':' + os.environ.get('PATH', '')
|
|
355
383
|
else:
|
|
356
384
|
util.info(f'--tool={tool} has path information, but {path} already in $PATH')
|
|
357
|
-
|
|
358
|
-
|
|
385
|
+
|
|
386
|
+
user_exe = os.path.join(path, exe)
|
|
387
|
+
if not os.access(user_exe, os.X_OK):
|
|
388
|
+
util.error(f'--tool setting for {tool}: {user_exe} is not an executable')
|
|
389
|
+
return name
|
|
390
|
+
|
|
391
|
+
user_exe = shutil.which(exe)
|
|
392
|
+
|
|
393
|
+
if update_config:
|
|
394
|
+
if isinstance(config_exe, list):
|
|
395
|
+
config['auto_tools_order'][0][name]['exe'][0] = user_exe
|
|
396
|
+
else:
|
|
397
|
+
config['auto_tools_order'][0][name]['exe'] = user_exe
|
|
398
|
+
util.debug(f'For {tool=}, auto_tools_order config updated')
|
|
399
|
+
|
|
400
|
+
util.debug(f'For {tool=}, final {user_exe=}')
|
|
401
|
+
|
|
402
|
+
return name
|
|
@@ -145,6 +145,7 @@ tools:
|
|
|
145
145
|
--timescale=1ns/1ns
|
|
146
146
|
--allow-dup-initial-drivers
|
|
147
147
|
-Wno-missing-top
|
|
148
|
+
compile-waivers: []
|
|
148
149
|
|
|
149
150
|
verilator:
|
|
150
151
|
defines: { }
|
|
@@ -153,11 +154,11 @@ tools:
|
|
|
153
154
|
- "%Fatal"
|
|
154
155
|
log-must-strings:
|
|
155
156
|
- "R e p o r t: Verilator" # These come at end of compile or simulation, since we don't suppress it.
|
|
157
|
+
# Note: -j $(nproc) is handled in verilator.py, but you can override it in compile-args
|
|
156
158
|
compile-args: |
|
|
157
159
|
--timing
|
|
158
160
|
--assert
|
|
159
161
|
--autoflush
|
|
160
|
-
-j 2
|
|
161
162
|
-sv
|
|
162
163
|
compile-coverage-args: |
|
|
163
164
|
--coverage
|
|
@@ -246,6 +247,9 @@ tools:
|
|
|
246
247
|
+accb +accr +access +r+w
|
|
247
248
|
coverage-args: |
|
|
248
249
|
-acdb -acdb_cov sbfectapm
|
|
250
|
+
simulate-coverage-tcl:
|
|
251
|
+
- acdb save
|
|
252
|
+
- acdb report -db work.acdb -txt -o cov.txt
|
|
249
253
|
|
|
250
254
|
|
|
251
255
|
modelsim_ase:
|
|
@@ -68,3 +68,22 @@ def get_all_handler_commands(config=None, tools_loaded=None) -> dict:
|
|
|
68
68
|
all_handler_commands[command].append(tool)
|
|
69
69
|
|
|
70
70
|
return all_handler_commands
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def get_handler_tool_version(tool: str, eda_command: str, config: dict) -> str:
|
|
74
|
+
'''Attempts to get a Command Handler's version given tool + eda_command'''
|
|
75
|
+
|
|
76
|
+
entry = config['auto_tools_order'][0].get(tool, {})
|
|
77
|
+
if not entry:
|
|
78
|
+
return ''
|
|
79
|
+
|
|
80
|
+
handler_name = entry.get('handlers', {}).get(eda_command, '')
|
|
81
|
+
if not handler_name:
|
|
82
|
+
return ''
|
|
83
|
+
|
|
84
|
+
module = util.import_class_from_string(handler_name)
|
|
85
|
+
obj = module(config=config)
|
|
86
|
+
if not getattr(obj, 'get_versions', None):
|
|
87
|
+
return ''
|
|
88
|
+
|
|
89
|
+
return obj.get_versions()
|
|
@@ -16,6 +16,7 @@ from opencos.utils.subprocess_helpers import subprocess_run_background
|
|
|
16
16
|
|
|
17
17
|
# Figure out what tools the system has available, without calling eda.main(..)
|
|
18
18
|
config, tools_loaded = eda_tool_helper.get_config_and_tools_loaded()
|
|
19
|
+
known_tool_versions = {}
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
def eda_wrap_is_sim_fail(rc: int, quiet: bool = False) -> bool:
|
|
@@ -32,6 +33,16 @@ def eda_wrap_is_sim_fail(rc: int, quiet: bool = False) -> bool:
|
|
|
32
33
|
status_constants.EDA_DEFAULT_ERROR
|
|
33
34
|
)
|
|
34
35
|
|
|
36
|
+
def handle_tool_version(tool: str, eda_command: str, cfg: dict = config) -> None:
|
|
37
|
+
'''Attempts to use a command handler for tool + eda_command and we'll
|
|
38
|
+
track the version globally'''
|
|
39
|
+
|
|
40
|
+
if not known_tool_versions.get(tool, ''):
|
|
41
|
+
handler_version = eda_tool_helper.get_handler_tool_version(
|
|
42
|
+
tool=tool, eda_command=eda_command, config=cfg
|
|
43
|
+
)
|
|
44
|
+
known_tool_versions[tool] = handler_version
|
|
45
|
+
|
|
35
46
|
def can_run_eda_command(*commands, cfg: dict = config) -> bool:
|
|
36
47
|
'''Returns True if we have any installed tool that can run: eda <command>'''
|
|
37
48
|
runnable = []
|
|
@@ -50,10 +61,36 @@ def can_run_eda_command(*commands, cfg: dict = config) -> bool:
|
|
|
50
61
|
if entry and entry.get('disable-auto', False):
|
|
51
62
|
# This tool cannot automatically run our command.
|
|
52
63
|
return False
|
|
64
|
+
# While we're here, set known tool versions.
|
|
65
|
+
handle_tool_version(tool=tool, eda_command=command, cfg=cfg)
|
|
53
66
|
|
|
54
67
|
runnable.append(True)
|
|
55
68
|
return runnable and all(runnable)
|
|
56
69
|
|
|
70
|
+
def can_uvm(tool: str) -> bool:
|
|
71
|
+
'''Returns True if we can run UVM, per tool'''
|
|
72
|
+
|
|
73
|
+
if tool not in tools_loaded:
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
if tool == 'verilator':
|
|
77
|
+
# requires UVM_HOME to be set with uvm_pkg.sv existing.
|
|
78
|
+
uvm_home = os.environ.get('UVM_HOME', '')
|
|
79
|
+
uvm_pkg = os.path.join(uvm_home, 'uvm_pkg.sv')
|
|
80
|
+
if not all((os.path.isdir(uvm_home), os.path.isfile(uvm_pkg))):
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
handle_tool_version(tool=tool, eda_command='sim', cfg=config)
|
|
84
|
+
version_list = known_tool_versions.get('verilator', '').split('.')
|
|
85
|
+
if int(version_list[0]) < 5 or \
|
|
86
|
+
(int(version_list[0]) == 5 and int(version_list[1]) < 42):
|
|
87
|
+
return False
|
|
88
|
+
|
|
89
|
+
return True
|
|
90
|
+
|
|
91
|
+
# default return False:
|
|
92
|
+
return False
|
|
93
|
+
|
|
57
94
|
def can_run_eda_sim(cfg: dict = config) -> bool:
|
|
58
95
|
'''Returns True if we have any installed tool that can run: eda sim'''
|
|
59
96
|
return can_run_eda_command('sim', cfg=cfg)
|
|
@@ -242,7 +279,9 @@ class Helpers:
|
|
|
242
279
|
|
|
243
280
|
return rc
|
|
244
281
|
|
|
245
|
-
def is_in_log(
|
|
282
|
+
def is_in_log(
|
|
283
|
+
self, *want_str, logfile=None, windows_path_support: bool = False
|
|
284
|
+
) -> bool:
|
|
246
285
|
'''Check if want_str (joined) is in the logfile, or self.DEFAULT_LOG'''
|
|
247
286
|
logfile = self._resolve_logfile(logfile)
|
|
248
287
|
want_str0 = ' '.join(list(want_str))
|
|
@@ -254,7 +293,9 @@ class Helpers:
|
|
|
254
293
|
return True
|
|
255
294
|
return False
|
|
256
295
|
|
|
257
|
-
def get_log_lines_with(
|
|
296
|
+
def get_log_lines_with(
|
|
297
|
+
self, *want_str, logfile=None, windows_path_support: bool = False
|
|
298
|
+
) -> list:
|
|
258
299
|
'''gets all log lines with any of want_str args are in the logfile, or self.DEFAULT_LOG'''
|
|
259
300
|
logfile = self._resolve_logfile(logfile)
|
|
260
301
|
ret_list = []
|
|
@@ -267,6 +308,21 @@ class Helpers:
|
|
|
267
308
|
ret_list.append(line)
|
|
268
309
|
return ret_list
|
|
269
310
|
|
|
311
|
+
def get_log_lines_with_all(
|
|
312
|
+
self, *want_str, logfile=None, windows_path_support: bool = False
|
|
313
|
+
) -> list:
|
|
314
|
+
'''gets all log lines with ALL of want_str args are in the logfile, or self.DEFAULT_LOG'''
|
|
315
|
+
logfile = self._resolve_logfile(logfile)
|
|
316
|
+
ret_list = []
|
|
317
|
+
with open(logfile, encoding='utf-8') as f:
|
|
318
|
+
for line in f.readlines():
|
|
319
|
+
if all(x in line for x in list(want_str)):
|
|
320
|
+
ret_list.append(line)
|
|
321
|
+
elif windows_path_support and \
|
|
322
|
+
all(x.replace('/', '\\') in line for x in list(want_str)):
|
|
323
|
+
ret_list.append(line)
|
|
324
|
+
return ret_list
|
|
325
|
+
|
|
270
326
|
def get_log_words_with(self, *want_str, logfile=None, windows_path_support=False):
|
|
271
327
|
'''gets all log words with any of *want_str within a single word
|
|
272
328
|
in the logfile or self.DEFAULT_LOG
|
|
@@ -100,9 +100,19 @@ class TestsRequiresVerilator( # pylint: disable=too-many-public-methods
|
|
|
100
100
|
def test_args_sim_tool_with_path(self):
|
|
101
101
|
'''Test for calling a tool as --tool=<tool>=</path/to/tool-exe>'''
|
|
102
102
|
verilator_fullpath = shutil.which('verilator')
|
|
103
|
+
verilator_path, _ = os.path.split(verilator_fullpath)
|
|
104
|
+
|
|
103
105
|
chdir_remove_work_dir('../../lib/tests')
|
|
104
106
|
rc = eda_sim_wrap('--tool', f'verilator={verilator_fullpath}', 'oclib_fifo_test')
|
|
105
|
-
|
|
107
|
+
assert rc == 0
|
|
108
|
+
|
|
109
|
+
rc = eda_sim_wrap('--tool', f'verilator:{verilator_fullpath}', 'oclib_fifo_test')
|
|
110
|
+
assert rc == 0
|
|
111
|
+
|
|
112
|
+
rc = eda_sim_wrap('--tool', f'verilator={verilator_path}', 'oclib_fifo_test')
|
|
113
|
+
assert rc == 0
|
|
114
|
+
|
|
115
|
+
rc = eda_sim_wrap('--tool', f'verilator:{verilator_fullpath}', 'oclib_fifo_test')
|
|
106
116
|
assert rc == 0
|
|
107
117
|
|
|
108
118
|
def test_args_sim_with_coverage(self):
|
|
@@ -160,6 +160,10 @@ class CommandSimIverilog(CommandSim, ToolIverilog):
|
|
|
160
160
|
cmd_list += self.tool_config.get('simulate-args', '').split()
|
|
161
161
|
if self.args['waves']:
|
|
162
162
|
cmd_list += self.tool_config.get('simulate-waves-args', '').split()
|
|
163
|
+
for x in self.args['sim-plusargs']:
|
|
164
|
+
if x[0] != '+':
|
|
165
|
+
x = f'+{x}'
|
|
166
|
+
cmd_list.append(x)
|
|
163
167
|
return [ util.ShellCommandList(cmd_list, tee_fpath='sim.log') ]
|
|
164
168
|
|
|
165
169
|
def get_post_simulate_command_lists(self, **kwargs) -> list:
|