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,125 @@
|
|
|
1
|
+
// Riviera-PRO/Active-HDL (VHPI) implementation of python_pkg: Python error handling
|
|
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-2023, Lars Asplund lars.anders.asplund@gmail.com
|
|
8
|
+
|
|
9
|
+
#include "python_pkg.h"
|
|
10
|
+
|
|
11
|
+
#include <string.h>
|
|
12
|
+
|
|
13
|
+
static py_error_handler_callback py_error_handler = NULL;
|
|
14
|
+
static ffi_error_handler_callback ffi_error_handler = NULL;
|
|
15
|
+
|
|
16
|
+
void register_py_error_handler(py_error_handler_callback callback) {
|
|
17
|
+
py_error_handler = callback;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
void register_ffi_error_handler(ffi_error_handler_callback callback) {
|
|
21
|
+
ffi_error_handler = callback;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
char* get_string(PyObject* pyobj) {
|
|
25
|
+
PyObject* str = PyObject_Str(pyobj);
|
|
26
|
+
if (str == NULL) {
|
|
27
|
+
return NULL;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
PyObject* str_utf_8 = PyUnicode_AsEncodedString(str, "utf-8", NULL);
|
|
31
|
+
Py_DECREF(str);
|
|
32
|
+
if (str_utf_8 == NULL) {
|
|
33
|
+
return NULL;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// A copy, since the bytes object is released here. The string is only used
|
|
37
|
+
// on the error path, so the copy is never freed.
|
|
38
|
+
char* result = strdup(PyBytes_AS_STRING(str_utf_8));
|
|
39
|
+
Py_DECREF(str_utf_8);
|
|
40
|
+
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
void check_conversion_error(const char* expr) {
|
|
45
|
+
PyObject* exc = PyErr_Occurred();
|
|
46
|
+
if (exc != NULL) {
|
|
47
|
+
Py_DECREF(exc);
|
|
48
|
+
py_error_handler("parsing evaluation result of", expr, NULL, true);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
void handle_type_check_error(PyObject* pyobj, const char* context,
|
|
53
|
+
const char* expr) {
|
|
54
|
+
PyTypeObject* type = pyobj->ob_type;
|
|
55
|
+
if (type == NULL) {
|
|
56
|
+
py_error_handler(context, expr, "Expression evaluates to an unknown type.",
|
|
57
|
+
true);
|
|
58
|
+
}
|
|
59
|
+
const char* type_name_str = type->tp_name;
|
|
60
|
+
Py_DECREF(type);
|
|
61
|
+
|
|
62
|
+
if (type_name_str == NULL) {
|
|
63
|
+
py_error_handler(context, expr, "Expression evaluates to an unknown type.",
|
|
64
|
+
true);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
char error_message[100] = "Expression evaluates to ";
|
|
68
|
+
strncat(error_message, type_name_str, 75);
|
|
69
|
+
py_error_handler(context, expr, error_message, true);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
PyObject* eval(const char* expr) {
|
|
73
|
+
PyObject* pyobj = PyRun_String(expr, Py_eval_input, globals, locals);
|
|
74
|
+
if (pyobj == NULL) {
|
|
75
|
+
py_error_handler("evaluating", expr, NULL, true);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return pyobj;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
int get_integer(PyObject* pyobj, const char* expr, bool dec_ref_count) {
|
|
82
|
+
// Check that the Python object has the correct type
|
|
83
|
+
if (!PyLong_Check(pyobj)) {
|
|
84
|
+
handle_type_check_error(pyobj, "evaluating to integer", expr);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Convert from Python-typed to C-typed value and check for any errors such as
|
|
88
|
+
// overflow/underflow
|
|
89
|
+
long value = PyLong_AsLong(pyobj);
|
|
90
|
+
if (dec_ref_count) {
|
|
91
|
+
Py_DECREF(pyobj);
|
|
92
|
+
}
|
|
93
|
+
check_conversion_error(expr);
|
|
94
|
+
|
|
95
|
+
// TODO: Assume that the simulator is limited to 32-bits for now
|
|
96
|
+
if ((value > pow(2, 31) - 1) || (value < -pow(2, 31))) {
|
|
97
|
+
py_error_handler("parsing evaluation result of", expr,
|
|
98
|
+
"Result out of VHDL integer range.", true);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return (int)value;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
double get_real(PyObject* pyobj, const char* expr, bool dec_ref_count) {
|
|
105
|
+
// Check that the Python object has the correct type
|
|
106
|
+
if (!PyFloat_Check(pyobj)) {
|
|
107
|
+
handle_type_check_error(pyobj, "evaluating to real", expr);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Convert from Python-typed to C-typed value and check for any errors such as
|
|
111
|
+
// overflow/underflow
|
|
112
|
+
double value = PyFloat_AsDouble(pyobj);
|
|
113
|
+
if (dec_ref_count) {
|
|
114
|
+
Py_DECREF(pyobj);
|
|
115
|
+
}
|
|
116
|
+
check_conversion_error(expr);
|
|
117
|
+
|
|
118
|
+
// TODO: Assume that the simulator is limited to 32-bits for now
|
|
119
|
+
if ((value > 3.4028234664e38) || (value < -3.4028234664e38)) {
|
|
120
|
+
py_error_handler("parsing evaluation result of", expr,
|
|
121
|
+
"Result out of VHDL real range.", true);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Riviera-PRO/Active-HDL (VHPI) implementation of python_pkg: shared declarations
|
|
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-2023, Lars Asplund lars.anders.asplund@gmail.com
|
|
8
|
+
|
|
9
|
+
#include <stdbool.h>
|
|
10
|
+
#include <stdio.h>
|
|
11
|
+
|
|
12
|
+
#define PY_SSIZE_T_CLEAN
|
|
13
|
+
#include "Python.h"
|
|
14
|
+
|
|
15
|
+
extern PyObject* globals;
|
|
16
|
+
extern PyObject* locals;
|
|
17
|
+
|
|
18
|
+
typedef void (*py_error_handler_callback)(const char*, const char*, const char*,
|
|
19
|
+
bool);
|
|
20
|
+
void register_py_error_handler(py_error_handler_callback callback);
|
|
21
|
+
|
|
22
|
+
typedef void (*ffi_error_handler_callback)(const char*, bool);
|
|
23
|
+
void register_ffi_error_handler(ffi_error_handler_callback callback);
|
|
24
|
+
|
|
25
|
+
char* get_string(PyObject* pyobj);
|
|
26
|
+
void check_conversion_error(const char* expr);
|
|
27
|
+
void handle_type_check_error(PyObject* pyobj, const char* context,
|
|
28
|
+
const char* expr);
|
|
29
|
+
PyObject* eval(const char* expr);
|
|
30
|
+
int get_integer(PyObject* pyobj, const char* expr, bool dec_ref_count);
|
|
31
|
+
double get_real(PyObject* pyobj, const char* expr, bool dec_ref_count);
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
// Riviera-PRO/Active-HDL (VHPI) implementation of python_pkg: the foreign subprograms
|
|
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-2023, Lars Asplund lars.anders.asplund@gmail.com
|
|
8
|
+
|
|
9
|
+
#include <aldecpli.h>
|
|
10
|
+
#include <stdbool.h>
|
|
11
|
+
#include <vhpi_user.h>
|
|
12
|
+
|
|
13
|
+
#include "python_pkg.h"
|
|
14
|
+
|
|
15
|
+
PyObject* globals = NULL;
|
|
16
|
+
PyObject* locals = NULL;
|
|
17
|
+
|
|
18
|
+
#define MAX_VHDL_PARAMETER_STRING_LENGTH 100000
|
|
19
|
+
|
|
20
|
+
PLI_VOID python_cleanup(const struct vhpiCbDataS* cb_p);
|
|
21
|
+
|
|
22
|
+
static void py_error_handler(const char* context, const char* code_or_expr,
|
|
23
|
+
const char* reason, bool cleanup) {
|
|
24
|
+
const char* unknown_error = "Unknown error";
|
|
25
|
+
|
|
26
|
+
// Use provided error reason or try extracting the reason from the Python
|
|
27
|
+
// exception
|
|
28
|
+
if (reason == NULL) {
|
|
29
|
+
PyObject *ptype, *pvalue, *ptraceback;
|
|
30
|
+
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
|
|
31
|
+
if (ptype != NULL) {
|
|
32
|
+
reason = get_string(pvalue);
|
|
33
|
+
}
|
|
34
|
+
// The reason has been extracted. The exception must not be left set:
|
|
35
|
+
// Py_FinalizeEx in python_cleanup would fail on it.
|
|
36
|
+
Py_XDECREF(ptype);
|
|
37
|
+
Py_XDECREF(pvalue);
|
|
38
|
+
Py_XDECREF(ptraceback);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Clean-up Python session first in case vhpi_assert stops the simulation
|
|
42
|
+
if (cleanup) {
|
|
43
|
+
python_cleanup(NULL);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Output error message
|
|
47
|
+
reason = reason == NULL ? unknown_error : reason;
|
|
48
|
+
if (code_or_expr == NULL) {
|
|
49
|
+
vhpi_assert(vhpiError, "ERROR %s:\n\n%s\n\n", context, reason);
|
|
50
|
+
} else {
|
|
51
|
+
vhpi_assert(vhpiError, "ERROR %s:\n\n%s\n\n%s\n\n", context, code_or_expr,
|
|
52
|
+
reason);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Stop the simulation if vhpi_assert didn't.
|
|
56
|
+
vhpi_control(vhpiStop);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
static void ffi_error_handler(const char* context, bool cleanup) {
|
|
60
|
+
vhpiErrorInfoT err;
|
|
61
|
+
|
|
62
|
+
// Clean-up Python session first in case vhpi_assert stops the simulation
|
|
63
|
+
if (cleanup) {
|
|
64
|
+
python_cleanup(NULL);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (vhpi_check_error(&err)) {
|
|
68
|
+
vhpi_assert(err.severity, "ERROR %s: \n\n%s (%d): %s\n\n", context,
|
|
69
|
+
err.file, err.line, err.message);
|
|
70
|
+
|
|
71
|
+
} else {
|
|
72
|
+
vhpi_assert(vhpiError, "ERROR %s\n\n", context);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Stop the simulation if vhpi_assert didn't.
|
|
76
|
+
vhpi_control(vhpiStop);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
PLI_VOID python_setup(const struct vhpiCbDataS* cb_p) {
|
|
80
|
+
Py_Initialize();
|
|
81
|
+
if (!Py_IsInitialized()) {
|
|
82
|
+
ffi_error_handler("Failed to initialize Python", false);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
PyObject* main_module = PyImport_AddModule("__main__");
|
|
86
|
+
if (main_module == NULL) {
|
|
87
|
+
ffi_error_handler("Failed to get the main module", true);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
globals = PyModule_GetDict(main_module);
|
|
91
|
+
if (globals == NULL) {
|
|
92
|
+
ffi_error_handler("Failed to get the global dictionary", true);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// globals and locals are the same at the top-level
|
|
96
|
+
locals = globals;
|
|
97
|
+
|
|
98
|
+
register_py_error_handler(py_error_handler);
|
|
99
|
+
register_ffi_error_handler(ffi_error_handler);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
PLI_VOID python_cleanup(const struct vhpiCbDataS* cb_p) {
|
|
103
|
+
if (!Py_IsInitialized()) {
|
|
104
|
+
// The interpreter was never started, there is nothing to release
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (locals != NULL) {
|
|
109
|
+
Py_DECREF(locals);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (Py_FinalizeEx()) {
|
|
113
|
+
vhpi_assert(vhpiWarning, "WARNING: Failed to finalize Python");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// python_setup is optional: every operation starts the interpreter if it is
|
|
118
|
+
// not already running.
|
|
119
|
+
static void ensure_initialized(void) {
|
|
120
|
+
if (!Py_IsInitialized()) {
|
|
121
|
+
python_setup(NULL);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static const char* get_parameter(const struct vhpiCbDataS* cb_p) {
|
|
126
|
+
// Get parameter from VHDL function call
|
|
127
|
+
vhpiHandleT parameter_handle =
|
|
128
|
+
vhpi_handle_by_index(vhpiParamDecls, cb_p->obj, 0);
|
|
129
|
+
if (parameter_handle == NULL) {
|
|
130
|
+
ffi_error_handler("getting VHDL parameter handle", true);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
vhpiValueT parameter;
|
|
134
|
+
static char vhdl_parameter_string[MAX_VHDL_PARAMETER_STRING_LENGTH];
|
|
135
|
+
|
|
136
|
+
parameter.bufSize = MAX_VHDL_PARAMETER_STRING_LENGTH;
|
|
137
|
+
parameter.value.str = vhdl_parameter_string;
|
|
138
|
+
parameter.format = vhpiStrVal;
|
|
139
|
+
|
|
140
|
+
if (vhpi_get_value(parameter_handle, ¶meter)) {
|
|
141
|
+
ffi_error_handler("getting VHDL parameter value", true);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
vhpi_release_handle(parameter_handle);
|
|
145
|
+
|
|
146
|
+
return vhdl_parameter_string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
PLI_VOID eval_integer(const struct vhpiCbDataS* cb_p) {
|
|
150
|
+
ensure_initialized();
|
|
151
|
+
|
|
152
|
+
// Get expression parameter from VHDL function call
|
|
153
|
+
const char* expr = get_parameter(cb_p);
|
|
154
|
+
|
|
155
|
+
// Eval(uate) expression in Python
|
|
156
|
+
PyObject* eval_result = eval(expr);
|
|
157
|
+
|
|
158
|
+
// Return result to VHDL
|
|
159
|
+
vhpiValueT vhdl_result;
|
|
160
|
+
vhdl_result.format = vhpiIntVal;
|
|
161
|
+
vhdl_result.bufSize = 0;
|
|
162
|
+
vhdl_result.value.intg = get_integer(eval_result, expr, true);
|
|
163
|
+
if (vhpi_put_value(cb_p->obj, &vhdl_result, vhpiDeposit)) {
|
|
164
|
+
py_error_handler("returning result for evaluation of", expr, NULL, true);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
PLI_VOID eval_real(const struct vhpiCbDataS* cb_p) {
|
|
169
|
+
ensure_initialized();
|
|
170
|
+
|
|
171
|
+
// Get expression parameter from VHDL function call
|
|
172
|
+
const char* expr = get_parameter(cb_p);
|
|
173
|
+
|
|
174
|
+
// Eval(uate) expression in Python
|
|
175
|
+
PyObject* eval_result = eval(expr);
|
|
176
|
+
|
|
177
|
+
// Return result to VHDL
|
|
178
|
+
vhpiValueT vhdl_result;
|
|
179
|
+
vhdl_result.format = vhpiRealVal;
|
|
180
|
+
vhdl_result.bufSize = 0;
|
|
181
|
+
vhdl_result.value.real = get_real(eval_result, expr, true);
|
|
182
|
+
if (vhpi_put_value(cb_p->obj, &vhdl_result, vhpiDeposit)) {
|
|
183
|
+
py_error_handler("returning result for evaluation of", expr, NULL, true);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
PLI_VOID eval_integer_vector(const struct vhpiCbDataS* cb_p) {
|
|
188
|
+
ensure_initialized();
|
|
189
|
+
|
|
190
|
+
// Get expression parameter from VHDL function call
|
|
191
|
+
const char* expr = get_parameter(cb_p);
|
|
192
|
+
|
|
193
|
+
// Eval(uate) expression in Python
|
|
194
|
+
PyObject* pyobj = eval(expr);
|
|
195
|
+
|
|
196
|
+
// Check that the eval results in a list. TODO: tuple and sets of integers
|
|
197
|
+
// should also work
|
|
198
|
+
if (!PyList_Check(pyobj)) {
|
|
199
|
+
handle_type_check_error(pyobj, "evaluating to integer_vector", expr);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const int list_size = PyList_GET_SIZE(pyobj);
|
|
203
|
+
const int n_bytes = list_size * sizeof(int);
|
|
204
|
+
int* int_array = (int*)malloc(n_bytes);
|
|
205
|
+
|
|
206
|
+
for (int idx = 0; idx < list_size; idx++) {
|
|
207
|
+
int_array[idx] = get_integer(PyList_GetItem(pyobj, idx), expr, false);
|
|
208
|
+
}
|
|
209
|
+
Py_DECREF(pyobj);
|
|
210
|
+
|
|
211
|
+
// Return result to VHDL
|
|
212
|
+
vhpiValueT vhdl_result;
|
|
213
|
+
vhdl_result.format = vhpiIntVecVal;
|
|
214
|
+
vhdl_result.bufSize = n_bytes;
|
|
215
|
+
vhdl_result.numElems = list_size;
|
|
216
|
+
vhdl_result.value.intgs = (vhpiIntT*)int_array;
|
|
217
|
+
|
|
218
|
+
if (vhpi_put_value(cb_p->obj, &vhdl_result, vhpiSizeConstraint)) {
|
|
219
|
+
free(int_array);
|
|
220
|
+
py_error_handler(
|
|
221
|
+
"setting size constraints when returning result for evaluation of",
|
|
222
|
+
expr, NULL, true);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (vhpi_put_value(cb_p->obj, &vhdl_result, vhpiDeposit)) {
|
|
226
|
+
free(int_array);
|
|
227
|
+
py_error_handler("returning result for evaluation of", expr, NULL, true);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
free(int_array);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
PLI_VOID eval_real_vector(const struct vhpiCbDataS* cb_p) {
|
|
234
|
+
ensure_initialized();
|
|
235
|
+
|
|
236
|
+
// Get expression parameter from VHDL function call
|
|
237
|
+
const char* expr = get_parameter(cb_p);
|
|
238
|
+
|
|
239
|
+
// Eval(uate) expression in Python
|
|
240
|
+
PyObject* pyobj = eval(expr);
|
|
241
|
+
|
|
242
|
+
// Check that the eval results in a list. TODO: tuple and sets of integers
|
|
243
|
+
// should also work
|
|
244
|
+
if (!PyList_Check(pyobj)) {
|
|
245
|
+
handle_type_check_error(pyobj, "evaluating to real_vector", expr);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const int list_size = PyList_GET_SIZE(pyobj);
|
|
249
|
+
const int n_bytes = list_size * sizeof(double);
|
|
250
|
+
double* double_array = (double*)malloc(n_bytes);
|
|
251
|
+
|
|
252
|
+
for (int idx = 0; idx < list_size; idx++) {
|
|
253
|
+
double_array[idx] = get_real(PyList_GetItem(pyobj, idx), expr, false);
|
|
254
|
+
}
|
|
255
|
+
Py_DECREF(pyobj);
|
|
256
|
+
|
|
257
|
+
// Return result to VHDL
|
|
258
|
+
vhpiValueT vhdl_result;
|
|
259
|
+
vhdl_result.format = vhpiRealVecVal;
|
|
260
|
+
vhdl_result.bufSize = n_bytes;
|
|
261
|
+
vhdl_result.numElems = list_size;
|
|
262
|
+
vhdl_result.value.reals = double_array;
|
|
263
|
+
|
|
264
|
+
if (vhpi_put_value(cb_p->obj, &vhdl_result, vhpiSizeConstraint)) {
|
|
265
|
+
free(double_array);
|
|
266
|
+
py_error_handler(
|
|
267
|
+
"setting size constraints when returning result for evaluation of",
|
|
268
|
+
expr, NULL, true);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (vhpi_put_value(cb_p->obj, &vhdl_result, vhpiDeposit)) {
|
|
272
|
+
free(double_array);
|
|
273
|
+
py_error_handler("returning result for evaluation of", expr, NULL, true);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
free(double_array);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
PLI_VOID eval_string(const struct vhpiCbDataS* cb_p) {
|
|
280
|
+
ensure_initialized();
|
|
281
|
+
|
|
282
|
+
// Get expression parameter from VHDL function call
|
|
283
|
+
const char* expr = get_parameter(cb_p);
|
|
284
|
+
|
|
285
|
+
// Eval(uate) expression in Python
|
|
286
|
+
PyObject* pyobj = eval(expr);
|
|
287
|
+
|
|
288
|
+
char* str = get_string(pyobj);
|
|
289
|
+
Py_DECREF(pyobj);
|
|
290
|
+
|
|
291
|
+
// Return result to VHDL
|
|
292
|
+
vhpiValueT vhdl_result;
|
|
293
|
+
vhdl_result.format = vhpiStrVal;
|
|
294
|
+
vhdl_result.bufSize = strlen(str) + 1; // null termination included
|
|
295
|
+
vhdl_result.numElems = strlen(str);
|
|
296
|
+
vhdl_result.value.str = str;
|
|
297
|
+
|
|
298
|
+
if (vhpi_put_value(cb_p->obj, &vhdl_result, vhpiSizeConstraint)) {
|
|
299
|
+
py_error_handler(
|
|
300
|
+
"setting size constraints when returning result for evaluation of",
|
|
301
|
+
expr, NULL, true);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (vhpi_put_value(cb_p->obj, &vhdl_result, vhpiDeposit)) {
|
|
305
|
+
py_error_handler("returning result for evaluation of", expr, NULL, true);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
PLI_VOID exec(const struct vhpiCbDataS* cb_p) {
|
|
310
|
+
ensure_initialized();
|
|
311
|
+
|
|
312
|
+
// Get code parameter from VHDL procedure call
|
|
313
|
+
const char* code = get_parameter(cb_p);
|
|
314
|
+
|
|
315
|
+
// Exec(ute) Python code
|
|
316
|
+
if (PyRun_String(code, Py_file_input, globals, locals) == NULL) {
|
|
317
|
+
py_error_handler("executing", code, NULL, true);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
PLI_VOID register_foreign_subprograms() {
|
|
322
|
+
char library_name[] = "python";
|
|
323
|
+
|
|
324
|
+
char python_setup_name[] = "python_setup";
|
|
325
|
+
vhpiForeignDataT python_setup_data = {vhpiProcF, library_name,
|
|
326
|
+
python_setup_name, NULL, python_setup};
|
|
327
|
+
// vhpi_assert doesn't seem to work at this point
|
|
328
|
+
assert(vhpi_register_foreignf(&python_setup_data) != NULL);
|
|
329
|
+
|
|
330
|
+
char python_cleanup_name[] = "python_cleanup";
|
|
331
|
+
vhpiForeignDataT python_cleanup_data = {
|
|
332
|
+
vhpiProcF, library_name, python_cleanup_name, NULL, python_cleanup};
|
|
333
|
+
assert(vhpi_register_foreignf(&python_cleanup_data) != NULL);
|
|
334
|
+
|
|
335
|
+
char eval_integer_name[] = "eval_integer";
|
|
336
|
+
vhpiForeignDataT eval_integer_data = {vhpiProcF, library_name,
|
|
337
|
+
eval_integer_name, NULL, eval_integer};
|
|
338
|
+
assert(vhpi_register_foreignf(&eval_integer_data) != NULL);
|
|
339
|
+
|
|
340
|
+
char eval_real_name[] = "eval_real";
|
|
341
|
+
vhpiForeignDataT eval_real_data = {vhpiProcF, library_name, eval_real_name,
|
|
342
|
+
NULL, eval_real};
|
|
343
|
+
assert(vhpi_register_foreignf(&eval_real_data) != NULL);
|
|
344
|
+
|
|
345
|
+
char eval_integer_vector_name[] = "eval_integer_vector";
|
|
346
|
+
vhpiForeignDataT eval_integer_vector_data = {vhpiProcF, library_name,
|
|
347
|
+
eval_integer_vector_name, NULL,
|
|
348
|
+
eval_integer_vector};
|
|
349
|
+
assert(vhpi_register_foreignf(&eval_integer_vector_data) != NULL);
|
|
350
|
+
|
|
351
|
+
char eval_real_vector_name[] = "eval_real_vector";
|
|
352
|
+
vhpiForeignDataT eval_real_vector_data = {
|
|
353
|
+
vhpiProcF, library_name, eval_real_vector_name, NULL, eval_real_vector};
|
|
354
|
+
assert(vhpi_register_foreignf(&eval_real_vector_data) != NULL);
|
|
355
|
+
|
|
356
|
+
char eval_string_name[] = "eval_string";
|
|
357
|
+
vhpiForeignDataT eval_string_data = {vhpiProcF, library_name,
|
|
358
|
+
eval_string_name, NULL, eval_string};
|
|
359
|
+
assert(vhpi_register_foreignf(&eval_string_data) != NULL);
|
|
360
|
+
|
|
361
|
+
char exec_name[] = "exec";
|
|
362
|
+
vhpiForeignDataT exec_data = {vhpiProcF, library_name, exec_name, NULL, exec};
|
|
363
|
+
assert(vhpi_register_foreignf(&exec_data) != NULL);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
PLI_VOID (*vhpi_startup_routines[])() = {register_foreign_subprograms, NULL};
|