/* GRT VHPI C helpers. Copyright (C) 2021 Marlon James GHDL is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GHDL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //----------------------------------------------------------------------------- // Description: VHPI interface for GRT runtime, "C" helpers // for loading VHPI foreign applications // and libraries of foreign models, // and implementing variadic functions in vhpi_user.h //----------------------------------------------------------------------------- #include #include // Define PLI_PROTOTYPES so that vhpi_user.h does not import functions. #define PLI_PROTOTYPES #define XXTERN extern #include "vhpi_user.h" #include "vhpi_thunk.h" #include "grt-cdynload.h" // See grt-vhpi.ads extern int Vhpi_Control_Internal (int command, int status); extern int Vhpi_Assert_Internal (int severity, const char *msg); // Forward declaration int vhpi_vassert (vhpiSeverityT severity, char *formatmsg, va_list args); static vhpi_thunk __ghdl_vhpi_thunk_v1 = { vhpi_vassert, vhpi_register_cb, vhpi_remove_cb, vhpi_disable_cb, vhpi_enable_cb, vhpi_get_cb_info, 0, //vhpi_sens_first, 0, //vhpi_sens_zero, 0, //vhpi_sens_clr, 0, //vhpi_sens_set, 0, //vhpi_sens_isset, vhpi_handle_by_name, vhpi_handle_by_index, vhpi_handle, vhpi_iterator, vhpi_scan, vhpi_get, vhpi_get_str, vhpi_get_real, vhpi_get_phys, vhpi_protected_call, vhpi_get_value, vhpi_put_value, vhpi_schedule_transaction, vhpi_format_value, vhpi_get_time, vhpi_get_next_time, Vhpi_Control_Internal, vhpi_vprintf, vhpi_is_printable, vhpi_compare_handles, vhpi_check_error, vhpi_release_handle, vhpi_create, vhpi_register_foreignf, vhpi_get_foreignf_info, vhpi_get_data, vhpi_put_data }; //----------------------------------------------------------------------------- // VHPI module load & startup // VHPI thunks are combined into libghdlvpi #if defined (__APPLE__) // On Darwin: look in rpath. #define LIBNAME "@rpath/libghdlvpi" DSO_EXT #else #define LIBNAME "libghdlvpi" DSO_EXT #endif static const char libghdlvpi_name[] = LIBNAME; int loadVhpiModule (const char* libname, const char* entrypoint) { static void *libghdlvpi_mod; int i; void *vhpimod; fprintf (stderr, "loading VHPI library '%s'", libname); if (entrypoint) { fprintf (stderr, " with registration function '%s'", entrypoint); } fprintf (stderr, "\n"); // TODO: on windows, use SetDllDirectory with: // - install dir (libdir) => add -DLIBDIR=xxx // - exec path\lib => see windows_default_path vhpimod = grt_dynload_open (libname); if (vhpimod == NULL) { const char *msg = grt_dynload_error (); fprintf (stderr, "%s\n", msg == NULL ? "unknown dlopen error" : msg); return -1; } // Try to load the libghdlvpi library and set the thunk pointer. // No need to load the library several times. if (libghdlvpi_mod == NULL) { libghdlvpi_mod = grt_dynload_open (libghdlvpi_name); if (libghdlvpi_mod != NULL) { vhpi_thunk **vhpi_thunk_ptr; for (i = 0; i < 2; i++) { vhpi_thunk_ptr = grt_dynload_symbol (libghdlvpi_mod, &"_VHPI_THUNK"[i]); if (vhpi_thunk_ptr != NULL) { *vhpi_thunk_ptr = &__ghdl_vhpi_thunk_v1; break; } } if (vhpi_thunk_ptr == NULL) fprintf (stderr, "warning: VHPI_THUNK not found in %s\n", libghdlvpi_name); } } if (entrypoint) { void *regfunc = grt_dynload_symbol (vhpimod, entrypoint); if (regfunc) { ((vhpiRegistrationFctT)regfunc)(); fprintf (stderr, "VHPI module loaded and registration function called!\n"); return 0; // successfully registered VHPI module } fprintf (stderr, "registration function '%s' not found\n", entrypoint); return -1; // failed to register VHPI module } for (i = 0; i < 2; i++) // try with and w/o leading underscores { void *vhpitable = grt_dynload_symbol (vhpimod, &"_vhpi_startup_routines"[i]); if (vhpitable) { unsigned int idx; vhpiRegistrationFctT *vhpifuncs; vhpifuncs = (vhpiRegistrationFctT*)vhpitable; for (idx = 0; vhpifuncs[idx]; idx++) { vhpifuncs[idx](); } fprintf (stderr, "VHPI module loaded and vhpi_startup_routines functions called!\n"); return 0; // successfully registered VHPI module } } fprintf (stderr, "vhpi_startup_routines not found\n"); return -1; // failed to register VHPI module } //----------------------------------------------------------------------------- // VHPI functions #define ASSERTMSG_SIZE 512 static char assertmsg_buff[ASSERTMSG_SIZE]; static const char* default_msg = "VHPI foreign application error"; int vhpi_vassert (vhpiSeverityT severity, char *formatmsg, va_list args) { if (formatmsg == NULL) { return Vhpi_Assert_Internal(severity, default_msg); } // construct assert message in the buffer vsnprintf(assertmsg_buff, ASSERTMSG_SIZE, formatmsg, args); return Vhpi_Assert_Internal(severity, assertmsg_buff); } int vhpi_assert (vhpiSeverityT severity, char *formatmsg, ...) { va_list args; int res; va_start (args, formatmsg); res = vhpi_vassert (severity, formatmsg, args); va_end(args); return res; } int vhpi_control (vhpiSimControlT command, ...) { va_list args; int status; int res; va_start (args, command); status = va_arg (args, int); res = Vhpi_Control_Internal (command, status); va_end (args); return res; } int vhpi_printf (const char *format, ...) { va_list args; int res; va_start (args, format); res = vprintf (format, args); va_end (args); return res; } int vhpi_vprintf (const char *format, va_list args) { return vprintf (format, args); }