cocotb 1.7.1__cp39-cp39-win_amd64.whl → 1.8.0rc1__cp39-cp39-win_amd64.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.
Potentially problematic release.
This version of cocotb might be problematic. Click here for more details.
- cocotb/__init__.py +7 -18
- cocotb/_sim_versions.py +16 -1
- cocotb/_version.py +1 -1
- cocotb/clock.py +8 -3
- cocotb/config.py +2 -1
- cocotb/decorators.py +40 -318
- cocotb/ipython_support.py +3 -1
- cocotb/libs/cocotb.dll +0 -0
- cocotb/libs/cocotb.exp +0 -0
- cocotb/libs/cocotb.lib +0 -0
- cocotb/libs/cocotbfli_modelsim.dll +0 -0
- cocotb/libs/cocotbfli_modelsim.exp +0 -0
- cocotb/libs/cocotbfli_modelsim.lib +0 -0
- cocotb/libs/cocotbutils.dll +0 -0
- cocotb/libs/cocotbutils.exp +0 -0
- cocotb/libs/cocotbutils.lib +0 -0
- cocotb/libs/cocotbvhpi_aldec.dll +0 -0
- cocotb/libs/cocotbvhpi_aldec.exp +0 -0
- cocotb/libs/cocotbvhpi_aldec.lib +0 -0
- cocotb/libs/cocotbvhpi_modelsim.dll +0 -0
- cocotb/libs/cocotbvhpi_modelsim.exp +0 -0
- cocotb/libs/cocotbvhpi_modelsim.lib +0 -0
- cocotb/libs/cocotbvpi_aldec.dll +0 -0
- cocotb/libs/cocotbvpi_aldec.exp +0 -0
- cocotb/libs/cocotbvpi_aldec.lib +0 -0
- cocotb/libs/cocotbvpi_ghdl.dll +0 -0
- cocotb/libs/cocotbvpi_ghdl.exp +0 -0
- cocotb/libs/cocotbvpi_ghdl.lib +0 -0
- cocotb/libs/cocotbvpi_icarus.exp +0 -0
- cocotb/libs/cocotbvpi_icarus.lib +0 -0
- cocotb/libs/cocotbvpi_icarus.vpl +0 -0
- cocotb/libs/cocotbvpi_modelsim.dll +0 -0
- cocotb/libs/cocotbvpi_modelsim.exp +0 -0
- cocotb/libs/cocotbvpi_modelsim.lib +0 -0
- cocotb/libs/embed.dll +0 -0
- cocotb/libs/embed.exp +0 -0
- cocotb/libs/embed.lib +0 -0
- cocotb/libs/gpi.dll +0 -0
- cocotb/libs/gpi.exp +0 -0
- cocotb/libs/gpi.lib +0 -0
- cocotb/libs/gpilog.dll +0 -0
- cocotb/libs/gpilog.exp +0 -0
- cocotb/libs/gpilog.lib +0 -0
- cocotb/libs/pygpilog.dll +0 -0
- cocotb/libs/pygpilog.exp +0 -0
- cocotb/libs/pygpilog.lib +0 -0
- cocotb/regression.py +32 -14
- cocotb/runner.py +541 -454
- cocotb/scheduler.py +35 -18
- cocotb/share/def/aldec.exp +0 -0
- cocotb/share/def/aldec.lib +0 -0
- cocotb/share/def/ghdl.exp +0 -0
- cocotb/share/def/ghdl.lib +0 -0
- cocotb/share/def/icarus.exp +0 -0
- cocotb/share/def/icarus.lib +0 -0
- cocotb/share/def/modelsim.def +2 -0
- cocotb/share/def/modelsim.exp +0 -0
- cocotb/share/def/modelsim.lib +0 -0
- cocotb/share/include/embed.h +1 -2
- cocotb/share/include/gpi.h +10 -15
- cocotb/share/include/vpi_user_ext.h +3 -0
- cocotb/share/lib/verilator/verilator.cpp +8 -4
- cocotb/share/makefiles/Makefile.inc +16 -4
- cocotb/share/makefiles/Makefile.sim +2 -2
- cocotb/share/makefiles/simulators/Makefile.icarus +19 -0
- cocotb/share/makefiles/simulators/Makefile.ius +12 -1
- cocotb/share/makefiles/simulators/Makefile.questa +2 -1
- cocotb/share/makefiles/simulators/Makefile.riviera +4 -0
- cocotb/share/makefiles/simulators/Makefile.vcs +4 -0
- cocotb/share/makefiles/simulators/Makefile.verilator +5 -1
- cocotb/share/makefiles/simulators/Makefile.xcelium +5 -1
- cocotb/simulator.cp39-win_amd64.exp +0 -0
- cocotb/simulator.cp39-win_amd64.lib +0 -0
- cocotb/simulator.cp39-win_amd64.pyd +0 -0
- cocotb/task.py +325 -0
- cocotb/triggers.py +23 -7
- cocotb/types/logic_array.py +34 -3
- {cocotb-1.7.1.dist-info → cocotb-1.8.0rc1.dist-info}/METADATA +166 -149
- cocotb-1.8.0rc1.dist-info/RECORD +120 -0
- {cocotb-1.7.1.dist-info → cocotb-1.8.0rc1.dist-info}/WHEEL +1 -1
- cocotb/_vendor/find_libpython/__init__.py +0 -358
- cocotb/_vendor/find_libpython/__main__.py +0 -5
- cocotb/_vendor/find_libpython/_version.py +0 -5
- cocotb-1.7.1.dist-info/RECORD +0 -122
- {cocotb-1.7.1.dist-info → cocotb-1.8.0rc1.dist-info}/LICENSE +0 -0
- {cocotb-1.7.1.dist-info → cocotb-1.8.0rc1.dist-info}/entry_points.txt +0 -0
- {cocotb-1.7.1.dist-info → cocotb-1.8.0rc1.dist-info}/top_level.txt +0 -0
cocotb/runner.py
CHANGED
|
@@ -2,18 +2,29 @@
|
|
|
2
2
|
# Licensed under the Revised BSD License, see LICENSE for details.
|
|
3
3
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
4
4
|
|
|
5
|
+
"""Build HDL and run cocotb tests."""
|
|
6
|
+
|
|
7
|
+
# TODO: maybe do globbing and expanduser/expandvars in --include, --vhdl-sources, --verilog-sources
|
|
8
|
+
# TODO: create a short README and a .gitignore (content: "*") in both build_dir and test_dir? (Some other tools do this.)
|
|
9
|
+
# TODO: support timescale
|
|
10
|
+
# TODO: support custom dependencies
|
|
11
|
+
|
|
5
12
|
import abc
|
|
6
13
|
import os
|
|
7
14
|
import re
|
|
15
|
+
import shlex
|
|
8
16
|
import shutil
|
|
9
17
|
import subprocess
|
|
10
18
|
import sys
|
|
11
19
|
import tempfile
|
|
12
20
|
import warnings
|
|
13
21
|
from contextlib import suppress
|
|
14
|
-
from
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import Dict, List, Mapping, Optional, Sequence, Tuple, Type, Union
|
|
15
24
|
from xml.etree import cElementTree as ET
|
|
16
25
|
|
|
26
|
+
import find_libpython
|
|
27
|
+
|
|
17
28
|
import cocotb.config
|
|
18
29
|
|
|
19
30
|
PathLike = Union["os.PathLike[str]", str]
|
|
@@ -40,220 +51,307 @@ def as_tcl_value(value: str) -> str:
|
|
|
40
51
|
return value
|
|
41
52
|
|
|
42
53
|
|
|
54
|
+
def shlex_join(split_command):
|
|
55
|
+
"""
|
|
56
|
+
Return a shell-escaped string from *split_command*
|
|
57
|
+
This is here more for compatibility purposes
|
|
58
|
+
"""
|
|
59
|
+
return " ".join(shlex.quote(arg) for arg in split_command)
|
|
60
|
+
|
|
61
|
+
|
|
43
62
|
class Simulator(abc.ABC):
|
|
63
|
+
|
|
64
|
+
supported_gpi_interfaces: Dict[str, List[str]] = {}
|
|
65
|
+
|
|
44
66
|
def __init__(self) -> None:
|
|
45
67
|
|
|
46
|
-
self.
|
|
68
|
+
self._simulator_in_path()
|
|
47
69
|
|
|
48
70
|
self.env: Dict[str, str] = {}
|
|
49
71
|
|
|
50
72
|
# for running test() independently of build()
|
|
51
|
-
self.build_dir = "sim_build"
|
|
52
|
-
self.parameters = {}
|
|
73
|
+
self.build_dir: Path = get_abs_path("sim_build")
|
|
74
|
+
self.parameters: Mapping[str, object] = {}
|
|
53
75
|
|
|
54
76
|
@abc.abstractmethod
|
|
55
|
-
def
|
|
56
|
-
"""
|
|
77
|
+
def _simulator_in_path(self) -> None:
|
|
78
|
+
"""Raise exception if the simulator executable does not exist in :envvar:`PATH`.
|
|
79
|
+
|
|
80
|
+
Raises:
|
|
81
|
+
SystemExit: Simulator executable does not exist in :envvar:`PATH`.
|
|
82
|
+
"""
|
|
57
83
|
|
|
58
84
|
raise NotImplementedError()
|
|
59
85
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"""Return *toplevel_lang* if supported by simulator, raise exception otherwise."""
|
|
86
|
+
def _check_hdl_toplevel_lang(self, hdl_toplevel_lang: Optional[str]) -> str:
|
|
87
|
+
"""Return *hdl_toplevel_lang* if supported by simulator, raise exception otherwise.
|
|
63
88
|
|
|
64
|
-
|
|
89
|
+
Returns:
|
|
90
|
+
*hdl_toplevel_lang* if supported by the simulator.
|
|
91
|
+
|
|
92
|
+
Raises:
|
|
93
|
+
ValueError: *hdl_toplevel_lang* is not supported by the simulator.
|
|
94
|
+
"""
|
|
95
|
+
if hdl_toplevel_lang is None:
|
|
96
|
+
if self.vhdl_sources and not self.verilog_sources:
|
|
97
|
+
lang = "vhdl"
|
|
98
|
+
elif self.verilog_sources and not self.vhdl_sources:
|
|
99
|
+
lang = "verilog"
|
|
100
|
+
else:
|
|
101
|
+
raise ValueError(
|
|
102
|
+
f"{type(self).__qualname__}: Must specify a hdl_toplevel_lang in a mixed-language design"
|
|
103
|
+
)
|
|
104
|
+
else:
|
|
105
|
+
lang = hdl_toplevel_lang
|
|
106
|
+
|
|
107
|
+
if lang in self.supported_gpi_interfaces.keys():
|
|
108
|
+
return lang
|
|
109
|
+
else:
|
|
110
|
+
raise ValueError(
|
|
111
|
+
f"{type(self).__qualname__}: hdl_toplevel_lang {hdl_toplevel_lang!r} is not "
|
|
112
|
+
f"in supported list: {', '.join(self.supported_gpi_interfaces.keys())}"
|
|
113
|
+
)
|
|
65
114
|
|
|
66
|
-
def
|
|
115
|
+
def _set_env(self) -> None:
|
|
67
116
|
"""Set environment variables for sub-processes."""
|
|
68
117
|
|
|
69
118
|
for e in os.environ:
|
|
70
119
|
self.env[e] = os.environ[e]
|
|
71
120
|
|
|
72
121
|
if "LIBPYTHON_LOC" not in self.env:
|
|
73
|
-
self.env["LIBPYTHON_LOC"] =
|
|
122
|
+
self.env["LIBPYTHON_LOC"] = find_libpython.find_libpython()
|
|
74
123
|
|
|
75
124
|
self.env["PATH"] += os.pathsep + cocotb.config.libs_dir
|
|
76
|
-
|
|
77
125
|
self.env["PYTHONPATH"] = os.pathsep.join(sys.path)
|
|
78
|
-
for path in self.python_search:
|
|
79
|
-
self.env["PYTHONPATH"] += os.pathsep + str(path)
|
|
80
|
-
|
|
81
126
|
self.env["PYTHONHOME"] = sys.prefix
|
|
82
|
-
|
|
83
|
-
self.env["
|
|
84
|
-
self.env["MODULE"] = self.module
|
|
127
|
+
self.env["TOPLEVEL"] = self.sim_hdl_toplevel
|
|
128
|
+
self.env["MODULE"] = self.test_module
|
|
85
129
|
|
|
86
130
|
@abc.abstractmethod
|
|
87
|
-
def
|
|
131
|
+
def _build_command(self) -> Sequence[Command]:
|
|
88
132
|
"""Return command to build the HDL sources."""
|
|
89
133
|
|
|
90
134
|
raise NotImplementedError()
|
|
91
135
|
|
|
92
136
|
@abc.abstractmethod
|
|
93
|
-
def
|
|
137
|
+
def _test_command(self) -> Sequence[Command]:
|
|
94
138
|
"""Return command to run a test."""
|
|
95
139
|
|
|
96
140
|
raise NotImplementedError()
|
|
97
141
|
|
|
98
142
|
def build(
|
|
99
143
|
self,
|
|
100
|
-
|
|
144
|
+
hdl_library: str = "top",
|
|
101
145
|
verilog_sources: Sequence[PathLike] = [],
|
|
102
146
|
vhdl_sources: Sequence[PathLike] = [],
|
|
103
147
|
includes: Sequence[PathLike] = [],
|
|
104
|
-
defines:
|
|
148
|
+
defines: Mapping[str, object] = {},
|
|
105
149
|
parameters: Mapping[str, object] = {},
|
|
106
|
-
|
|
107
|
-
|
|
150
|
+
build_args: Sequence[str] = [],
|
|
151
|
+
hdl_toplevel: Optional[str] = None,
|
|
108
152
|
always: bool = False,
|
|
109
153
|
build_dir: PathLike = "sim_build",
|
|
154
|
+
verbose: bool = False,
|
|
110
155
|
) -> None:
|
|
111
|
-
"""Build the HDL sources.
|
|
112
|
-
|
|
113
|
-
|
|
156
|
+
"""Build the HDL sources.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
hdl_library: The library name to compile into.
|
|
160
|
+
verilog_sources: Verilog source files to build.
|
|
161
|
+
vhdl_sources: VHDL source files to build.
|
|
162
|
+
includes: Verilog include directories.
|
|
163
|
+
defines: Defines to set.
|
|
164
|
+
parameters: Verilog parameters or VHDL generics.
|
|
165
|
+
build_args: Extra build arguments for the simulator.
|
|
166
|
+
hdl_toplevel: The name of the HDL toplevel module.
|
|
167
|
+
always: Always run the build step.
|
|
168
|
+
build_dir: Directory to run the build step in.
|
|
169
|
+
verbose: Enable verbose messages.
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
self.build_dir = get_abs_path(build_dir)
|
|
114
173
|
os.makedirs(self.build_dir, exist_ok=True)
|
|
115
174
|
|
|
116
175
|
# note: to avoid mutating argument defaults, we ensure that no value
|
|
117
176
|
# is written without a copy. This is much more concise and leads to
|
|
118
177
|
# a better docstring than using `None` as a default in the parameters
|
|
119
178
|
# list.
|
|
120
|
-
self.
|
|
121
|
-
self.verilog_sources = get_abs_paths(verilog_sources)
|
|
122
|
-
self.vhdl_sources = get_abs_paths(vhdl_sources)
|
|
123
|
-
self.includes = get_abs_paths(includes)
|
|
124
|
-
self.defines =
|
|
179
|
+
self.hdl_library: str = hdl_library
|
|
180
|
+
self.verilog_sources: List[Path] = get_abs_paths(verilog_sources)
|
|
181
|
+
self.vhdl_sources: List[Path] = get_abs_paths(vhdl_sources)
|
|
182
|
+
self.includes: List[Path] = get_abs_paths(includes)
|
|
183
|
+
self.defines = dict(defines)
|
|
125
184
|
self.parameters = dict(parameters)
|
|
126
|
-
self.
|
|
127
|
-
self.always = always
|
|
128
|
-
self.hdl_toplevel =
|
|
185
|
+
self.build_args = list(build_args)
|
|
186
|
+
self.always: bool = always
|
|
187
|
+
self.hdl_toplevel: Optional[str] = hdl_toplevel
|
|
188
|
+
self.verbose: bool = verbose
|
|
129
189
|
|
|
130
190
|
for e in os.environ:
|
|
131
191
|
self.env[e] = os.environ[e]
|
|
132
192
|
|
|
133
|
-
cmds = self.
|
|
134
|
-
self.
|
|
193
|
+
cmds: Sequence[Command] = self._build_command()
|
|
194
|
+
self._execute(cmds, cwd=self.build_dir)
|
|
135
195
|
|
|
136
196
|
def test(
|
|
137
197
|
self,
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
198
|
+
test_module: Union[str, Sequence[str]],
|
|
199
|
+
hdl_toplevel: str,
|
|
200
|
+
hdl_toplevel_library: str = "top",
|
|
201
|
+
hdl_toplevel_lang: Optional[str] = None,
|
|
202
|
+
gpi_interfaces: Optional[List[str]] = None,
|
|
203
|
+
testcase: Optional[Union[str, Sequence[str]]] = None,
|
|
142
204
|
seed: Optional[Union[str, int]] = None,
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
plus_args: Sequence[str] = [],
|
|
205
|
+
test_args: Sequence[str] = [],
|
|
206
|
+
plusargs: Sequence[str] = [],
|
|
146
207
|
extra_env: Mapping[str, str] = {},
|
|
147
208
|
waves: Optional[bool] = None,
|
|
148
209
|
gui: Optional[bool] = None,
|
|
149
210
|
parameters: Mapping[str, object] = None,
|
|
150
211
|
build_dir: Optional[PathLike] = None,
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
212
|
+
test_dir: Optional[PathLike] = None,
|
|
213
|
+
results_xml: str = "results.xml",
|
|
214
|
+
verbose: bool = False,
|
|
215
|
+
) -> Path:
|
|
216
|
+
"""Run the tests.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
test_module: Name(s) of the Python module(s) containing the tests to run.
|
|
220
|
+
Can be a comma-separated list.
|
|
221
|
+
hdl_toplevel: Name of the HDL toplevel module.
|
|
222
|
+
hdl_toplevel_library: The library name for HDL toplevel module.
|
|
223
|
+
hdl_toplevel_lang: Language of the HDL toplevel module.
|
|
224
|
+
gpi_interfaces: List of GPI interfaces to use, with the first one being the entry point.
|
|
225
|
+
testcase: Name(s) of a specific testcase(s) to run.
|
|
226
|
+
If not set, run all testcases found in *test_module*.
|
|
227
|
+
Can be a comma-separated list.
|
|
228
|
+
seed: A specific random seed to use.
|
|
229
|
+
test_args: Extra arguments for the simulator.
|
|
230
|
+
plusargs: 'plusargs' to set for the simulator.
|
|
231
|
+
extra_env: Extra environment variables to set.
|
|
232
|
+
waves: Record signal traces.
|
|
233
|
+
gui: Run with simulator GUI.
|
|
234
|
+
parameters: Verilog parameters or VHDL generics.
|
|
235
|
+
build_dir: Directory the build step has been run in.
|
|
236
|
+
test_dir: Directory to run the tests in.
|
|
237
|
+
results_xml: Name of xUnit XML file to store test results in.
|
|
238
|
+
When running with pytest, the testcase name is prefixed to this name.
|
|
239
|
+
verbose: Enable verbose messages.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
The absolute location of the results XML file which can be
|
|
243
|
+
defined by the *results_xml* argument.
|
|
244
|
+
The default is :file:`{build_dir}/{pytest_test_name}.results.xml`
|
|
245
|
+
when run with ``pytest``,
|
|
246
|
+
:file:`{build_dir}/results.xml` otherwise.
|
|
247
|
+
"""
|
|
154
248
|
|
|
155
249
|
__tracebackhide__ = True # Hide the traceback when using pytest
|
|
156
250
|
|
|
157
251
|
if build_dir is not None:
|
|
158
|
-
self.build_dir = build_dir
|
|
252
|
+
self.build_dir = get_abs_path(build_dir)
|
|
159
253
|
|
|
160
254
|
if parameters is not None:
|
|
161
255
|
self.parameters = dict(parameters)
|
|
162
256
|
|
|
163
|
-
if
|
|
164
|
-
self.
|
|
257
|
+
if test_dir is None:
|
|
258
|
+
self.test_dir = self.build_dir
|
|
165
259
|
else:
|
|
166
|
-
self.
|
|
260
|
+
self.test_dir = get_abs_path(test_dir)
|
|
261
|
+
os.makedirs(self.test_dir, exist_ok=True)
|
|
167
262
|
|
|
168
|
-
if isinstance(
|
|
169
|
-
self.
|
|
263
|
+
if isinstance(test_module, str):
|
|
264
|
+
self.test_module = test_module
|
|
170
265
|
else:
|
|
171
|
-
self.
|
|
266
|
+
self.test_module = ",".join(test_module)
|
|
172
267
|
|
|
173
268
|
# note: to avoid mutating argument defaults, we ensure that no value
|
|
174
269
|
# is written without a copy. This is much more concise and leads to
|
|
175
270
|
# a better docstring than using `None` as a default in the parameters
|
|
176
271
|
# list.
|
|
177
|
-
self.
|
|
178
|
-
self.
|
|
179
|
-
self.
|
|
180
|
-
|
|
181
|
-
|
|
272
|
+
self.sim_hdl_toplevel = hdl_toplevel
|
|
273
|
+
self.hdl_toplevel_library: str = hdl_toplevel_library
|
|
274
|
+
self.hdl_toplevel_lang = self._check_hdl_toplevel_lang(hdl_toplevel_lang)
|
|
275
|
+
if gpi_interfaces:
|
|
276
|
+
self.gpi_interfaces = gpi_interfaces
|
|
277
|
+
else:
|
|
278
|
+
self.gpi_interfaces = []
|
|
279
|
+
for gpi_if in self.supported_gpi_interfaces.values():
|
|
280
|
+
self.gpi_interfaces.append(gpi_if[0])
|
|
281
|
+
|
|
282
|
+
self.test_args = list(test_args)
|
|
283
|
+
self.plusargs = list(plusargs)
|
|
182
284
|
self.env = dict(extra_env)
|
|
183
285
|
|
|
184
286
|
if testcase is not None:
|
|
185
|
-
|
|
287
|
+
if isinstance(testcase, str):
|
|
288
|
+
self.env["TESTCASE"] = testcase
|
|
289
|
+
else:
|
|
290
|
+
self.env["TESTCASE"] = ",".join(testcase)
|
|
186
291
|
|
|
187
292
|
if seed is not None:
|
|
188
293
|
self.env["RANDOM_SEED"] = str(seed)
|
|
189
294
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
else:
|
|
193
|
-
self.waves = bool(waves)
|
|
295
|
+
self.waves = bool(waves)
|
|
296
|
+
self.gui = bool(gui)
|
|
194
297
|
|
|
195
|
-
if
|
|
196
|
-
self.
|
|
197
|
-
else:
|
|
198
|
-
self.gui = bool(gui)
|
|
298
|
+
if verbose is not None:
|
|
299
|
+
self.verbose = verbose
|
|
199
300
|
|
|
200
301
|
# When using pytest, use test name as result file name
|
|
201
302
|
pytest_current_test = os.getenv("PYTEST_CURRENT_TEST", "")
|
|
202
303
|
if pytest_current_test:
|
|
203
304
|
self.current_test_name = pytest_current_test.split(":")[-1].split(" ")[0]
|
|
204
|
-
results_xml_name = f"{self.current_test_name}.
|
|
305
|
+
results_xml_name = f"{self.current_test_name}.{results_xml}"
|
|
205
306
|
else:
|
|
206
307
|
self.current_test_name = "test"
|
|
207
|
-
results_xml_name =
|
|
208
|
-
|
|
209
|
-
results_xml_file = os.getenv(
|
|
210
|
-
"COCOTB_RESULTS_FILE", os.path.join(self.build_dir, results_xml_name)
|
|
211
|
-
)
|
|
308
|
+
results_xml_name = results_xml
|
|
212
309
|
|
|
213
|
-
self.
|
|
310
|
+
results_xml_file = Path(self.test_dir) / results_xml_name
|
|
214
311
|
|
|
215
312
|
with suppress(OSError):
|
|
216
313
|
os.remove(results_xml_file)
|
|
217
314
|
|
|
218
|
-
|
|
219
|
-
self.
|
|
220
|
-
self.
|
|
315
|
+
# transport the settings to cocotb via environment variables
|
|
316
|
+
self._set_env()
|
|
317
|
+
self.env["COCOTB_RESULTS_FILE"] = str(results_xml_file)
|
|
221
318
|
|
|
222
|
-
|
|
319
|
+
cmds: Sequence[Command] = self._test_command()
|
|
320
|
+
self._execute(cmds, cwd=self.test_dir)
|
|
321
|
+
|
|
322
|
+
# Only when running under pytest, check the results file here,
|
|
323
|
+
# potentially raising an exception with failing testcases,
|
|
324
|
+
# otherwise return the results file for later analysis.
|
|
325
|
+
if pytest_current_test:
|
|
326
|
+
check_results_file(results_xml_file)
|
|
223
327
|
|
|
224
328
|
print(f"INFO: Results file: {results_xml_file}")
|
|
225
329
|
return results_xml_file
|
|
226
330
|
|
|
227
|
-
@
|
|
228
|
-
def
|
|
229
|
-
"""Return simulator
|
|
331
|
+
@staticmethod
|
|
332
|
+
def _get_include_options(self, includes: Sequence[PathLike]) -> Command:
|
|
333
|
+
"""Return simulator-specific formatted option strings with *includes* directories."""
|
|
230
334
|
|
|
231
335
|
raise NotImplementedError()
|
|
232
336
|
|
|
233
|
-
@
|
|
234
|
-
def
|
|
235
|
-
"""Return simulator
|
|
337
|
+
@staticmethod
|
|
338
|
+
def _get_define_options(self, defines: Mapping[str, object]) -> Command:
|
|
339
|
+
"""Return simulator-specific formatted option strings with *defines* macros."""
|
|
236
340
|
|
|
237
341
|
raise NotImplementedError()
|
|
238
342
|
|
|
239
343
|
@abc.abstractmethod
|
|
240
|
-
def
|
|
241
|
-
"""Return simulator
|
|
344
|
+
def _get_parameter_options(self, parameters: Mapping[str, object]) -> Command:
|
|
345
|
+
"""Return simulator-specific formatted option strings with *parameters*/generics."""
|
|
242
346
|
|
|
243
347
|
raise NotImplementedError()
|
|
244
348
|
|
|
245
|
-
def
|
|
349
|
+
def _execute(self, cmds: Sequence[Command], cwd: PathLike) -> None:
|
|
246
350
|
|
|
247
351
|
__tracebackhide__ = True # Hide the traceback when using PyTest.
|
|
248
352
|
|
|
249
353
|
for cmd in cmds:
|
|
250
|
-
print(
|
|
251
|
-
"INFO: Running command: "
|
|
252
|
-
+ ' "'.join(cmd)
|
|
253
|
-
+ '" in directory:"'
|
|
254
|
-
+ str(cwd)
|
|
255
|
-
+ '"'
|
|
256
|
-
)
|
|
354
|
+
print(f"INFO: Running command {shlex_join(cmd)} in directory {cwd}")
|
|
257
355
|
|
|
258
356
|
# TODO: create a thread to handle stderr and log as error?
|
|
259
357
|
# TODO: log forwarding
|
|
@@ -266,86 +364,105 @@ class Simulator(abc.ABC):
|
|
|
266
364
|
)
|
|
267
365
|
|
|
268
366
|
|
|
269
|
-
def
|
|
270
|
-
"""
|
|
367
|
+
def get_results(results_xml_file: Path) -> Tuple[int, int]:
|
|
368
|
+
"""Return number of tests and fails in *results_xml_file*.
|
|
369
|
+
|
|
370
|
+
Returns:
|
|
371
|
+
Tuple of number of tests and number of fails.
|
|
372
|
+
|
|
373
|
+
Raises:
|
|
374
|
+
SystemExit: *results_xml_file* is non-existent.
|
|
375
|
+
"""
|
|
271
376
|
|
|
272
377
|
__tracebackhide__ = True # Hide the traceback when using PyTest.
|
|
273
378
|
|
|
274
|
-
|
|
275
|
-
if not results_file_exist:
|
|
379
|
+
if not results_xml_file.is_file():
|
|
276
380
|
raise SystemExit(
|
|
277
|
-
"ERROR: Simulation terminated abnormally. Results file not found."
|
|
381
|
+
f"ERROR: Simulation terminated abnormally. Results file {results_xml_file} not found."
|
|
278
382
|
)
|
|
279
383
|
|
|
280
|
-
|
|
384
|
+
num_tests = 0
|
|
385
|
+
num_failed = 0
|
|
281
386
|
|
|
282
387
|
tree = ET.parse(results_xml_file)
|
|
283
388
|
for ts in tree.iter("testsuite"):
|
|
284
389
|
for tc in ts.iter("testcase"):
|
|
390
|
+
num_tests += 1
|
|
285
391
|
for _ in tc.iter("failure"):
|
|
286
|
-
|
|
392
|
+
num_failed += 1
|
|
393
|
+
|
|
394
|
+
return (num_tests, num_failed)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def check_results_file(results_xml_file: Path) -> None:
|
|
398
|
+
"""Raise exception if *results_xml_file* does not exist or contains failed tests.
|
|
399
|
+
|
|
400
|
+
Raises:
|
|
401
|
+
SystemExit: *results_xml_file* is non-existent or contains fails.
|
|
402
|
+
"""
|
|
403
|
+
|
|
404
|
+
__tracebackhide__ = True # Hide the traceback when using PyTest.
|
|
405
|
+
|
|
406
|
+
(num_tests, num_failed) = get_results(results_xml_file)
|
|
287
407
|
|
|
288
|
-
if
|
|
289
|
-
raise SystemExit(f"ERROR: Failed {
|
|
408
|
+
if num_failed:
|
|
409
|
+
raise SystemExit(f"ERROR: Failed {num_failed} of {num_tests} tests.")
|
|
290
410
|
|
|
291
411
|
|
|
292
|
-
def outdated(output:
|
|
293
|
-
"""
|
|
412
|
+
def outdated(output: Path, dependencies: Sequence[Path]) -> bool:
|
|
413
|
+
"""Return ``True`` if any source files in *dependencies* are newer than the *output* directory.
|
|
294
414
|
|
|
295
|
-
|
|
415
|
+
Returns:
|
|
416
|
+
``True`` if any source files are newer, ``False`` otherwise.
|
|
417
|
+
"""
|
|
418
|
+
|
|
419
|
+
if not output.is_file():
|
|
296
420
|
return True
|
|
297
421
|
|
|
298
|
-
output_mtime =
|
|
422
|
+
output_mtime = output.stat().st_mtime
|
|
299
423
|
|
|
300
424
|
dep_mtime = 0.0
|
|
301
|
-
for
|
|
302
|
-
mtime =
|
|
425
|
+
for dependency in dependencies:
|
|
426
|
+
mtime = dependency.stat().st_mtime
|
|
303
427
|
if mtime > dep_mtime:
|
|
304
428
|
dep_mtime = mtime
|
|
305
429
|
|
|
306
|
-
|
|
307
|
-
return True
|
|
430
|
+
return dep_mtime > output_mtime
|
|
308
431
|
|
|
309
|
-
return False
|
|
310
432
|
|
|
433
|
+
def get_abs_path(path: PathLike) -> Path:
|
|
434
|
+
"""Return *path* in absolute form."""
|
|
311
435
|
|
|
312
|
-
|
|
313
|
-
|
|
436
|
+
path = Path(path)
|
|
437
|
+
if path.is_absolute():
|
|
438
|
+
return path.resolve()
|
|
439
|
+
else:
|
|
440
|
+
return Path(Path.cwd() / path).resolve()
|
|
314
441
|
|
|
315
|
-
paths_abs: List[str] = []
|
|
316
|
-
for path in paths:
|
|
317
|
-
if os.path.isabs(path):
|
|
318
|
-
paths_abs.append(os.path.abspath(path))
|
|
319
|
-
else:
|
|
320
|
-
paths_abs.append(os.path.abspath(os.path.join(os.getcwd(), path)))
|
|
321
442
|
|
|
322
|
-
|
|
443
|
+
def get_abs_paths(paths: Sequence[PathLike]) -> List[Path]:
|
|
444
|
+
"""Return list of *paths* in absolute form."""
|
|
445
|
+
|
|
446
|
+
return [get_abs_path(path) for path in paths]
|
|
323
447
|
|
|
324
448
|
|
|
325
449
|
class Icarus(Simulator):
|
|
326
|
-
|
|
327
|
-
def simulator_in_path() -> None:
|
|
328
|
-
if shutil.which("iverilog") is None:
|
|
329
|
-
raise SystemExit("ERROR: iverilog exacutable not found!")
|
|
450
|
+
supported_gpi_interfaces = {"verilog": ["vpi"]}
|
|
330
451
|
|
|
331
452
|
@staticmethod
|
|
332
|
-
def
|
|
333
|
-
if
|
|
334
|
-
|
|
335
|
-
else:
|
|
336
|
-
raise ValueError(
|
|
337
|
-
f"iverilog does not support {toplevel_lang!r} as a toplevel_lang"
|
|
338
|
-
)
|
|
453
|
+
def _simulator_in_path() -> None:
|
|
454
|
+
if shutil.which("iverilog") is None:
|
|
455
|
+
raise SystemExit("ERROR: iverilog executable not found!")
|
|
339
456
|
|
|
340
457
|
@staticmethod
|
|
341
|
-
def
|
|
342
|
-
return ["-I"
|
|
458
|
+
def _get_include_options(includes: Sequence[PathLike]) -> Command:
|
|
459
|
+
return [f"-I{include}" for include in includes]
|
|
343
460
|
|
|
344
461
|
@staticmethod
|
|
345
|
-
def
|
|
346
|
-
return ["-D"
|
|
462
|
+
def _get_define_options(defines: Mapping[str, object]) -> Command:
|
|
463
|
+
return [f"-D{name}={value}" for name, value in defines.items()]
|
|
347
464
|
|
|
348
|
-
def
|
|
465
|
+
def _get_parameter_options(self, parameters: Mapping[str, object]) -> Command:
|
|
349
466
|
assert self.hdl_toplevel is not None
|
|
350
467
|
return [
|
|
351
468
|
f"-P{self.hdl_toplevel}.{name}={value}"
|
|
@@ -353,10 +470,10 @@ class Icarus(Simulator):
|
|
|
353
470
|
]
|
|
354
471
|
|
|
355
472
|
@property
|
|
356
|
-
def sim_file(self) ->
|
|
357
|
-
return
|
|
473
|
+
def sim_file(self) -> Path:
|
|
474
|
+
return self.build_dir / "sim.vvp"
|
|
358
475
|
|
|
359
|
-
def
|
|
476
|
+
def _test_command(self) -> List[Command]:
|
|
360
477
|
|
|
361
478
|
return [
|
|
362
479
|
[
|
|
@@ -366,99 +483,91 @@ class Icarus(Simulator):
|
|
|
366
483
|
"-m",
|
|
367
484
|
cocotb.config.lib_name("vpi", "icarus"),
|
|
368
485
|
]
|
|
369
|
-
+ self.
|
|
370
|
-
+ [self.sim_file]
|
|
371
|
-
+ self.
|
|
486
|
+
+ self.test_args
|
|
487
|
+
+ [str(self.sim_file)]
|
|
488
|
+
+ self.plusargs
|
|
372
489
|
]
|
|
373
490
|
|
|
374
|
-
def
|
|
491
|
+
def _build_command(self) -> List[Command]:
|
|
375
492
|
|
|
376
493
|
if self.vhdl_sources:
|
|
377
|
-
raise ValueError(
|
|
494
|
+
raise ValueError(
|
|
495
|
+
f"{type(self).__qualname__}: Simulator does not support VHDL"
|
|
496
|
+
)
|
|
378
497
|
|
|
379
|
-
|
|
498
|
+
cmds = []
|
|
380
499
|
if outdated(self.sim_file, self.verilog_sources) or self.always:
|
|
381
500
|
|
|
382
|
-
|
|
383
|
-
["iverilog", "-o", self.sim_file, "-D", "COCOTB_SIM=1", "-g2012"]
|
|
384
|
-
+ self.
|
|
385
|
-
+ self.
|
|
386
|
-
+ self.
|
|
387
|
-
+ self.
|
|
388
|
-
+ self.verilog_sources
|
|
501
|
+
cmds = [
|
|
502
|
+
["iverilog", "-o", str(self.sim_file), "-D", "COCOTB_SIM=1", "-g2012"]
|
|
503
|
+
+ self._get_define_options(self.defines)
|
|
504
|
+
+ self._get_include_options(self.includes)
|
|
505
|
+
+ self._get_parameter_options(self.parameters)
|
|
506
|
+
+ self.build_args
|
|
507
|
+
+ [str(source_file) for source_file in self.verilog_sources]
|
|
389
508
|
]
|
|
390
509
|
|
|
391
510
|
else:
|
|
392
|
-
print("WARNING: Skipping compilation
|
|
511
|
+
print("WARNING: Skipping compilation of", self.sim_file)
|
|
393
512
|
|
|
394
|
-
return
|
|
513
|
+
return cmds
|
|
395
514
|
|
|
396
515
|
|
|
397
516
|
class Questa(Simulator):
|
|
517
|
+
supported_gpi_interfaces = {"verilog": ["vpi"], "vhdl": ["fli", "vhpi"]}
|
|
518
|
+
|
|
398
519
|
@staticmethod
|
|
399
|
-
def
|
|
520
|
+
def _simulator_in_path() -> None:
|
|
400
521
|
if shutil.which("vsim") is None:
|
|
401
522
|
raise SystemExit("ERROR: vsim executable not found!")
|
|
402
523
|
|
|
403
|
-
def check_toplevel_lang(self, toplevel_lang: Optional[str]) -> str:
|
|
404
|
-
if toplevel_lang is None:
|
|
405
|
-
if self.vhdl_sources and not self.verilog_sources:
|
|
406
|
-
return "vhdl"
|
|
407
|
-
elif self.verilog_sources and not self.vhdl_sources:
|
|
408
|
-
return "verilog"
|
|
409
|
-
else:
|
|
410
|
-
raise ValueError("Must specify a toplevel_lang in a mixed design")
|
|
411
|
-
elif toplevel_lang in ("verilog", "vhdl"):
|
|
412
|
-
return toplevel_lang
|
|
413
|
-
else:
|
|
414
|
-
raise ValueError(
|
|
415
|
-
f"Questa does not support {toplevel_lang!r} as a toplevel_lang"
|
|
416
|
-
)
|
|
417
|
-
|
|
418
524
|
@staticmethod
|
|
419
|
-
def
|
|
420
|
-
return ["+incdir+
|
|
525
|
+
def _get_include_options(includes: Sequence[PathLike]) -> Command:
|
|
526
|
+
return [f"+incdir+{as_tcl_value(str(include))}" for include in includes]
|
|
421
527
|
|
|
422
528
|
@staticmethod
|
|
423
|
-
def
|
|
424
|
-
return [
|
|
529
|
+
def _get_define_options(defines: Mapping[str, object]) -> Command:
|
|
530
|
+
return [
|
|
531
|
+
f"+define+{as_tcl_value(name)}={as_tcl_value(str(value))}"
|
|
532
|
+
for name, value in defines.items()
|
|
533
|
+
]
|
|
425
534
|
|
|
426
535
|
@staticmethod
|
|
427
|
-
def
|
|
428
|
-
return ["-g
|
|
536
|
+
def _get_parameter_options(parameters: Mapping[str, object]) -> Command:
|
|
537
|
+
return [f"-g{name}={value}" for name, value in parameters.items()]
|
|
429
538
|
|
|
430
|
-
def
|
|
539
|
+
def _build_command(self) -> List[Command]:
|
|
431
540
|
|
|
432
|
-
|
|
541
|
+
cmds = []
|
|
433
542
|
|
|
434
543
|
if self.vhdl_sources:
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
["vcom"
|
|
438
|
-
+ ["-work", as_tcl_value(self.
|
|
439
|
-
+ [as_tcl_value(v) for v in self.
|
|
440
|
-
+ [as_tcl_value(v) for v in self.vhdl_sources]
|
|
544
|
+
cmds.append(["vlib", as_tcl_value(self.hdl_library)])
|
|
545
|
+
cmds.append(
|
|
546
|
+
["vcom"]
|
|
547
|
+
+ ["-work", as_tcl_value(self.hdl_library)]
|
|
548
|
+
+ [as_tcl_value(v) for v in self.build_args]
|
|
549
|
+
+ [as_tcl_value(str(v)) for v in self.vhdl_sources]
|
|
441
550
|
)
|
|
442
551
|
|
|
443
552
|
if self.verilog_sources:
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
["vlog"
|
|
553
|
+
cmds.append(["vlib", as_tcl_value(self.hdl_library)])
|
|
554
|
+
cmds.append(
|
|
555
|
+
["vlog"]
|
|
447
556
|
+ ([] if self.always else ["-incr"])
|
|
448
|
-
+ ["-work", as_tcl_value(self.
|
|
557
|
+
+ ["-work", as_tcl_value(self.hdl_library)]
|
|
449
558
|
+ ["+define+COCOTB_SIM"]
|
|
450
559
|
+ ["-sv"]
|
|
451
|
-
+ self.
|
|
452
|
-
+ self.
|
|
453
|
-
+ [as_tcl_value(v) for v in self.
|
|
454
|
-
+ [as_tcl_value(v) for v in self.verilog_sources]
|
|
560
|
+
+ self._get_define_options(self.defines)
|
|
561
|
+
+ self._get_include_options(self.includes)
|
|
562
|
+
+ [as_tcl_value(v) for v in self.build_args]
|
|
563
|
+
+ [as_tcl_value(str(v)) for v in self.verilog_sources]
|
|
455
564
|
)
|
|
456
565
|
|
|
457
|
-
return
|
|
566
|
+
return cmds
|
|
458
567
|
|
|
459
|
-
def
|
|
568
|
+
def _test_command(self) -> List[Command]:
|
|
460
569
|
|
|
461
|
-
|
|
570
|
+
cmds = []
|
|
462
571
|
|
|
463
572
|
do_script = ""
|
|
464
573
|
if self.waves:
|
|
@@ -467,200 +576,169 @@ class Questa(Simulator):
|
|
|
467
576
|
if not self.gui:
|
|
468
577
|
do_script += "run -all; quit"
|
|
469
578
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
if self.toplevel_lang == "vhdl":
|
|
473
|
-
|
|
474
|
-
if not os.path.isfile(fli_lib_path):
|
|
475
|
-
raise SystemExit(
|
|
476
|
-
"ERROR: cocotb was not installed with an FLI library, as the mti.h header could not be located.\n\
|
|
477
|
-
If you installed an FLI-capable simulator after cocotb, you will need to reinstall cocotb.\n\
|
|
478
|
-
Please check the cocotb documentation on ModelSim support."
|
|
479
|
-
)
|
|
579
|
+
gpi_if_entry = self.gpi_interfaces[0]
|
|
580
|
+
gpi_if_entry_lib_path = cocotb.config.lib_name_path(gpi_if_entry, "questa")
|
|
480
581
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
+
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
+
|
|
493
|
-
|
|
494
|
-
|
|
582
|
+
if gpi_if_entry == "fli":
|
|
583
|
+
lib_opts = [
|
|
584
|
+
"-foreign",
|
|
585
|
+
"cocotb_init "
|
|
586
|
+
+ as_tcl_value(cocotb.config.lib_name_path("fli", "questa")),
|
|
587
|
+
]
|
|
588
|
+
elif gpi_if_entry == "vhpi":
|
|
589
|
+
lib_opts = ["-voptargs=-access=rw+/."]
|
|
590
|
+
lib_opts += [
|
|
591
|
+
"-foreign",
|
|
592
|
+
"vhpi_startup_routines_bootstrap "
|
|
593
|
+
+ as_tcl_value(cocotb.config.lib_name_path("vhpi", "questa")),
|
|
594
|
+
]
|
|
595
|
+
else:
|
|
596
|
+
lib_opts = [
|
|
597
|
+
"-pli",
|
|
598
|
+
as_tcl_value(cocotb.config.lib_name_path("vpi", "questa")),
|
|
599
|
+
]
|
|
495
600
|
|
|
496
|
-
|
|
497
|
-
|
|
601
|
+
if not Path(gpi_if_entry_lib_path).is_file():
|
|
602
|
+
raise SystemExit(
|
|
603
|
+
"ERROR: cocotb was not installed with a {gpi_if_entry} library."
|
|
498
604
|
)
|
|
499
605
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
)
|
|
606
|
+
cmds.append(
|
|
607
|
+
["vsim"]
|
|
608
|
+
+ ["-gui" if self.gui else "-c"]
|
|
609
|
+
+ ["-onfinish", "stop" if self.gui else "exit"]
|
|
610
|
+
+ lib_opts
|
|
611
|
+
+ [as_tcl_value(v) for v in self.test_args]
|
|
612
|
+
+ [as_tcl_value(v) for v in self._get_parameter_options(self.parameters)]
|
|
613
|
+
+ [as_tcl_value(f"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}")]
|
|
614
|
+
+ [as_tcl_value(v) for v in self.plusargs]
|
|
615
|
+
+ ["-do", do_script]
|
|
616
|
+
)
|
|
512
617
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
618
|
+
gpi_extra_list = []
|
|
619
|
+
for gpi_if in self.gpi_interfaces[1:]:
|
|
620
|
+
gpi_if_lib_path = cocotb.config.lib_name_path(gpi_if, "questa")
|
|
621
|
+
if Path(gpi_if_lib_path).is_file():
|
|
622
|
+
gpi_extra_list.append(
|
|
623
|
+
cocotb.config.lib_name_path(gpi_if, "questa")
|
|
624
|
+
+ f":cocotb{gpi_if}_entry_point"
|
|
517
625
|
)
|
|
518
626
|
else:
|
|
519
|
-
print(
|
|
520
|
-
|
|
521
|
-
)
|
|
627
|
+
print("WARNING: {gpi_if_lib_path} library not found.")
|
|
628
|
+
self.env["GPI_EXTRA"] = ",".join(gpi_extra_list)
|
|
522
629
|
|
|
523
|
-
return
|
|
630
|
+
return cmds
|
|
524
631
|
|
|
525
632
|
|
|
526
633
|
class Ghdl(Simulator):
|
|
634
|
+
supported_gpi_interfaces = {"vhdl": ["vpi"]}
|
|
635
|
+
|
|
527
636
|
@staticmethod
|
|
528
|
-
def
|
|
637
|
+
def _simulator_in_path() -> None:
|
|
529
638
|
if shutil.which("ghdl") is None:
|
|
530
639
|
raise SystemExit("ERROR: ghdl executable not found!")
|
|
531
640
|
|
|
532
|
-
def check_toplevel_lang(self, toplevel_lang: Optional[str]) -> str:
|
|
533
|
-
if toplevel_lang is None or toplevel_lang == "vhdl":
|
|
534
|
-
return "vhdl"
|
|
535
|
-
else:
|
|
536
|
-
raise ValueError(
|
|
537
|
-
f"GHDL does not support {toplevel_lang!r} as a toplevel_lang"
|
|
538
|
-
)
|
|
539
|
-
|
|
540
|
-
@staticmethod
|
|
541
|
-
def get_include_options(includes: Sequence[str]) -> List[str]:
|
|
542
|
-
return [f"-I{dir}" for dir in includes]
|
|
543
|
-
|
|
544
|
-
@staticmethod
|
|
545
|
-
def get_define_options(defines: Sequence[str]) -> List[str]:
|
|
546
|
-
return [f"-D{define}" for define in defines]
|
|
547
|
-
|
|
548
641
|
@staticmethod
|
|
549
|
-
def
|
|
550
|
-
return ["-g
|
|
642
|
+
def _get_parameter_options(parameters: Mapping[str, object]) -> Command:
|
|
643
|
+
return [f"-g{name}={value}" for name, value in parameters.items()]
|
|
551
644
|
|
|
552
|
-
def
|
|
645
|
+
def _build_command(self) -> List[Command]:
|
|
553
646
|
|
|
554
647
|
if self.verilog_sources:
|
|
555
|
-
raise ValueError("This simulator does not support Verilog")
|
|
556
|
-
|
|
557
|
-
if self.hdl_toplevel is None:
|
|
558
648
|
raise ValueError(
|
|
559
|
-
"
|
|
649
|
+
f"{type(self).__qualname__}: Simulator does not support Verilog"
|
|
560
650
|
)
|
|
561
651
|
|
|
562
|
-
|
|
652
|
+
cmds = [
|
|
563
653
|
["ghdl", "-i"]
|
|
564
|
-
+ [f"--work={self.
|
|
565
|
-
+ self.
|
|
566
|
-
+ [source_file]
|
|
567
|
-
for source_file in self.vhdl_sources
|
|
654
|
+
+ [f"--work={self.hdl_library}"]
|
|
655
|
+
+ self.build_args
|
|
656
|
+
+ [str(source_file) for source_file in self.vhdl_sources]
|
|
568
657
|
]
|
|
569
658
|
|
|
570
|
-
|
|
571
|
-
[
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
659
|
+
if self.hdl_toplevel is not None:
|
|
660
|
+
cmds += [
|
|
661
|
+
["ghdl", "-m"]
|
|
662
|
+
+ [f"--work={self.hdl_library}"]
|
|
663
|
+
+ self.build_args
|
|
664
|
+
+ [self.hdl_toplevel]
|
|
665
|
+
]
|
|
576
666
|
|
|
577
|
-
return
|
|
667
|
+
return cmds
|
|
578
668
|
|
|
579
|
-
def
|
|
669
|
+
def _test_command(self) -> List[Command]:
|
|
580
670
|
|
|
581
|
-
|
|
671
|
+
cmds = [
|
|
582
672
|
["ghdl", "-r"]
|
|
583
|
-
+ [self.
|
|
673
|
+
+ [f"--work={self.hdl_toplevel_library}"]
|
|
674
|
+
+ self.test_args
|
|
675
|
+
+ [self.sim_hdl_toplevel]
|
|
584
676
|
+ ["--vpi=" + cocotb.config.lib_name_path("vpi", "ghdl")]
|
|
585
|
-
+ self.
|
|
586
|
-
+ self.
|
|
677
|
+
+ self.plusargs
|
|
678
|
+
+ self._get_parameter_options(self.parameters)
|
|
587
679
|
]
|
|
588
680
|
|
|
589
|
-
return
|
|
681
|
+
return cmds
|
|
590
682
|
|
|
591
683
|
|
|
592
684
|
class Riviera(Simulator):
|
|
685
|
+
supported_gpi_interfaces = {"verilog": ["vpi"], "vhdl": ["vhpi"]}
|
|
686
|
+
|
|
593
687
|
@staticmethod
|
|
594
|
-
def
|
|
688
|
+
def _simulator_in_path() -> None:
|
|
595
689
|
if shutil.which("vsimsa") is None:
|
|
596
690
|
raise SystemExit("ERROR: vsimsa executable not found!")
|
|
597
691
|
|
|
598
|
-
def check_toplevel_lang(self, toplevel_lang: Optional[str]) -> str:
|
|
599
|
-
if toplevel_lang is None:
|
|
600
|
-
if self.vhdl_sources and not self.verilog_sources:
|
|
601
|
-
return "vhdl"
|
|
602
|
-
elif self.verilog_sources and not self.vhdl_sources:
|
|
603
|
-
return "verilog"
|
|
604
|
-
else:
|
|
605
|
-
raise ValueError(
|
|
606
|
-
"Must specify a toplevel_lang in a mixed-language design"
|
|
607
|
-
)
|
|
608
|
-
elif toplevel_lang in ("verilog", "vhdl"):
|
|
609
|
-
return toplevel_lang
|
|
610
|
-
else:
|
|
611
|
-
raise ValueError(
|
|
612
|
-
f"Riviera does not support {toplevel_lang!r} as a toplevel_lang"
|
|
613
|
-
)
|
|
614
|
-
|
|
615
692
|
@staticmethod
|
|
616
|
-
def
|
|
617
|
-
return ["+incdir+
|
|
693
|
+
def _get_include_options(includes: Sequence[PathLike]) -> Command:
|
|
694
|
+
return [f"+incdir+{as_tcl_value(str(include))}" for include in includes]
|
|
618
695
|
|
|
619
696
|
@staticmethod
|
|
620
|
-
def
|
|
621
|
-
return [
|
|
697
|
+
def _get_define_options(defines: Mapping[str, object]) -> Command:
|
|
698
|
+
return [
|
|
699
|
+
f"+define+{as_tcl_value(name)}={as_tcl_value(str(value))}"
|
|
700
|
+
for name, value in defines.items()
|
|
701
|
+
]
|
|
622
702
|
|
|
623
703
|
@staticmethod
|
|
624
|
-
def
|
|
625
|
-
return ["-g
|
|
704
|
+
def _get_parameter_options(parameters: Mapping[str, object]) -> Command:
|
|
705
|
+
return [f"-g{name}={value}" for name, value in parameters.items()]
|
|
626
706
|
|
|
627
|
-
def
|
|
707
|
+
def _build_command(self) -> List[Command]:
|
|
628
708
|
|
|
629
709
|
do_script = "\nonerror {\n quit -code 1 \n} \n"
|
|
630
710
|
|
|
631
|
-
out_file =
|
|
632
|
-
self.build_dir, self.library_name, self.library_name + ".lib"
|
|
633
|
-
)
|
|
711
|
+
out_file = self.build_dir / self.hdl_library / f"{self.hdl_library}.lib"
|
|
634
712
|
|
|
635
713
|
if outdated(out_file, self.verilog_sources + self.vhdl_sources) or self.always:
|
|
636
714
|
|
|
637
715
|
do_script += "alib {RTL_LIBRARY} \n".format(
|
|
638
|
-
RTL_LIBRARY=as_tcl_value(self.
|
|
716
|
+
RTL_LIBRARY=as_tcl_value(self.hdl_library)
|
|
639
717
|
)
|
|
640
718
|
|
|
641
719
|
if self.vhdl_sources:
|
|
642
720
|
do_script += (
|
|
643
721
|
"acom -work {RTL_LIBRARY} {EXTRA_ARGS} {VHDL_SOURCES}\n".format(
|
|
644
|
-
RTL_LIBRARY=as_tcl_value(self.
|
|
722
|
+
RTL_LIBRARY=as_tcl_value(self.hdl_library),
|
|
645
723
|
VHDL_SOURCES=" ".join(
|
|
646
|
-
as_tcl_value(v) for v in self.vhdl_sources
|
|
724
|
+
as_tcl_value(str(v)) for v in self.vhdl_sources
|
|
647
725
|
),
|
|
648
|
-
EXTRA_ARGS=" ".join(as_tcl_value(v) for v in self.
|
|
726
|
+
EXTRA_ARGS=" ".join(as_tcl_value(v) for v in self.build_args),
|
|
649
727
|
)
|
|
650
728
|
)
|
|
651
729
|
|
|
652
730
|
if self.verilog_sources:
|
|
653
731
|
do_script += "alog -work {RTL_LIBRARY} +define+COCOTB_SIM -sv {DEFINES} {INCDIR} {EXTRA_ARGS} {VERILOG_SOURCES} \n".format(
|
|
654
|
-
RTL_LIBRARY=as_tcl_value(self.
|
|
732
|
+
RTL_LIBRARY=as_tcl_value(self.hdl_library),
|
|
655
733
|
VERILOG_SOURCES=" ".join(
|
|
656
|
-
as_tcl_value(v) for v in self.verilog_sources
|
|
734
|
+
as_tcl_value(str(v)) for v in self.verilog_sources
|
|
657
735
|
),
|
|
658
|
-
DEFINES=" ".join(self.
|
|
659
|
-
INCDIR=" ".join(self.
|
|
660
|
-
EXTRA_ARGS=" ".join(as_tcl_value(v) for v in self.
|
|
736
|
+
DEFINES=" ".join(self._get_define_options(self.defines)),
|
|
737
|
+
INCDIR=" ".join(self._get_include_options(self.includes)),
|
|
738
|
+
EXTRA_ARGS=" ".join(as_tcl_value(v) for v in self.build_args),
|
|
661
739
|
)
|
|
662
740
|
else:
|
|
663
|
-
print("WARNING: Skipping compilation
|
|
741
|
+
print("WARNING: Skipping compilation of", out_file)
|
|
664
742
|
|
|
665
743
|
do_file = tempfile.NamedTemporaryFile(delete=False)
|
|
666
744
|
do_file.write(do_script.encode())
|
|
@@ -668,36 +746,41 @@ class Riviera(Simulator):
|
|
|
668
746
|
|
|
669
747
|
return [["vsimsa"] + ["-do"] + ["do"] + [do_file.name]]
|
|
670
748
|
|
|
671
|
-
def
|
|
749
|
+
def _test_command(self) -> List[Command]:
|
|
672
750
|
|
|
673
751
|
do_script = "\nonerror {\n quit -code 1 \n} \n"
|
|
674
752
|
|
|
675
|
-
if self.
|
|
676
|
-
do_script += "asim +access +w -interceptcoutput -O2 -loadvhpi {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} \n".format(
|
|
677
|
-
TOPLEVEL=as_tcl_value(
|
|
753
|
+
if self.hdl_toplevel_lang == "vhdl":
|
|
754
|
+
do_script += "asim +access +w -interceptcoutput -O2 -loadvhpi {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {PLUSARGS}\n".format(
|
|
755
|
+
TOPLEVEL=as_tcl_value(
|
|
756
|
+
f"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}"
|
|
757
|
+
),
|
|
678
758
|
EXT_NAME=as_tcl_value(cocotb.config.lib_name_path("vhpi", "riviera")),
|
|
679
759
|
EXTRA_ARGS=" ".join(
|
|
680
760
|
as_tcl_value(v)
|
|
681
761
|
for v in (
|
|
682
|
-
self.
|
|
762
|
+
self.test_args + self._get_parameter_options(self.parameters)
|
|
683
763
|
)
|
|
684
764
|
),
|
|
765
|
+
PLUSARGS=" ".join(as_tcl_value(v) for v in self.plusargs),
|
|
685
766
|
)
|
|
686
767
|
|
|
687
768
|
self.env["GPI_EXTRA"] = (
|
|
688
769
|
cocotb.config.lib_name_path("vpi", "riviera") + ":cocotbvpi_entry_point"
|
|
689
770
|
)
|
|
690
771
|
else:
|
|
691
|
-
do_script += "asim +access +w -interceptcoutput -O2 -pli {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {
|
|
692
|
-
TOPLEVEL=as_tcl_value(
|
|
772
|
+
do_script += "asim +access +w -interceptcoutput -O2 -pli {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {PLUSARGS} \n".format(
|
|
773
|
+
TOPLEVEL=as_tcl_value(
|
|
774
|
+
f"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}"
|
|
775
|
+
),
|
|
693
776
|
EXT_NAME=as_tcl_value(cocotb.config.lib_name_path("vpi", "riviera")),
|
|
694
777
|
EXTRA_ARGS=" ".join(
|
|
695
778
|
as_tcl_value(v)
|
|
696
779
|
for v in (
|
|
697
|
-
self.
|
|
780
|
+
self.test_args + self._get_parameter_options(self.parameters)
|
|
698
781
|
)
|
|
699
782
|
),
|
|
700
|
-
|
|
783
|
+
PLUSARGS=" ".join(as_tcl_value(v) for v in self.plusargs),
|
|
701
784
|
)
|
|
702
785
|
|
|
703
786
|
self.env["GPI_EXTRA"] = (
|
|
@@ -718,61 +801,58 @@ class Riviera(Simulator):
|
|
|
718
801
|
|
|
719
802
|
|
|
720
803
|
class Verilator(Simulator):
|
|
721
|
-
|
|
804
|
+
supported_gpi_interfaces = {"verilog": ["vpi"]}
|
|
805
|
+
|
|
806
|
+
def _simulator_in_path(self) -> None:
|
|
722
807
|
executable = shutil.which("verilator")
|
|
723
808
|
if executable is None:
|
|
724
809
|
raise SystemExit("ERROR: verilator executable not found!")
|
|
725
|
-
self.executable = executable
|
|
726
|
-
|
|
727
|
-
@staticmethod
|
|
728
|
-
def check_toplevel_lang(toplevel_lang: Optional[str]) -> str:
|
|
729
|
-
if toplevel_lang is None or toplevel_lang == "verilog":
|
|
730
|
-
return "verilog"
|
|
731
|
-
else:
|
|
732
|
-
raise ValueError(
|
|
733
|
-
f"Verilator does not support {toplevel_lang!r} as a toplevel_lang"
|
|
734
|
-
)
|
|
810
|
+
self.executable: str = executable
|
|
735
811
|
|
|
736
812
|
@staticmethod
|
|
737
|
-
def
|
|
738
|
-
return ["-I"
|
|
813
|
+
def _get_include_options(includes: Sequence[PathLike]) -> Command:
|
|
814
|
+
return [f"-I{include}" for include in includes]
|
|
739
815
|
|
|
740
816
|
@staticmethod
|
|
741
|
-
def
|
|
742
|
-
return ["-D"
|
|
817
|
+
def _get_define_options(defines: Mapping[str, object]) -> Command:
|
|
818
|
+
return [f"-D{name}={value}" for name, value in defines.items()]
|
|
743
819
|
|
|
744
820
|
@staticmethod
|
|
745
|
-
def
|
|
746
|
-
return ["-G
|
|
821
|
+
def _get_parameter_options(parameters: Mapping[str, object]) -> Command:
|
|
822
|
+
return [f"-G{name}={value}" for name, value in parameters.items()]
|
|
747
823
|
|
|
748
|
-
def
|
|
824
|
+
def _build_command(self) -> List[Command]:
|
|
749
825
|
|
|
750
826
|
if self.vhdl_sources:
|
|
751
|
-
raise ValueError(
|
|
827
|
+
raise ValueError(
|
|
828
|
+
f"{type(self).__qualname__}: Simulator does not support VHDL"
|
|
829
|
+
)
|
|
752
830
|
|
|
753
831
|
if self.hdl_toplevel is None:
|
|
754
832
|
raise ValueError(
|
|
755
|
-
"
|
|
833
|
+
f"{type(self).__qualname__}: Simulator requires the hdl_toplevel parameter to be specified"
|
|
756
834
|
)
|
|
757
835
|
|
|
758
|
-
|
|
836
|
+
# TODO: set "--debug" if self.verbose
|
|
837
|
+
# TODO: support "--always"
|
|
759
838
|
|
|
760
|
-
verilator_cpp =
|
|
761
|
-
|
|
762
|
-
"share"
|
|
763
|
-
"lib"
|
|
764
|
-
"verilator"
|
|
765
|
-
"verilator.cpp"
|
|
839
|
+
verilator_cpp = str(
|
|
840
|
+
Path(cocotb.__file__).parent
|
|
841
|
+
/ "share"
|
|
842
|
+
/ "lib"
|
|
843
|
+
/ "verilator"
|
|
844
|
+
/ "verilator.cpp"
|
|
766
845
|
)
|
|
767
846
|
|
|
768
|
-
|
|
847
|
+
cmds = []
|
|
848
|
+
cmds.append(
|
|
769
849
|
[
|
|
770
850
|
"perl",
|
|
771
851
|
self.executable,
|
|
772
852
|
"-cc",
|
|
773
853
|
"--exe",
|
|
774
854
|
"-Mdir",
|
|
775
|
-
self.build_dir,
|
|
855
|
+
str(self.build_dir),
|
|
776
856
|
"-DCOCOTB_SIM=1",
|
|
777
857
|
"--top-module",
|
|
778
858
|
self.hdl_toplevel,
|
|
@@ -787,132 +867,154 @@ class Verilator(Simulator):
|
|
|
787
867
|
LIB_DIR=cocotb.config.libs_dir
|
|
788
868
|
),
|
|
789
869
|
]
|
|
790
|
-
+ self.
|
|
791
|
-
+ self.
|
|
792
|
-
+ self.
|
|
793
|
-
+ self.
|
|
870
|
+
+ self.build_args
|
|
871
|
+
+ self._get_define_options(self.defines)
|
|
872
|
+
+ self._get_include_options(self.includes)
|
|
873
|
+
+ self._get_parameter_options(self.parameters)
|
|
794
874
|
+ [verilator_cpp]
|
|
795
|
-
+ self.verilog_sources
|
|
875
|
+
+ [str(source_file) for source_file in self.verilog_sources]
|
|
796
876
|
)
|
|
797
877
|
|
|
798
|
-
|
|
878
|
+
cmds.append(["make", "-C", str(self.build_dir), "-f", "Vtop.mk"])
|
|
799
879
|
|
|
800
|
-
return
|
|
880
|
+
return cmds
|
|
801
881
|
|
|
802
|
-
def
|
|
803
|
-
out_file =
|
|
804
|
-
return [[out_file] + self.
|
|
882
|
+
def _test_command(self) -> List[Command]:
|
|
883
|
+
out_file = self.build_dir / self.sim_hdl_toplevel
|
|
884
|
+
return [[str(out_file)] + self.plusargs]
|
|
805
885
|
|
|
806
886
|
|
|
807
887
|
class Xcelium(Simulator):
|
|
888
|
+
supported_gpi_interfaces = {"verilog": ["vpi"], "vhdl": ["vhpi"]}
|
|
889
|
+
|
|
808
890
|
@staticmethod
|
|
809
|
-
def
|
|
891
|
+
def _simulator_in_path() -> None:
|
|
810
892
|
if shutil.which("xrun") is None:
|
|
811
893
|
raise SystemExit("ERROR: xrun executable not found!")
|
|
812
894
|
|
|
813
|
-
def check_toplevel_lang(self, toplevel_lang: Optional[str]) -> str:
|
|
814
|
-
if toplevel_lang is None:
|
|
815
|
-
if self.vhdl_sources and not self.verilog_sources:
|
|
816
|
-
return "vhdl"
|
|
817
|
-
elif self.verilog_sources and not self.vhdl_sources:
|
|
818
|
-
return "verilog"
|
|
819
|
-
else:
|
|
820
|
-
raise ValueError("Must specify a toplevel_lang in a mixed design")
|
|
821
|
-
elif toplevel_lang in ("verilog", "vhdl"):
|
|
822
|
-
return toplevel_lang
|
|
823
|
-
else:
|
|
824
|
-
raise ValueError(
|
|
825
|
-
f"Xcelium does not support {toplevel_lang!r} as a toplevel_lang"
|
|
826
|
-
)
|
|
827
|
-
|
|
828
895
|
@staticmethod
|
|
829
|
-
def
|
|
896
|
+
def _get_include_options(includes: Sequence[PathLike]) -> Command:
|
|
830
897
|
return [f"-incdir {include}" for include in includes]
|
|
831
898
|
|
|
832
899
|
@staticmethod
|
|
833
|
-
def
|
|
834
|
-
return [f"-define {
|
|
900
|
+
def _get_define_options(defines: Mapping[str, object]) -> Command:
|
|
901
|
+
return [f"-define {name}={value}" for name, value in defines.items()]
|
|
835
902
|
|
|
836
903
|
@staticmethod
|
|
837
|
-
def
|
|
904
|
+
def _get_parameter_options(parameters: Mapping[str, object]) -> Command:
|
|
838
905
|
return [f'-gpg "{name} => {value}"' for name, value in parameters.items()]
|
|
839
906
|
|
|
840
|
-
def
|
|
841
|
-
|
|
907
|
+
def _build_command(self) -> List[Command]:
|
|
842
908
|
self.env["CDS_AUTO_64BIT"] = "all"
|
|
843
|
-
|
|
909
|
+
|
|
910
|
+
verbosity_opts = []
|
|
911
|
+
if self.verbose:
|
|
912
|
+
verbosity_opts += ["-messages"]
|
|
913
|
+
verbosity_opts += ["-status"]
|
|
914
|
+
verbosity_opts += ["-gverbose"] # print assigned generics/parameters
|
|
915
|
+
verbosity_opts += ["-pliverbose"]
|
|
916
|
+
verbosity_opts += ["-plidebug"] # Enhance the profile output with PLI info
|
|
917
|
+
verbosity_opts += [
|
|
918
|
+
"-plierr_verbose"
|
|
919
|
+
] # Expand handle info in PLI/VPI/VHPI messages
|
|
920
|
+
|
|
921
|
+
else:
|
|
922
|
+
verbosity_opts += ["-quiet"]
|
|
923
|
+
verbosity_opts += ["-plinowarn"]
|
|
924
|
+
|
|
925
|
+
cmds = [
|
|
844
926
|
["xrun"]
|
|
845
|
-
+ ["-logfile
|
|
927
|
+
+ ["-logfile"]
|
|
928
|
+
+ ["xrun_build.log"]
|
|
846
929
|
+ ["-elaborate"]
|
|
847
|
-
+ [
|
|
930
|
+
+ ["-xmlibdirname"]
|
|
931
|
+
+ [f"{self.build_dir}/xrun_snapshot"]
|
|
848
932
|
+ ["-licqueue"]
|
|
849
|
-
|
|
850
|
-
+
|
|
851
|
-
+ ["-gverbose"] # print assigned generics/parameters
|
|
852
|
-
+ ["-plinowarn"]
|
|
853
|
-
# + ["-pliverbose"]
|
|
854
|
-
# + ["-plidebug"] # Enhance the profile output with PLI info
|
|
855
|
-
# + ["-plierr_verbose"] # Expand handle info in PLI/VPI/VHPI messages
|
|
933
|
+
+ (["-clean"] if self.always else [])
|
|
934
|
+
+ verbosity_opts
|
|
856
935
|
# + ["-vpicompat 1800v2005"] # <1364v1995|1364v2001|1364v2005|1800v2005> Specify the IEEE VPI
|
|
857
936
|
+ ["-access +rwc"]
|
|
937
|
+
+ ["-loadvpi"]
|
|
938
|
+
# always start with VPI on Xcelium
|
|
858
939
|
+ [
|
|
859
|
-
"
|
|
860
|
-
+ cocotb.config.lib_name_path("vpi", "xcelium")
|
|
940
|
+
cocotb.config.lib_name_path("vpi", "xcelium")
|
|
861
941
|
+ ":vlog_startup_routines_bootstrap"
|
|
862
942
|
]
|
|
863
|
-
+ [f"-work {self.
|
|
864
|
-
+ self.
|
|
943
|
+
+ [f"-work {self.hdl_library}"]
|
|
944
|
+
+ self.build_args
|
|
865
945
|
+ ["-define COCOTB_SIM"]
|
|
866
|
-
+ self.
|
|
867
|
-
+ self.
|
|
868
|
-
+ self.
|
|
946
|
+
+ self._get_include_options(self.includes)
|
|
947
|
+
+ self._get_define_options(self.defines)
|
|
948
|
+
+ self._get_parameter_options(self.parameters)
|
|
869
949
|
+ [f"-top {self.hdl_toplevel}"]
|
|
870
|
-
+
|
|
871
|
-
|
|
950
|
+
+ [
|
|
951
|
+
str(source_file)
|
|
952
|
+
for source_file in self.vhdl_sources + self.verilog_sources
|
|
953
|
+
]
|
|
872
954
|
]
|
|
873
955
|
|
|
874
|
-
return
|
|
956
|
+
return cmds
|
|
875
957
|
|
|
876
|
-
def
|
|
958
|
+
def _test_command(self) -> List[Command]:
|
|
877
959
|
self.env["CDS_AUTO_64BIT"] = "all"
|
|
878
960
|
|
|
961
|
+
verbosity_opts = []
|
|
962
|
+
if self.verbose:
|
|
963
|
+
verbosity_opts += ["-messages"]
|
|
964
|
+
verbosity_opts += ["-status"]
|
|
965
|
+
verbosity_opts += ["-gverbose"] # print assigned generics/parameters
|
|
966
|
+
verbosity_opts += ["-pliverbose"]
|
|
967
|
+
verbosity_opts += ["-plidebug"] # Enhance the profile output with PLI info
|
|
968
|
+
verbosity_opts += [
|
|
969
|
+
"-plierr_verbose"
|
|
970
|
+
] # Expand handle info in PLI/VPI/VHPI messages
|
|
971
|
+
|
|
972
|
+
else:
|
|
973
|
+
verbosity_opts += ["-quiet"]
|
|
974
|
+
verbosity_opts += ["-plinowarn"]
|
|
975
|
+
|
|
879
976
|
tmpdir = f"implicit_tmpdir_{self.current_test_name}"
|
|
880
|
-
cmd = [["mkdir", "-p", tmpdir]]
|
|
881
977
|
|
|
882
|
-
|
|
978
|
+
if self.hdl_toplevel_lang == "vhdl":
|
|
979
|
+
xrun_top = ":"
|
|
980
|
+
else:
|
|
981
|
+
xrun_top = self.sim_hdl_toplevel
|
|
982
|
+
|
|
983
|
+
cmds = [["mkdir", "-p", tmpdir]]
|
|
984
|
+
cmds += [
|
|
883
985
|
["xrun"]
|
|
884
|
-
+ [
|
|
885
|
-
+ [
|
|
886
|
-
|
|
887
|
-
]
|
|
986
|
+
+ ["-logfile"]
|
|
987
|
+
+ [f"xrun_{self.current_test_name}.log"]
|
|
988
|
+
+ ["-xmlibdirname"]
|
|
989
|
+
+ [f"{self.build_dir}/xrun_snapshot"]
|
|
990
|
+
+ ["-cds_implicit_tmpdir"]
|
|
991
|
+
+ [tmpdir]
|
|
888
992
|
+ ["-licqueue"]
|
|
889
|
-
|
|
890
|
-
+ ["-messages"]
|
|
891
|
-
+ ["-plinowarn"]
|
|
892
|
-
# + ["-pliverbose"]
|
|
893
|
-
# + ["-plidebug"] # Enhance the profile output with PLI info
|
|
894
|
-
# + ["-plierr_verbose"] # Expand handle info in PLI/VPI/VHPI messages
|
|
895
|
-
# + ["-vpicompat 1800v2005"] # <1364v1995|1364v2001|1364v2005|1800v2005> Specify the IEEE VPI
|
|
993
|
+
+ verbosity_opts
|
|
896
994
|
+ ["-R"]
|
|
897
|
-
+ self.
|
|
898
|
-
+ self.
|
|
995
|
+
+ self.test_args
|
|
996
|
+
+ self.plusargs
|
|
899
997
|
+ ["-gui" if self.gui else ""]
|
|
998
|
+
+ ["-input"]
|
|
900
999
|
+ [
|
|
901
|
-
'-input "@
|
|
1000
|
+
f'-input "@database -open cocotb_waves -default" '
|
|
1001
|
+
f'-input "@probe -database cocotb_waves -create {xrun_top} -all -depth all" '
|
|
1002
|
+
f'-input "@run" '
|
|
1003
|
+
f'-input "@exit" '
|
|
902
1004
|
if self.waves
|
|
903
|
-
else ""
|
|
1005
|
+
else "@run; exit;"
|
|
904
1006
|
]
|
|
905
1007
|
]
|
|
906
1008
|
self.env["GPI_EXTRA"] = (
|
|
907
1009
|
cocotb.config.lib_name_path("vhpi", "xcelium") + ":cocotbvhpi_entry_point"
|
|
908
1010
|
)
|
|
909
1011
|
|
|
910
|
-
return
|
|
1012
|
+
return cmds
|
|
911
1013
|
|
|
912
1014
|
|
|
913
|
-
def get_runner(simulator_name: str) ->
|
|
1015
|
+
def get_runner(simulator_name: str) -> Simulator:
|
|
1016
|
+
"""Return the *simulator_name* instance."""
|
|
914
1017
|
|
|
915
|
-
sim_name = simulator_name.lower()
|
|
916
1018
|
supported_sims: Dict[str, Type[Simulator]] = {
|
|
917
1019
|
"icarus": Icarus,
|
|
918
1020
|
"questa": Questa,
|
|
@@ -921,26 +1023,11 @@ def get_runner(simulator_name: str) -> Type[Simulator]:
|
|
|
921
1023
|
"verilator": Verilator,
|
|
922
1024
|
"xcelium": Xcelium,
|
|
923
1025
|
# TODO: "vcs": Vcs,
|
|
1026
|
+
# TODO: "activehdl": ActiveHdl,
|
|
924
1027
|
}
|
|
925
1028
|
try:
|
|
926
|
-
return supported_sims[
|
|
1029
|
+
return supported_sims[simulator_name]()
|
|
927
1030
|
except KeyError:
|
|
928
|
-
raise
|
|
929
|
-
"
|
|
1031
|
+
raise ValueError(
|
|
1032
|
+
f"Simulator {simulator_name!r} is not in supported list: {', '.join(supported_sims)}"
|
|
930
1033
|
) from None
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
def clean(recursive: bool = False) -> None:
|
|
934
|
-
dir = os.getcwd()
|
|
935
|
-
|
|
936
|
-
def rm_clean() -> None:
|
|
937
|
-
build_dir = os.path.join(dir, "sim_build")
|
|
938
|
-
if os.path.isdir(build_dir):
|
|
939
|
-
print("INFO: Removing:", build_dir)
|
|
940
|
-
shutil.rmtree(build_dir, ignore_errors=True)
|
|
941
|
-
|
|
942
|
-
rm_clean()
|
|
943
|
-
|
|
944
|
-
if recursive:
|
|
945
|
-
for dir, _, _ in os.walk(dir):
|
|
946
|
-
rm_clean()
|