vunit-python-bridge 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vunit_python_bridge/__init__.py +92 -0
- vunit_python_bridge/bin/vunit_python_bridge-cp310-win_amd64.dll +0 -0
- vunit_python_bridge/bin/vunit_python_bridge-cp311-win_amd64.dll +0 -0
- vunit_python_bridge/bin/vunit_python_bridge-cp312-win_amd64.dll +0 -0
- vunit_python_bridge/bin/vunit_python_bridge-cp313-win_amd64.dll +0 -0
- vunit_python_bridge/bin/vunit_python_bridge-cp314-win_amd64.dll +0 -0
- vunit_python_bridge/bridge.py +171 -0
- vunit_python_bridge/foreign_application.py +90 -0
- vunit_python_bridge/hdl/src/python_bridge_pkg.vhd.in +91 -0
- vunit_python_bridge/hdl/src/python_context.vhd +13 -0
- vunit_python_bridge/hdl/src/python_ffi_pkg_bridge.vhd +507 -0
- vunit_python_bridge/hdl/src/python_pkg.vhd +1087 -0
- vunit_python_bridge/hdl/src/python_pkg_vhpi.vhd +270 -0
- vunit_python_bridge/hdl/tools/generate_python_pkg.py +386 -0
- vunit_python_bridge/hdl/tools/python_pkg.vhd.in +765 -0
- vunit_python_bridge/native/arguments.c +191 -0
- vunit_python_bridge/native/bridge.h +117 -0
- vunit_python_bridge/native/config.c +201 -0
- vunit_python_bridge/native/error.c +120 -0
- vunit_python_bridge/native/fli.c +98 -0
- vunit_python_bridge/native/interpreter.c +271 -0
- vunit_python_bridge/native/operations.c +239 -0
- vunit_python_bridge/native/vhpi/python_pkg.c +125 -0
- vunit_python_bridge/native/vhpi/python_pkg.h +31 -0
- vunit_python_bridge/native/vhpi/python_pkg_vhpi.c +366 -0
- vunit_python_bridge/native_library.py +455 -0
- vunit_python_bridge/runtime.py +645 -0
- vunit_python_bridge/simulator_hooks.py +141 -0
- vunit_python_bridge/vunit_pkg.toml +17 -0
- vunit_python_bridge-0.1.0.dist-info/METADATA +116 -0
- vunit_python_bridge-0.1.0.dist-info/RECORD +34 -0
- vunit_python_bridge-0.1.0.dist-info/WHEEL +5 -0
- vunit_python_bridge-0.1.0.dist-info/licenses/LICENSE +373 -0
- vunit_python_bridge-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
3
|
+
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2014-2026, Lars Asplund lars.anders.asplund@gmail.com
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
The VUnit package making Python callable from VHDL.
|
|
10
|
+
|
|
11
|
+
``vu.add_package("vunit-python-bridge", allow_setup=True)`` compiles
|
|
12
|
+
``python_pkg``/``python_context`` into the ``python_bridge`` library and sets up the foreign
|
|
13
|
+
language interface implementing them for the selected simulator:
|
|
14
|
+
|
|
15
|
+
* NVC, GHDL (VHPIDIRECT) and Questa/ModelSim (FLI) are served by the VUnit Python bridge, a
|
|
16
|
+
small C library (native/*.c) embedding CPython in the simulator process.
|
|
17
|
+
* Riviera-PRO/Active-HDL are served by a VHPI application built with the simulator's own
|
|
18
|
+
compiler driver.
|
|
19
|
+
|
|
20
|
+
Modules:
|
|
21
|
+
|
|
22
|
+
* bridge: setup of the bridge, its configuration and its generated VHDL.
|
|
23
|
+
* native_library: compiles and caches the library on Linux and macOS, selects the prebuilt
|
|
24
|
+
DLL on Windows.
|
|
25
|
+
* foreign_application: builds the VHPI application.
|
|
26
|
+
* simulator_hooks: makes NVC and GHDL find the library.
|
|
27
|
+
* runtime: runs inside the simulator's embedded interpreter.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
|
|
32
|
+
VHDL_PATH = Path(__file__).parent.resolve() / "hdl" / "src"
|
|
33
|
+
|
|
34
|
+
# The foreign language interface implementing the package for a simulator. VUnit says which
|
|
35
|
+
# simulator was selected, the package says how it is served: NVC and GHDL both go through
|
|
36
|
+
# VHPIDIRECT but bind the library differently, Questa/ModelSim goes through the FLI and
|
|
37
|
+
# Riviera-PRO/Active-HDL through a VHPI application of their own.
|
|
38
|
+
FOREIGN_LANGUAGE_INTERFACES = {
|
|
39
|
+
"nvc": "VHPIDIRECT_NVC",
|
|
40
|
+
"ghdl": "VHPIDIRECT_GHDL",
|
|
41
|
+
"modelsim": "FLI",
|
|
42
|
+
"rivierapro": "VHPI",
|
|
43
|
+
"activehdl": "VHPI",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# The simulators of the table, named as a user knows them
|
|
47
|
+
SUPPORTED_SIMULATORS = "NVC, GHDL, Questa/ModelSim, Riviera-PRO or Active-HDL"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def setup(context):
|
|
51
|
+
"""
|
|
52
|
+
Complete the addition of the package.
|
|
53
|
+
|
|
54
|
+
``vunit_pkg.toml`` lists the sources both variants of the package share, this adds the
|
|
55
|
+
foreign language interface of the selected simulator: the VHPI application for
|
|
56
|
+
Riviera-PRO/Active-HDL, the VUnit Python bridge for everyone else.
|
|
57
|
+
"""
|
|
58
|
+
# pylint: disable=import-outside-toplevel
|
|
59
|
+
from .bridge import setup as setup_bridge
|
|
60
|
+
from .foreign_application import setup_vhpi_application
|
|
61
|
+
from . import simulator_hooks
|
|
62
|
+
|
|
63
|
+
simulator_name = context.simulator_name
|
|
64
|
+
if simulator_name is None:
|
|
65
|
+
raise RuntimeError(
|
|
66
|
+
f"The vunit-python-bridge package requires {SUPPORTED_SIMULATORS} but no simulator was found"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
interface = FOREIGN_LANGUAGE_INTERFACES.get(simulator_name)
|
|
70
|
+
if interface is None:
|
|
71
|
+
raise RuntimeError(
|
|
72
|
+
f"The vunit-python-bridge package requires {SUPPORTED_SIMULATORS}, "
|
|
73
|
+
f"it has no foreign language interface for {simulator_name}"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
if interface == "VHPI":
|
|
77
|
+
# Riviera-PRO/Active-HDL, the simulators served by the VHPI application
|
|
78
|
+
context.add_source_files(context.library.name, [VHDL_PATH / "python_pkg_vhpi.vhd"])
|
|
79
|
+
setup_vhpi_application(context.output_path, simulator_name, context.simulator_prefix)
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
bridge = setup_bridge(
|
|
83
|
+
context.output_path,
|
|
84
|
+
context.run_script_path,
|
|
85
|
+
simulator_name,
|
|
86
|
+
context.simulator_prefix,
|
|
87
|
+
context.simulator_backend,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
context.add_source_files(context.library.name, list(bridge.vhdl_files))
|
|
91
|
+
|
|
92
|
+
simulator_hooks.register(context, bridge)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
3
|
+
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2014-2026, Lars Asplund lars.anders.asplund@gmail.com
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
Setup of the Python bridge of a project: native library, configuration and generated VHDL.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
import re
|
|
14
|
+
import sys
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import List, NamedTuple, Optional
|
|
17
|
+
|
|
18
|
+
from .native_library import (
|
|
19
|
+
PACKAGE_PATH,
|
|
20
|
+
PythonBridgeError,
|
|
21
|
+
check_python_build,
|
|
22
|
+
check_windows_64bit_simulator,
|
|
23
|
+
prepare_library,
|
|
24
|
+
windows_python_dll,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
RUNTIME_SOURCE = PACKAGE_PATH / "runtime.py"
|
|
28
|
+
VHDL_SOURCE_PATH = PACKAGE_PATH / "hdl" / "src"
|
|
29
|
+
BRIDGE_PACKAGE_TEMPLATE = VHDL_SOURCE_PATH / "python_bridge_pkg.vhd.in"
|
|
30
|
+
CONFIG_FILE_NAME = "vunit_python_bridge.cfg"
|
|
31
|
+
|
|
32
|
+
# The simulators the bridge serves, reaching it through VHPIDIRECT and through the FLI.
|
|
33
|
+
# The rest of the simulators of the package are served by the VHPI application.
|
|
34
|
+
FLI_SIMULATORS = ("modelsim",)
|
|
35
|
+
BRIDGE_SIMULATORS = ("nvc", "ghdl") + FLI_SIMULATORS
|
|
36
|
+
|
|
37
|
+
# GHDL backends that link the design ahead of time. For these the library
|
|
38
|
+
# token in the VHPIDIRECT attribute is passed to the linker instead of being
|
|
39
|
+
# dlopen()ed at run time.
|
|
40
|
+
GHDL_LINKING_BACKENDS = ("llvm", "gcc")
|
|
41
|
+
|
|
42
|
+
# {foreign:<entry point>} placeholder of the bridge package template
|
|
43
|
+
FOREIGN_PATTERN = re.compile(r"\{foreign:(\w+)\}")
|
|
44
|
+
# The subprogram declarations of the template, whose bodies are generated
|
|
45
|
+
SUBPROGRAM_PATTERN = re.compile(r"^ (impure function|procedure) (\w+)(\([^)]*\))?( return \w+)?;", re.MULTILINE)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class PythonBridge(NamedTuple):
|
|
49
|
+
"""
|
|
50
|
+
A prepared bridge: the native library and the generated VHDL.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
library_file: Path
|
|
54
|
+
vhdl_files: List[Path]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def setup(
|
|
58
|
+
output_path,
|
|
59
|
+
run_script_path: Optional[Path],
|
|
60
|
+
simulator_name: Optional[str] = None,
|
|
61
|
+
simulator_prefix: Optional[str] = None,
|
|
62
|
+
simulator_backend: Optional[str] = None,
|
|
63
|
+
) -> PythonBridge:
|
|
64
|
+
"""
|
|
65
|
+
Prepare the Python bridge for a project. Called by the package setup function.
|
|
66
|
+
|
|
67
|
+
:param run_script_path: The run script or None. The runtime puts its directory, or the current
|
|
68
|
+
directory without a run script, first on sys.path, like python does.
|
|
69
|
+
:param simulator_name: The name of the selected simulator, None for no simulator.
|
|
70
|
+
:param simulator_prefix: The path its executables were found in.
|
|
71
|
+
:param simulator_backend: How the installation found there was built, which for GHDL
|
|
72
|
+
is the code generator deciding how the library is bound.
|
|
73
|
+
:returns: The bridge. Its vhdl_files are to be added to the package library.
|
|
74
|
+
"""
|
|
75
|
+
if simulator_name is not None and simulator_name not in BRIDGE_SIMULATORS:
|
|
76
|
+
raise PythonBridgeError(
|
|
77
|
+
f"The vunit-python-bridge package requires NVC, GHDL or Questa/ModelSim, "
|
|
78
|
+
f"it is not supported for {simulator_name}"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
check_python_build()
|
|
82
|
+
check_windows_64bit_simulator(simulator_name, simulator_prefix)
|
|
83
|
+
|
|
84
|
+
is_fli = simulator_name in FLI_SIMULATORS
|
|
85
|
+
if is_fli and simulator_prefix is None:
|
|
86
|
+
raise PythonBridgeError(
|
|
87
|
+
f"The FLI variant of the bridge is built against the {simulator_name} installation, but it was not found"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
root = Path(output_path) / "python_bridge"
|
|
91
|
+
library_file = prepare_library(root, Path(simulator_prefix) if is_fli else None)
|
|
92
|
+
run_script_dir = str(Path.cwd() if run_script_path is None else Path(run_script_path).resolve().parent)
|
|
93
|
+
_write_if_changed(library_file.parent / CONFIG_FILE_NAME, _config_text(run_script_dir))
|
|
94
|
+
|
|
95
|
+
# The foreign attribute string of an entry point: the name of its wrapper in native/fli.c
|
|
96
|
+
# and the library, by absolute path since Questa accepts it, for the FLI; the VHPIDIRECT
|
|
97
|
+
# library token and the entry point itself for NVC and GHDL.
|
|
98
|
+
foreign = (
|
|
99
|
+
f"fli_{{entry_point}} {library_file!s}"
|
|
100
|
+
if is_fli
|
|
101
|
+
else f"VHPIDIRECT {_vhpidirect_token(simulator_name, simulator_backend, library_file)} {{entry_point}}"
|
|
102
|
+
)
|
|
103
|
+
bridge_package = root / "vhdl" / "python_bridge_pkg.vhd"
|
|
104
|
+
_write_if_changed(bridge_package, _render_bridge_package(foreign))
|
|
105
|
+
|
|
106
|
+
return PythonBridge(
|
|
107
|
+
library_file,
|
|
108
|
+
[
|
|
109
|
+
bridge_package,
|
|
110
|
+
VHDL_SOURCE_PATH / "python_ffi_pkg_bridge.vhd",
|
|
111
|
+
],
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _vhpidirect_token(simulator_name, simulator_backend: Optional[str], library_file: Path) -> str:
|
|
116
|
+
"""
|
|
117
|
+
The library token of the VHPIDIRECT attributes: the file name the simulator dlopen()s,
|
|
118
|
+
or the linker flag of the GHDL backends that link the design ahead of time.
|
|
119
|
+
"""
|
|
120
|
+
if simulator_name == "ghdl" and simulator_backend in GHDL_LINKING_BACKENDS:
|
|
121
|
+
return "-lvunit_python_bridge"
|
|
122
|
+
return library_file.name
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _render_bridge_package(foreign: str) -> str:
|
|
126
|
+
"""
|
|
127
|
+
The generated python_bridge_pkg.vhd: the declarations of the template with the foreign
|
|
128
|
+
attribute of every subprogram, and a body reporting a failure for each of them since the
|
|
129
|
+
bodies are replaced by the foreign implementations and never executed.
|
|
130
|
+
"""
|
|
131
|
+
template = BRIDGE_PACKAGE_TEMPLATE.read_text(encoding="utf-8")
|
|
132
|
+
declarations = FOREIGN_PATTERN.sub(lambda match: foreign.format(entry_point=match.group(1)), template)
|
|
133
|
+
stubs = []
|
|
134
|
+
for kind, name, parameters, result in SUBPROGRAM_PATTERN.findall(declarations):
|
|
135
|
+
stubs.append(f" {kind} {name}{parameters}{result} is\n begin")
|
|
136
|
+
stubs.append(f' report "VUnit Python bridge: foreign subprogram {name} is not bound" severity failure;')
|
|
137
|
+
if result:
|
|
138
|
+
stubs.append(f" return {'0.0' if result.endswith('real') else '1'};")
|
|
139
|
+
stubs.append(" end;\n")
|
|
140
|
+
return declarations + "\npackage body python_bridge_pkg is\n" + "\n".join(stubs) + "end package body;\n"
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _config_text(run_script_dir: str) -> str:
|
|
144
|
+
"""
|
|
145
|
+
Content of the configuration file read by the bridge library at run time.
|
|
146
|
+
"""
|
|
147
|
+
lines = {
|
|
148
|
+
"executable": sys.executable,
|
|
149
|
+
"prefix": sys.prefix,
|
|
150
|
+
"runtime": str(RUNTIME_SOURCE),
|
|
151
|
+
"run_script_dir": run_script_dir,
|
|
152
|
+
}
|
|
153
|
+
if sys.platform == "win32":
|
|
154
|
+
lines["python_dll"] = windows_python_dll()
|
|
155
|
+
for key, value in lines.items():
|
|
156
|
+
if "\n" in value or "\r" in value:
|
|
157
|
+
raise PythonBridgeError(f"VHDL Python support cannot handle line breaks in the path {value!r}")
|
|
158
|
+
return "".join(f"{key}={value}\n" for key, value in lines.items())
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _write_if_changed(path: Path, text: str) -> None:
|
|
162
|
+
"""
|
|
163
|
+
Write a file unless it already has the given content, keeping timestamps stable.
|
|
164
|
+
"""
|
|
165
|
+
data = text.encode("utf-8")
|
|
166
|
+
if path.is_file() and path.read_bytes() == data:
|
|
167
|
+
return
|
|
168
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
169
|
+
tmp = path.with_name(path.name + f".{os.getpid()}.tmp")
|
|
170
|
+
tmp.write_bytes(data)
|
|
171
|
+
os.replace(tmp, path)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
3
|
+
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2014-2026, Lars Asplund lars.anders.asplund@gmail.com
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
Building the foreign language application implementing ``python_pkg``/``python_context``
|
|
9
|
+
for the simulators the VUnit Python bridge does not serve.
|
|
10
|
+
|
|
11
|
+
``setup_vhpi_application`` is called by the setup function of the package for
|
|
12
|
+
Riviera-PRO/Active-HDL (VHPI). The application is built under the output path on first use and
|
|
13
|
+
rebuilt when its sources, the Python running VUnit or the simulator change.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
import os
|
|
18
|
+
import sys
|
|
19
|
+
import hashlib
|
|
20
|
+
|
|
21
|
+
from .native_library import (
|
|
22
|
+
add_python_dll_to_path,
|
|
23
|
+
check_windows_64bit_simulator,
|
|
24
|
+
compile_library,
|
|
25
|
+
python_dev_paths,
|
|
26
|
+
windows_gcc,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
SRC_PATH = Path(__file__).parent.resolve() / "native" / "vhpi"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def setup_vhpi_application(output_path, simulator_name, simulator_prefix):
|
|
33
|
+
"""
|
|
34
|
+
Build the VHPI application for Riviera-PRO/Active-HDL under the output path, unless the one
|
|
35
|
+
already there was built from the same sources for the same Python and simulator.
|
|
36
|
+
|
|
37
|
+
:param simulator_prefix: The path the executables of the simulator were found in, which is
|
|
38
|
+
where its ccomp compiler driver is.
|
|
39
|
+
"""
|
|
40
|
+
if simulator_prefix is None:
|
|
41
|
+
raise RuntimeError(f"The VHPI application is built with the ccomp of {simulator_name}, but it was not found")
|
|
42
|
+
|
|
43
|
+
check_windows_64bit_simulator(simulator_name, simulator_prefix)
|
|
44
|
+
target = Path(output_path) / simulator_name / "libraries" / "python.dll"
|
|
45
|
+
sources = [SRC_PATH / "python_pkg_vhpi.c", SRC_PATH / "python_pkg.c"]
|
|
46
|
+
simulator_prefix = Path(simulator_prefix).resolve()
|
|
47
|
+
fingerprint = _fingerprint(sources, simulator_prefix)
|
|
48
|
+
fingerprint_file = target.with_suffix(target.suffix + ".fingerprint")
|
|
49
|
+
if target.exists() and fingerprint_file.exists() and fingerprint_file.read_text(encoding="utf-8") == fingerprint:
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
53
|
+
fingerprint_file.unlink(missing_ok=True)
|
|
54
|
+
_build_vhpi(target, sources, simulator_prefix)
|
|
55
|
+
fingerprint_file.write_text(fingerprint, encoding="utf-8")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _fingerprint(sources, simulator_prefix):
|
|
59
|
+
"""
|
|
60
|
+
Everything the built application depends on: the C sources and headers, the Python that is
|
|
61
|
+
embedded and the simulator whose headers and libraries are used.
|
|
62
|
+
"""
|
|
63
|
+
digest = hashlib.sha256()
|
|
64
|
+
for path in sorted(sources) + sorted(SRC_PATH.glob("*.h")):
|
|
65
|
+
digest.update(path.name.encode("utf-8") + b"\0" + path.read_bytes() + b"\0")
|
|
66
|
+
for item in [sys.executable, sys.prefix, sys.version, sys.platform, str(simulator_prefix)]:
|
|
67
|
+
digest.update(item.encode("utf-8") + b"\0")
|
|
68
|
+
return digest.hexdigest()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _build_vhpi(target, sources, simulator_prefix):
|
|
72
|
+
"""
|
|
73
|
+
Compile the VHPI application with the ccomp compiler driver of Riviera-PRO/Active-HDL.
|
|
74
|
+
"""
|
|
75
|
+
python_include, python_libs = python_dev_paths()
|
|
76
|
+
ccomp = simulator_prefix / ("ccomp.exe" if sys.platform == "win32" else "ccomp")
|
|
77
|
+
env = None
|
|
78
|
+
if sys.platform == "win32":
|
|
79
|
+
add_python_dll_to_path()
|
|
80
|
+
# Riviera-PRO bundles a MinGW gcc under <installation>/mingw, other installations may not.
|
|
81
|
+
# ponytail: untested (no Aldec license), assumes ccomp finds gcc on PATH when none is bundled
|
|
82
|
+
gcc = windows_gcc(simulator_prefix)
|
|
83
|
+
if gcc is not None:
|
|
84
|
+
env = dict(os.environ, PATH=os.pathsep.join([str(Path(gcc[0]).parent), os.environ.get("PATH", "")]))
|
|
85
|
+
# One argument per item: subprocess quotes them, quotes added here would reach ccomp literally
|
|
86
|
+
args = [str(ccomp), "-vhpi", "-dbg", "-verbose", "-o", str(target)]
|
|
87
|
+
args += ["-l", f"python{sys.version_info[0]}{sys.version_info[1]}", "-l", "python3", "-l", "_tkinter"]
|
|
88
|
+
args += ["-I", str(python_include), "-I", str(SRC_PATH), "-L", str(python_libs)]
|
|
89
|
+
args += [str(path) for path in sources]
|
|
90
|
+
compile_library(args, target, target, env)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
-- This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
-- License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
3
|
+
-- You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
4
|
+
--
|
|
5
|
+
-- Copyright (c) 2014-2026, Lars Asplund lars.anders.asplund@gmail.com
|
|
6
|
+
--
|
|
7
|
+
-- PRIVATE foreign subprograms of the VUnit Python bridge (src/vunit_python_bridge/native).
|
|
8
|
+
--
|
|
9
|
+
-- This file is a template. The setup function of the package substitutes every
|
|
10
|
+
-- {foreign:<entry point>} placeholder with the foreign attribute string of the
|
|
11
|
+
-- selected simulator -- "VHPIDIRECT <library> <entry point>" for NVC and GHDL,
|
|
12
|
+
-- "fli_<entry point> <library>" for the FLI of Questa/ModelSim -- and adds the
|
|
13
|
+
-- result to the python_bridge library, together with a generated package body
|
|
14
|
+
-- whose subprograms are never executed. The public API is
|
|
15
|
+
-- python_pkg/python_ffi_pkg, which is implemented on top of this package.
|
|
16
|
+
--
|
|
17
|
+
-- Only scalars and constrained arrays cross the foreign interface since their
|
|
18
|
+
-- ABI is identical for NVC and GHDL on all platforms and is translated to the
|
|
19
|
+
-- FLI parameter passing conventions by native/fli.c.
|
|
20
|
+
|
|
21
|
+
package python_bridge_pkg is
|
|
22
|
+
constant chunk_length : positive := 1024;
|
|
23
|
+
subtype string_chunk_t is string(1 to chunk_length);
|
|
24
|
+
subtype integer_chunk_t is integer_vector(0 to chunk_length - 1);
|
|
25
|
+
subtype real_chunk_t is real_vector(0 to chunk_length - 1);
|
|
26
|
+
|
|
27
|
+
-- Start the interpreter. Idempotent.
|
|
28
|
+
impure function vpy_setup return integer;
|
|
29
|
+
attribute foreign of vpy_setup : function is "{foreign:vpy_setup}";
|
|
30
|
+
|
|
31
|
+
-- Flush Python's streams and drop the last result and the staged values.
|
|
32
|
+
-- The interpreter is not finalized: later operations keep working.
|
|
33
|
+
impure function vpy_cleanup return integer;
|
|
34
|
+
attribute foreign of vpy_cleanup : function is "{foreign:vpy_cleanup}";
|
|
35
|
+
|
|
36
|
+
impure function vpy_buffer_clear return integer;
|
|
37
|
+
attribute foreign of vpy_buffer_clear : function is "{foreign:vpy_buffer_clear}";
|
|
38
|
+
|
|
39
|
+
impure function vpy_buffer_append(chunk : string_chunk_t; length : integer) return integer;
|
|
40
|
+
attribute foreign of vpy_buffer_append : function is "{foreign:vpy_buffer_append}";
|
|
41
|
+
|
|
42
|
+
-- Start an operation in the session named by the buffer ("default" is __main__).
|
|
43
|
+
impure function vpy_begin return integer;
|
|
44
|
+
attribute foreign of vpy_begin : function is "{foreign:vpy_begin}";
|
|
45
|
+
|
|
46
|
+
-- Execute the buffer as Python source (is_file = 0) or as a file name (is_file = 1).
|
|
47
|
+
impure function vpy_execute(is_file : integer) return integer;
|
|
48
|
+
attribute foreign of vpy_execute : function is "{foreign:vpy_execute}";
|
|
49
|
+
|
|
50
|
+
-- Evaluate the buffer as a Python expression and convert the value to the
|
|
51
|
+
-- VHDL type given by kind. width is the length of a std_ulogic_vector,
|
|
52
|
+
-- signed or unsigned result, -1 when it is not known.
|
|
53
|
+
impure function vpy_eval(kind, width : integer) return integer;
|
|
54
|
+
attribute foreign of vpy_eval : function is "{foreign:vpy_eval}";
|
|
55
|
+
|
|
56
|
+
impure function vpy_push_array(length, width, height, depth, bit_width, is_signed : integer) return integer;
|
|
57
|
+
attribute foreign of vpy_push_array : function is "{foreign:vpy_push_array}";
|
|
58
|
+
|
|
59
|
+
impure function vpy_array_write(chunk : integer_chunk_t; length : integer) return integer;
|
|
60
|
+
attribute foreign of vpy_array_write : function is "{foreign:vpy_array_write}";
|
|
61
|
+
|
|
62
|
+
-- Stage the pushed array and return its id (>= 1), -1 on error. Python
|
|
63
|
+
-- source code refers to the value as __vunit__.staged(<id>).
|
|
64
|
+
impure function vpy_stage return integer;
|
|
65
|
+
attribute foreign of vpy_stage : function is "{foreign:vpy_stage}";
|
|
66
|
+
|
|
67
|
+
impure function vpy_result_integer return integer;
|
|
68
|
+
attribute foreign of vpy_result_integer : function is "{foreign:vpy_result_integer}";
|
|
69
|
+
|
|
70
|
+
impure function vpy_result_real return real;
|
|
71
|
+
attribute foreign of vpy_result_real : function is "{foreign:vpy_result_real}";
|
|
72
|
+
|
|
73
|
+
impure function vpy_result_meta(idx : integer) return integer;
|
|
74
|
+
attribute foreign of vpy_result_meta : function is "{foreign:vpy_result_meta}";
|
|
75
|
+
|
|
76
|
+
impure function vpy_error_length return integer;
|
|
77
|
+
attribute foreign of vpy_error_length : function is "{foreign:vpy_error_length}";
|
|
78
|
+
|
|
79
|
+
procedure vpy_result_read_string(chunk : out string_chunk_t; offset, length : integer);
|
|
80
|
+
attribute foreign of vpy_result_read_string : procedure is "{foreign:vpy_result_read_string}";
|
|
81
|
+
|
|
82
|
+
procedure vpy_result_read_integers(chunk : out integer_chunk_t; offset, length : integer);
|
|
83
|
+
attribute foreign of vpy_result_read_integers : procedure is "{foreign:vpy_result_read_integers}";
|
|
84
|
+
|
|
85
|
+
procedure vpy_result_read_reals(chunk : out real_chunk_t; offset, length : integer);
|
|
86
|
+
attribute foreign of vpy_result_read_reals : procedure is "{foreign:vpy_result_read_reals}";
|
|
87
|
+
|
|
88
|
+
procedure vpy_error_read(chunk : out string_chunk_t; offset, length : integer);
|
|
89
|
+
attribute foreign of vpy_error_read : procedure is "{foreign:vpy_error_read}";
|
|
90
|
+
end package;
|
|
91
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- This package provides a dictionary types and operations
|
|
2
|
+
--
|
|
3
|
+
-- This Source Code Form is subject to the terms of the Mozilla Public
|
|
4
|
+
-- License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
5
|
+
-- You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
6
|
+
--
|
|
7
|
+
-- Copyright (c) 2014-2026, Lars Asplund lars.anders.asplund@gmail.com
|
|
8
|
+
|
|
9
|
+
context python_context is
|
|
10
|
+
library python_bridge;
|
|
11
|
+
use python_bridge.python_pkg.all;
|
|
12
|
+
use python_bridge.python_ffi_pkg.all;
|
|
13
|
+
end context;
|