1 /*
2 * Copyright (c) 2008-2020 Stephen Williams (steve@icarus.com)
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 "version_base.h"
21 # include "vpi_priv.h"
22 # include "schedule.h"
23 #ifdef CHECK_WITH_VALGRIND
24 # include "vvp_cleanup.h"
25 #endif
26 # include <vector>
27 # include <cstdio>
28 # include <cstdarg>
29 # include <cstring>
30 # include <cassert>
31 # include <cstdlib>
32 # include <cmath>
33 # include <iostream>
34
35 using namespace std;
36 vpi_mode_t vpi_mode_flag = VPI_MODE_NONE;
37 FILE*vpi_trace = 0;
38
39 static s_vpi_vlog_info vpi_vlog_info;
40 static s_vpi_error_info vpip_last_error = { 0, 0, 0, 0, 0, 0, 0 };
41
~__vpiHandle()42 __vpiHandle::~__vpiHandle()
43 { }
44
vpi_get(int)45 int __vpiHandle::vpi_get(int)
46 { return vpiUndefined; }
47
vpi_get_str(int)48 char* __vpiHandle::vpi_get_str(int)
49 { return 0; }
50
vpi_get_value(p_vpi_value)51 void __vpiHandle::vpi_get_value(p_vpi_value)
52 { }
53
vpi_put_value(p_vpi_value,int)54 vpiHandle __vpiHandle::vpi_put_value(p_vpi_value, int)
55 { return 0; }
56
vpi_handle(int)57 vpiHandle __vpiHandle::vpi_handle(int)
58 { return 0; }
59
vpi_iterate(int)60 vpiHandle __vpiHandle::vpi_iterate(int)
61 { return 0; }
62
vpi_index(int)63 vpiHandle __vpiHandle::vpi_index(int)
64 { return 0; }
65
vpi_get_delays(p_vpi_delay)66 void __vpiHandle::vpi_get_delays(p_vpi_delay)
67 { }
68
vpi_put_delays(p_vpi_delay)69 void __vpiHandle::vpi_put_delays(p_vpi_delay)
70 { }
71
__vpiBaseVar(__vpiScope * scope,const char * name,vvp_net_t * net)72 __vpiBaseVar::__vpiBaseVar(__vpiScope*scope, const char*name, vvp_net_t*net)
73 : scope_(scope), name_(name), net_(net)
74 {
75 }
76
77 #ifdef CHECK_WITH_VALGRIND
~__vpiBaseVar()78 __vpiBaseVar::~__vpiBaseVar()
79 {
80 vvp_net_delete(net_);
81 }
82 #endif
83
84 /*
85 * The default behavior for the vpi_free_object to an object is to
86 * suppress the actual operation. This is because handles are
87 * generally allocated semi-permanently within vvp context. Dynamic
88 * objects will override the free_object_fun method to return an
89 * appropriately effective function.
90 */
suppress_free(vpiHandle)91 static int suppress_free(vpiHandle)
92 { return 1; }
free_object_fun(void)93 __vpiHandle::free_object_fun_t __vpiHandle::free_object_fun(void)
94 { return &suppress_free; }
95
96 /*
97 * The vpip_string function creates a constant string from the pass
98 * input. This constant string is permanently allocated from an
99 * efficient string buffer store.
100 */
101 struct vpip_string_chunk {
102 struct vpip_string_chunk*next;
103 char data[64*1024 - sizeof (struct vpip_string_chunk*)];
104 };
105
vpip_size(__vpiSignal * sig)106 unsigned vpip_size(__vpiSignal *sig)
107 {
108 return abs(sig->msb.get_value() - sig->lsb.get_value()) + 1;
109 }
110
vpip_scope(__vpiSignal * sig)111 __vpiScope* vpip_scope(__vpiSignal*sig)
112 {
113 if (sig->is_netarray)
114 return (__vpiScope*) vpi_handle(vpiScope, sig->within.parent);
115 else
116 return sig->within.scope;
117 }
118
vpip_scope(__vpiRealVar * sig)119 __vpiScope* vpip_scope(__vpiRealVar*sig)
120 {
121 if (sig->is_netarray)
122 return (__vpiScope*) vpi_handle(vpiScope, sig->within.parent);
123 else
124 return sig->within.scope;
125 }
126
vpip_module(__vpiScope * scope)127 vpiHandle vpip_module(__vpiScope*scope)
128 {
129 while(scope && scope->get_type_code() != vpiModule) {
130 scope = scope->scope;
131 }
132 assert(scope);
133 return scope;
134 }
135
vpip_string(const char * str)136 const char *vpip_string(const char*str)
137 {
138 static vpip_string_chunk first_chunk = {0, {0}};
139 static vpip_string_chunk*chunk_list = &first_chunk;
140 static unsigned chunk_fill = 0;
141
142 unsigned len = strlen(str);
143 assert( (len+1) <= sizeof chunk_list->data );
144
145 if ( (len+1) > (sizeof chunk_list->data - chunk_fill) ) {
146 vpip_string_chunk*tmp = new vpip_string_chunk;
147 tmp->next = chunk_list;
148 chunk_list = tmp;
149 chunk_fill = 0;
150 }
151
152 char*res = chunk_list->data + chunk_fill;
153 chunk_fill += len + 1;
154
155 strcpy(res, str);
156 return res;
157 }
158
hash_string(const char * text)159 static unsigned hash_string(const char*text)
160 {
161 unsigned h = 0;
162
163 while (*text) {
164 h = (h << 4) ^ (h >> 28) ^ (unsigned)*text;
165 text += 1;
166 }
167 return h;
168 }
169
vpip_name_string(const char * text)170 const char* vpip_name_string(const char*text)
171 {
172 const unsigned HASH_SIZE = 4096;
173 static const char*hash_table[HASH_SIZE] = {0};
174
175 unsigned hash_value = hash_string(text) % HASH_SIZE;
176
177 /* If we easily find the string in the hash table, then return
178 that and be done. */
179 if (hash_table[hash_value]
180 && (strcmp(hash_table[hash_value], text) == 0)) {
181 return hash_table[hash_value];
182 }
183
184 /* The existing hash entry is not a match. Replace it with the
185 newly allocated value, and return the new pointer as the
186 result to the add. */
187 const char*res = vpip_string(text);
188 hash_table[hash_value] = res;
189
190 return res;
191 }
192
vpi_chk_error(p_vpi_error_info info)193 PLI_INT32 vpi_chk_error(p_vpi_error_info info)
194 {
195 if (vpip_last_error.state == 0)
196 return 0;
197
198 info->state = vpip_last_error.state;
199 info->level = vpip_last_error.level;
200 info->message = vpip_last_error.message;
201 info->product = vpi_vlog_info.product;
202 info->code = (char *) "";
203 info->file = 0;
204 info->line = 0;
205
206 return info->level;
207 }
208
vpi_compare_objects(vpiHandle obj1,vpiHandle obj2)209 PLI_INT32 vpi_compare_objects(vpiHandle obj1, vpiHandle obj2)
210 {
211 assert(obj1);
212 assert(obj2);
213
214 // Does this actually work for all cases?
215 if (obj1 != obj2) return 0;
216 else return 1;
217 }
218
219 /*
220 * Copy the internal information to the data structure. Do not free or
221 * change the tfname/user_data since they are a pointer to the real
222 * string/data values. We also support passing a task or function handle
223 * instead of just a handle to a vpiUserSystf.
224 */
vpi_get_systf_info(vpiHandle ref,p_vpi_systf_data data)225 void vpi_get_systf_info(vpiHandle ref, p_vpi_systf_data data)
226 {
227 struct __vpiUserSystf* rfp = dynamic_cast<__vpiUserSystf*>(ref);
228 if (rfp == 0) {
229 struct __vpiSysTaskCall*call = dynamic_cast<__vpiSysTaskCall*>(ref);
230 assert(call);
231 rfp = call->defn;
232 }
233
234 /* Assert that vpiUserDefn is true! */
235 assert(rfp->is_user_defn);
236
237 data->type = rfp->info.type;
238 data->sysfunctype = rfp->info.sysfunctype;
239 data->tfname = rfp->info.tfname;
240 data->calltf = rfp->info.calltf;
241 data->compiletf = rfp->info.compiletf;
242 data->sizetf = rfp->info.sizetf;
243 data->user_data = rfp->info.user_data;
244 }
245
246 /*
247 * When a task is called, this value is set so that vpi_handle can
248 * fathom the vpi_handle(vpiSysTfCall,0) function.
249 */
250 struct __vpiSysTaskCall*vpip_cur_task = 0;
251
vpi_free_object(vpiHandle ref)252 PLI_INT32 vpi_free_object(vpiHandle ref)
253 {
254 int rtn;
255
256 if (vpi_trace) {
257 fprintf(vpi_trace, "vpi_free_object(%p)", ref);
258 fflush(vpi_trace);
259 }
260
261 assert(ref);
262 __vpiHandle::free_object_fun_t fun = ref->free_object_fun();
263 rtn = fun (ref);
264
265 if (vpi_trace)
266 fprintf(vpi_trace, " --> %d\n", rtn);
267
268 return rtn;
269 }
270
vpip_get_global(int property)271 static int vpip_get_global(int property)
272 {
273 switch (property) {
274
275 case vpiTimeUnit:
276 case vpiTimePrecision:
277 return vpip_get_time_precision();
278
279 default:
280 fprintf(stderr, "vpi error: bad global property: %d\n", property);
281 assert(0);
282 return vpiUndefined;
283 }
284 }
285
vpi_property_str(PLI_INT32 code)286 static const char* vpi_property_str(PLI_INT32 code)
287 {
288 static char buf[32];
289 switch (code) {
290 case vpiConstType:
291 return "vpiConstType";
292 case vpiName:
293 return "vpiName";
294 case vpiFullName:
295 return "vpiFullName";
296 case vpiTimeUnit:
297 return "vpiTimeUnit";
298 case vpiTimePrecision:
299 return "vpiTimePrecision";
300 case vpiSize:
301 return "vpiSize";
302 default:
303 sprintf(buf, "%d", (int)code);
304 }
305 return buf;
306 }
307
vpi_type_values(PLI_INT32 code)308 static const char* vpi_type_values(PLI_INT32 code)
309 {
310 static char buf[32];
311 switch (code) {
312 case vpiArrayType:
313 return "vpiArrayType";
314 case vpiBitVar:
315 return "vpiBitVar";
316 case vpiByteVar:
317 return "vpiByteVar";
318 case vpiClassVar:
319 return "vpiClassVar";
320 case vpiConstant:
321 return "vpiConstant";
322 case vpiEnumTypespec:
323 return "vpiEnumTypespec";
324 case vpiFunction:
325 return "vpiFunction";
326 case vpiGenScope:
327 return "vpiGenScope";
328 case vpiIntVar:
329 return "vpiIntVar";
330 case vpiIntegerVar:
331 return "vpiIntegerVar";
332 case vpiIterator:
333 return "vpiIterator";
334 case vpiLongIntVar:
335 return "vpiLongIntVar";
336 case vpiMemory:
337 return "vpiMemory";
338 case vpiMemoryWord:
339 return "vpiMemoryWord";
340 case vpiModule:
341 return "vpiModule";
342 case vpiNamedBegin:
343 return "vpiNamedBegin";
344 case vpiNamedEvent:
345 return "vpiNamedEvent";
346 case vpiNamedFork:
347 return "vpiNamedFork";
348 case vpiPackage:
349 return "vpiPackage";
350 case vpiPathTerm:
351 return "vpiPathTerm";
352 case vpiPort:
353 return "vpiPort";
354 case vpiNet:
355 return "vpiNet";
356 case vpiNetArray:
357 return "vpiNetArray";
358 case vpiNetBit:
359 return "vpiNetBit";
360 case vpiParameter:
361 return "vpiParameter";
362 case vpiPartSelect:
363 return "vpiPartSelect";
364 case vpiRealVar:
365 return "vpiRealVar";
366 case vpiReg:
367 return "vpiReg";
368 case vpiRegBit:
369 return "vpiRegBit";
370 case vpiShortIntVar:
371 return "vpiShortIntVar";
372 case vpiStringVar:
373 return "vpiStringVar";
374 case vpiSysFuncCall:
375 return "vpiSysFuncCall";
376 case vpiSysTaskCall:
377 return "vpiSysTaskCall";
378 case vpiTask:
379 return "vpiTask";
380 case vpiTimeVar:
381 return "vpiTimeVar";
382 case vpiUserSystf:
383 return "vpiUserSystf";
384 default:
385 sprintf(buf, "%d", (int)code);
386 }
387 return buf;
388 }
389
vpi_get(int property,vpiHandle ref)390 PLI_INT32 vpi_get(int property, vpiHandle ref)
391 {
392 /* We don't care what the ref is there is only one delay selection. */
393 if (property == _vpiDelaySelection) return vpip_delay_selection;
394
395 if (ref == 0)
396 return vpip_get_global(property);
397
398 if (property == vpiType) {
399 if (vpi_trace) {
400 fprintf(vpi_trace, "vpi_get(vpiType, %p) --> %s\n",
401 ref, vpi_type_values(ref->get_type_code()));
402 }
403
404 if (ref->get_type_code() == vpiMemory && is_net_array(ref))
405 return vpiNetArray;
406 else
407 return ref->get_type_code();
408 }
409
410 int res = ref->vpi_get(property);
411
412 if (vpi_trace) {
413 fprintf(vpi_trace, "vpi_get(%s, %p) --> %d\n",
414 vpi_property_str(property), ref, res);
415 }
416
417 return res;
418 }
419
vpi_get_str(PLI_INT32 property,vpiHandle ref)420 char* vpi_get_str(PLI_INT32 property, vpiHandle ref)
421 {
422 /* We don't care what the ref is there is only one delay selection. */
423 if (property == _vpiDelaySelection) {
424 switch (vpip_delay_selection) {
425 case _vpiDelaySelMinimum:
426 return simple_set_rbuf_str("MINIMUM");
427 case _vpiDelaySelTypical:
428 return simple_set_rbuf_str("TYPICAL");
429 case _vpiDelaySelMaximum:
430 return simple_set_rbuf_str("MAXIMUM");
431 default:
432 assert(0);
433 }
434 }
435
436 if (ref == 0) {
437 fprintf(stderr, "vpi error: vpi_get_str(%s, 0) called "
438 "with null vpiHandle.\n", vpi_property_str(property));
439 return 0;
440 }
441
442 if (property == vpiType) {
443 if (vpi_trace) {
444 fprintf(vpi_trace, "vpi_get(vpiType, %p) --> %s\n",
445 ref, vpi_type_values(ref->get_type_code()));
446 }
447
448 PLI_INT32 type;
449 if (ref->get_type_code() == vpiMemory && is_net_array(ref))
450 type = vpiNetArray;
451 else
452 type = ref->get_type_code();
453 return (char *)vpi_type_values(type);
454 }
455
456 char*res = ref->vpi_get_str(property);
457
458 if (vpi_trace) {
459 fprintf(vpi_trace, "vpi_get_str(%s, %p) --> %s\n",
460 vpi_property_str(property), ref, res? res : "<NULL>");
461 }
462
463 return res;
464 }
465
vpip_time_units_from_handle(vpiHandle obj)466 int vpip_time_units_from_handle(vpiHandle obj)
467 {
468 struct __vpiSysTaskCall*task;
469 __vpiScope*scope;
470 struct __vpiSignal*signal;
471 __vpiNamedEvent*event;
472
473 if (obj == 0)
474 return vpip_get_time_precision();
475
476 switch (obj->get_type_code()) {
477 case vpiSysTaskCall:
478 task = dynamic_cast<__vpiSysTaskCall*>(obj);
479 return task->scope->time_units;
480
481 case vpiModule:
482 scope = dynamic_cast<__vpiScope*>(obj);
483 return scope->time_units;
484
485 case vpiNet:
486 case vpiReg:
487 signal = dynamic_cast<__vpiSignal*>(obj);
488 scope = vpip_scope(signal);
489 return scope->time_units;
490
491 case vpiNamedEvent:
492 event = dynamic_cast<__vpiNamedEvent*>(obj);
493 scope = event->get_scope();
494 return scope->time_units;
495
496 default:
497 fprintf(stderr, "ERROR: vpip_time_units_from_handle called with "
498 "object handle type=%u\n", obj->get_type_code());
499 assert(0);
500 return 0;
501 }
502 }
503
vpip_time_precision_from_handle(vpiHandle obj)504 int vpip_time_precision_from_handle(vpiHandle obj)
505 {
506 struct __vpiSysTaskCall*task;
507 __vpiScope*scope;
508 struct __vpiSignal*signal;
509
510 if (obj == 0)
511 return vpip_get_time_precision();
512
513 switch (obj->get_type_code()) {
514 case vpiSysTaskCall:
515 task = dynamic_cast<__vpiSysTaskCall*>(obj);
516 return task->scope->time_precision;
517
518 case vpiModule:
519 scope = dynamic_cast<__vpiScope*>(obj);
520 return scope->time_precision;
521
522 case vpiNet:
523 case vpiReg:
524 signal = dynamic_cast<__vpiSignal*>(obj);
525 scope = vpip_scope(signal);
526 return scope->time_precision;
527
528 default:
529 fprintf(stderr, "ERROR: vpip_time_precision_from_handle called "
530 "with object handle type=%u\n", obj->get_type_code());
531 assert(0);
532 return 0;
533 }
534 }
535
vpi_get_time(vpiHandle obj,s_vpi_time * vp)536 void vpi_get_time(vpiHandle obj, s_vpi_time*vp)
537 {
538 int scale;
539 vvp_time64_t time;
540
541 assert(vp);
542
543 time = schedule_simtime();
544
545 switch (vp->type) {
546 case vpiSimTime:
547 vp->high = (time >> 32) & 0xffffffff;
548 vp->low = time & 0xffffffff;
549 break;
550
551 case vpiScaledRealTime:
552 scale = vpip_get_time_precision() -
553 vpip_time_units_from_handle(obj);
554 if (scale >= 0) vp->real = (double)time * pow(10.0, scale);
555 else vp->real = (double)time / pow(10.0, -scale);
556 break;
557
558 default:
559 fprintf(stderr, "vpi_get_time: unknown type: %d\n", (int)vp->type);
560 assert(0);
561 break;
562 }
563 }
564
vpi_get_vlog_info(p_vpi_vlog_info vlog_info_p)565 PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info vlog_info_p)
566 {
567 if (vlog_info_p != 0) {
568 *vlog_info_p = vpi_vlog_info;
569 return 1;
570 } else {
571 return 0;
572 }
573 }
574
vpi_set_vlog_info(int argc,char ** argv)575 void vpi_set_vlog_info(int argc, char** argv)
576 {
577 static char icarus_product[] = "Icarus Verilog";
578 static char icarus_version[] = VERSION;
579 vpi_vlog_info.product = icarus_product;
580 vpi_vlog_info.version = icarus_version;
581 vpi_vlog_info.argc = argc;
582 vpi_vlog_info.argv = argv;
583
584 static char trace_buf[1024];
585 if (const char*path = getenv("VPI_TRACE")) {
586 if (!strcmp(path,"-"))
587 vpi_trace = stdout;
588 else {
589 vpi_trace = fopen(path, "w");
590 if (!vpi_trace) {
591 perror(path);
592 exit(1);
593 }
594 setvbuf(vpi_trace, trace_buf, _IOLBF, sizeof(trace_buf));
595 }
596 }
597 }
598
vec4_get_value_string(const vvp_vector4_t & word_val,unsigned width,s_vpi_value * vp)599 static void vec4_get_value_string(const vvp_vector4_t&word_val, unsigned width,
600 s_vpi_value*vp)
601 {
602 unsigned nchar = width / 8;
603 unsigned tail = width % 8;
604
605 char*rbuf = (char *) need_result_buf(nchar + 1, RBUF_VAL);
606 char*cp = rbuf;
607
608 if (tail > 0) {
609 char char_val = 0;
610 for (unsigned idx = width-tail; idx < width ; idx += 1) {
611 vvp_bit4_t val = word_val.value(idx);
612 if (val == BIT4_1)
613 char_val |= 1 << idx;
614 }
615
616 if (char_val != 0)
617 *cp++ = char_val;
618 }
619
620 for (unsigned idx = 0 ; idx < nchar ; idx += 1) {
621 unsigned bit = (nchar - idx - 1) * 8;
622 char char_val = 0;
623 for (unsigned bdx = 0 ; bdx < 8 ; bdx += 1) {
624 vvp_bit4_t val = word_val.value(bit+bdx);
625 if (val == BIT4_1)
626 char_val |= 1 << bdx;
627 }
628 if (char_val != 0)
629 *cp++ = char_val;
630 }
631
632 *cp = 0;
633 vp->value.str = rbuf;
634 }
635
636 /*
637 * This is a generic function to convert a vvp_vector4_t value into a
638 * vpi_value structure. The format is selected by the format of the
639 * value pointer. The width is the real width of the word, in case the
640 * word_val width is not accurate.
641 */
vpip_vec4_get_value(const vvp_vector4_t & word_val,unsigned width,bool signed_flag,s_vpi_value * vp)642 void vpip_vec4_get_value(const vvp_vector4_t&word_val, unsigned width,
643 bool signed_flag, s_vpi_value*vp)
644 {
645 char *rbuf = 0;
646
647 switch (vp->format) {
648 default:
649 fprintf(stderr, "sorry: Format %d not implemented for "
650 "getting vector values.\n", (int)vp->format);
651 assert(0);
652
653 case vpiSuppressVal:
654 break;
655
656 case vpiBinStrVal:
657 rbuf = (char *) need_result_buf(width+1, RBUF_VAL);
658 for (unsigned idx = 0 ; idx < width ; idx += 1) {
659 vvp_bit4_t bit = word_val.value(idx);
660 rbuf[width-idx-1] = vvp_bit4_to_ascii(bit);
661 }
662 rbuf[width] = 0;
663 vp->value.str = rbuf;
664 break;
665
666 case vpiOctStrVal: {
667 unsigned hwid = ((width+2) / 3) + 1;
668 rbuf = (char *) need_result_buf(hwid, RBUF_VAL);
669 vpip_vec4_to_oct_str(word_val, rbuf, hwid);
670 vp->value.str = rbuf;
671 break;
672 }
673
674 case vpiDecStrVal: {
675 // HERE need a better estimate.
676 rbuf = (char *) need_result_buf(width+1, RBUF_VAL);
677 vpip_vec4_to_dec_str(word_val, rbuf, width+1, signed_flag);
678 vp->value.str = rbuf;
679 break;
680 }
681
682 case vpiHexStrVal: {
683 unsigned hwid = ((width + 3) / 4) + 1;
684 rbuf = (char *) need_result_buf(hwid, RBUF_VAL);
685 vpip_vec4_to_hex_str(word_val, rbuf, hwid);
686 vp->value.str = rbuf;
687 break;
688 }
689
690 case vpiScalarVal: {
691 // scalars should be of size 1
692 assert(width == 1);
693 switch(word_val.value(0)) {
694 case BIT4_0:
695 vp->value.scalar = vpi0;
696 break;
697 case BIT4_1:
698 vp->value.scalar = vpi1;
699 break;
700 case BIT4_X:
701 vp->value.scalar = vpiX;
702 break;
703 case BIT4_Z:
704 vp->value.scalar = vpiZ;
705 break;
706 }
707 break;
708 }
709
710 case vpiIntVal: {
711 long val = 0;
712 vvp_bit4_t pad = BIT4_0;
713 if (signed_flag && word_val.size() > 0)
714 pad = word_val.value(word_val.size()-1);
715
716 for (unsigned idx = 0 ; idx < 8*sizeof(val) ; idx += 1) {
717 vvp_bit4_t val4 = pad;
718 if (idx < word_val.size())
719 val4 = word_val.value(idx);
720 if (val4 == BIT4_1)
721 val |= 1L << idx;
722 }
723
724 vp->value.integer = val;
725 break;
726 }
727
728 case vpiObjTypeVal:
729 // Use the following case to actually set the value!
730 vp->format = vpiVectorVal;
731 // fallthrough
732 case vpiVectorVal: {
733 unsigned hwid = (width + 31)/32;
734
735 s_vpi_vecval *op = (p_vpi_vecval)
736 need_result_buf(hwid * sizeof(s_vpi_vecval), RBUF_VAL);
737 vp->value.vector = op;
738
739 op->aval = op->bval = 0;
740 for (unsigned idx = 0 ; idx < width ; idx += 1) {
741 switch (word_val.value(idx)) {
742 case BIT4_0:
743 op->aval &= ~(1 << idx % 32);
744 op->bval &= ~(1 << idx % 32);
745 break;
746 case BIT4_1:
747 op->aval |= (1 << idx % 32);
748 op->bval &= ~(1 << idx % 32);
749 break;
750 case BIT4_X:
751 op->aval |= (1 << idx % 32);
752 op->bval |= (1 << idx % 32);
753 break;
754 case BIT4_Z:
755 op->aval &= ~(1 << idx % 32);
756 op->bval |= (1 << idx % 32);
757 break;
758 }
759 if (!((idx+1) % 32) && (idx+1 < width)) {
760 op++;
761 op->aval = op->bval = 0;
762 }
763 }
764 break;
765 }
766
767 case vpiStringVal:
768 vec4_get_value_string(word_val, width, vp);
769 break;
770
771 case vpiRealVal:
772 vector4_to_value(word_val, vp->value.real, signed_flag);
773 break;
774 }
775 }
776
vpip_vec2_get_value(const vvp_vector2_t & word_val,unsigned width,bool signed_flag,s_vpi_value * vp)777 void vpip_vec2_get_value(const vvp_vector2_t&word_val, unsigned width,
778 bool signed_flag, s_vpi_value*vp)
779 {
780 switch (vp->format) {
781 default:
782 fprintf(stderr, "sorry: Format %d not implemented for "
783 "getting vector2 values.\n", (int)vp->format);
784 assert(0);
785
786 case vpiSuppressVal:
787 break;
788
789 case vpiObjTypeVal:
790 vp->format = vpiIntVal;
791 // fallthrough
792 case vpiIntVal:
793 vector2_to_value(word_val, vp->value.integer, signed_flag);
794 break;
795
796 case vpiVectorVal: {
797 unsigned hwid = (width + 31)/32;
798
799 s_vpi_vecval *op = (p_vpi_vecval)
800 need_result_buf(hwid * sizeof(s_vpi_vecval), RBUF_VAL);
801 vp->value.vector = op;
802
803 op->aval = op->bval = 0;
804 for (unsigned idx = 0 ; idx < width ; idx += 1) {
805 if (word_val.value(idx)) {
806 op->aval |= (1 << idx % 32);
807 op->bval &= ~(1 << idx % 32);
808 } else {
809 op->aval &= ~(1 << idx % 32);
810 op->bval &= ~(1 << idx % 32);
811 }
812 if (!((idx+1) % 32) && (idx+1 < width)) {
813 op++;
814 op->aval = op->bval = 0;
815 }
816 }
817 break;
818 }
819 }
820
821 }
822
823 /*
824 * Convert a real value to the appropriate integer.
825 */
get_real_as_int(double real)826 static PLI_INT32 get_real_as_int(double real)
827 {
828 double rtn;
829
830 /* We would normally want to return 'bx for a NaN or
831 * +/- infinity, but for an integer the standard says
832 * to convert 'bx to 0, so we just return 0. */
833 if (real != real || (real && (real == 0.5*real))) {
834 return 0;
835 }
836
837 /* Round away from zero. */
838 if (real >= 0.0) {
839 rtn = floor(real);
840 if (real >= (rtn + 0.5)) rtn += 1.0;
841 } else {
842 rtn = ceil(real);
843 if (real <= (rtn - 0.5)) rtn -= 1.0;
844 }
845
846 return (PLI_INT32) rtn;
847 }
848
849 /*
850 * This is a generic function to convert a double value into a
851 * vpi_value structure. The format is selected by the format of the
852 * value pointer.
853 */
vpip_real_get_value(double real,s_vpi_value * vp)854 void vpip_real_get_value(double real, s_vpi_value*vp)
855 {
856 char *rbuf = 0;
857
858 switch (vp->format) {
859 default:
860 fprintf(stderr, "sorry: Format %d not implemented for "
861 "getting real values.\n", (int)vp->format);
862 assert(0);
863
864 case vpiSuppressVal:
865 break;
866
867 case vpiObjTypeVal:
868 // Use the following case to actually set the value!
869 vp->format = vpiRealVal;
870 // fallthrough
871 case vpiRealVal:
872 vp->value.real = real;
873 break;
874
875 case vpiIntVal:
876 vp->value.integer = get_real_as_int(real);
877 break;
878
879 case vpiDecStrVal:
880 rbuf = (char *) need_result_buf(1025, RBUF_VAL);
881 vpip_vec4_to_dec_str(vvp_vector4_t(1024, real), rbuf, 1025, true);
882 vp->value.str = rbuf;
883 break;
884 }
885 }
886
real_from_vpi_value(s_vpi_value * vp)887 double real_from_vpi_value(s_vpi_value*vp)
888 {
889 vvp_vector4_t vec4(1024);
890 double result;
891 bool is_signed = false;
892
893 switch (vp->format) {
894 default:
895 fprintf(stderr, "sorry: Format %d not implemented for "
896 "putting real values.\n", (int)vp->format);
897 assert(0);
898
899 case vpiRealVal:
900 result = vp->value.real;
901 break;
902
903 case vpiIntVal:
904 result = (double) vp->value.integer;
905 break;
906
907 case vpiBinStrVal:
908 vpip_bin_str_to_vec4(vec4, vp->value.str);
909 if (vp->value.str[0] == '-') is_signed = true;
910 vector4_to_value(vec4, result, is_signed);
911 break;
912
913 case vpiOctStrVal:
914 vpip_oct_str_to_vec4(vec4, vp->value.str);
915 if (vp->value.str[0] == '-') is_signed = true;
916 vector4_to_value(vec4, result, is_signed);
917 break;
918
919 case vpiDecStrVal:
920 vpip_dec_str_to_vec4(vec4, vp->value.str);
921 if (vp->value.str[0] == '-') is_signed = true;
922 vector4_to_value(vec4, result, is_signed);
923 break;
924
925 case vpiHexStrVal:
926 vpip_hex_str_to_vec4(vec4, vp->value.str);
927 if (vp->value.str[0] == '-') is_signed = true;
928 vector4_to_value(vec4, result, is_signed);
929 break;
930
931 }
932
933 return result;
934 }
935
vpip_string_get_value(const string & val,s_vpi_value * vp)936 void vpip_string_get_value(const string&val, s_vpi_value*vp)
937 {
938 char *rbuf = 0;
939
940 switch (vp->format) {
941 default:
942 fprintf(stderr, "sorry: Format %d not implemented for "
943 "getting string values.\n", (int)vp->format);
944 assert(0);
945
946 case vpiSuppressVal:
947 break;
948
949 case vpiObjTypeVal:
950 // Use the following case to actually set the value!
951 vp->format = vpiStringVal;
952 // fallthrough
953 case vpiStringVal:
954 rbuf = (char *) need_result_buf(val.size() + 1, RBUF_VAL);
955 strcpy(rbuf, val.c_str());
956 vp->value.str = rbuf;
957 break;
958 }
959 }
960
961
vpi_get_value(vpiHandle expr,s_vpi_value * vp)962 void vpi_get_value(vpiHandle expr, s_vpi_value*vp)
963 {
964 assert(expr);
965 assert(vp);
966
967 // Never bother with suppressed values. All the derived
968 // classes can ignore this type.
969 if (vp->format == vpiSuppressVal)
970 return;
971
972 expr->vpi_get_value(vp);
973
974 if (vpi_trace) switch (vp->format) {
975 case vpiStringVal:
976 fprintf(vpi_trace,"vpi_get_value(%p=<%d>) -> string=\"%s\"\n",
977 expr, expr->get_type_code(), vp->value.str);
978 break;
979
980 case vpiBinStrVal:
981 fprintf(vpi_trace, "vpi_get_value(<%d>...) -> binstr=%s\n",
982 expr->get_type_code(), vp->value.str);
983 break;
984
985 case vpiIntVal:
986 fprintf(vpi_trace, "vpi_get_value(<%d>...) -> int=%d\n",
987 expr->get_type_code(), (int)vp->value.integer);
988 break;
989
990 case vpiSuppressVal:
991 fprintf(vpi_trace, "vpi_get_value(<%d>...) -> <suppress>\n",
992 expr->get_type_code());
993 break;
994
995 default:
996 fprintf(vpi_trace, "vpi_get_value(<%d>...) -> <%d>=?\n",
997 expr->get_type_code(), (int)vp->format);
998 }
999 }
1000
1001 struct vpip_put_value_event : vvp_gen_event_s {
1002 vpiHandle handle;
1003 s_vpi_value value;
1004 int flags;
1005 virtual void run_run();
~vpip_put_value_eventvpip_put_value_event1006 ~vpip_put_value_event() { }
1007 };
1008
run_run()1009 void vpip_put_value_event::run_run()
1010 {
1011 handle->vpi_put_value(&value, flags);
1012 switch (value.format) {
1013 /* Free the copied string. */
1014 case vpiBinStrVal:
1015 case vpiOctStrVal:
1016 case vpiDecStrVal:
1017 case vpiHexStrVal:
1018 case vpiStringVal:
1019 free(value.value.str);
1020 break;
1021 /* Free the copied time structure. */
1022 case vpiTimeVal:
1023 free(value.value.time);
1024 break;
1025 /* Free the copied vector structure. */
1026 case vpiVectorVal:
1027 free(value.value.vector);
1028 break;
1029 /* Free the copied strength structure. */
1030 case vpiStrengthVal:
1031 free(value.value.strength);
1032 break;
1033 /* Everything else is static in the structure. */
1034 default:
1035 break;
1036 }
1037 }
1038
1039 /* Make a copy of a pointer to a time structure. */
timedup(t_vpi_time * val)1040 static t_vpi_time *timedup(t_vpi_time *val)
1041 {
1042 t_vpi_time *rtn;
1043 rtn = static_cast<t_vpi_time *> (malloc(sizeof(t_vpi_time)));
1044 *rtn = *val;
1045 return rtn;
1046 }
1047
1048 /* Make a copy of a pointer to a vector value structure. */
vectordup(t_vpi_vecval * val,PLI_INT32 size)1049 static t_vpi_vecval *vectordup(t_vpi_vecval *val, PLI_INT32 size)
1050 {
1051 unsigned num_bytes;
1052 t_vpi_vecval *rtn;
1053 assert(size > 0);
1054 num_bytes = ((size + 31)/32)*sizeof(t_vpi_vecval);
1055 rtn = static_cast<t_vpi_vecval *> (malloc(num_bytes));
1056 memcpy(rtn, val, num_bytes);
1057 return rtn;
1058 }
1059
1060 /* Make a copy of a pointer to a strength structure. */
strengthdup(t_vpi_strengthval * val)1061 static t_vpi_strengthval *strengthdup(t_vpi_strengthval *val)
1062 {
1063 t_vpi_strengthval *rtn;
1064 rtn = static_cast<t_vpi_strengthval *>
1065 (malloc(sizeof(t_vpi_strengthval)));
1066 *rtn = *val;
1067 return rtn;
1068 }
1069
vpi_put_value(vpiHandle obj,s_vpi_value * vp,s_vpi_time * when,PLI_INT32 flags)1070 vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp,
1071 s_vpi_time*when, PLI_INT32 flags)
1072 {
1073 assert(obj);
1074
1075 flags &= ~vpiReturnEvent;
1076
1077 if (flags!=vpiNoDelay && flags!=vpiForceFlag && flags!=vpiReleaseFlag) {
1078 vvp_time64_t dly;
1079 int scale;
1080
1081 if (vpi_get(vpiAutomatic, obj)) {
1082 fprintf(stderr, "VPI error: cannot put a value with "
1083 "a delay on automatically allocated "
1084 "variable '%s'.\n",
1085 vpi_get_str(vpiName, obj));
1086 return 0;
1087 }
1088
1089 assert(when != 0);
1090
1091 switch (when->type) {
1092 case vpiScaledRealTime:
1093 scale = vpip_time_units_from_handle(obj) -
1094 vpip_get_time_precision();
1095 if (scale >= 0) {
1096 dly = (vvp_time64_t)(when->real * pow(10.0, scale));
1097 } else {
1098 dly = (vvp_time64_t)(when->real / pow(10.0, -scale));
1099 }
1100 break;
1101 case vpiSimTime:
1102 dly = vpip_timestruct_to_time(when);
1103 break;
1104 default:
1105 dly = 0;
1106 break;
1107 }
1108
1109 if ((dly == 0) && schedule_at_rosync()) {
1110 fprintf(stderr, "VPI error: attempted to put a value to "
1111 "variable '%s' during a read-only synch "
1112 "callback.\n", vpi_get_str(vpiName, obj));
1113 return 0;
1114 }
1115
1116 vpip_put_value_event*put = new vpip_put_value_event;
1117 put->handle = obj;
1118 if (dynamic_cast<__vpiNamedEvent*>(obj)) {
1119 put->value.format = vpiIntVal;
1120 put->value.value.integer = 0;
1121 } else {
1122 assert(vp);
1123 put->value = *vp;
1124 }
1125 /* Since this is a scheduled put event we must copy any pointer
1126 * data to keep it available until the event is actually run. */
1127 switch (put->value.format) {
1128 /* Copy the string items. */
1129 case vpiBinStrVal:
1130 case vpiOctStrVal:
1131 case vpiDecStrVal:
1132 case vpiHexStrVal:
1133 case vpiStringVal:
1134 put->value.value.str = strdup(put->value.value.str);
1135 break;
1136 /* Copy a time pointer item. */
1137 case vpiTimeVal:
1138 put->value.value.time = timedup(put->value.value.time);
1139 break;
1140 /* Copy a vector pointer item. */
1141 case vpiVectorVal:
1142 put->value.value.vector = vectordup(put->value.value.vector,
1143 vpi_get(vpiSize, obj));
1144 break;
1145 /* Copy a strength pointer item. */
1146 case vpiStrengthVal:
1147 put->value.value.strength =
1148 strengthdup(put->value.value.strength);
1149 break;
1150 /* Everything thing else is already in the structure. */
1151 default:
1152 break;
1153 }
1154 put->flags = flags;
1155 schedule_generic(put, dly, false, true, true);
1156 return 0;
1157 }
1158
1159 if (schedule_at_rosync()) {
1160 fprintf(stderr, "VPI error: attempted to put a value to "
1161 "variable '%s' during a read-only synch "
1162 "callback.\n", vpi_get_str(vpiName, obj));
1163 return 0;
1164 }
1165
1166 obj->vpi_put_value(vp, flags);
1167
1168 return 0;
1169 }
1170
vpi_handle(PLI_INT32 type,vpiHandle ref)1171 vpiHandle vpi_handle(PLI_INT32 type, vpiHandle ref)
1172 {
1173 vpiHandle res = 0;
1174
1175 if (ref == 0) {
1176 // A few types can apply to a nil handle. These are ways
1177 // that the current function can get started finding things.
1178 switch (type) {
1179
1180 case vpiScope:
1181 // The IEEE1364-2005 doesn't seem to allow this,
1182 // but some users seem to think it's handy, so
1183 // return the scope that contains this SysTfCall.
1184 assert(vpip_cur_task);
1185 res = vpip_cur_task->vpi_handle(vpiScope);
1186 break;
1187
1188 case vpiSysTfCall:
1189 // This is how VPI users get a first handle into
1190 // the system. This is the handle of the system
1191 // task/function call currently being executed.
1192 if (vpi_trace) {
1193 fprintf(vpi_trace, "vpi_handle(vpiSysTfCall, 0) "
1194 "-> %p (%s)\n", vpip_cur_task,
1195 vpip_cur_task->defn->info.tfname);
1196 }
1197 return vpip_cur_task;
1198
1199 default:
1200 fprintf(stderr, "VPI error: vpi_handle(type=%d, ref=0).\n",
1201 (int)type);
1202 res = 0;
1203 break;
1204 }
1205
1206 } else {
1207
1208 if (type == vpiSysTfCall) {
1209 fprintf(stderr, "VPI error: vpi_handle(vpiSysTfCall, "
1210 "ref!=0).\n");
1211 return 0;
1212 }
1213
1214 res = ref->vpi_handle(type);
1215 }
1216
1217
1218 if (vpi_trace) {
1219 fprintf(vpi_trace, "vpi_handle(vpiScope, ref=%p) "
1220 "-> %p\n", vpip_cur_task, ref);
1221 }
1222
1223 return res;
1224 }
1225
vpip_make_udp_iterator()1226 static vpiHandle vpip_make_udp_iterator()
1227 {
1228 // HERE: Add support for iterating over UDP definitions.
1229 // See 26.6.16 (page 400 in 1364-2005).
1230 return 0;
1231 }
1232
1233 /*
1234 * This function asks the object to return an iterator for
1235 * the specified reference. It is up to the iterate_ method to
1236 * allocate a properly formed iterator.
1237 */
vpi_iterate_global(int type)1238 static vpiHandle vpi_iterate_global(int type)
1239 {
1240 switch (type) {
1241 case vpiModule:
1242 return vpip_make_root_iterator();
1243
1244 case vpiUdpDefn:
1245 return vpip_make_udp_iterator();
1246
1247 case vpiUserSystf:
1248 return vpip_make_systf_iterator();
1249 }
1250
1251 return 0;
1252 }
1253
vpi_iterate(PLI_INT32 type,vpiHandle ref)1254 vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle ref)
1255 {
1256 vpiHandle rtn = 0;
1257
1258 assert(vpi_mode_flag != VPI_MODE_NONE);
1259 if (vpi_mode_flag == VPI_MODE_REGISTER) {
1260 fprintf(stderr, "vpi error: vpi_iterate called during "
1261 "vpi_register_systf. You can't do that!\n");
1262 return 0;
1263 }
1264
1265 if (ref == 0)
1266 rtn = vpi_iterate_global(type);
1267 else
1268 rtn = ref->vpi_iterate(type);
1269
1270 if (vpi_trace) {
1271 fprintf(vpi_trace, "vpi_iterate(%d, %p) ->%s\n",
1272 (int)type, ref, rtn ? "" : " (null)");
1273 }
1274
1275 return rtn;
1276 }
1277
vpi_handle_by_index(vpiHandle ref,PLI_INT32 idx)1278 vpiHandle vpi_handle_by_index(vpiHandle ref, PLI_INT32 idx)
1279 {
1280 assert(ref);
1281 return ref->vpi_index(idx);
1282 }
1283
find_name(const char * name,vpiHandle handle)1284 static vpiHandle find_name(const char *name, vpiHandle handle)
1285 {
1286 vpiHandle rtn = 0;
1287 __vpiScope*ref = dynamic_cast<__vpiScope*>(handle);
1288
1289 /* check module names */
1290 if (!strcmp(name, vpi_get_str(vpiName, handle)))
1291 rtn = handle;
1292
1293 /* brute force search for the name in all objects in this scope */
1294 for (unsigned i = 0 ; i < ref->intern.size() ; i += 1) {
1295 /* The standard says that since a port does not have a full
1296 * name it cannot be found by name. Because of this we need
1297 * to skip ports here so the correct handle can be located. */
1298 if (vpi_get(vpiType, ref->intern[i]) == vpiPort) continue;
1299 char *nm = vpi_get_str(vpiName, ref->intern[i]);
1300 if (nm && !strcmp(name, nm)) {
1301 rtn = ref->intern[i];
1302 break;
1303 } else if (vpi_get(vpiType, ref->intern[i]) == vpiMemory ||
1304 vpi_get(vpiType, ref->intern[i]) == vpiNetArray) {
1305 /* We need to iterate on the words */
1306 vpiHandle word_i, word_h;
1307 word_i = vpi_iterate(vpiMemoryWord, ref->intern[i]);
1308 while (word_i && (word_h = vpi_scan(word_i))) {
1309 nm = vpi_get_str(vpiName, word_h);
1310 if (nm && !strcmp(name, nm)) {
1311 rtn = word_h;
1312 vpi_free_object(word_i);
1313 break;
1314 }
1315 }
1316 }
1317 /* found it yet? */
1318 if (rtn) break;
1319 }
1320
1321 return rtn;
1322 }
1323
1324 // Find the end of the escaped identifier or simple identifier
find_rest(char * name)1325 static char * find_rest(char *name)
1326 {
1327 char *rest;
1328 if (*name == '\\') {
1329 rest = strchr(name, ' ');
1330 if (rest) {
1331 *rest++ = 0; // The space is not part of the string
1332 // There should be a '.' after the escaped ID if there is
1333 // anything more. If it is missing add it to avoid a crash
1334 if ((*rest != '.') && (*rest != 0)) {
1335 *--rest = '.';
1336 fprintf(stderr, "ERROR: Malformed scope string: \"%s\"", name);
1337 }
1338 if (*rest == 0) {
1339 rest = 0;
1340 }
1341 }
1342 } else {
1343 rest = strchr(name, '.');
1344 }
1345 return rest;
1346 }
1347
find_scope(const char * name,vpiHandle handle,int depth)1348 static vpiHandle find_scope(const char *name, vpiHandle handle, int depth)
1349 {
1350
1351 vpiHandle iter = handle==0
1352 ? vpi_iterate(vpiModule, NULL)
1353 : vpi_iterate(vpiInternalScope, handle);
1354
1355 vector<char> name_buf (strlen(name)+1);
1356 strcpy(&name_buf[0], name);
1357 char*nm_first = &name_buf[0];
1358 char*nm_rest = find_rest(nm_first);
1359 if (*nm_first == '\\') ++nm_first;
1360 if (nm_rest) {
1361 *nm_rest++ = 0;
1362 }
1363
1364 vpiHandle rtn = 0;
1365 vpiHandle hand;
1366 while (iter && (hand = vpi_scan(iter))) {
1367 char *nm = vpi_get_str(vpiName, hand);
1368
1369 if (strcmp(nm_first,nm)==0) {
1370 if (nm_rest)
1371 rtn=find_scope(nm_rest, hand, depth+1);
1372 else
1373 rtn = hand;
1374 }
1375
1376 /* found it yet ? */
1377 if (rtn) {
1378 vpi_free_object(iter);
1379 break;
1380 }
1381 }
1382
1383 return rtn;
1384 }
1385
1386 // Find the end of the first escaped identifier or simple identifier
find_next(char * name)1387 static char * find_next(char *name)
1388 {
1389 char *next;
1390 if (*name == '\\') {
1391 next = strchr(name, ' ');
1392 if (next && *++next == 0) next = 0;
1393 } else {
1394 next = strchr(name, '.');
1395 }
1396 return next;
1397 }
1398
vpi_handle_by_name(const char * name,vpiHandle scope)1399 vpiHandle vpi_handle_by_name(const char *name, vpiHandle scope)
1400 {
1401 vpiHandle hand;
1402
1403 if (vpi_trace) {
1404 fprintf(vpi_trace, "vpi_handle_by_name(%s, %p) -->\n",
1405 name, scope);
1406 }
1407
1408 // Chop the name into path and base. For example, if the name
1409 // is "a.b.c", then nm_path becomes "a.b" and nm_base becomes
1410 // "c". If the name is "c" then nm_path is nil and nm_base is "c".
1411 vector<char> name_buf (strlen(name)+1);
1412 strcpy(&name_buf[0], name);
1413 char*nm_path = &name_buf[0];
1414 char*nm_base;
1415
1416 // Check to see if we have an escaped identifier and if so search
1417 // the long way because a '.' could be in the escaped name.
1418 if (strchr(nm_path, '\\')) {
1419 char *next;
1420 nm_base = nm_path;
1421 while ((next = find_next(nm_base))) {
1422 nm_base = ++next;
1423 }
1424 if (nm_path == nm_base) {
1425 nm_path = 0;
1426 } else {
1427 *(nm_base-1) = 0;
1428 }
1429
1430 if (*nm_base == '\\') {
1431 // Skip the \ at the beginning
1432 ++nm_base;
1433
1434 // Drop the space at the end if it exists
1435 if ((next = strchr(nm_base, ' '))) {
1436 *next = 0;
1437 }
1438 }
1439
1440 // If there is no escaped identifier then just look for the last '.'
1441 } else {
1442 nm_base = strrchr(nm_path, '.');
1443 if (nm_base) {
1444 *nm_base++ = 0;
1445 } else {
1446 nm_base = nm_path;
1447 nm_path = 0;
1448 }
1449 }
1450
1451 /* If scope provided, look in corresponding module; otherwise
1452 * traverse the hierarchy specified in name to find the leaf module
1453 * and try finding it there.
1454 */
1455 if (scope) {
1456 /* Some implementations support either a module or a scope. */
1457 switch (vpi_get(vpiType, scope)) {
1458 case vpiScope:
1459 hand = vpi_handle(vpiModule, scope);
1460 break;
1461 case vpiModule:
1462 hand = scope;
1463 break;
1464 default:
1465 if (vpi_trace) {
1466 fprintf(vpi_trace, "vpi_handle_by_name: "
1467 "Scope is not a vpiScope or vpiModule\n");
1468 }
1469 // Use vpi_chk_error() here when it is implemented.
1470 return 0;
1471 }
1472
1473 } else if (nm_path) {
1474 // The name has a path, and no other scope handle was
1475 // passed in. That suggests we are looking for "a.b.c"
1476 // in the root scope. So convert "a.b" to a scope and
1477 // start there to look for "c".
1478 hand = find_scope(nm_path, NULL, 0);
1479 nm_path = 0;
1480
1481 } else {
1482 // Special case: scope==<nil>, meaning we are looking in
1483 // the root, and there is no path to the name, i.e. the
1484 // string is "c" instead of "top.c". Try to find "c" as
1485 // a scope and return that.
1486 hand = find_scope(nm_base, NULL, 0);
1487 }
1488
1489 if (hand == 0) {
1490 if (vpi_trace) {
1491 fprintf(vpi_trace, "vpi_handle_by_name: "
1492 "Scope does not exist. Giving up.\n");
1493 }
1494
1495 return 0;
1496 }
1497
1498 // If there is a path part, then use it to find the
1499 // scope. For example, if the full name is a.b.c, then
1500 // the nm_path string is a.b and we search for that
1501 // scope. If we find it, then set hand to that scope.
1502 if (nm_path) {
1503 vpiHandle tmp = find_scope(nm_path, hand, 0);
1504 while (tmp == 0 && hand != 0) {
1505 hand = vpi_handle(vpiScope, hand);
1506 tmp = find_scope(nm_path, hand, 0);
1507 }
1508 hand = tmp;
1509 }
1510
1511 // Now we have the correct scope, look for the item.
1512 vpiHandle out = find_name(nm_base, hand);
1513
1514 if (vpi_trace) {
1515 fprintf(vpi_trace, "vpi_handle_by_name: DONE\n");
1516 }
1517
1518 return out;
1519 }
1520
1521
1522 /*
1523 We increment the two vpi methods to enable the
1524 read/write of SDF delay values from/into
1525 the modpath vpiHandle
1526
1527
1528 basically, they will redirect the generic vpi_interface
1529
1530 vpi_get_delay ( .. )
1531 vpi_put_delay ( .. )
1532
1533
1534 to the
1535
1536 modpath_get_delay ( .. ) ;
1537 modpath_put_delay ( .. ) ;
1538
1539 */
1540
1541
1542
vpi_get_delays(vpiHandle expr,p_vpi_delay delays)1543 void vpi_get_delays(vpiHandle expr, p_vpi_delay delays)
1544 {
1545 assert(expr);
1546 assert(delays);
1547
1548 expr->vpi_get_delays(delays);
1549
1550 if (vpi_trace) {
1551 fprintf(vpi_trace,
1552 "vpi_get_delays(%p, %p) -->\n", expr, delays);
1553 }
1554 }
1555
1556
vpi_put_delays(vpiHandle expr,p_vpi_delay delays)1557 void vpi_put_delays(vpiHandle expr, p_vpi_delay delays)
1558 {
1559 assert(expr );
1560 assert(delays );
1561
1562 expr->vpi_put_delays(delays);
1563
1564 if (vpi_trace) {
1565 fprintf(vpi_trace,
1566 "vpi_put_delays(%p, %p) -->\n", expr, delays);
1567 }
1568 }
1569
1570
1571
1572
1573
1574
1575
1576
vpi_vprintf(const char * fmt,va_list ap)1577 extern "C" PLI_INT32 vpi_vprintf(const char*fmt, va_list ap)
1578 {
1579 return vpi_mcd_vprintf(1, fmt, ap);
1580 }
1581
vpi_printf(const char * fmt,...)1582 extern "C" PLI_INT32 vpi_printf(const char *fmt, ...)
1583 {
1584 va_list ap;
1585 va_start(ap, fmt);
1586 int r = vpi_mcd_vprintf(1, fmt, ap);
1587 va_end(ap);
1588 return r;
1589 }
1590
vpi_flush(void)1591 extern "C" PLI_INT32 vpi_flush(void)
1592 {
1593 return vpi_mcd_flush(1);
1594 }
1595
1596
vpi_sim_vcontrol(int operation,va_list ap)1597 extern "C" void vpi_sim_vcontrol(int operation, va_list ap)
1598 {
1599 long diag_msg;
1600
1601 switch (operation) {
1602 case vpiFinish:
1603 case __ivl_legacy_vpiFinish:
1604 diag_msg = va_arg(ap, long);
1605 schedule_finish(diag_msg);
1606 break;
1607
1608 case vpiStop:
1609 case __ivl_legacy_vpiStop:
1610 diag_msg = va_arg(ap, long);
1611 schedule_stop(diag_msg);
1612 break;
1613
1614 default:
1615 fprintf(stderr, "Unsupported operation %d.\n", operation);
1616 assert(0);
1617 }
1618 }
1619
vpi_sim_control(PLI_INT32 operation,...)1620 extern "C" void vpi_sim_control(PLI_INT32 operation, ...)
1621 {
1622 va_list ap;
1623 va_start(ap, operation);
1624 vpi_sim_vcontrol(operation, ap);
1625 va_end(ap);
1626 }
1627
vpi_control(PLI_INT32 operation,...)1628 extern "C" void vpi_control(PLI_INT32 operation, ...)
1629 {
1630 va_list ap;
1631 va_start(ap, operation);
1632 vpi_sim_vcontrol(operation, ap);
1633 va_end(ap);
1634 }
1635
1636 /*
1637 * This routine calculated the return value for $clog2.
1638 * It is easier to do it here vs trying to to use the VPI interface.
1639 */
vpip_calc_clog2(vpiHandle arg)1640 extern "C" s_vpi_vecval vpip_calc_clog2(vpiHandle arg)
1641 {
1642 s_vpi_vecval rtn;
1643 s_vpi_value val;
1644 vvp_vector4_t vec4;
1645 bool is_neg = false; // At this point only a real can be negative.
1646
1647 /* Get the value as a vvp_vector4_t. */
1648 val.format = vpiObjTypeVal;
1649 vpi_get_value(arg, &val);
1650 if (val.format == vpiRealVal) {
1651 vpi_get_value(arg, &val);
1652 /* All double values can be represented in 1024 bits. */
1653 vec4 = vvp_vector4_t(1024, val.value.real);
1654 if (val.value.real < 0) is_neg = true;
1655 } else {
1656 val.format = vpiVectorVal;
1657 vpi_get_value(arg, &val);
1658 unsigned wid = vpi_get(vpiSize, arg);
1659 vec4 = vvp_vector4_t(wid, BIT4_0);
1660 for (unsigned idx=0; idx < wid; idx += 1) {
1661 PLI_INT32 aval = val.value.vector[idx/32].aval;
1662 PLI_INT32 bval = val.value.vector[idx/32].bval;
1663 aval >>= idx % 32;
1664 bval >>= idx % 32;
1665 int bitmask = (aval&1) | ((bval<<1)&2);
1666 vvp_bit4_t bit = scalar_to_bit4(bitmask);
1667 vec4.set_bit(idx, bit);
1668 }
1669 }
1670
1671 if (vec4.has_xz()) {
1672 rtn.aval = rtn.bval = 0xFFFFFFFFU; /* Set to 'bx. */
1673 return rtn;
1674 }
1675
1676 vvp_vector2_t vec2(vec4);
1677
1678 if (is_neg) vec2.trim_neg(); /* This is a special trim! */
1679 else vec2.trim(); /* This makes less work shifting. */
1680
1681 /* Calculate the clog2 result. */
1682 PLI_INT32 res = 0;
1683 if (!vec2.is_zero()) {
1684 vec2 -= vvp_vector2_t(1, vec2.size());
1685 while(!vec2.is_zero()) {
1686 res += 1;
1687 vec2 >>= 1;
1688 }
1689 }
1690
1691 rtn.aval = res;
1692 rtn.bval = 0;
1693 return rtn;
1694 }
1695
1696 /*
1697 * This routine provides the information needed to implement $countdrivers.
1698 * It is done here for performance reasons - interrogating the drivers
1699 * individually via the VPI interface would be much slower.
1700 */
vpip_count_drivers(vpiHandle ref,unsigned idx,unsigned counts[4])1701 extern "C" void vpip_count_drivers(vpiHandle ref, unsigned idx,
1702 unsigned counts[4])
1703 {
1704 struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref);
1705 assert(rfp);
1706 rfp->node->count_drivers(idx, counts);
1707 }
1708
1709 #if defined(__MINGW32__) || defined (__CYGWIN__)
1710 vpip_routines_s vpi_routines = {
1711 .register_cb = vpi_register_cb,
1712 .remove_cb = vpi_remove_cb,
1713 .register_systf = vpi_register_systf,
1714 .get_systf_info = vpi_get_systf_info,
1715 .handle_by_name = vpi_handle_by_name,
1716 .handle_by_index = vpi_handle_by_index,
1717 .handle = vpi_handle,
1718 .iterate = vpi_iterate,
1719 .scan = vpi_scan,
1720 .get = vpi_get,
1721 .get_str = vpi_get_str,
1722 .get_delays = vpi_get_delays,
1723 .put_delays = vpi_put_delays,
1724 .get_value = vpi_get_value,
1725 .put_value = vpi_put_value,
1726 .get_time = vpi_get_time,
1727 .get_userdata = vpi_get_userdata,
1728 .put_userdata = vpi_put_userdata,
1729 .mcd_open = vpi_mcd_open,
1730 .mcd_close = vpi_mcd_close,
1731 .mcd_flush = vpi_mcd_flush,
1732 .mcd_name = vpi_mcd_name,
1733 .mcd_vprintf = vpi_mcd_vprintf,
1734 .flush = vpi_flush,
1735 .vprintf = vpi_vprintf,
1736 .chk_error = vpi_chk_error,
1737 .compare_objects = vpi_compare_objects,
1738 .free_object = vpi_free_object,
1739 .get_vlog_info = vpi_get_vlog_info,
1740 .vcontrol = vpi_sim_vcontrol,
1741 .fopen = vpi_fopen,
1742 .get_file = vpi_get_file,
1743 .calc_clog2 = vpip_calc_clog2,
1744 .count_drivers = vpip_count_drivers,
1745 .format_strength = vpip_format_strength,
1746 .make_systf_system_defined = vpip_make_systf_system_defined,
1747 .mcd_rawwrite = vpip_mcd_rawwrite,
1748 .set_return_value = vpip_set_return_value,
1749 };
1750 #endif
1751