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