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,270 @@
|
|
|
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
|
+
use std.textio.all;
|
|
10
|
+
|
|
11
|
+
library vunit_lib;
|
|
12
|
+
use vunit_lib.id_pkg.all;
|
|
13
|
+
use vunit_lib.integer_array_pkg.all;
|
|
14
|
+
use vunit_lib.integer_vector_ptr_pkg.all;
|
|
15
|
+
use vunit_lib.logger_pkg.all;
|
|
16
|
+
|
|
17
|
+
package python_ffi_pkg is
|
|
18
|
+
-- The identity of the Python interface, the identity of python_logger and
|
|
19
|
+
-- the parent of the identities of the sessions created from a name
|
|
20
|
+
constant p_python_id : id_t := get_id("python_bridge:python");
|
|
21
|
+
|
|
22
|
+
-- A session is a Python namespace with an identity, created from a name
|
|
23
|
+
-- under the identity of the Python interface or from an identity of its
|
|
24
|
+
-- own. Only the default session, the __main__ namespace, is supported by
|
|
25
|
+
-- this foreign language interface.
|
|
26
|
+
type python_session_t is record
|
|
27
|
+
p_data : integer_vector_ptr_t;
|
|
28
|
+
end record;
|
|
29
|
+
|
|
30
|
+
impure function new_session(name : string) return python_session_t;
|
|
31
|
+
impure function new_session(id : id_t) return python_session_t;
|
|
32
|
+
|
|
33
|
+
-- The identity of a session, which is what two sessions are compared by
|
|
34
|
+
impure function get_id(session : python_session_t) return id_t;
|
|
35
|
+
|
|
36
|
+
-- The name of the identity of a session, without hierarchy
|
|
37
|
+
impure function name(session : python_session_t) return string;
|
|
38
|
+
|
|
39
|
+
-- The session the operations are performed in when no other one is given.
|
|
40
|
+
-- It is created the way new_session does, which cannot be called here since
|
|
41
|
+
-- its body is not elaborated until the package body is.
|
|
42
|
+
constant default_session : python_session_t :=
|
|
43
|
+
(p_data => new_integer_vector_ptr(1, value => to_integer(get_id("default", parent => p_python_id))));
|
|
44
|
+
|
|
45
|
+
procedure python_setup;
|
|
46
|
+
-- TODO: Looks like Riviera-PRO requires the path to the shared library to be fixed at compile time
|
|
47
|
+
-- and that may become a bit limited. VHDL standard allow for expressions.
|
|
48
|
+
attribute foreign of python_setup : procedure is "VHPI libraries/python python_setup";
|
|
49
|
+
procedure python_cleanup;
|
|
50
|
+
attribute foreign of python_cleanup : procedure is "VHPI libraries/python python_cleanup";
|
|
51
|
+
|
|
52
|
+
function p_eval_integer(expr : string) return integer;
|
|
53
|
+
attribute foreign of p_eval_integer : function is "VHPI libraries/python eval_integer";
|
|
54
|
+
impure function eval_integer(expr : string; session : python_session_t := default_session) return integer;
|
|
55
|
+
alias eval is eval_integer[string, python_session_t return integer];
|
|
56
|
+
|
|
57
|
+
function p_eval_real(expr : string) return real;
|
|
58
|
+
attribute foreign of p_eval_real : function is "VHPI libraries/python eval_real";
|
|
59
|
+
impure function eval_real(expr : string; session : python_session_t := default_session) return real;
|
|
60
|
+
alias eval is eval_real[string, python_session_t return real];
|
|
61
|
+
|
|
62
|
+
function p_eval_integer_vector(expr : string) return integer_vector;
|
|
63
|
+
attribute foreign of p_eval_integer_vector : function is "VHPI libraries/python eval_integer_vector";
|
|
64
|
+
impure function eval_integer_vector(
|
|
65
|
+
expr : string; session : python_session_t := default_session
|
|
66
|
+
) return integer_vector;
|
|
67
|
+
alias eval is eval_integer_vector[string, python_session_t return integer_vector];
|
|
68
|
+
|
|
69
|
+
function p_eval_real_vector(expr : string) return real_vector;
|
|
70
|
+
attribute foreign of p_eval_real_vector : function is "VHPI libraries/python eval_real_vector";
|
|
71
|
+
impure function eval_real_vector(
|
|
72
|
+
expr : string; session : python_session_t := default_session
|
|
73
|
+
) return real_vector;
|
|
74
|
+
alias eval is eval_real_vector[string, python_session_t return real_vector];
|
|
75
|
+
|
|
76
|
+
function p_eval_string(expr : string) return string;
|
|
77
|
+
attribute foreign of p_eval_string : function is "VHPI libraries/python eval_string";
|
|
78
|
+
impure function eval_string(expr : string; session : python_session_t := default_session) return string;
|
|
79
|
+
alias eval is eval_string[string, python_session_t return string];
|
|
80
|
+
|
|
81
|
+
procedure p_exec(code : string);
|
|
82
|
+
attribute foreign of p_exec : procedure is "VHPI libraries/python exec";
|
|
83
|
+
procedure exec(code : string; session : python_session_t := default_session);
|
|
84
|
+
|
|
85
|
+
-----------------------------------------------------------------------------
|
|
86
|
+
-- Private, the primitives the bridge operations of python_pkg are built on
|
|
87
|
+
-----------------------------------------------------------------------------
|
|
88
|
+
-- Some operations of python_pkg are implemented by the VUnit Python
|
|
89
|
+
-- bridge, which is only available for NVC, GHDL and Questa. The primitives
|
|
90
|
+
-- below are declared so that python_pkg has one body for every simulator,
|
|
91
|
+
-- but they report a failure when they are used.
|
|
92
|
+
|
|
93
|
+
-- Logger of the Python interface, the parent of the session loggers
|
|
94
|
+
constant python_logger : logger_t := get_logger(p_python_id);
|
|
95
|
+
|
|
96
|
+
-- Result kinds, must match src/vunit_python_bridge/runtime.py
|
|
97
|
+
constant p_kind_integer : integer := 0;
|
|
98
|
+
constant p_kind_real : integer := 1;
|
|
99
|
+
constant p_kind_boolean : integer := 2;
|
|
100
|
+
constant p_kind_string : integer := 3;
|
|
101
|
+
constant p_kind_std_ulogic : integer := 4;
|
|
102
|
+
constant p_kind_std_ulogic_vector : integer := 5;
|
|
103
|
+
constant p_kind_signed : integer := 6;
|
|
104
|
+
constant p_kind_unsigned : integer := 7;
|
|
105
|
+
constant p_kind_integer_array : integer := 8;
|
|
106
|
+
constant p_kind_integer_vector : integer := 9;
|
|
107
|
+
constant p_kind_real_vector : integer := 10;
|
|
108
|
+
|
|
109
|
+
-- Name of the operation, used in the error messages
|
|
110
|
+
impure function p_eval_operation(expr : string; session : python_session_t := default_session) return string;
|
|
111
|
+
|
|
112
|
+
-- Execute the Python file with the given name
|
|
113
|
+
impure function p_exec_file(
|
|
114
|
+
file_name : string; session : python_session_t := default_session
|
|
115
|
+
) return boolean;
|
|
116
|
+
|
|
117
|
+
-- Evaluate expr and convert the value to the VHDL type given by kind. width
|
|
118
|
+
-- is the length of a std_ulogic_vector, signed or unsigned result, -1 when
|
|
119
|
+
-- it is not known.
|
|
120
|
+
impure function p_eval(
|
|
121
|
+
expr : string;
|
|
122
|
+
kind : integer;
|
|
123
|
+
width : integer;
|
|
124
|
+
operation : string;
|
|
125
|
+
session : python_session_t := default_session
|
|
126
|
+
) return boolean;
|
|
127
|
+
|
|
128
|
+
-- The result of the last evaluation
|
|
129
|
+
impure function p_result_integer return integer;
|
|
130
|
+
impure function p_result_string return string;
|
|
131
|
+
impure function p_result_integer_array return integer_array_t;
|
|
132
|
+
|
|
133
|
+
-- Transfer an integer_array_t to Python and return the id it is staged
|
|
134
|
+
-- under, -1 on failure.
|
|
135
|
+
impure function p_stage_array(arr : integer_array_t; operation : string) return integer;
|
|
136
|
+
end package;
|
|
137
|
+
|
|
138
|
+
package body python_ffi_pkg is
|
|
139
|
+
impure function new_session(name : string) return python_session_t is
|
|
140
|
+
begin
|
|
141
|
+
return new_session(get_id(name, parent => p_python_id));
|
|
142
|
+
end;
|
|
143
|
+
|
|
144
|
+
impure function new_session(id : id_t) return python_session_t is
|
|
145
|
+
begin
|
|
146
|
+
return (p_data => new_integer_vector_ptr(1, value => to_integer(id)));
|
|
147
|
+
end;
|
|
148
|
+
|
|
149
|
+
impure function get_id(session : python_session_t) return id_t is
|
|
150
|
+
begin
|
|
151
|
+
return to_id(get(session.p_data, 0));
|
|
152
|
+
end;
|
|
153
|
+
|
|
154
|
+
impure function name(session : python_session_t) return string is
|
|
155
|
+
begin
|
|
156
|
+
return name(get_id(session));
|
|
157
|
+
end;
|
|
158
|
+
|
|
159
|
+
impure function p_is_default(session : python_session_t) return boolean is
|
|
160
|
+
begin
|
|
161
|
+
return get_id(session) = get_id(default_session);
|
|
162
|
+
end;
|
|
163
|
+
|
|
164
|
+
procedure p_check_session(session : python_session_t) is
|
|
165
|
+
begin
|
|
166
|
+
if not p_is_default(session) then
|
|
167
|
+
report "Python sessions are only supported with NVC, GHDL and Questa" severity failure;
|
|
168
|
+
end if;
|
|
169
|
+
end;
|
|
170
|
+
|
|
171
|
+
impure function eval_integer(expr : string; session : python_session_t := default_session) return integer is
|
|
172
|
+
begin
|
|
173
|
+
p_check_session(session);
|
|
174
|
+
return p_eval_integer(expr);
|
|
175
|
+
end;
|
|
176
|
+
|
|
177
|
+
impure function eval_real(expr : string; session : python_session_t := default_session) return real is
|
|
178
|
+
begin
|
|
179
|
+
p_check_session(session);
|
|
180
|
+
return p_eval_real(expr);
|
|
181
|
+
end;
|
|
182
|
+
|
|
183
|
+
impure function eval_integer_vector(
|
|
184
|
+
expr : string; session : python_session_t := default_session
|
|
185
|
+
) return integer_vector is
|
|
186
|
+
begin
|
|
187
|
+
p_check_session(session);
|
|
188
|
+
return p_eval_integer_vector(expr);
|
|
189
|
+
end;
|
|
190
|
+
|
|
191
|
+
impure function eval_real_vector(
|
|
192
|
+
expr : string; session : python_session_t := default_session
|
|
193
|
+
) return real_vector is
|
|
194
|
+
begin
|
|
195
|
+
p_check_session(session);
|
|
196
|
+
return p_eval_real_vector(expr);
|
|
197
|
+
end;
|
|
198
|
+
|
|
199
|
+
impure function eval_string(expr : string; session : python_session_t := default_session) return string is
|
|
200
|
+
begin
|
|
201
|
+
p_check_session(session);
|
|
202
|
+
return p_eval_string(expr);
|
|
203
|
+
end;
|
|
204
|
+
|
|
205
|
+
procedure exec(code : string; session : python_session_t := default_session) is
|
|
206
|
+
begin
|
|
207
|
+
p_check_session(session);
|
|
208
|
+
p_exec(code);
|
|
209
|
+
end;
|
|
210
|
+
|
|
211
|
+
-----------------------------------------------------------------------------
|
|
212
|
+
-- Private, the primitives the bridge operations of python_pkg are built on
|
|
213
|
+
-----------------------------------------------------------------------------
|
|
214
|
+
procedure p_unsupported(name : string) is
|
|
215
|
+
begin
|
|
216
|
+
failure(python_logger, name & " requires NVC, GHDL or Questa");
|
|
217
|
+
end;
|
|
218
|
+
|
|
219
|
+
impure function p_eval_operation(expr : string; session : python_session_t := default_session) return string is
|
|
220
|
+
begin
|
|
221
|
+
if p_is_default(session) then
|
|
222
|
+
return "eval(""" & expr & """)";
|
|
223
|
+
end if;
|
|
224
|
+
return "eval(""" & expr & """, session => """ & name(session) & """)";
|
|
225
|
+
end;
|
|
226
|
+
|
|
227
|
+
impure function p_exec_file(
|
|
228
|
+
file_name : string; session : python_session_t := default_session
|
|
229
|
+
) return boolean is
|
|
230
|
+
begin
|
|
231
|
+
p_unsupported("exec_file");
|
|
232
|
+
return false;
|
|
233
|
+
end;
|
|
234
|
+
|
|
235
|
+
impure function p_eval(
|
|
236
|
+
expr : string;
|
|
237
|
+
kind : integer;
|
|
238
|
+
width : integer;
|
|
239
|
+
operation : string;
|
|
240
|
+
session : python_session_t := default_session
|
|
241
|
+
) return boolean is
|
|
242
|
+
begin
|
|
243
|
+
p_unsupported(operation);
|
|
244
|
+
return false;
|
|
245
|
+
end;
|
|
246
|
+
|
|
247
|
+
impure function p_result_integer return integer is
|
|
248
|
+
begin
|
|
249
|
+
p_unsupported("p_result_integer");
|
|
250
|
+
return integer'low;
|
|
251
|
+
end;
|
|
252
|
+
|
|
253
|
+
impure function p_result_string return string is
|
|
254
|
+
begin
|
|
255
|
+
p_unsupported("p_result_string");
|
|
256
|
+
return "";
|
|
257
|
+
end;
|
|
258
|
+
|
|
259
|
+
impure function p_result_integer_array return integer_array_t is
|
|
260
|
+
begin
|
|
261
|
+
p_unsupported("p_result_integer_array");
|
|
262
|
+
return null_integer_array;
|
|
263
|
+
end;
|
|
264
|
+
|
|
265
|
+
impure function p_stage_array(arr : integer_array_t; operation : string) return integer is
|
|
266
|
+
begin
|
|
267
|
+
p_unsupported(operation);
|
|
268
|
+
return -1;
|
|
269
|
+
end;
|
|
270
|
+
end package body;
|
|
@@ -0,0 +1,386 @@
|
|
|
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
|
+
Generate python_pkg.vhd from python_pkg.vhd.in in this directory.
|
|
9
|
+
|
|
10
|
+
The template holds the parts of python_pkg that are written by hand. The
|
|
11
|
+
generated parts are the argument value types of call, the result types of eval
|
|
12
|
+
and call and the execution of Python files. They are mostly one overload per
|
|
13
|
+
type, which is why they are generated. The operations that are implemented by
|
|
14
|
+
the Python bridge (NVC, GHDL and Questa) are built on the p_ prefixed
|
|
15
|
+
primitives of python_ffi_pkg, which the VHPI variant of that package
|
|
16
|
+
implements by reporting a failure.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from string import Template
|
|
21
|
+
|
|
22
|
+
SRC_PATH = Path(__file__).parent.parent / "src"
|
|
23
|
+
TEMPLATE_PATH = Path(__file__).parent
|
|
24
|
+
|
|
25
|
+
# Like the operations of python_pkg, every operation takes the session it is
|
|
26
|
+
# performed in as its last parameter
|
|
27
|
+
SESSION = "session : python_session_t := default_session"
|
|
28
|
+
|
|
29
|
+
# The 10 arguments of call
|
|
30
|
+
ARGS = [f"arg{index}" for index in range(1, 11)]
|
|
31
|
+
ARG_PARAMETERS = f"{', '.join(ARGS)} : arg_t := null_arg"
|
|
32
|
+
ARG_ACTUALS = ", ".join(ARGS)
|
|
33
|
+
ARG_SIGNATURE = ", ".join(["string"] + ["arg_t"] * len(ARGS) + ["python_session_t"])
|
|
34
|
+
|
|
35
|
+
# Value types of arg and kwarg that are generated rather than declared in the
|
|
36
|
+
# template.
|
|
37
|
+
#
|
|
38
|
+
# vhdl: the VHDL type
|
|
39
|
+
# impure: true when the functions must be impure
|
|
40
|
+
# fails: true when the conversion can fail, which makes p_arg_value take the
|
|
41
|
+
# name of the operation to report the value it cannot convert
|
|
42
|
+
# suffix: appended to the arg and kwarg names, empty for an overload
|
|
43
|
+
#
|
|
44
|
+
# The integer_array_t value is transferred by the Python bridge, which makes it
|
|
45
|
+
# available for NVC, GHDL and Questa only. The other values are built from the
|
|
46
|
+
# Python source text of the value alone and work on any simulator.
|
|
47
|
+
#
|
|
48
|
+
# The unsigned and signed values are passed to typed names, arg_unsigned and
|
|
49
|
+
# arg_signed, on purpose: plain overloads would make a string literal
|
|
50
|
+
# argument, arg("Hello"), ambiguous since a string literal belongs to every
|
|
51
|
+
# character array type. std_ulogic needs no such name, being a scalar, and
|
|
52
|
+
# std_ulogic_vector is deliberately not among the types at all. Such values
|
|
53
|
+
# are passed as arg(to_string(slv)) and arg_unsigned(unsigned(slv)).
|
|
54
|
+
ARG_VALUES = [
|
|
55
|
+
dict(vhdl="real_vector", impure=False, fails=False, suffix=""),
|
|
56
|
+
dict(vhdl="integer_vector_ptr_t", impure=True, fails=False, suffix=""),
|
|
57
|
+
dict(vhdl="std_ulogic", impure=True, fails=True, suffix=""),
|
|
58
|
+
dict(vhdl="unsigned", impure=True, fails=True, suffix="_unsigned"),
|
|
59
|
+
dict(vhdl="signed", impure=True, fails=True, suffix="_signed"),
|
|
60
|
+
dict(vhdl="integer_array_t", impure=True, fails=True, suffix=""),
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
# Result types of eval and call.
|
|
64
|
+
#
|
|
65
|
+
# name: suffix of eval_<name> and call_<name>
|
|
66
|
+
# vhdl: the VHDL type
|
|
67
|
+
# kind: result kind passed to the bridge, see src/vunit_python_bridge/runtime.py
|
|
68
|
+
# value: expression giving the result of a successful evaluation
|
|
69
|
+
# default: value returned after a failure
|
|
70
|
+
# hand_written_eval/hand_written_call: true when the eval/call function is
|
|
71
|
+
# declared in the template rather than generated. value and default
|
|
72
|
+
# are only needed when the eval function is generated.
|
|
73
|
+
RESULTS = [
|
|
74
|
+
dict(
|
|
75
|
+
name="integer",
|
|
76
|
+
vhdl="integer",
|
|
77
|
+
kind="p_kind_integer",
|
|
78
|
+
hand_written_eval=True,
|
|
79
|
+
hand_written_call=True,
|
|
80
|
+
),
|
|
81
|
+
dict(
|
|
82
|
+
name="real",
|
|
83
|
+
vhdl="real",
|
|
84
|
+
kind="p_kind_real",
|
|
85
|
+
hand_written_eval=True,
|
|
86
|
+
hand_written_call=True,
|
|
87
|
+
),
|
|
88
|
+
dict(
|
|
89
|
+
name="integer_vector",
|
|
90
|
+
vhdl="integer_vector",
|
|
91
|
+
kind="p_kind_integer_vector",
|
|
92
|
+
hand_written_eval=True,
|
|
93
|
+
hand_written_call=True,
|
|
94
|
+
),
|
|
95
|
+
dict(
|
|
96
|
+
name="real_vector",
|
|
97
|
+
vhdl="real_vector",
|
|
98
|
+
kind="p_kind_real_vector",
|
|
99
|
+
hand_written_eval=True,
|
|
100
|
+
hand_written_call=False,
|
|
101
|
+
),
|
|
102
|
+
dict(
|
|
103
|
+
name="string",
|
|
104
|
+
vhdl="string",
|
|
105
|
+
kind="p_kind_string",
|
|
106
|
+
hand_written_eval=True,
|
|
107
|
+
hand_written_call=False,
|
|
108
|
+
),
|
|
109
|
+
dict(
|
|
110
|
+
name="integer_vector_ptr",
|
|
111
|
+
vhdl="integer_vector_ptr_t",
|
|
112
|
+
kind="p_kind_integer_vector",
|
|
113
|
+
hand_written_eval=True,
|
|
114
|
+
hand_written_call=False,
|
|
115
|
+
),
|
|
116
|
+
dict(
|
|
117
|
+
name="boolean",
|
|
118
|
+
vhdl="boolean",
|
|
119
|
+
kind="p_kind_boolean",
|
|
120
|
+
value="p_result_integer /= 0",
|
|
121
|
+
default="false",
|
|
122
|
+
hand_written_eval=False,
|
|
123
|
+
hand_written_call=False,
|
|
124
|
+
),
|
|
125
|
+
dict(
|
|
126
|
+
name="std_ulogic",
|
|
127
|
+
vhdl="std_ulogic",
|
|
128
|
+
kind="p_kind_std_ulogic",
|
|
129
|
+
value="p_to_std_ulogic(p_result_string(1))",
|
|
130
|
+
default="'U'",
|
|
131
|
+
hand_written_eval=False,
|
|
132
|
+
hand_written_call=False,
|
|
133
|
+
),
|
|
134
|
+
dict(
|
|
135
|
+
name="std_ulogic_vector",
|
|
136
|
+
vhdl="std_ulogic_vector",
|
|
137
|
+
kind="p_kind_std_ulogic_vector",
|
|
138
|
+
value="p_to_std_ulogic_vector(p_result_string)",
|
|
139
|
+
default='""',
|
|
140
|
+
hand_written_eval=False,
|
|
141
|
+
hand_written_call=False,
|
|
142
|
+
# No eval/call alias: check_equal(eval("17"), 17) would otherwise be ambiguous
|
|
143
|
+
# with check_equal(std_ulogic_vector, natural). Use the explicit names.
|
|
144
|
+
alias_eval=False,
|
|
145
|
+
alias_call=False,
|
|
146
|
+
),
|
|
147
|
+
dict(
|
|
148
|
+
name="integer_array",
|
|
149
|
+
vhdl="integer_array_t",
|
|
150
|
+
kind="p_kind_integer_array",
|
|
151
|
+
value="p_result_integer_array",
|
|
152
|
+
default="null_integer_array",
|
|
153
|
+
hand_written_eval=False,
|
|
154
|
+
hand_written_call=False,
|
|
155
|
+
# No eval alias: length(eval(...)) would otherwise be ambiguous between
|
|
156
|
+
# the integer_array_t and integer_vector_ptr_t results. Use eval_integer_array.
|
|
157
|
+
alias_eval=False,
|
|
158
|
+
),
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
# Result types whose width is given by the actual of the result parameter
|
|
162
|
+
PROCEDURE_RESULTS = [
|
|
163
|
+
dict(
|
|
164
|
+
name="std_ulogic_vector",
|
|
165
|
+
vhdl="std_ulogic_vector",
|
|
166
|
+
kind="p_kind_std_ulogic_vector",
|
|
167
|
+
value="p_to_std_ulogic_vector(p_result_string)",
|
|
168
|
+
),
|
|
169
|
+
dict(
|
|
170
|
+
name="signed",
|
|
171
|
+
vhdl="signed",
|
|
172
|
+
kind="p_kind_signed",
|
|
173
|
+
value="signed(p_to_std_ulogic_vector(p_result_string))",
|
|
174
|
+
),
|
|
175
|
+
dict(
|
|
176
|
+
name="unsigned",
|
|
177
|
+
vhdl="unsigned",
|
|
178
|
+
kind="p_kind_unsigned",
|
|
179
|
+
value="unsigned(p_to_std_ulogic_vector(p_result_string))",
|
|
180
|
+
),
|
|
181
|
+
]
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def call_name(result):
|
|
185
|
+
"""
|
|
186
|
+
Name of the call function of a result type. The integer one is named
|
|
187
|
+
call_integer_w_arg by python_pkg.
|
|
188
|
+
"""
|
|
189
|
+
return "call_integer_w_arg" if result["name"] == "integer" else f"call_{result['name']}"
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
# -------------------------------------------------------------------------
|
|
193
|
+
# arg and kwarg
|
|
194
|
+
# -------------------------------------------------------------------------
|
|
195
|
+
def arg_declarations():
|
|
196
|
+
"""
|
|
197
|
+
Declarations of the generated arg and kwarg subprograms.
|
|
198
|
+
"""
|
|
199
|
+
lines = []
|
|
200
|
+
for value in ARG_VALUES:
|
|
201
|
+
purity = "impure " if value["impure"] else ""
|
|
202
|
+
suffix = value["suffix"]
|
|
203
|
+
lines.append(f" {purity}function arg{suffix}(value : {value['vhdl']}) return arg_t;")
|
|
204
|
+
lines.append(f" {purity}function kwarg{suffix}(kw : string; value : {value['vhdl']}) return arg_t;")
|
|
205
|
+
return "\n".join(lines)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def arg_functions():
|
|
209
|
+
"""
|
|
210
|
+
Bodies of the generated arg and kwarg subprograms. p_arg_value reports a
|
|
211
|
+
value it cannot convert and gives it a Python source text raising the same
|
|
212
|
+
message, so that the call the argument is used in fails as well.
|
|
213
|
+
"""
|
|
214
|
+
parts = []
|
|
215
|
+
for value in ARG_VALUES:
|
|
216
|
+
purity = "impure " if value["impure"] else ""
|
|
217
|
+
value_type = value["vhdl"]
|
|
218
|
+
suffix = value["suffix"]
|
|
219
|
+
for name, parameters, target in [
|
|
220
|
+
(f"arg{suffix}", f"value : {value_type}", "p_positional_arg"),
|
|
221
|
+
(f"kwarg{suffix}", f"kw : string; value : {value_type}", "kw"),
|
|
222
|
+
]:
|
|
223
|
+
arg_value = f'p_arg_value(value, "{name}")' if value["fails"] else "p_arg_value(value)"
|
|
224
|
+
parts.append(
|
|
225
|
+
f"""\
|
|
226
|
+
{purity}function {name}({parameters}) return arg_t is
|
|
227
|
+
begin
|
|
228
|
+
return ({target}, {arg_value});
|
|
229
|
+
end;
|
|
230
|
+
"""
|
|
231
|
+
)
|
|
232
|
+
return "\n".join(parts).rstrip("\n")
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
# -------------------------------------------------------------------------
|
|
236
|
+
# eval
|
|
237
|
+
# -------------------------------------------------------------------------
|
|
238
|
+
def eval_declarations():
|
|
239
|
+
"""
|
|
240
|
+
Declarations of the generated eval functions and of the eval procedures.
|
|
241
|
+
"""
|
|
242
|
+
lines = []
|
|
243
|
+
for result in RESULTS:
|
|
244
|
+
if result["hand_written_eval"]:
|
|
245
|
+
continue
|
|
246
|
+
lines.append(f" impure function eval_{result['name']}(")
|
|
247
|
+
lines.append(f" expr : string; {SESSION}")
|
|
248
|
+
lines.append(f" ) return {result['vhdl']};")
|
|
249
|
+
if result.get("alias_eval", True):
|
|
250
|
+
lines.append(f" alias eval is eval_{result['name']}[string, python_session_t return {result['vhdl']}];")
|
|
251
|
+
lines.append("")
|
|
252
|
+
for result in PROCEDURE_RESULTS:
|
|
253
|
+
lines.append(f" procedure eval_{result['name']}(")
|
|
254
|
+
lines.append(f" expr : string; result : out {result['vhdl']}; {SESSION}")
|
|
255
|
+
lines.append(" );")
|
|
256
|
+
return "\n".join(lines)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def eval_subprograms():
|
|
260
|
+
"""
|
|
261
|
+
Bodies of the generated eval functions and of the eval procedures.
|
|
262
|
+
"""
|
|
263
|
+
parts = []
|
|
264
|
+
for result in RESULTS:
|
|
265
|
+
if result["hand_written_eval"]:
|
|
266
|
+
continue
|
|
267
|
+
parts.append(
|
|
268
|
+
f"""\
|
|
269
|
+
impure function eval_{result['name']}(
|
|
270
|
+
expr : string; {SESSION}
|
|
271
|
+
) return {result['vhdl']} is
|
|
272
|
+
begin
|
|
273
|
+
if p_eval(expr, {result['kind']}, -1, p_eval_operation(expr, session), session) then
|
|
274
|
+
return {result['value']};
|
|
275
|
+
end if;
|
|
276
|
+
return {result['default']};
|
|
277
|
+
end;
|
|
278
|
+
"""
|
|
279
|
+
)
|
|
280
|
+
for result in PROCEDURE_RESULTS:
|
|
281
|
+
parts.append(
|
|
282
|
+
f"""\
|
|
283
|
+
procedure eval_{result['name']}(
|
|
284
|
+
expr : string; result : out {result['vhdl']}; {SESSION}
|
|
285
|
+
) is
|
|
286
|
+
begin
|
|
287
|
+
if p_eval(expr, {result['kind']}, result'length, p_eval_operation(expr, session), session) then
|
|
288
|
+
result := {result['value']};
|
|
289
|
+
end if;
|
|
290
|
+
end;
|
|
291
|
+
"""
|
|
292
|
+
)
|
|
293
|
+
return "\n".join(parts).rstrip("\n")
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
# -------------------------------------------------------------------------
|
|
297
|
+
# call
|
|
298
|
+
# -------------------------------------------------------------------------
|
|
299
|
+
def call_declarations():
|
|
300
|
+
"""
|
|
301
|
+
Declarations of the generated call functions and of the call procedures.
|
|
302
|
+
"""
|
|
303
|
+
lines = []
|
|
304
|
+
for result in RESULTS:
|
|
305
|
+
if result["hand_written_call"]:
|
|
306
|
+
continue
|
|
307
|
+
name = call_name(result)
|
|
308
|
+
lines.append(f" impure function {name}(")
|
|
309
|
+
lines.append(f" identifier : string; {ARG_PARAMETERS};")
|
|
310
|
+
lines.append(f" {SESSION}")
|
|
311
|
+
lines.append(f" ) return {result['vhdl']};")
|
|
312
|
+
if result.get("alias_call", True):
|
|
313
|
+
lines.append(f" alias call is {name}[")
|
|
314
|
+
lines.append(f" {ARG_SIGNATURE} return {result['vhdl']}];")
|
|
315
|
+
lines.append("")
|
|
316
|
+
for result in PROCEDURE_RESULTS:
|
|
317
|
+
lines.append(f" procedure call_{result['name']}(")
|
|
318
|
+
lines.append(f" identifier : string; result : out {result['vhdl']};")
|
|
319
|
+
lines.append(f" {ARG_PARAMETERS};")
|
|
320
|
+
lines.append(f" {SESSION}")
|
|
321
|
+
lines.append(" );")
|
|
322
|
+
return "\n".join(lines)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def call_subprograms():
|
|
326
|
+
"""
|
|
327
|
+
Bodies of the generated call functions and of the call procedures. A call
|
|
328
|
+
is the evaluation of the Python expression calling the identifier with the
|
|
329
|
+
given arguments.
|
|
330
|
+
"""
|
|
331
|
+
parts = []
|
|
332
|
+
for result in RESULTS:
|
|
333
|
+
if result["hand_written_call"]:
|
|
334
|
+
continue
|
|
335
|
+
parts.append(
|
|
336
|
+
f"""\
|
|
337
|
+
impure function {call_name(result)}(
|
|
338
|
+
identifier : string; {ARG_PARAMETERS};
|
|
339
|
+
{SESSION}
|
|
340
|
+
) return {result['vhdl']} is
|
|
341
|
+
begin
|
|
342
|
+
return eval_{result['name']}(
|
|
343
|
+
to_call_str(identifier, {ARG_ACTUALS}), session
|
|
344
|
+
);
|
|
345
|
+
end;
|
|
346
|
+
"""
|
|
347
|
+
)
|
|
348
|
+
for result in PROCEDURE_RESULTS:
|
|
349
|
+
parts.append(
|
|
350
|
+
f"""\
|
|
351
|
+
procedure call_{result['name']}(
|
|
352
|
+
identifier : string; result : out {result['vhdl']};
|
|
353
|
+
{ARG_PARAMETERS};
|
|
354
|
+
{SESSION}
|
|
355
|
+
) is
|
|
356
|
+
begin
|
|
357
|
+
eval_{result['name']}(
|
|
358
|
+
to_call_str(identifier, {ARG_ACTUALS}), result, session
|
|
359
|
+
);
|
|
360
|
+
end;
|
|
361
|
+
"""
|
|
362
|
+
)
|
|
363
|
+
return "\n".join(parts).rstrip("\n")
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def generate_package():
|
|
367
|
+
"""
|
|
368
|
+
Generate python_pkg from the template and the generated declarations.
|
|
369
|
+
"""
|
|
370
|
+
template = (TEMPLATE_PATH / "python_pkg.vhd.in").read_text(encoding="utf-8")
|
|
371
|
+
return Template(template).substitute(
|
|
372
|
+
arg_declarations=arg_declarations(),
|
|
373
|
+
arg_functions=arg_functions(),
|
|
374
|
+
eval_declarations=eval_declarations(),
|
|
375
|
+
call_declarations=call_declarations(),
|
|
376
|
+
eval_subprograms=eval_subprograms(),
|
|
377
|
+
call_subprograms=call_subprograms(),
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def main():
|
|
382
|
+
(SRC_PATH / "python_pkg.vhd").write_text(generate_package(), encoding="utf-8", newline="\n")
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
if __name__ == "__main__":
|
|
386
|
+
main()
|