cocotb 1.8.1__cp312-cp312-win32.whl → 1.9.0rc2__cp312-cp312-win32.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/_version.py +1 -1
- cocotb/binary.py +48 -14
- cocotb/config.py +10 -16
- cocotb/decorators.py +7 -1
- cocotb/handle.py +1 -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/runner.py +487 -120
- cocotb/scheduler.py +4 -8
- 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.exp +0 -0
- cocotb/share/def/modelsim.lib +0 -0
- cocotb/share/lib/verilator/verilator.cpp +50 -8
- cocotb/share/makefiles/Makefile.inc +4 -10
- cocotb/share/makefiles/Makefile.sim +5 -5
- cocotb/share/makefiles/simulators/Makefile.activehdl +3 -3
- cocotb/share/makefiles/simulators/Makefile.cvc +1 -1
- cocotb/share/makefiles/simulators/Makefile.ghdl +29 -1
- cocotb/share/makefiles/simulators/Makefile.icarus +4 -4
- cocotb/share/makefiles/simulators/Makefile.ius +1 -1
- cocotb/share/makefiles/simulators/Makefile.nvc +64 -0
- cocotb/share/makefiles/simulators/Makefile.questa +1 -1
- cocotb/share/makefiles/simulators/Makefile.riviera +28 -12
- cocotb/share/makefiles/simulators/Makefile.vcs +2 -2
- cocotb/share/makefiles/simulators/Makefile.verilator +11 -5
- cocotb/share/makefiles/simulators/Makefile.xcelium +6 -1
- cocotb/simulator.cp312-win32.exp +0 -0
- cocotb/simulator.cp312-win32.lib +0 -0
- cocotb/simulator.cp312-win32.pyd +0 -0
- cocotb/triggers.py +102 -29
- {cocotb-1.8.1.dist-info → cocotb-1.9.0rc2.dist-info}/METADATA +3 -3
- cocotb-1.9.0rc2.dist-info/RECORD +121 -0
- {cocotb-1.8.1.dist-info → cocotb-1.9.0rc2.dist-info}/WHEEL +1 -1
- cocotb-1.8.1.dist-info/RECORD +0 -120
- {cocotb-1.8.1.dist-info → cocotb-1.9.0rc2.dist-info}/LICENSE +0 -0
- {cocotb-1.8.1.dist-info → cocotb-1.9.0rc2.dist-info}/entry_points.txt +0 -0
- {cocotb-1.8.1.dist-info → cocotb-1.9.0rc2.dist-info}/top_level.txt +0 -0
cocotb/runner.py
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
# TODO: maybe do globbing and expanduser/expandvars in --include, --vhdl-sources, --verilog-sources
|
|
8
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
|
|
9
|
+
# TODO: support timescale on all simulators
|
|
10
10
|
# TODO: support custom dependencies
|
|
11
11
|
|
|
12
12
|
import abc
|
|
@@ -20,8 +20,8 @@ import tempfile
|
|
|
20
20
|
import warnings
|
|
21
21
|
from contextlib import suppress
|
|
22
22
|
from pathlib import Path
|
|
23
|
-
from typing import Dict, List, Mapping, Optional, Sequence, Tuple, Type, Union
|
|
24
|
-
from xml.etree import
|
|
23
|
+
from typing import Dict, List, Mapping, Optional, Sequence, TextIO, Tuple, Type, Union
|
|
24
|
+
from xml.etree import ElementTree as ET
|
|
25
25
|
|
|
26
26
|
import find_libpython
|
|
27
27
|
|
|
@@ -29,6 +29,7 @@ import cocotb.config
|
|
|
29
29
|
|
|
30
30
|
PathLike = Union["os.PathLike[str]", str]
|
|
31
31
|
Command = List[str]
|
|
32
|
+
Timescale = Tuple[str, str]
|
|
32
33
|
|
|
33
34
|
warnings.warn(
|
|
34
35
|
"Python runners and associated APIs are an experimental feature and subject to change.",
|
|
@@ -59,6 +60,14 @@ def shlex_join(split_command):
|
|
|
59
60
|
return " ".join(shlex.quote(arg) for arg in split_command)
|
|
60
61
|
|
|
61
62
|
|
|
63
|
+
class VHDL(str):
|
|
64
|
+
"""Tags source files and build arguments to :meth:`~cocotb.runner.Simulator.build` as VHDL-specific."""
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class Verilog(str):
|
|
68
|
+
"""Tags source files and build arguments to :meth:`~cocotb.runner.Simulator.build` as Verilog-specific."""
|
|
69
|
+
|
|
70
|
+
|
|
62
71
|
class Simulator(abc.ABC):
|
|
63
72
|
|
|
64
73
|
supported_gpi_interfaces: Dict[str, List[str]] = {}
|
|
@@ -93,10 +102,17 @@ class Simulator(abc.ABC):
|
|
|
93
102
|
ValueError: *hdl_toplevel_lang* is not supported by the simulator.
|
|
94
103
|
"""
|
|
95
104
|
if hdl_toplevel_lang is None:
|
|
96
|
-
if self.vhdl_sources and not self.verilog_sources:
|
|
105
|
+
if self.vhdl_sources and not self.verilog_sources and not self.sources:
|
|
97
106
|
lang = "vhdl"
|
|
98
|
-
elif self.verilog_sources and not self.vhdl_sources:
|
|
107
|
+
elif self.verilog_sources and not self.vhdl_sources and not self.sources:
|
|
99
108
|
lang = "verilog"
|
|
109
|
+
elif self.sources and not self.vhdl_sources and not self.verilog_sources:
|
|
110
|
+
if is_vhdl_source(self.sources[-1]):
|
|
111
|
+
lang = "vhdl"
|
|
112
|
+
elif is_verilog_source(self.sources[-1]):
|
|
113
|
+
lang = "verilog"
|
|
114
|
+
else:
|
|
115
|
+
raise UnknownFileExtension(self.sources[-1])
|
|
100
116
|
else:
|
|
101
117
|
raise ValueError(
|
|
102
118
|
f"{type(self).__qualname__}: Must specify a hdl_toplevel_lang in a mixed-language design"
|
|
@@ -119,7 +135,12 @@ class Simulator(abc.ABC):
|
|
|
119
135
|
self.env[e] = os.environ[e]
|
|
120
136
|
|
|
121
137
|
if "LIBPYTHON_LOC" not in self.env:
|
|
122
|
-
|
|
138
|
+
libpython_path = find_libpython.find_libpython()
|
|
139
|
+
if not libpython_path:
|
|
140
|
+
raise ValueError(
|
|
141
|
+
"Unable to find libpython, please make sure the appropriate libpython is installed"
|
|
142
|
+
)
|
|
143
|
+
self.env["LIBPYTHON_LOC"] = libpython_path
|
|
123
144
|
|
|
124
145
|
self.env["PATH"] += os.pathsep + cocotb.config.libs_dir
|
|
125
146
|
self.env["PYTHONPATH"] = os.pathsep.join(sys.path)
|
|
@@ -144,21 +165,58 @@ class Simulator(abc.ABC):
|
|
|
144
165
|
hdl_library: str = "top",
|
|
145
166
|
verilog_sources: Sequence[PathLike] = [],
|
|
146
167
|
vhdl_sources: Sequence[PathLike] = [],
|
|
168
|
+
sources: Sequence[Union[PathLike, VHDL, Verilog]] = [],
|
|
147
169
|
includes: Sequence[PathLike] = [],
|
|
148
170
|
defines: Mapping[str, object] = {},
|
|
149
171
|
parameters: Mapping[str, object] = {},
|
|
150
|
-
build_args: Sequence[str] = [],
|
|
172
|
+
build_args: Sequence[Union[str, VHDL, Verilog]] = [],
|
|
151
173
|
hdl_toplevel: Optional[str] = None,
|
|
152
174
|
always: bool = False,
|
|
153
175
|
build_dir: PathLike = "sim_build",
|
|
176
|
+
clean: bool = False,
|
|
154
177
|
verbose: bool = False,
|
|
178
|
+
timescale: Optional[Timescale] = None,
|
|
179
|
+
waves: Optional[bool] = None,
|
|
180
|
+
log_file: Optional[PathLike] = None,
|
|
155
181
|
) -> None:
|
|
156
182
|
"""Build the HDL sources.
|
|
157
183
|
|
|
184
|
+
With mixed language simulators, *sources* will be built,
|
|
185
|
+
followed by *vhdl_sources*, then *verilog_sources*.
|
|
186
|
+
With simulators that only support either VHDL or Verilog, *sources* will be built,
|
|
187
|
+
followed by *vhdl_sources* and *verilog_sources*, respectively.
|
|
188
|
+
|
|
189
|
+
If your source files use an atypical file extension,
|
|
190
|
+
use :class:`VHDL` and :class:`Verilog` to tag the path as a VHDL or Verilog source file, respectively.
|
|
191
|
+
If the filepaths aren't tagged, the extension is used to determine if they are VHDL or Verilog files.
|
|
192
|
+
|
|
193
|
+
+----------+------------------------------------+
|
|
194
|
+
| Language | File Extensions |
|
|
195
|
+
+==========+====================================+
|
|
196
|
+
| VHDL | ``.vhd``, ``.vhdl`` |
|
|
197
|
+
+----------+------------------------------------+
|
|
198
|
+
| Verilog | ``.v``, ``.sv``, ``.vh``, ``.svh`` |
|
|
199
|
+
+----------+------------------------------------+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
.. code-block:: python3
|
|
203
|
+
|
|
204
|
+
runner.build(
|
|
205
|
+
sources=[
|
|
206
|
+
VHDL("/my/file.is_actually_vhdl"),
|
|
207
|
+
Verilog("/other/file.verilog"),
|
|
208
|
+
],
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
The same tagging works for *build_args*.
|
|
212
|
+
Tagged *build_args* only supply that option to the compiler when building the source file for the tagged language.
|
|
213
|
+
Non-tagged *build_args* are supplied when compiling any language.
|
|
214
|
+
|
|
158
215
|
Args:
|
|
159
216
|
hdl_library: The library name to compile into.
|
|
160
217
|
verilog_sources: Verilog source files to build.
|
|
161
218
|
vhdl_sources: VHDL source files to build.
|
|
219
|
+
sources: Language-agnostic list of source files to build.
|
|
162
220
|
includes: Verilog include directories.
|
|
163
221
|
defines: Defines to set.
|
|
164
222
|
parameters: Verilog parameters or VHDL generics.
|
|
@@ -166,10 +224,17 @@ class Simulator(abc.ABC):
|
|
|
166
224
|
hdl_toplevel: The name of the HDL toplevel module.
|
|
167
225
|
always: Always run the build step.
|
|
168
226
|
build_dir: Directory to run the build step in.
|
|
227
|
+
clean: Delete build_dir before building
|
|
169
228
|
verbose: Enable verbose messages.
|
|
229
|
+
timescale: Tuple containing time unit and time precision for simulation.
|
|
230
|
+
waves: Record signal traces.
|
|
231
|
+
log_file: File to write the build log to.
|
|
170
232
|
"""
|
|
171
233
|
|
|
234
|
+
self.clean: bool = clean
|
|
172
235
|
self.build_dir = get_abs_path(build_dir)
|
|
236
|
+
if self.clean:
|
|
237
|
+
self.rm_build_folder(self.build_dir)
|
|
173
238
|
os.makedirs(self.build_dir, exist_ok=True)
|
|
174
239
|
|
|
175
240
|
# note: to avoid mutating argument defaults, we ensure that no value
|
|
@@ -179,6 +244,7 @@ class Simulator(abc.ABC):
|
|
|
179
244
|
self.hdl_library: str = hdl_library
|
|
180
245
|
self.verilog_sources: List[Path] = get_abs_paths(verilog_sources)
|
|
181
246
|
self.vhdl_sources: List[Path] = get_abs_paths(vhdl_sources)
|
|
247
|
+
self.sources: List[Path] = get_abs_paths(sources)
|
|
182
248
|
self.includes: List[Path] = get_abs_paths(includes)
|
|
183
249
|
self.defines = dict(defines)
|
|
184
250
|
self.parameters = dict(parameters)
|
|
@@ -186,6 +252,10 @@ class Simulator(abc.ABC):
|
|
|
186
252
|
self.always: bool = always
|
|
187
253
|
self.hdl_toplevel: Optional[str] = hdl_toplevel
|
|
188
254
|
self.verbose: bool = verbose
|
|
255
|
+
self.timescale: Optional[Timescale] = timescale
|
|
256
|
+
self.log_file: Optional[PathLike] = log_file
|
|
257
|
+
|
|
258
|
+
self.waves = bool(waves)
|
|
189
259
|
|
|
190
260
|
for e in os.environ:
|
|
191
261
|
self.env[e] = os.environ[e]
|
|
@@ -210,8 +280,11 @@ class Simulator(abc.ABC):
|
|
|
210
280
|
parameters: Mapping[str, object] = None,
|
|
211
281
|
build_dir: Optional[PathLike] = None,
|
|
212
282
|
test_dir: Optional[PathLike] = None,
|
|
213
|
-
results_xml: str =
|
|
283
|
+
results_xml: Optional[str] = None,
|
|
284
|
+
pre_cmd: List[str] = [],
|
|
214
285
|
verbose: bool = False,
|
|
286
|
+
timescale: Optional[Timescale] = None,
|
|
287
|
+
log_file: Optional[PathLike] = None,
|
|
215
288
|
) -> Path:
|
|
216
289
|
"""Run the tests.
|
|
217
290
|
|
|
@@ -235,15 +308,17 @@ class Simulator(abc.ABC):
|
|
|
235
308
|
build_dir: Directory the build step has been run in.
|
|
236
309
|
test_dir: Directory to run the tests in.
|
|
237
310
|
results_xml: Name of xUnit XML file to store test results in.
|
|
238
|
-
|
|
311
|
+
If an absolute path is provided it will be used as-is,
|
|
312
|
+
``{build_dir}/results.xml`` otherwise.
|
|
313
|
+
This argument should not be set when run with ``pytest``.
|
|
239
314
|
verbose: Enable verbose messages.
|
|
315
|
+
pre_cmd: Commands to run before simulation begins.
|
|
316
|
+
timescale: Tuple containing time unit and time precision for simulation.
|
|
317
|
+
log_file: File to write the test log to.
|
|
240
318
|
|
|
241
319
|
Returns:
|
|
242
320
|
The absolute location of the results XML file which can be
|
|
243
321
|
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
322
|
"""
|
|
248
323
|
|
|
249
324
|
__tracebackhide__ = True # Hide the traceback when using pytest
|
|
@@ -279,6 +354,8 @@ class Simulator(abc.ABC):
|
|
|
279
354
|
for gpi_if in self.supported_gpi_interfaces.values():
|
|
280
355
|
self.gpi_interfaces.append(gpi_if[0])
|
|
281
356
|
|
|
357
|
+
self.pre_cmd = pre_cmd
|
|
358
|
+
|
|
282
359
|
self.test_args = list(test_args)
|
|
283
360
|
self.plusargs = list(plusargs)
|
|
284
361
|
self.env = dict(extra_env)
|
|
@@ -292,22 +369,31 @@ class Simulator(abc.ABC):
|
|
|
292
369
|
if seed is not None:
|
|
293
370
|
self.env["RANDOM_SEED"] = str(seed)
|
|
294
371
|
|
|
372
|
+
self.log_file = log_file
|
|
295
373
|
self.waves = bool(waves)
|
|
296
374
|
self.gui = bool(gui)
|
|
375
|
+
self.timescale: Optional[Timescale] = timescale
|
|
297
376
|
|
|
298
377
|
if verbose is not None:
|
|
299
378
|
self.verbose = verbose
|
|
300
379
|
|
|
301
380
|
# When using pytest, use test name as result file name
|
|
302
|
-
pytest_current_test = os.getenv("PYTEST_CURRENT_TEST",
|
|
303
|
-
|
|
381
|
+
pytest_current_test = os.getenv("PYTEST_CURRENT_TEST", None)
|
|
382
|
+
test_dir_path = Path(self.test_dir)
|
|
383
|
+
self.current_test_name = "test"
|
|
384
|
+
if results_xml is not None:
|
|
385
|
+
# PYTEST_CURRENT_TEST only allowed when results_xml is not set
|
|
386
|
+
assert not pytest_current_test
|
|
387
|
+
results_xml_path = Path(results_xml)
|
|
388
|
+
if results_xml_path.is_absolute():
|
|
389
|
+
results_xml_file = results_xml_path
|
|
390
|
+
else:
|
|
391
|
+
results_xml_file = test_dir_path / results_xml_path
|
|
392
|
+
elif pytest_current_test is not None:
|
|
304
393
|
self.current_test_name = pytest_current_test.split(":")[-1].split(" ")[0]
|
|
305
|
-
|
|
394
|
+
results_xml_file = test_dir_path / f"{self.current_test_name}.{results_xml}"
|
|
306
395
|
else:
|
|
307
|
-
|
|
308
|
-
results_xml_name = results_xml
|
|
309
|
-
|
|
310
|
-
results_xml_file = Path(self.test_dir) / results_xml_name
|
|
396
|
+
results_xml_file = test_dir_path / "results.xml"
|
|
311
397
|
|
|
312
398
|
with suppress(OSError):
|
|
313
399
|
os.remove(results_xml_file)
|
|
@@ -350,19 +436,38 @@ class Simulator(abc.ABC):
|
|
|
350
436
|
|
|
351
437
|
__tracebackhide__ = True # Hide the traceback when using PyTest.
|
|
352
438
|
|
|
439
|
+
if self.log_file is None:
|
|
440
|
+
self._execute_cmds(cmds, cwd)
|
|
441
|
+
else:
|
|
442
|
+
with open(self.log_file, "w") as f:
|
|
443
|
+
self._execute_cmds(cmds, cwd, f)
|
|
444
|
+
|
|
445
|
+
def _execute_cmds(
|
|
446
|
+
self, cmds: Sequence[Command], cwd: PathLike, stdout: Optional[TextIO] = None
|
|
447
|
+
) -> None:
|
|
448
|
+
__tracebackhide__ = True # Hide the traceback when using PyTest.
|
|
449
|
+
|
|
353
450
|
for cmd in cmds:
|
|
354
451
|
print(f"INFO: Running command {shlex_join(cmd)} in directory {cwd}")
|
|
355
452
|
|
|
356
453
|
# TODO: create a thread to handle stderr and log as error?
|
|
357
454
|
# TODO: log forwarding
|
|
358
455
|
|
|
359
|
-
|
|
456
|
+
stderr = None if stdout is None else subprocess.STDOUT
|
|
457
|
+
process = subprocess.run(
|
|
458
|
+
cmd, cwd=cwd, env=self.env, stdout=stdout, stderr=stderr
|
|
459
|
+
)
|
|
360
460
|
|
|
361
461
|
if process.returncode != 0:
|
|
362
462
|
raise SystemExit(
|
|
363
463
|
f"Process {process.args[0]!r} terminated with error {process.returncode}"
|
|
364
464
|
)
|
|
365
465
|
|
|
466
|
+
def rm_build_folder(self, build_dir: Path):
|
|
467
|
+
if os.path.isdir(build_dir):
|
|
468
|
+
print("Removing:", build_dir)
|
|
469
|
+
shutil.rmtree(build_dir, ignore_errors=True)
|
|
470
|
+
|
|
366
471
|
|
|
367
472
|
def get_results(results_xml_file: Path) -> Tuple[int, int]:
|
|
368
473
|
"""Return number of tests and fails in *results_xml_file*.
|
|
@@ -446,6 +551,40 @@ def get_abs_paths(paths: Sequence[PathLike]) -> List[Path]:
|
|
|
446
551
|
return [get_abs_path(path) for path in paths]
|
|
447
552
|
|
|
448
553
|
|
|
554
|
+
_verilog_extensions = (".v", ".sv", ".vh", ".svh")
|
|
555
|
+
_vhdl_extensions = (".vhd", ".vhdl")
|
|
556
|
+
|
|
557
|
+
_vhdl_extensions_s = ", ".join(f"`{c}`" for c in _vhdl_extensions)
|
|
558
|
+
_verilog_extensions_s = ", ".join(f"`{c}`" for c in _verilog_extensions)
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
class UnknownFileExtension(ValueError):
|
|
562
|
+
def __init__(self, source: PathLike) -> None:
|
|
563
|
+
super().__init__(
|
|
564
|
+
f"Can't determine if {source} is a VHDL or Verilog file. "
|
|
565
|
+
f"Use a standard file extension ({_vhdl_extensions_s} for VHDL files and {_verilog_extensions_s} for Verilog files) "
|
|
566
|
+
"or tag the source with `VHDL(source)` or `Verilog(source)`."
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
def is_vhdl_source(source: PathLike) -> bool:
|
|
571
|
+
if isinstance(source, VHDL):
|
|
572
|
+
return True
|
|
573
|
+
source_as_path = Path(source)
|
|
574
|
+
if source_as_path.suffix in _vhdl_extensions:
|
|
575
|
+
return True
|
|
576
|
+
return False
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def is_verilog_source(source: PathLike) -> bool:
|
|
580
|
+
if isinstance(source, Verilog):
|
|
581
|
+
return True
|
|
582
|
+
source_as_path = Path(source)
|
|
583
|
+
if source_as_path.suffix in _verilog_extensions:
|
|
584
|
+
return True
|
|
585
|
+
return False
|
|
586
|
+
|
|
587
|
+
|
|
449
588
|
class Icarus(Simulator):
|
|
450
589
|
supported_gpi_interfaces = {"verilog": ["vpi"]}
|
|
451
590
|
|
|
@@ -469,11 +608,39 @@ class Icarus(Simulator):
|
|
|
469
608
|
for name, value in parameters.items()
|
|
470
609
|
]
|
|
471
610
|
|
|
611
|
+
def _create_cmd_file(self) -> None:
|
|
612
|
+
with open(self.cmds_file, "w") as f:
|
|
613
|
+
f.write("+timescale+{}/{}\n".format(*self.timescale))
|
|
614
|
+
|
|
615
|
+
def _create_iverilog_dump_file(self) -> None:
|
|
616
|
+
dumpfile_path = Path(self.build_dir, f"{self.hdl_toplevel}.fst").as_posix()
|
|
617
|
+
with open(self.iverilog_dump_file, "w") as f:
|
|
618
|
+
f.write("module cocotb_iverilog_dump();\n")
|
|
619
|
+
f.write("initial begin\n")
|
|
620
|
+
f.write(f' $dumpfile("{dumpfile_path}");\n')
|
|
621
|
+
f.write(f" $dumpvars(0, {self.hdl_toplevel});\n")
|
|
622
|
+
f.write("end\n")
|
|
623
|
+
f.write("endmodule\n")
|
|
624
|
+
|
|
472
625
|
@property
|
|
473
626
|
def sim_file(self) -> Path:
|
|
474
627
|
return self.build_dir / "sim.vvp"
|
|
475
628
|
|
|
629
|
+
@property
|
|
630
|
+
def iverilog_dump_file(self) -> Path:
|
|
631
|
+
return self.build_dir / "cocotb_iverilog_dump.v"
|
|
632
|
+
|
|
633
|
+
@property
|
|
634
|
+
def cmds_file(self) -> Path:
|
|
635
|
+
return self.build_dir / "cmds.f"
|
|
636
|
+
|
|
476
637
|
def _test_command(self) -> List[Command]:
|
|
638
|
+
plusargs = self.plusargs
|
|
639
|
+
if self.waves:
|
|
640
|
+
plusargs += ["-fst"]
|
|
641
|
+
|
|
642
|
+
if self.pre_cmd:
|
|
643
|
+
print("WARNING: pre_cmd is not implemented for Icarus Verilog.")
|
|
477
644
|
|
|
478
645
|
return [
|
|
479
646
|
[
|
|
@@ -485,26 +652,56 @@ class Icarus(Simulator):
|
|
|
485
652
|
]
|
|
486
653
|
+ self.test_args
|
|
487
654
|
+ [str(self.sim_file)]
|
|
488
|
-
+
|
|
655
|
+
+ plusargs
|
|
489
656
|
]
|
|
490
657
|
|
|
491
658
|
def _build_command(self) -> List[Command]:
|
|
659
|
+
for source in self.sources:
|
|
660
|
+
if not is_verilog_source(source):
|
|
661
|
+
raise ValueError(
|
|
662
|
+
f"{type(self).__qualname__} only supports Verilog. {str(source)!r} cannot be compiled."
|
|
663
|
+
)
|
|
664
|
+
for arg in self.build_args:
|
|
665
|
+
if type(arg) not in (str, Verilog):
|
|
666
|
+
print(
|
|
667
|
+
f"WARNING: {type(self).__qualname__} only supports Verilog. build_args {arg!r} will not be applied."
|
|
668
|
+
)
|
|
492
669
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
670
|
+
build_args = list(self.build_args)
|
|
671
|
+
if self.waves:
|
|
672
|
+
self._create_iverilog_dump_file()
|
|
673
|
+
build_args += ["-s", "cocotb_iverilog_dump"]
|
|
497
674
|
|
|
498
|
-
|
|
499
|
-
|
|
675
|
+
if self.timescale is not None:
|
|
676
|
+
self._create_cmd_file()
|
|
677
|
+
build_args += ["-f", str(self.cmds_file)]
|
|
500
678
|
|
|
679
|
+
cmds = []
|
|
680
|
+
sources = [
|
|
681
|
+
source for source in self.sources if is_verilog_source(source)
|
|
682
|
+
] + self.verilog_sources
|
|
683
|
+
if outdated(self.sim_file, sources) or self.always:
|
|
501
684
|
cmds = [
|
|
502
|
-
[
|
|
685
|
+
[
|
|
686
|
+
"iverilog",
|
|
687
|
+
"-o",
|
|
688
|
+
str(self.sim_file),
|
|
689
|
+
"-D",
|
|
690
|
+
"COCOTB_SIM=1",
|
|
691
|
+
"-s",
|
|
692
|
+
self.hdl_toplevel,
|
|
693
|
+
"-g2012",
|
|
694
|
+
]
|
|
503
695
|
+ self._get_define_options(self.defines)
|
|
504
696
|
+ self._get_include_options(self.includes)
|
|
505
697
|
+ self._get_parameter_options(self.parameters)
|
|
506
|
-
+
|
|
507
|
-
+ [str(source_file) for source_file in
|
|
698
|
+
+ [arg for arg in build_args if type(arg) in (str, Verilog)]
|
|
699
|
+
+ [str(source_file) for source_file in sources]
|
|
700
|
+
+ [
|
|
701
|
+
str(source_file)
|
|
702
|
+
for source_file in [self.iverilog_dump_file]
|
|
703
|
+
if self.waves
|
|
704
|
+
]
|
|
508
705
|
]
|
|
509
706
|
|
|
510
707
|
else:
|
|
@@ -540,35 +737,48 @@ class Questa(Simulator):
|
|
|
540
737
|
|
|
541
738
|
cmds = []
|
|
542
739
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
cmds.append(
|
|
555
|
-
["vlog"]
|
|
556
|
-
+ ([] if self.always else ["-incr"])
|
|
557
|
-
+ ["-work", as_tcl_value(self.hdl_library)]
|
|
558
|
-
+ ["+define+COCOTB_SIM"]
|
|
559
|
-
+ ["-sv"]
|
|
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]
|
|
564
|
-
)
|
|
740
|
+
cmds.append(["vlib", as_tcl_value(self.hdl_library)])
|
|
741
|
+
for source in self.sources:
|
|
742
|
+
if is_vhdl_source(source):
|
|
743
|
+
cmds.append(self._build_vhdl_command(source))
|
|
744
|
+
elif is_verilog_source(source):
|
|
745
|
+
cmds.append(self._build_verilog_command(source))
|
|
746
|
+
else:
|
|
747
|
+
raise UnknownFileExtension(source)
|
|
748
|
+
for source in self.vhdl_sources:
|
|
749
|
+
cmds.append(self._build_vhdl_command(source))
|
|
750
|
+
for source in self.verilog_sources:
|
|
751
|
+
cmds.append(self._build_verilog_command(source))
|
|
565
752
|
|
|
566
753
|
return cmds
|
|
567
754
|
|
|
755
|
+
def _build_vhdl_command(self, source: PathLike) -> Command:
|
|
756
|
+
return (
|
|
757
|
+
["vcom"]
|
|
758
|
+
+ ["-work", as_tcl_value(self.hdl_library)]
|
|
759
|
+
+ [as_tcl_value(v) for v in self.build_args if type(v) in (str, VHDL)]
|
|
760
|
+
+ [as_tcl_value(str(source))]
|
|
761
|
+
)
|
|
762
|
+
|
|
763
|
+
def _build_verilog_command(self, source: PathLike) -> Command:
|
|
764
|
+
return (
|
|
765
|
+
["vlog"]
|
|
766
|
+
+ ([] if self.always else ["-incr"])
|
|
767
|
+
+ ["-work", as_tcl_value(self.hdl_library)]
|
|
768
|
+
+ ["-sv"]
|
|
769
|
+
+ self._get_define_options(self.defines)
|
|
770
|
+
+ self._get_include_options(self.includes)
|
|
771
|
+
+ [as_tcl_value(v) for v in self.build_args if type(v) in (str, Verilog)]
|
|
772
|
+
+ [as_tcl_value(str(source))]
|
|
773
|
+
)
|
|
774
|
+
|
|
568
775
|
def _test_command(self) -> List[Command]:
|
|
569
776
|
|
|
570
777
|
cmds = []
|
|
571
778
|
|
|
779
|
+
if self.pre_cmd:
|
|
780
|
+
self.pre_cmd = ["-do"] + self.pre_cmd
|
|
781
|
+
|
|
572
782
|
do_script = ""
|
|
573
783
|
if self.waves:
|
|
574
784
|
do_script += "log -recursive /*;"
|
|
@@ -577,8 +787,6 @@ class Questa(Simulator):
|
|
|
577
787
|
do_script += "run -all; quit"
|
|
578
788
|
|
|
579
789
|
gpi_if_entry = self.gpi_interfaces[0]
|
|
580
|
-
gpi_if_entry_lib_path = cocotb.config.lib_name_path(gpi_if_entry, "questa")
|
|
581
|
-
|
|
582
790
|
if gpi_if_entry == "fli":
|
|
583
791
|
lib_opts = [
|
|
584
792
|
"-foreign",
|
|
@@ -598,11 +806,6 @@ class Questa(Simulator):
|
|
|
598
806
|
as_tcl_value(cocotb.config.lib_name_path("vpi", "questa")),
|
|
599
807
|
]
|
|
600
808
|
|
|
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."
|
|
604
|
-
)
|
|
605
|
-
|
|
606
809
|
cmds.append(
|
|
607
810
|
["vsim"]
|
|
608
811
|
+ ["-gui" if self.gui else "-c"]
|
|
@@ -612,6 +815,7 @@ class Questa(Simulator):
|
|
|
612
815
|
+ [as_tcl_value(v) for v in self._get_parameter_options(self.parameters)]
|
|
613
816
|
+ [as_tcl_value(f"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}")]
|
|
614
817
|
+ [as_tcl_value(v) for v in self.plusargs]
|
|
818
|
+
+ self.pre_cmd
|
|
615
819
|
+ ["-do", do_script]
|
|
616
820
|
)
|
|
617
821
|
|
|
@@ -638,22 +842,39 @@ class Ghdl(Simulator):
|
|
|
638
842
|
if shutil.which("ghdl") is None:
|
|
639
843
|
raise SystemExit("ERROR: ghdl executable not found!")
|
|
640
844
|
|
|
845
|
+
def _is_mcode_backend(self) -> bool:
|
|
846
|
+
"""Is GHDL using the mcode backend?"""
|
|
847
|
+
result = subprocess.run(
|
|
848
|
+
["ghdl", "--version"],
|
|
849
|
+
check=True,
|
|
850
|
+
text=True,
|
|
851
|
+
stdout=subprocess.PIPE,
|
|
852
|
+
stderr=subprocess.STDOUT,
|
|
853
|
+
)
|
|
854
|
+
return "mcode" in result.stdout
|
|
855
|
+
|
|
641
856
|
@staticmethod
|
|
642
857
|
def _get_parameter_options(parameters: Mapping[str, object]) -> Command:
|
|
643
858
|
return [f"-g{name}={value}" for name, value in parameters.items()]
|
|
644
859
|
|
|
645
860
|
def _build_command(self) -> List[Command]:
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
861
|
+
for source in self.sources:
|
|
862
|
+
if not is_vhdl_source(source):
|
|
863
|
+
raise ValueError(
|
|
864
|
+
f"{type(self).__qualname__} only supports VHDL. {str(source)!r} cannot be compiled."
|
|
865
|
+
)
|
|
866
|
+
for arg in self.build_args:
|
|
867
|
+
if type(arg) not in (str, VHDL):
|
|
868
|
+
print(
|
|
869
|
+
f"WARNING: {type(self).__qualname__} only supports VHDL. build_args {arg!r} will not be applied."
|
|
870
|
+
)
|
|
651
871
|
|
|
652
872
|
cmds = [
|
|
653
873
|
["ghdl", "-i"]
|
|
654
874
|
+ [f"--work={self.hdl_library}"]
|
|
655
|
-
+ self.build_args
|
|
656
|
-
+ [str(
|
|
875
|
+
+ [arg for arg in self.build_args if type(arg) in (str, VHDL)]
|
|
876
|
+
+ [str(source) for source in self.sources if is_vhdl_source(source)]
|
|
877
|
+
+ [str(source) for source in self.vhdl_sources]
|
|
657
878
|
]
|
|
658
879
|
|
|
659
880
|
if self.hdl_toplevel is not None:
|
|
@@ -667,11 +888,42 @@ class Ghdl(Simulator):
|
|
|
667
888
|
return cmds
|
|
668
889
|
|
|
669
890
|
def _test_command(self) -> List[Command]:
|
|
891
|
+
if self.pre_cmd:
|
|
892
|
+
print("WARNING: pre_cmd is not implemented for GHDL.")
|
|
893
|
+
|
|
894
|
+
ghdl_run_args = self.test_args
|
|
895
|
+
|
|
896
|
+
if self._is_mcode_backend() and self.timescale:
|
|
897
|
+
_, precision = self.timescale
|
|
898
|
+
# Convert the time precision to a format string supported by GHDL,
|
|
899
|
+
# if possible.
|
|
900
|
+
# GHDL only supports setting the time precision if the mcode backend
|
|
901
|
+
# is used, using the --time-resolution argument causes GHDL to error
|
|
902
|
+
# out otherwise.
|
|
903
|
+
# https://ghdl.github.io/ghdl/using/InvokingGHDL.html#cmdoption-ghdl-time-resolution
|
|
904
|
+
if precision == "1fs":
|
|
905
|
+
ghdl_time_resolution = "fs"
|
|
906
|
+
elif precision == "1ps":
|
|
907
|
+
ghdl_time_resolution = "ps"
|
|
908
|
+
elif precision == "1ns":
|
|
909
|
+
ghdl_time_resolution = "ns"
|
|
910
|
+
elif precision == "1us":
|
|
911
|
+
ghdl_time_resolution = "us"
|
|
912
|
+
elif precision == "1ms":
|
|
913
|
+
ghdl_time_resolution = "ms"
|
|
914
|
+
elif precision == "1s":
|
|
915
|
+
ghdl_time_resolution = "sec"
|
|
916
|
+
else:
|
|
917
|
+
raise ValueError(
|
|
918
|
+
"GHDL only supports the following precisions in timescale: 1fs, 1ps, 1us, 1ms, 1s"
|
|
919
|
+
)
|
|
920
|
+
|
|
921
|
+
ghdl_run_args.append(f"--time-resolution={ghdl_time_resolution}")
|
|
670
922
|
|
|
671
923
|
cmds = [
|
|
672
924
|
["ghdl", "-r"]
|
|
673
925
|
+ [f"--work={self.hdl_toplevel_library}"]
|
|
674
|
-
+
|
|
926
|
+
+ ghdl_run_args
|
|
675
927
|
+ [self.sim_hdl_toplevel]
|
|
676
928
|
+ ["--vpi=" + cocotb.config.lib_name_path("vpi", "ghdl")]
|
|
677
929
|
+ self.plusargs
|
|
@@ -681,6 +933,55 @@ class Ghdl(Simulator):
|
|
|
681
933
|
return cmds
|
|
682
934
|
|
|
683
935
|
|
|
936
|
+
class Nvc(Simulator):
|
|
937
|
+
supported_gpi_interfaces = {"vhdl": ["vhpi"]}
|
|
938
|
+
|
|
939
|
+
@staticmethod
|
|
940
|
+
def _simulator_in_path() -> None:
|
|
941
|
+
if shutil.which("nvc") is None:
|
|
942
|
+
raise SystemExit("ERROR: nvc executable not found!")
|
|
943
|
+
|
|
944
|
+
@staticmethod
|
|
945
|
+
def _get_parameter_options(parameters: Mapping[str, object]) -> Command:
|
|
946
|
+
return [f"-g{name}={value}" for name, value in parameters.items()]
|
|
947
|
+
|
|
948
|
+
def _build_command(self) -> List[Command]:
|
|
949
|
+
for source in self.sources:
|
|
950
|
+
if not is_vhdl_source(source):
|
|
951
|
+
raise ValueError(
|
|
952
|
+
f"{type(self).__qualname__} only supports VHDL. {str(source)!r} cannot be compiled."
|
|
953
|
+
)
|
|
954
|
+
for arg in self.build_args:
|
|
955
|
+
if type(arg) not in (str, VHDL):
|
|
956
|
+
print(
|
|
957
|
+
f"WARNING: {type(self).__qualname__} only supports VHDL. build_args {arg!r} will not be applied."
|
|
958
|
+
)
|
|
959
|
+
|
|
960
|
+
cmds = [
|
|
961
|
+
["nvc", f"--work={self.hdl_library}"]
|
|
962
|
+
+ [arg for arg in self.build_args if type(arg) in (str, VHDL)]
|
|
963
|
+
+ ["-a"]
|
|
964
|
+
+ [str(source) for source in self.sources if is_vhdl_source(source)]
|
|
965
|
+
+ [str(source) for source in self.vhdl_sources]
|
|
966
|
+
]
|
|
967
|
+
|
|
968
|
+
return cmds
|
|
969
|
+
|
|
970
|
+
def _test_command(self) -> List[Command]:
|
|
971
|
+
cmds = [
|
|
972
|
+
["nvc", f"--work={self.hdl_toplevel_library}"]
|
|
973
|
+
+ self.build_args
|
|
974
|
+
+ ["-e", self.sim_hdl_toplevel, "--no-save", "--jit"]
|
|
975
|
+
+ self._get_parameter_options(self.parameters)
|
|
976
|
+
+ ["-r"]
|
|
977
|
+
+ self.test_args
|
|
978
|
+
+ ["--load=" + cocotb.config.lib_name_path("vhpi", "nvc")]
|
|
979
|
+
+ self.plusargs
|
|
980
|
+
]
|
|
981
|
+
|
|
982
|
+
return cmds
|
|
983
|
+
|
|
984
|
+
|
|
684
985
|
class Riviera(Simulator):
|
|
685
986
|
supported_gpi_interfaces = {"verilog": ["vpi"], "vhdl": ["vhpi"]}
|
|
686
987
|
|
|
@@ -705,53 +1006,67 @@ class Riviera(Simulator):
|
|
|
705
1006
|
return [f"-g{name}={value}" for name, value in parameters.items()]
|
|
706
1007
|
|
|
707
1008
|
def _build_command(self) -> List[Command]:
|
|
708
|
-
|
|
709
|
-
do_script = "\nonerror {\n quit -code 1 \n} \n"
|
|
1009
|
+
do_script: List[str] = ["onerror {\n quit -code 1 \n}"]
|
|
710
1010
|
|
|
711
1011
|
out_file = self.build_dir / self.hdl_library / f"{self.hdl_library}.lib"
|
|
712
1012
|
|
|
713
1013
|
if outdated(out_file, self.verilog_sources + self.vhdl_sources) or self.always:
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
as_tcl_value(str(v)) for v in self.verilog_sources
|
|
735
|
-
),
|
|
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),
|
|
739
|
-
)
|
|
740
|
-
else:
|
|
741
|
-
print("WARNING: Skipping compilation of", out_file)
|
|
1014
|
+
do_script.append(f"alib {as_tcl_value(self.hdl_library)}")
|
|
1015
|
+
|
|
1016
|
+
for source in self.sources:
|
|
1017
|
+
if is_verilog_source(source):
|
|
1018
|
+
do_script.append(self._build_verilog_source(source))
|
|
1019
|
+
elif is_vhdl_source(source):
|
|
1020
|
+
do_script.append(self._build_vhdl_source(source))
|
|
1021
|
+
else:
|
|
1022
|
+
raise UnknownFileExtension(source)
|
|
1023
|
+
for source in self.vhdl_sources:
|
|
1024
|
+
do_script.append(self._build_vhdl_source(source))
|
|
1025
|
+
for source in self.verilog_sources:
|
|
1026
|
+
do_script.append(self._build_verilog_source(source))
|
|
1027
|
+
|
|
1028
|
+
# Explicitly exit the script at the end. In batch mode, which is invoked
|
|
1029
|
+
# implicitly by redirecting STDOUT/STDERR of the alog/acom commands,
|
|
1030
|
+
# the tool exits by itself even without this 'exit' command -- but not
|
|
1031
|
+
# when running from an interactive terminal. Be explicit for predictable
|
|
1032
|
+
# behavior.
|
|
1033
|
+
do_script.append("exit")
|
|
742
1034
|
|
|
743
1035
|
do_file = tempfile.NamedTemporaryFile(delete=False)
|
|
744
|
-
do_file.write(do_script.encode())
|
|
1036
|
+
do_file.write("\n".join(do_script).encode())
|
|
745
1037
|
do_file.close()
|
|
746
1038
|
|
|
747
1039
|
return [["vsimsa"] + ["-do"] + ["do"] + [do_file.name]]
|
|
748
1040
|
|
|
1041
|
+
def _build_vhdl_source(self, source: PathLike) -> str:
|
|
1042
|
+
return "acom -work {RTL_LIBRARY} {EXTRA_ARGS} {VHDL_SOURCES}".format(
|
|
1043
|
+
RTL_LIBRARY=as_tcl_value(self.hdl_library),
|
|
1044
|
+
VHDL_SOURCES=as_tcl_value(str(source)),
|
|
1045
|
+
EXTRA_ARGS=" ".join(
|
|
1046
|
+
as_tcl_value(v) for v in self.build_args if type(v) in (str, VHDL)
|
|
1047
|
+
),
|
|
1048
|
+
)
|
|
1049
|
+
|
|
1050
|
+
def _build_verilog_source(self, source: PathLike) -> str:
|
|
1051
|
+
return "alog -work {RTL_LIBRARY} -pli {EXT_NAME} -sv {DEFINES} {INCDIR} {EXTRA_ARGS} {VERILOG_SOURCES}".format(
|
|
1052
|
+
RTL_LIBRARY=as_tcl_value(self.hdl_library),
|
|
1053
|
+
EXT_NAME=as_tcl_value(cocotb.config.lib_name_path("vpi", "riviera")),
|
|
1054
|
+
VERILOG_SOURCES=as_tcl_value(str(source)),
|
|
1055
|
+
DEFINES=" ".join(self._get_define_options(self.defines)),
|
|
1056
|
+
INCDIR=" ".join(self._get_include_options(self.includes)),
|
|
1057
|
+
EXTRA_ARGS=" ".join(
|
|
1058
|
+
as_tcl_value(v) for v in self.build_args if type(v) in (str, Verilog)
|
|
1059
|
+
),
|
|
1060
|
+
)
|
|
1061
|
+
|
|
749
1062
|
def _test_command(self) -> List[Command]:
|
|
1063
|
+
if self.pre_cmd:
|
|
1064
|
+
print("WARNING: pre_cmd is not implemented for Riviera.")
|
|
750
1065
|
|
|
751
|
-
do_script = "\nonerror {\n quit -code 1 \n} \n"
|
|
1066
|
+
do_script: str = "\nonerror {\n quit -code 1 \n} \n"
|
|
752
1067
|
|
|
753
1068
|
if self.hdl_toplevel_lang == "vhdl":
|
|
754
|
-
do_script += "asim +access +
|
|
1069
|
+
do_script += "asim +access +w_nets -interceptcoutput -loadvhpi {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {PLUSARGS}\n".format(
|
|
755
1070
|
TOPLEVEL=as_tcl_value(
|
|
756
1071
|
f"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}"
|
|
757
1072
|
),
|
|
@@ -769,7 +1084,7 @@ class Riviera(Simulator):
|
|
|
769
1084
|
cocotb.config.lib_name_path("vpi", "riviera") + ":cocotbvpi_entry_point"
|
|
770
1085
|
)
|
|
771
1086
|
else:
|
|
772
|
-
do_script += "asim +access +
|
|
1087
|
+
do_script += "asim +access +w_nets -interceptcoutput -pli {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {PLUSARGS} \n".format(
|
|
773
1088
|
TOPLEVEL=as_tcl_value(
|
|
774
1089
|
f"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}"
|
|
775
1090
|
),
|
|
@@ -804,6 +1119,10 @@ class Verilator(Simulator):
|
|
|
804
1119
|
supported_gpi_interfaces = {"verilog": ["vpi"]}
|
|
805
1120
|
|
|
806
1121
|
def _simulator_in_path(self) -> None:
|
|
1122
|
+
# the verilator binary is only needed for building
|
|
1123
|
+
return
|
|
1124
|
+
|
|
1125
|
+
def _simulator_in_path_build_only(self) -> None:
|
|
807
1126
|
executable = shutil.which("verilator")
|
|
808
1127
|
if executable is None:
|
|
809
1128
|
raise SystemExit("ERROR: verilator executable not found!")
|
|
@@ -822,15 +1141,22 @@ class Verilator(Simulator):
|
|
|
822
1141
|
return [f"-G{name}={value}" for name, value in parameters.items()]
|
|
823
1142
|
|
|
824
1143
|
def _build_command(self) -> List[Command]:
|
|
1144
|
+
self._simulator_in_path_build_only()
|
|
825
1145
|
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
1146
|
+
for source in self.sources:
|
|
1147
|
+
if not is_verilog_source(source):
|
|
1148
|
+
raise ValueError(
|
|
1149
|
+
f"{type(self).__qualname__} only supports Verilog. {str(source)!r} cannot be compiled."
|
|
1150
|
+
)
|
|
1151
|
+
for arg in self.build_args:
|
|
1152
|
+
if type(arg) not in (str, Verilog):
|
|
1153
|
+
print(
|
|
1154
|
+
f"WARNING: {type(self).__qualname__} only supports Verilog. build_args {arg!r} will not be applied."
|
|
1155
|
+
)
|
|
830
1156
|
|
|
831
1157
|
if self.hdl_toplevel is None:
|
|
832
1158
|
raise ValueError(
|
|
833
|
-
f"{type(self).__qualname__}
|
|
1159
|
+
f"{type(self).__qualname__} requires the hdl_toplevel parameter to be specified"
|
|
834
1160
|
)
|
|
835
1161
|
|
|
836
1162
|
# TODO: set "--debug" if self.verbose
|
|
@@ -867,21 +1193,40 @@ class Verilator(Simulator):
|
|
|
867
1193
|
LIB_DIR=cocotb.config.libs_dir
|
|
868
1194
|
),
|
|
869
1195
|
]
|
|
870
|
-
+ self.
|
|
1196
|
+
+ (["--trace"] if self.waves else [])
|
|
1197
|
+
+ [arg for arg in self.build_args if type(arg) in (str, Verilog)]
|
|
871
1198
|
+ self._get_define_options(self.defines)
|
|
872
1199
|
+ self._get_include_options(self.includes)
|
|
873
1200
|
+ self._get_parameter_options(self.parameters)
|
|
874
1201
|
+ [verilator_cpp]
|
|
875
|
-
+ [str(
|
|
1202
|
+
+ [str(source) for source in self.sources if is_verilog_source(source)]
|
|
1203
|
+
+ [str(source) for source in self.verilog_sources]
|
|
876
1204
|
)
|
|
877
1205
|
|
|
878
|
-
cmds.append(
|
|
1206
|
+
cmds.append(
|
|
1207
|
+
[
|
|
1208
|
+
"make",
|
|
1209
|
+
"-C",
|
|
1210
|
+
str(self.build_dir),
|
|
1211
|
+
"-f",
|
|
1212
|
+
"Vtop.mk",
|
|
1213
|
+
f"VM_TRACE={int(self.waves)}",
|
|
1214
|
+
]
|
|
1215
|
+
)
|
|
879
1216
|
|
|
880
1217
|
return cmds
|
|
881
1218
|
|
|
882
1219
|
def _test_command(self) -> List[Command]:
|
|
1220
|
+
if self.pre_cmd:
|
|
1221
|
+
print("WARNING: pre_cmd is not implemented for Verilator.")
|
|
1222
|
+
|
|
883
1223
|
out_file = self.build_dir / self.sim_hdl_toplevel
|
|
884
|
-
return [
|
|
1224
|
+
return [
|
|
1225
|
+
[str(out_file)]
|
|
1226
|
+
+ (["--trace"] if self.waves else [])
|
|
1227
|
+
+ self.test_args
|
|
1228
|
+
+ self.plusargs
|
|
1229
|
+
]
|
|
885
1230
|
|
|
886
1231
|
|
|
887
1232
|
class Xcelium(Simulator):
|
|
@@ -907,6 +1252,8 @@ class Xcelium(Simulator):
|
|
|
907
1252
|
def _build_command(self) -> List[Command]:
|
|
908
1253
|
self.env["CDS_AUTO_64BIT"] = "all"
|
|
909
1254
|
|
|
1255
|
+
assert self.hdl_toplevel, "A HDL toplevel is required in all Xcelium compiles."
|
|
1256
|
+
|
|
910
1257
|
verbosity_opts = []
|
|
911
1258
|
if self.verbose:
|
|
912
1259
|
verbosity_opts += ["-messages"]
|
|
@@ -922,6 +1269,11 @@ class Xcelium(Simulator):
|
|
|
922
1269
|
verbosity_opts += ["-quiet"]
|
|
923
1270
|
verbosity_opts += ["-plinowarn"]
|
|
924
1271
|
|
|
1272
|
+
vhpi_opts = []
|
|
1273
|
+
# Xcelium 23.09.004 fixes cocotb issue #1076 as long as the
|
|
1274
|
+
# following define is set.
|
|
1275
|
+
vhpi_opts.append("-NEW_VHPI_PROPAGATE_DELAY")
|
|
1276
|
+
|
|
925
1277
|
cmds = [
|
|
926
1278
|
["xrun"]
|
|
927
1279
|
+ ["-logfile"]
|
|
@@ -940,6 +1292,7 @@ class Xcelium(Simulator):
|
|
|
940
1292
|
cocotb.config.lib_name_path("vpi", "xcelium")
|
|
941
1293
|
+ ":vlog_startup_routines_bootstrap"
|
|
942
1294
|
]
|
|
1295
|
+
+ vhpi_opts
|
|
943
1296
|
+ [f"-work {self.hdl_library}"]
|
|
944
1297
|
+ self.build_args
|
|
945
1298
|
+ ["-define COCOTB_SIM"]
|
|
@@ -949,13 +1302,18 @@ class Xcelium(Simulator):
|
|
|
949
1302
|
+ [f"-top {self.hdl_toplevel}"]
|
|
950
1303
|
+ [
|
|
951
1304
|
str(source_file)
|
|
952
|
-
for source_file in
|
|
1305
|
+
for source_file in (
|
|
1306
|
+
self.sources + self.vhdl_sources + self.verilog_sources
|
|
1307
|
+
)
|
|
953
1308
|
]
|
|
954
1309
|
]
|
|
955
1310
|
|
|
956
1311
|
return cmds
|
|
957
1312
|
|
|
958
1313
|
def _test_command(self) -> List[Command]:
|
|
1314
|
+
if self.pre_cmd:
|
|
1315
|
+
print("WARNING: pre_cmd is not implemented for Xcelium.")
|
|
1316
|
+
|
|
959
1317
|
self.env["CDS_AUTO_64BIT"] = "all"
|
|
960
1318
|
|
|
961
1319
|
verbosity_opts = []
|
|
@@ -980,6 +1338,21 @@ class Xcelium(Simulator):
|
|
|
980
1338
|
else:
|
|
981
1339
|
xrun_top = self.sim_hdl_toplevel
|
|
982
1340
|
|
|
1341
|
+
if self.waves:
|
|
1342
|
+
input_tcl = [
|
|
1343
|
+
f'-input "@database -open cocotb_waves -default" '
|
|
1344
|
+
f'-input "@probe -database cocotb_waves -create {xrun_top} -all -depth all" '
|
|
1345
|
+
f'-input "@run" '
|
|
1346
|
+
f'-input "@exit" '
|
|
1347
|
+
]
|
|
1348
|
+
else:
|
|
1349
|
+
input_tcl = ["-input", "@run; exit;"]
|
|
1350
|
+
|
|
1351
|
+
vhpi_opts = []
|
|
1352
|
+
# Xcelium 23.09.004 fixes cocotb issue #1076 as long as the
|
|
1353
|
+
# following define is set.
|
|
1354
|
+
vhpi_opts.append("-NEW_VHPI_PROPAGATE_DELAY")
|
|
1355
|
+
|
|
983
1356
|
cmds = [["mkdir", "-p", tmpdir]]
|
|
984
1357
|
cmds += [
|
|
985
1358
|
["xrun"]
|
|
@@ -990,20 +1363,13 @@ class Xcelium(Simulator):
|
|
|
990
1363
|
+ ["-cds_implicit_tmpdir"]
|
|
991
1364
|
+ [tmpdir]
|
|
992
1365
|
+ ["-licqueue"]
|
|
1366
|
+
+ vhpi_opts
|
|
993
1367
|
+ verbosity_opts
|
|
994
1368
|
+ ["-R"]
|
|
995
1369
|
+ self.test_args
|
|
996
1370
|
+ self.plusargs
|
|
997
1371
|
+ ["-gui" if self.gui else ""]
|
|
998
|
-
+
|
|
999
|
-
+ [
|
|
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" '
|
|
1004
|
-
if self.waves
|
|
1005
|
-
else "@run; exit;"
|
|
1006
|
-
]
|
|
1372
|
+
+ input_tcl
|
|
1007
1373
|
]
|
|
1008
1374
|
self.env["GPI_EXTRA"] = (
|
|
1009
1375
|
cocotb.config.lib_name_path("vhpi", "xcelium") + ":cocotbvhpi_entry_point"
|
|
@@ -1022,6 +1388,7 @@ def get_runner(simulator_name: str) -> Simulator:
|
|
|
1022
1388
|
"riviera": Riviera,
|
|
1023
1389
|
"verilator": Verilator,
|
|
1024
1390
|
"xcelium": Xcelium,
|
|
1391
|
+
"nvc": Nvc,
|
|
1025
1392
|
# TODO: "vcs": Vcs,
|
|
1026
1393
|
# TODO: "activehdl": ActiveHdl,
|
|
1027
1394
|
}
|