1 /*
2  * Copyright (c) 2019-2020 Martin Whitaker (icarus@martin-whitaker.me.uk)
3  *
4  *    This source code is free software; you can redistribute it
5  *    and/or modify it in source code form under the terms of the GNU
6  *    General Public License as published by the Free Software
7  *    Foundation; either version 2 of the License, or (at your option)
8  *    any later version.
9  *
10  *    This program is distributed in the hope that it will be useful,
11  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *    GNU General Public License for more details.
14  *
15  *    You should have received a copy of the GNU General Public License
16  *    along with this program; if not, write to the Free Software
17  *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 #include "config.h"
21 #include "compiler.h"
22 #include "vpi_user.h"
23 #include "sv_vpi_user.h"
24 #include "vvp/ivl_dlfcn.h"
25 
26 /* The only VPI routines that can be legally called when the functions in
27    the vlog_startup_routines[] array are executed are vpi_register_systf()
28    and vpi_register_cb(), so we can simply provide stubs for the rest. We
29    aren't going to execute any callbacks, so we can just provide a stub for
30    vpi_register_cb() too.
31 
32    Note that the Icarus system module illegally calls vpi_get_vlog_info()
33    during startup, so take care to fill in the data structure for that.
34 */
35 
36 // callback related
37 
vpi_register_cb(p_cb_data)38 vpiHandle   vpi_register_cb(p_cb_data) { return 0; }
vpi_remove_cb(vpiHandle)39 PLI_INT32   vpi_remove_cb(vpiHandle) { return 0; }
40 
vpi_get_systf_info(vpiHandle,p_vpi_systf_data)41 void        vpi_get_systf_info(vpiHandle, p_vpi_systf_data) { }
42 
43 // for obtaining handles
44 
vpi_handle_by_name(const char *,vpiHandle)45 vpiHandle   vpi_handle_by_name(const char*, vpiHandle) { return 0; }
vpi_handle_by_index(vpiHandle,PLI_INT32)46 vpiHandle   vpi_handle_by_index(vpiHandle, PLI_INT32) { return 0; }
47 
48 // for traversing relationships
49 
vpi_handle(PLI_INT32,vpiHandle)50 vpiHandle   vpi_handle(PLI_INT32, vpiHandle) { return 0; }
vpi_iterate(PLI_INT32,vpiHandle)51 vpiHandle   vpi_iterate(PLI_INT32, vpiHandle) { return 0; }
vpi_scan(vpiHandle)52 vpiHandle   vpi_scan(vpiHandle) { return 0; }
53 
54 // for processing properties
55 
vpi_get(int,vpiHandle)56 PLI_INT32   vpi_get(int, vpiHandle) { return 0; }
vpi_get_str(PLI_INT32,vpiHandle)57 char*       vpi_get_str(PLI_INT32, vpiHandle) { return 0; }
58 
59 // delay processing
60 
vpi_get_delays(vpiHandle,p_vpi_delay)61 void        vpi_get_delays(vpiHandle, p_vpi_delay) { }
vpi_put_delays(vpiHandle,p_vpi_delay)62 void        vpi_put_delays(vpiHandle, p_vpi_delay) { }
63 
64 // value processing
65 
vpi_get_value(vpiHandle,p_vpi_value)66 void        vpi_get_value(vpiHandle, p_vpi_value) { }
vpi_put_value(vpiHandle,p_vpi_value,p_vpi_time,PLI_INT32)67 vpiHandle   vpi_put_value(vpiHandle, p_vpi_value, p_vpi_time, PLI_INT32) { return 0; }
68 
69 // time processing
70 
vpi_get_time(vpiHandle,s_vpi_time *)71 void        vpi_get_time(vpiHandle, s_vpi_time*) { }
72 
73 // data processing
74 
vpi_get_userdata(vpiHandle)75 void*       vpi_get_userdata(vpiHandle) { return 0; }
vpi_put_userdata(vpiHandle,void *)76 PLI_INT32   vpi_put_userdata(vpiHandle, void*) { return 0; }
77 
78 // I/O routines
79 
vpi_mcd_open(char *)80 PLI_UINT32  vpi_mcd_open(char *) { return 0; }
vpi_mcd_close(PLI_UINT32)81 PLI_UINT32  vpi_mcd_close(PLI_UINT32) { return 0; }
vpi_mcd_flush(PLI_UINT32)82 PLI_INT32   vpi_mcd_flush(PLI_UINT32) { return 0; }
vpi_mcd_name(PLI_UINT32)83 char*       vpi_mcd_name(PLI_UINT32) { return 0; }
vpi_mcd_printf(PLI_UINT32,const char *,...)84 PLI_INT32   vpi_mcd_printf(PLI_UINT32, const char*, ...) { return 0; }
vpi_mcd_vprintf(PLI_UINT32,const char *,va_list)85 PLI_INT32   vpi_mcd_vprintf(PLI_UINT32, const char*, va_list) { return 0; }
86 
vpi_flush(void)87 PLI_INT32   vpi_flush(void) { return 0; }
vpi_printf(const char *,...)88 PLI_INT32   vpi_printf(const char*, ...) { return 0; }
vpi_vprintf(const char *,va_list)89 PLI_INT32   vpi_vprintf(const char*, va_list) { return 0; }
90 
91 // utility routines
92 
vpi_chk_error(p_vpi_error_info)93 PLI_INT32   vpi_chk_error(p_vpi_error_info) { return 0; }
vpi_compare_objects(vpiHandle,vpiHandle)94 PLI_INT32   vpi_compare_objects(vpiHandle, vpiHandle) { return 0; }
vpi_free_object(vpiHandle)95 PLI_INT32   vpi_free_object(vpiHandle) { return 0; }
vpi_get_vlog_info(p_vpi_vlog_info info)96 PLI_INT32   vpi_get_vlog_info(p_vpi_vlog_info info)
97 {
98     info->argc = 0;
99     info->argv = 0;
100     info->product = 0;
101     info->version = 0;
102     return 0;
103 }
104 
105 // control routines
106 
vpi_control(PLI_INT32,...)107 void        vpi_control(PLI_INT32, ...) { }
vpi_sim_control(PLI_INT32,...)108 void        vpi_sim_control(PLI_INT32, ...) { }
109 
110 // proposed standard extensions
111 
vpi_fopen(const char *,const char *)112 PLI_INT32   vpi_fopen(const char*, const char*) { return 0; }
vpi_get_file(PLI_INT32)113 FILE*       vpi_get_file(PLI_INT32) { return 0; }
114 
115 // Icarus extensions
116 
vpip_calc_clog2(vpiHandle)117 s_vpi_vecval vpip_calc_clog2(vpiHandle)
118 {
119     s_vpi_vecval val = { 0, 0 };
120     return val;
121 }
vpip_count_drivers(vpiHandle,unsigned,unsigned[4])122 void        vpip_count_drivers(vpiHandle, unsigned, unsigned [4]) { }
vpip_format_strength(char *,s_vpi_value *,unsigned)123 void        vpip_format_strength(char*, s_vpi_value*, unsigned) { }
vpip_make_systf_system_defined(vpiHandle)124 void        vpip_make_systf_system_defined(vpiHandle) { }
vpip_mcd_rawwrite(PLI_UINT32,const char *,size_t)125 void        vpip_mcd_rawwrite(PLI_UINT32, const char*, size_t) { }
vpip_set_return_value(int)126 void        vpip_set_return_value(int) { }
vpi_vcontrol(PLI_INT32,va_list)127 void        vpi_vcontrol(PLI_INT32, va_list) { }
128 
129 
130 /* When a module registers a system function, extract and save the return
131    type for use during elaboration. */
vpi_register_systf(const struct t_vpi_systf_data * ss)132 vpiHandle vpi_register_systf(const struct t_vpi_systf_data*ss)
133 {
134     if (ss->type != vpiSysFunc)
135         return 0;
136 
137     struct sfunc_return_type ret_type;
138     ret_type.name = ss->tfname;
139     switch (ss->sysfunctype) {
140       case vpiIntFunc:
141         ret_type.type = IVL_VT_LOGIC;
142         ret_type.wid  = 32;
143         ret_type.signed_flag = true;
144         break;
145       case vpiRealFunc:
146         ret_type.type = IVL_VT_REAL;
147         ret_type.wid  = 1;
148         ret_type.signed_flag = true;
149         break;
150       case vpiTimeFunc:
151         ret_type.type = IVL_VT_LOGIC;
152         ret_type.wid  = 64;
153         ret_type.signed_flag = false;
154         break;
155       case vpiSizedFunc:
156         ret_type.type = IVL_VT_LOGIC;
157         ret_type.wid  = ss->sizetf ? ss->sizetf(ss->user_data) : 32;
158         ret_type.signed_flag = false;
159         break;
160       case vpiSizedSignedFunc:
161         ret_type.type = IVL_VT_LOGIC;
162         ret_type.wid  = ss->sizetf ? ss->sizetf(ss->user_data) : 32;
163         ret_type.signed_flag = true;
164         break;
165       case vpiStringFunc:
166         ret_type.type = IVL_VT_STRING;
167         ret_type.wid  = 0;
168         ret_type.signed_flag = false;
169         break;
170       case vpiOtherFunc:
171         ret_type.type = IVL_VT_NO_TYPE;
172         ret_type.wid  = 0;
173         ret_type.signed_flag = false;
174         break;
175       default:
176         cerr << "warning: " << ss->tfname << " has an unknown return type. "
177                 "Assuming 32 bit unsigned." << endl;
178         ret_type.type = IVL_VT_LOGIC;
179         ret_type.wid  = 32;
180         ret_type.signed_flag = false;
181         break;
182     }
183     ret_type.override_flag = false;
184     add_sys_func(ret_type);
185     return 0;
186 }
187 
188 #if defined(__MINGW32__) || defined (__CYGWIN__)
189 vpip_routines_s vpi_routines = {
190     .register_cb                = vpi_register_cb,
191     .remove_cb                  = vpi_remove_cb,
192     .register_systf             = vpi_register_systf,
193     .get_systf_info             = vpi_get_systf_info,
194     .handle_by_name             = vpi_handle_by_name,
195     .handle_by_index            = vpi_handle_by_index,
196     .handle                     = vpi_handle,
197     .iterate                    = vpi_iterate,
198     .scan                       = vpi_scan,
199     .get                        = vpi_get,
200     .get_str                    = vpi_get_str,
201     .get_delays                 = vpi_get_delays,
202     .put_delays                 = vpi_put_delays,
203     .get_value                  = vpi_get_value,
204     .put_value                  = vpi_put_value,
205     .get_time                   = vpi_get_time,
206     .get_userdata               = vpi_get_userdata,
207     .put_userdata               = vpi_put_userdata,
208     .mcd_open                   = vpi_mcd_open,
209     .mcd_close                  = vpi_mcd_close,
210     .mcd_flush                  = vpi_mcd_flush,
211     .mcd_name                   = vpi_mcd_name,
212     .mcd_vprintf                = vpi_mcd_vprintf,
213     .flush                      = vpi_flush,
214     .vprintf                    = vpi_vprintf,
215     .chk_error                  = vpi_chk_error,
216     .compare_objects            = vpi_compare_objects,
217     .free_object                = vpi_free_object,
218     .get_vlog_info              = vpi_get_vlog_info,
219     .vcontrol                   = vpi_vcontrol,
220     .fopen                      = vpi_fopen,
221     .get_file                   = vpi_get_file,
222     .calc_clog2                 = vpip_calc_clog2,
223     .count_drivers              = vpip_count_drivers,
224     .format_strength            = vpip_format_strength,
225     .make_systf_system_defined  = vpip_make_systf_system_defined,
226     .mcd_rawwrite               = vpip_mcd_rawwrite,
227     .set_return_value           = vpip_set_return_value,
228 };
229 
230 typedef PLI_UINT32 (*vpip_set_callback_t)(vpip_routines_s*, PLI_UINT32);
231 #endif
232 typedef void (*vlog_startup_routines_t)(void);
233 
load_vpi_module(const char * path)234 bool load_vpi_module(const char*path)
235 {
236     ivl_dll_t dll = ivl_dlopen(path, false);
237     if (dll == 0) {
238 	cerr << "error: Failed to open '" << path << "' because:" << endl;
239         cerr << "     : " << dlerror() << endl;
240 	return false;
241     }
242 
243 #if defined(__MINGW32__) || defined (__CYGWIN__)
244     void*function = ivl_dlsym(dll, "vpip_set_callback");
245     if (function == 0) {
246         cerr << "warning: '" << path << "' has no vpip_set_callback()" << endl;
247         ivl_dlclose(dll);
248         return true;
249     }
250     vpip_set_callback_t set_callback = (vpip_set_callback_t)function;
251     if (!set_callback(&vpi_routines, vpip_routines_version)) {
252         cerr << "error: Failed to link '" << path << "'. "
253                 "Try rebuilding it with iverilog-vpi." << endl;
254         ivl_dlclose(dll);
255         return true;
256     }
257 #endif
258 
259     void*table = ivl_dlsym(dll, LU "vlog_startup_routines" TU);
260     if (table == 0) {
261         cerr << "warning: '" << path << "' has no vlog_startup_routines" << endl;
262         ivl_dlclose(dll);
263         return true;
264     }
265 
266     vlog_startup_routines_t*routines = (vlog_startup_routines_t*)table;
267     for (unsigned idx = 0; routines[idx]; idx += 1) {
268         (routines[idx])();
269     }
270 
271     ivl_dlclose(dll);
272     return true;
273 }
274