1 /*
2 * Copyright (c) 2001-2018 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 /*
21 * Callbacks are objects that carry a function to be called when some
22 * event in the simulation occurs. The VPI code create a __vpiCallback
23 * object, and that object is put in some location that the simulation
24 * can look when the event in question is tripped.
25 */
26
27 # include "vpi_user.h"
28 # include "vpi_priv.h"
29 # include "vvp_net.h"
30 # include "schedule.h"
31 # include "event.h"
32 # include "vvp_net_sig.h"
33 # include "config.h"
34 #ifdef CHECK_WITH_VALGRIND
35 #include "vvp_cleanup.h"
36 #endif
37 # include <cstdio>
38 # include <cassert>
39 # include <cstdlib>
40 /*
41 * Callback handles are created when the VPI function registers a
42 * callback. The handle is stored by the run time, and it triggered
43 * when the run-time thing that it is waiting for happens.
44 *
45 * This is the thing that the VPI code references by the vpiHandle. It
46 * also points to callback data that the caller attached to the event,
47 * as well as the time structure to receive data.
48 *
49 * The cb_sync is a private member that points to the schedulable
50 * event that is triggered when the event happens. The sync_cb class
51 * represents the action to execute when the scheduler gets to this
52 * event. This member is only used for things like cbReadOnlySync.
53 */
54
55 class sync_callback;
56
57 struct sync_cb : public vvp_gen_event_s {
58 sync_callback*handle;
59 bool sync_flag;
60
~sync_cbsync_cb61 ~sync_cb () { }
62
63 virtual void run_run();
64 };
65
__vpiCallback()66 inline __vpiCallback::__vpiCallback()
67 {
68 next = 0;
69 }
70
~__vpiCallback()71 __vpiCallback::~__vpiCallback()
72 {
73 }
74
get_type_code(void) const75 int __vpiCallback::get_type_code(void) const
76 { return vpiCallback; }
77
78
value_callback(p_cb_data data)79 value_callback::value_callback(p_cb_data data)
80 {
81 cb_data = *data;
82 if (data->time) {
83 cb_time = *(data->time);
84 } else {
85 cb_time.type = vpiSuppressTime;
86 }
87 cb_data.time = &cb_time;
88 if (data->value) {
89 cb_value = *(data->value);
90 } else {
91 cb_value.format = vpiSuppressVal;
92 }
93 cb_data.value = &cb_value;
94 }
95
96 /*
97 * Normally, any assign to a value triggers a value change callback,
98 * so return a constant true here. This is a stub.
99 */
test_value_callback_ready(void)100 bool value_callback::test_value_callback_ready(void)
101 {
102 return true;
103 }
104
vpip_real_value_change(value_callback * cbh,vpiHandle ref)105 static void vpip_real_value_change(value_callback*cbh, vpiHandle ref)
106 {
107 struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref);
108 assert(rfp);
109 vvp_vpi_callback*obj = dynamic_cast<vvp_vpi_callback*>(rfp->net->fil);
110 assert(obj);
111
112 obj->add_vpi_callback(cbh);
113 }
114
115 class value_part_callback : public value_callback {
116 public:
117 explicit value_part_callback(p_cb_data data);
118 ~value_part_callback();
119
120 bool test_value_callback_ready(void);
121
122 private:
123 char*value_bits_;
124 size_t value_off_;
125 };
126
value_part_callback(p_cb_data data)127 inline value_part_callback::value_part_callback(p_cb_data data)
128 : value_callback(data)
129 {
130 struct __vpiPV*pobj = dynamic_cast<__vpiPV*>(data->obj);
131 assert(pobj);
132
133 vvp_vpi_callback*sig_fil;
134 sig_fil = dynamic_cast<vvp_vpi_callback*>(pobj->net->fil);
135 assert(sig_fil);
136
137 sig_fil->add_vpi_callback(this);
138 // Get a reference value that can be used to compare with an
139 // updated value. Use the filter get_value to get the value,
140 // and get it in BinStr form so that compares are easy. Note
141 // that the vpiBinStr format has the MSB first, but the tbase
142 // is lsb first.
143 s_vpi_value tmp_value;
144 tmp_value.format = vpiBinStrVal;
145 sig_fil->get_value(&tmp_value);
146
147 value_bits_ = new char[pobj->width+1];
148 value_off_ = pobj->parent->vpi_get(vpiSize) - pobj->width - pobj->tbase;
149
150 memcpy(value_bits_, tmp_value.value.str + value_off_, pobj->width);
151 value_bits_[pobj->width] = 0;
152 }
153
~value_part_callback()154 value_part_callback::~value_part_callback()
155 {
156 delete[]value_bits_;
157 }
158
test_value_callback_ready(void)159 bool value_part_callback::test_value_callback_ready(void)
160 {
161 struct __vpiPV*pobj = dynamic_cast<__vpiPV*>(cb_data.obj);
162 assert(pobj);
163
164 vvp_vpi_callback*sig_fil;
165 sig_fil = dynamic_cast<vvp_vpi_callback*>(pobj->net->fil);
166 assert(sig_fil);
167
168 // Get a reference value that can be used to compare with an
169 // updated value.
170 s_vpi_value tmp_value;
171 tmp_value.format = vpiBinStrVal;
172 sig_fil->get_value(&tmp_value);
173
174 if (memcmp(value_bits_, tmp_value.value.str + value_off_, pobj->width) == 0)
175 return false;
176
177 memcpy(value_bits_, tmp_value.value.str + value_off_, pobj->width);
178 return true;
179 }
180
181 /*
182 * Attach the __vpiCallback to the object that this part select
183 * selects from. The part select itself is not a vvp_vpi_callback
184 * object, but it refers to a net that is a vvp_vpi_callback, so
185 * add the callback to that object.
186 */
make_value_change_part(p_cb_data data)187 static value_callback*make_value_change_part(p_cb_data data)
188 {
189 /* Attach the __vpiCallback object to the signal. */
190 value_callback*cbh = new value_part_callback(data);
191 return cbh;
192 }
193
194 /*
195 * A value change callback is tripped when a bit of a signal
196 * changes. This function creates that value change callback and
197 * attaches it to the relevant vpiSignal object. Also, if the signal
198 * does not already have them, create some callback functors to do the
199 * actual value change detection.
200 */
make_value_change(p_cb_data data)201 static value_callback* make_value_change(p_cb_data data)
202 {
203 if (vpi_get(vpiAutomatic, data->obj)) {
204 fprintf(stderr, "vpi error: cannot place value change "
205 "callback on automatically allocated "
206 "variable '%s'\n",
207 vpi_get_str(vpiName, data->obj));
208 return 0;
209 }
210
211 // Special case: the target object is a vpiPartSelect
212 if (data->obj->get_type_code() == vpiPartSelect) {
213 if (data->obj->vpi_handle(vpiArray))
214 return vpip_array_word_change(data);
215 else
216 return make_value_change_part(data);
217 }
218
219 if (data->obj->get_type_code() == vpiMemoryWord)
220 return vpip_array_word_change(data);
221
222 if (data->obj->get_type_code() == vpiMemory)
223 return vpip_array_change(data);
224
225 value_callback*obj = new value_callback(data);
226
227 assert(data->obj);
228 switch (data->obj->get_type_code()) {
229
230 case vpiReg:
231 case vpiNet:
232 case vpiIntegerVar:
233 case vpiBitVar:
234 case vpiByteVar:
235 case vpiShortIntVar:
236 case vpiIntVar:
237 case vpiLongIntVar:
238 /* Attach the callback to the vvp_fun_signal node by
239 putting it in the vpi_callbacks list. */
240 struct __vpiSignal*sig;
241 sig = dynamic_cast<__vpiSignal*>(data->obj);
242
243 vvp_net_fil_t*sig_fil;
244 sig_fil = dynamic_cast<vvp_net_fil_t*>(sig->node->fil);
245 assert(sig_fil);
246
247 /* Attach the __vpiCallback object to the signal. */
248 sig_fil->add_vpi_callback(obj);
249 break;
250
251 case vpiRealVar:
252 vpip_real_value_change(obj, data->obj);
253 break;
254
255 case vpiNamedEvent:
256 __vpiNamedEvent*nev;
257 nev = dynamic_cast<__vpiNamedEvent*>(data->obj);
258 nev->add_vpi_callback(obj);
259 break;
260
261 case vpiModule:
262 case vpiConstant:
263 case vpiParameter:
264 /* These are constant, so there are no value change
265 lists to put them in. */
266 break;
267
268 default:
269 fprintf(stderr, "make_value_change: sorry: I cannot callback "
270 "values on type code=%d\n",
271 data->obj->get_type_code());
272 delete obj;
273 return 0;
274 }
275
276 return obj;
277 }
278
279 class sync_callback : public __vpiCallback {
280 public:
281 explicit sync_callback(p_cb_data data);
282 ~sync_callback();
283
284 public:
285 // scheduled event
286 struct sync_cb* cb_sync;
287 // user supplied callback data
288 struct t_vpi_time cb_time;
289
290 private:
291 };
292
sync_callback(p_cb_data data)293 inline sync_callback::sync_callback(p_cb_data data)
294 {
295 cb_sync = 0;
296
297 cb_data = *data;
298 assert(data->time);
299 cb_time = *(data->time);
300 cb_data.time = &cb_time;
301 }
302
~sync_callback()303 sync_callback::~sync_callback()
304 {
305 delete cb_sync;
306 }
307
run_run()308 void sync_cb::run_run()
309 {
310 if (handle == 0)
311 return;
312
313 sync_callback*cur = handle;
314 cur->cb_data.time->type = vpiSimTime;
315 vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime());
316
317 /* Run the callback. If the cb_rtn function pointer is set to
318 null, then just skip the whole thing and free it. This is
319 the usual way to cancel one-time callbacks of this sort. */
320 if (cur->cb_data.cb_rtn != 0) {
321 assert(vpi_mode_flag == VPI_MODE_NONE);
322 vpi_mode_flag = sync_flag? VPI_MODE_ROSYNC : VPI_MODE_RWSYNC;
323 vpip_cur_task = dynamic_cast<__vpiSysTaskCall*>(cur->cb_data.obj);
324 (cur->cb_data.cb_rtn)(&cur->cb_data);
325 vpip_cur_task = 0;
326 vpi_mode_flag = VPI_MODE_NONE;
327 }
328
329 delete cur;
330 }
331
make_sync(p_cb_data data,bool readonly_flag)332 static sync_callback* make_sync(p_cb_data data, bool readonly_flag)
333 {
334 sync_callback*obj = new sync_callback(data);
335
336 struct sync_cb*cb = new sync_cb;
337 cb->sync_flag = readonly_flag? true : false;
338 cb->handle = obj;
339 obj->cb_sync = cb;
340
341 vvp_time64_t tv = 0;
342 switch (obj->cb_time.type) {
343 case vpiSuppressTime:
344 break;
345
346 case vpiSimTime:
347 tv = vpip_timestruct_to_time(&obj->cb_time);
348 break;
349
350 default:
351 fprintf(stderr, "Unsupported time type %d.\n",
352 (int)obj->cb_time.type);
353 assert(0);
354 break;
355 }
356 schedule_generic(cb, tv, true, readonly_flag);
357 return obj;
358 }
359
make_afterdelay(p_cb_data data)360 static struct __vpiCallback* make_afterdelay(p_cb_data data)
361 {
362 sync_callback*obj = new sync_callback(data);
363 struct sync_cb*cb = new sync_cb;
364 cb->sync_flag = false;
365 cb->handle = obj;
366 obj->cb_sync = cb;
367
368 vvp_time64_t tv = 0;
369 switch (obj->cb_time.type) {
370 case vpiSimTime:
371 tv = vpip_timestruct_to_time(&obj->cb_time);
372 break;
373
374 default:
375 fprintf(stderr, "Unsupported time type %d.\n",
376 (int)obj->cb_time.type);
377 assert(0);
378 break;
379 }
380
381 schedule_generic(cb, tv, false);
382
383 return obj;
384 }
385
make_at_start_of_sim_time(p_cb_data data)386 static struct __vpiCallback* make_at_start_of_sim_time(p_cb_data data)
387 {
388 sync_callback*obj = new sync_callback(data);
389 struct sync_cb*cb = new sync_cb;
390 cb->sync_flag = false;
391 cb->handle = obj;
392 obj->cb_sync = cb;
393
394 vvp_time64_t tv = 0;
395 switch (obj->cb_time.type) {
396 case vpiSimTime:
397 tv = vpip_timestruct_to_time(&obj->cb_time);
398 break;
399
400 default:
401 fprintf(stderr, "Unsupported time type %d.\n",
402 (int)obj->cb_time.type);
403 assert(0);
404 break;
405 }
406
407 vvp_time64_t cur = schedule_simtime();
408 if (cur > tv) {
409 tv = 0;
410 assert(0);
411 } else if (cur == tv) {
412 tv = 0;
413 } else {
414 tv -= cur;
415 }
416 schedule_at_start_of_simtime(cb, tv);
417
418 return obj;
419 }
420
make_at_end_of_sim_time(p_cb_data data)421 static struct __vpiCallback* make_at_end_of_sim_time(p_cb_data data)
422 {
423 sync_callback*obj = new sync_callback(data);
424 struct sync_cb*cb = new sync_cb;
425 cb->sync_flag = false;
426 cb->handle = obj;
427 obj->cb_sync = cb;
428
429 vvp_time64_t tv = 0;
430 switch (obj->cb_time.type) {
431 case vpiSimTime:
432 tv = vpip_timestruct_to_time(&obj->cb_time);
433 break;
434
435 default:
436 fprintf(stderr, "Unsupported time type %d.\n",
437 (int)obj->cb_time.type);
438 assert(0);
439 break;
440 }
441
442 vvp_time64_t cur = schedule_simtime();
443 if (cur > tv) {
444 tv = 0;
445 assert(0);
446 } else if (cur == tv) {
447 tv = 0;
448 } else {
449 tv -= cur;
450 }
451 schedule_at_end_of_simtime(cb, tv);
452
453 return obj;
454 }
455
456 /*
457 * The following functions are the used for pre and post simulation
458 * callbacks.
459 */
460
461 class simulator_callback : public __vpiCallback {
462 public:
simulator_callback(struct t_cb_data * data)463 inline explicit simulator_callback(struct t_cb_data*data)
464 { cb_data = *data; }
465
466 public:
467 };
468
469 static simulator_callback*NextSimTime = 0;
470 static simulator_callback*EndOfCompile = 0;
471 static simulator_callback*StartOfSimulation = 0;
472 static simulator_callback*EndOfSimulation = 0;
473
474 #ifdef CHECK_WITH_VALGRIND
475 /* This is really only needed if the simulator aborts before starting the
476 * main event loop. For that reason we can skip the next sim time queue. */
simulator_cb_delete(void)477 void simulator_cb_delete(void)
478 {
479 simulator_callback* cur;
480
481 /* Delete all the end of compile callbacks. */
482 while (EndOfCompile) {
483 cur = EndOfCompile;
484 EndOfCompile = dynamic_cast<simulator_callback*>(cur->next);
485 delete cur;
486 }
487
488 /* Delete all the start of simulation callbacks. */
489 while (StartOfSimulation) {
490 cur = StartOfSimulation;
491 StartOfSimulation = dynamic_cast<simulator_callback*>(cur->next);
492 delete cur;
493 }
494
495 /* Delete all the end of simulation callbacks. */
496 while (EndOfSimulation) {
497 cur = EndOfSimulation;
498 EndOfSimulation = dynamic_cast<simulator_callback*>(cur->next);
499 delete cur;
500 }
501 }
502 #endif
503
vpiEndOfCompile(void)504 void vpiEndOfCompile(void) {
505 simulator_callback* cur;
506
507 /*
508 * Walk the list of register callbacks, executing them and
509 * freeing them when done.
510 */
511 assert(vpi_mode_flag == VPI_MODE_NONE);
512 vpi_mode_flag = VPI_MODE_RWSYNC;
513
514 while (EndOfCompile) {
515 cur = EndOfCompile;
516 EndOfCompile = dynamic_cast<simulator_callback*>(cur->next);
517 (cur->cb_data.cb_rtn)(&cur->cb_data);
518 delete cur;
519 }
520
521 vpi_mode_flag = VPI_MODE_NONE;
522 }
523
vpiStartOfSim(void)524 void vpiStartOfSim(void) {
525 simulator_callback* cur;
526
527 /*
528 * Walk the list of register callbacks, executing them and
529 * freeing them when done.
530 */
531 assert(vpi_mode_flag == VPI_MODE_NONE);
532 vpi_mode_flag = VPI_MODE_RWSYNC;
533
534 while (StartOfSimulation) {
535 cur = StartOfSimulation;
536 StartOfSimulation = dynamic_cast<simulator_callback*>(cur->next);
537 (cur->cb_data.cb_rtn)(&cur->cb_data);
538 delete cur;
539 }
540
541 vpi_mode_flag = VPI_MODE_NONE;
542 }
543
vpiPostsim(void)544 void vpiPostsim(void) {
545 simulator_callback* cur;
546
547 /*
548 * Walk the list of register callbacks
549 */
550 assert(vpi_mode_flag == VPI_MODE_NONE);
551 vpi_mode_flag = VPI_MODE_ROSYNC;
552
553 while (EndOfSimulation) {
554 cur = EndOfSimulation;
555 EndOfSimulation = dynamic_cast<simulator_callback*>(cur->next);
556 /* Only set the time if it is not NULL. */
557 if (cur->cb_data.time)
558 vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime());
559 (cur->cb_data.cb_rtn)(&cur->cb_data);
560 delete cur;
561 }
562
563 vpi_mode_flag = VPI_MODE_NONE;
564 }
565
566 /*
567 * The scheduler invokes this to clear out callbacks for the next
568 * simulation time.
569 */
vpiNextSimTime(void)570 void vpiNextSimTime(void)
571 {
572 simulator_callback* cur;
573
574 assert(vpi_mode_flag == VPI_MODE_NONE);
575 vpi_mode_flag = VPI_MODE_RWSYNC;
576
577 while (NextSimTime) {
578 cur = NextSimTime;
579 NextSimTime = dynamic_cast<simulator_callback*>(cur->next);
580 (cur->cb_data.cb_rtn)(&cur->cb_data);
581 delete cur;
582 }
583
584 vpi_mode_flag = VPI_MODE_NONE;
585 }
586
make_prepost(p_cb_data data)587 static simulator_callback* make_prepost(p_cb_data data)
588 {
589 simulator_callback*obj = new simulator_callback(data);
590
591 /* Insert at head of list */
592 switch (data->reason) {
593 case cbEndOfCompile:
594 obj->next = EndOfCompile;
595 EndOfCompile = obj;
596 break;
597 case cbStartOfSimulation:
598 obj->next = StartOfSimulation;
599 StartOfSimulation = obj;
600 break;
601 case cbEndOfSimulation:
602 obj->next = EndOfSimulation;
603 EndOfSimulation = obj;
604 break;
605 case cbNextSimTime:
606 obj->next = NextSimTime;
607 NextSimTime = obj;
608 }
609
610 return obj;
611 }
612
vpi_register_cb(p_cb_data data)613 vpiHandle vpi_register_cb(p_cb_data data)
614 {
615 struct __vpiCallback*obj = 0;
616
617 assert(data);
618 switch (data->reason) {
619
620 case cbValueChange:
621 obj = make_value_change(data);
622 break;
623
624 case cbReadOnlySynch:
625 obj = make_sync(data, true);
626 break;
627
628 case cbReadWriteSynch:
629 obj = make_sync(data, false);
630 break;
631
632 case cbAtStartOfSimTime:
633 obj = make_at_start_of_sim_time(data);
634 break;
635
636 case cbAtEndOfSimTime:
637 obj = make_at_end_of_sim_time(data);
638 break;
639
640 case cbAfterDelay:
641 obj = make_afterdelay(data);
642 break;
643
644 case cbEndOfCompile:
645 case cbStartOfSimulation:
646 case cbEndOfSimulation:
647 case cbNextSimTime:
648 obj = make_prepost(data);
649 break;
650
651 default:
652 fprintf(stderr, "vpi error: vpi_register_cb invalid or "
653 "unsupported callback reason: %d\n",
654 (int)data->reason);
655 break;
656 }
657
658 return obj;
659 }
660
661 /*
662 * Removing a callback doesn't really delete it right away. Instead,
663 * it clears the reference to the user callback function. This causes
664 * the callback to quietly reap itself.
665 */
vpi_remove_cb(vpiHandle ref)666 PLI_INT32 vpi_remove_cb(vpiHandle ref)
667 {
668 struct __vpiCallback*obj = dynamic_cast<__vpiCallback*>(ref);
669 assert(obj);
670 obj->cb_data.cb_rtn = 0;
671
672 return 1;
673 }
674
callback_execute(struct __vpiCallback * cur)675 void callback_execute(struct __vpiCallback*cur)
676 {
677 const vpi_mode_t save_mode = vpi_mode_flag;
678 vpi_mode_flag = VPI_MODE_RWSYNC;
679
680 assert(cur->cb_data.cb_rtn);
681 switch (cur->cb_data.time->type) {
682 case vpiSimTime:
683 vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime());
684 break;
685 case vpiScaledRealTime: {
686 cur->cb_data.time->real =
687 vpip_time_to_scaled_real(schedule_simtime(),
688 (__vpiScope *) vpi_handle(vpiScope, cur->cb_data.obj));
689 break;
690 }
691 case vpiSuppressTime:
692 break;
693 default:
694 fprintf(stderr, "Unsupported time format %d.\n",
695 (int)cur->cb_data.time->type);
696 assert(0);
697 break;
698 }
699 (cur->cb_data.cb_rtn)(&cur->cb_data);
700
701 vpi_mode_flag = save_mode;
702 }
703
704 /*
705 * Usually there is at most one array word associated with a vvp signal, but
706 * due to port collapsing, there may be more. Using a linked list to record
707 * the array words minimises memory use for the most common case (no array
708 * words) or next most common case (one array word).
709 */
710 struct __vpi_array_word {
711 struct __vpi_array_word* next;
712 struct __vpiArray* array;
713 unsigned long word;
714 };
715
vvp_vpi_callback()716 vvp_vpi_callback::vvp_vpi_callback()
717 {
718 vpi_callbacks_ = 0;
719 array_words_ = 0;
720 }
721
~vvp_vpi_callback()722 vvp_vpi_callback::~vvp_vpi_callback()
723 {
724 assert(vpi_callbacks_ == 0);
725 assert(array_words_ == 0);
726 }
727
attach_as_word(vvp_array_t arr,unsigned long addr)728 void vvp_vpi_callback::attach_as_word(vvp_array_t arr, unsigned long addr)
729 {
730 struct __vpi_array_word*tmp = new __vpi_array_word;
731 tmp->array = arr;
732 tmp->word = addr;
733 tmp->next = array_words_;
734 array_words_ = tmp;
735 }
736
add_vpi_callback(value_callback * cb)737 void vvp_vpi_callback::add_vpi_callback(value_callback*cb)
738 {
739 cb->next = vpi_callbacks_;
740 vpi_callbacks_ = cb;
741 }
742
743 #ifdef CHECK_WITH_VALGRIND
clear_all_callbacks()744 void vvp_vpi_callback::clear_all_callbacks()
745 {
746 while (vpi_callbacks_) {
747 value_callback *tmp = dynamic_cast<value_callback*>
748 (vpi_callbacks_->next);
749 delete vpi_callbacks_;
750 vpi_callbacks_ = tmp;
751 }
752 while (array_words_) {
753 struct __vpi_array_word*tmp = array_words_->next;
754 delete array_words_;
755 array_words_ = tmp;
756 }
757 }
758 #endif
759
760 /*
761 * A vvp_fun_signal uses this method to run its callbacks whenever it
762 * has a value change. If the cb_rtn is non-nil, then call the
763 * callback function. If the cb_rtn pointer is nil, then the object
764 * has been marked for deletion. Free it.
765 */
run_vpi_callbacks()766 void vvp_vpi_callback::run_vpi_callbacks()
767 {
768 struct __vpi_array_word*array_word = array_words_;
769 while (array_word) {
770 array_word->array->word_change(array_word->word);
771 array_word = array_word->next;
772 }
773
774 value_callback *next = vpi_callbacks_;
775 value_callback *prev = 0;
776
777 while (next) {
778 value_callback*cur = next;
779 next = dynamic_cast<value_callback*>(cur->next);
780
781 if (cur->cb_data.cb_rtn != 0) {
782 if (cur->test_value_callback_ready()) {
783 if (cur->cb_data.value)
784 get_value(cur->cb_data.value);
785
786 callback_execute(cur);
787 }
788 prev = cur;
789
790 } else if (prev == 0) {
791
792 vpi_callbacks_ = next;
793 cur->next = 0;
794 delete cur;
795
796 } else {
797 assert(prev->next == cur);
798 prev->next = next;
799 cur->next = 0;
800 delete cur;
801 }
802 }
803 }
804
get_signal_value(struct t_vpi_value * vp)805 void vvp_signal_value::get_signal_value(struct t_vpi_value*vp)
806 {
807 switch (vp->format) {
808 case vpiScalarVal:
809 // This works because vvp_bit4_t has the same encoding
810 // as a scalar value! See vpip_vec4_get_value() for a
811 // more robust method.
812 vp->value.scalar = value(0);
813 break;
814
815 case vpiBinStrVal:
816 case vpiOctStrVal:
817 case vpiDecStrVal:
818 case vpiHexStrVal:
819 case vpiIntVal:
820 case vpiVectorVal:
821 case vpiStringVal:
822 case vpiRealVal: {
823 unsigned wid = value_size();
824 vvp_vector4_t vec4(wid);
825 for (unsigned idx = 0; idx < wid; idx += 1) {
826 vec4.set_bit(idx, value(idx));
827 }
828 vpip_vec4_get_value(vec4, wid, false, vp);
829 break;
830 }
831
832 case vpiSuppressVal:
833 break;
834
835 default:
836 fprintf(stderr, "vpi_callback: value "
837 "format %d not supported (fun_signal)\n",
838 (int)vp->format);
839 }
840 }
841
vlg_round(double rval)842 static double vlg_round(double rval)
843 {
844 if (rval >= 0.0) {
845 return floor(rval + 0.5);
846 } else {
847 return ceil(rval - 0.5);
848 }
849 }
850
real_signal_value(struct t_vpi_value * vp,double rval)851 static void real_signal_value(struct t_vpi_value*vp, double rval)
852 {
853 char*rbuf = (char *) need_result_buf(64 + 1, RBUF_VAL);
854
855 switch (vp->format) {
856 case vpiObjTypeVal:
857 vp->format = vpiRealVal;
858 // fallthrough
859 case vpiRealVal:
860 vp->value.real = rval;
861 break;
862
863 case vpiIntVal:
864 /* NaN or +/- infinity are translated as 0. */
865 if (rval != rval || (rval && (rval == 0.5*rval))) {
866 rval = 0.0;
867 } else {
868 rval = vlg_round(rval);
869 }
870 vp->value.integer = (PLI_INT32)rval;
871 break;
872
873 case vpiDecStrVal:
874 if (isnan(rval))
875 sprintf(rbuf, "%s", "nan");
876 else
877 sprintf(rbuf, "%0.0f", vlg_round(rval));
878 vp->value.str = rbuf;
879 break;
880
881 case vpiHexStrVal:
882 sprintf(rbuf, "%" PRIx64, (uint64_t)vlg_round(rval));
883 vp->value.str = rbuf;
884 break;
885
886 case vpiBinStrVal: {
887 uint64_t val = (uint64_t)vlg_round(rval);
888 unsigned len = 0;
889
890 while (val > 0) {
891 len += 1;
892 val /= 2;
893 }
894
895 val = (uint64_t)vlg_round(rval);
896 for (unsigned idx = 0 ; idx < len ; idx += 1) {
897 rbuf[len-idx-1] = (val & 1)? '1' : '0';
898 val /= 2;
899 }
900
901 rbuf[len] = 0;
902 if (len == 0) {
903 rbuf[0] = '0';
904 rbuf[1] = 0;
905 }
906 vp->value.str = rbuf;
907 break;
908 }
909
910 case vpiSuppressVal:
911 break;
912
913 default:
914 fprintf(stderr, "vpi_callback: value "
915 "format %d not supported (fun_signal_real)\n",
916 (int)vp->format);
917 }
918 }
919
get_signal_value(struct t_vpi_value * vp)920 void vvp_fun_signal_real_aa::get_signal_value(struct t_vpi_value*vp)
921 {
922 real_signal_value(vp, real_value());
923 }
924
get_signal_value(struct t_vpi_value * vp)925 void vvp_wire_real::get_signal_value(struct t_vpi_value*vp)
926 {
927 real_signal_value(vp, real_value());
928 }
929
get_signal_value(struct t_vpi_value *)930 void vvp_fun_signal_string_aa::get_signal_value(struct t_vpi_value*)
931 {
932 assert(0);
933 }
934 #if 0
935 void vvp_wire_string::get_signal_value(struct t_vpi_value*vp)
936 {
937 assert(0);
938 }
939 #endif
get_value(struct t_vpi_value * val)940 void vvp_wire_vec4::get_value(struct t_vpi_value*val)
941 {
942 get_signal_value(val);
943 }
944
get_value(struct t_vpi_value * val)945 void vvp_wire_vec8::get_value(struct t_vpi_value*val)
946 {
947 get_signal_value(val);
948 }
949
get_value(struct t_vpi_value * val)950 void vvp_wire_real::get_value(struct t_vpi_value*val)
951 {
952 get_signal_value(val);
953 }
954 #if 0
955 void vvp_wire_string::get_value(struct t_vpi_value*val)
956 {
957 assert(0);
958 }
959 #endif
960