2 * Copyright (c) 2001-2003 Stephen Williams (steve@icarus.com)
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)
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20 #ident "$Id: vpi_callback.cc,v 1.46 2007/04/10 04:32:05 steve Exp $"
24 * Callbacks are objects that carry a function to be called when some
25 * event in the simulation occurs. The VPI code create a __vpiCallback
26 * object, and that object is put in some location that the simulation
27 * can look when the event in question is tripped.
30 # include <vpi_user.h>
31 # include "vpi_priv.h"
33 # include "schedule.h"
43 * The vpi_free_object() call to a callback doesn't actually delete
44 * anything, we instead allow the object to run its course and delete
45 * itself. The semantics of vpi_free_object for a callback is that it
46 * deletes the *handle*, and not the object itself, so given the vvp
47 * implementation, there is nothing to do here.
49 static int free_simple_callback(vpiHandle ref
)
54 const struct __vpirt callback_rt
= {
70 * Callback handles are created when the VPI function registers a
71 * callback. The handle is stored by the run time, and it triggered
72 * when the run-time thing that it is waiting for happens.
74 * This is the thing that the VPI code references by the vpiHandle. It
75 * also points to callback data that the caller attached to the event,
76 * as well as the time structure to receive data.
78 * The cb_sync is a private member that points to the schedulable
79 * event that is triggered when the event happens. The sync_cb class
80 * represents the action to execute when the scheduler gets to this
81 * event. This member is only used for things like cbReadOnlySync.
84 struct sync_cb
: public vvp_gen_event_s
{
85 struct __vpiCallback
*handle
;
90 virtual void run_run();
94 struct __vpiCallback
* new_vpi_callback()
96 struct __vpiCallback
* obj
;
98 obj
= new __vpiCallback
;
100 obj
->base
.vpi_type
= &callback_rt
;
106 static void delete_vpi_callback(struct __vpiCallback
* ref
)
109 assert(ref
->base
.vpi_type
);
110 assert(ref
->base
.vpi_type
->type_code
== vpiCallback
);
116 * A value change callback is tripped when a bit of a signal
117 * changes. This function creates that value change callback and
118 * attaches it to the relevant vpiSignal object. Also, if the signal
119 * does not already have them, create some callback functors to do the
120 * actual value change detection.
122 static struct __vpiCallback
* make_value_change(p_cb_data data
)
124 struct __vpiCallback
*obj
= new_vpi_callback();
125 obj
->cb_data
= *data
;
127 obj
->cb_time
= *(data
->time
);
129 obj
->cb_time
.type
= vpiSuppressTime
;
131 obj
->cb_data
.time
= &obj
->cb_time
;
134 assert(data
->obj
->vpi_type
);
136 switch (data
->obj
->vpi_type
->type_code
) {
141 /* Attach the callback to the vvp_fun_signal node by
142 putting it in the vpi_callbacks list. */
143 struct __vpiSignal
*sig
;
144 sig
= reinterpret_cast<__vpiSignal
*>(data
->obj
);
146 vvp_fun_signal_base
*sig_fun
;
147 sig_fun
= dynamic_cast<vvp_fun_signal_base
*>(sig
->node
->fun
);
150 /* Attach the __vpiCallback object to the signal. */
151 sig_fun
->add_vpi_callback(obj
);
155 vpip_real_value_change(obj
, data
->obj
);
159 struct __vpiNamedEvent
*nev
;
160 nev
= reinterpret_cast<__vpiNamedEvent
*>(data
->obj
);
161 obj
->next
= nev
->callbacks
;
162 nev
->callbacks
= obj
;
166 vpip_memory_value_change(obj
, data
->obj
);
172 /* These are constant, so there are no value change
173 lists to put them in. */
177 fprintf(stderr
, "make_value_change: sorry: I cannot callback "
178 "values on type code=%d\n",
179 data
->obj
->vpi_type
->type_code
);
187 void sync_cb::run_run()
192 struct __vpiCallback
*cur
= handle
;
193 cur
->cb_data
.time
->type
= vpiSimTime
;
194 vpip_time_to_timestruct(cur
->cb_data
.time
, schedule_simtime());
196 /* Run the callback. If the cb_rtn function pointer is set to
197 null, then just skip the whole thing and free it. This is
198 the usual way to cancel one-time callbacks of this sort. */
199 if (cur
->cb_data
.cb_rtn
!= 0) {
200 assert(vpi_mode_flag
== VPI_MODE_NONE
);
201 vpi_mode_flag
= sync_flag
? VPI_MODE_ROSYNC
: VPI_MODE_RWSYNC
;
202 (cur
->cb_data
.cb_rtn
)(&cur
->cb_data
);
203 vpi_mode_flag
= VPI_MODE_NONE
;
206 delete_vpi_callback(cur
);
209 static struct __vpiCallback
* make_sync(p_cb_data data
, bool readonly_flag
)
211 struct __vpiCallback
*obj
= new_vpi_callback();
212 obj
->cb_data
= *data
;
214 obj
->cb_time
= *(data
->time
);
215 obj
->cb_data
.time
= &obj
->cb_time
;
219 struct sync_cb
*cb
= new sync_cb
;
220 cb
->sync_flag
= readonly_flag
? true : false;
224 switch (obj
->cb_time
.type
) {
225 case vpiSuppressTime
:
226 schedule_generic(cb
, 0, true, readonly_flag
);
230 { vvp_time64_t tv
= vpip_timestruct_to_time(&obj
->cb_time
);
231 vvp_time64_t tn
= schedule_simtime();
233 schedule_generic(cb
, 0, true, readonly_flag
);
235 schedule_generic(cb
, tv
- tn
, true, readonly_flag
);
241 fprintf(stderr
, "Unsupported time type %d.\n", obj
->cb_time
.type
);
248 static struct __vpiCallback
* make_afterdelay(p_cb_data data
)
250 struct __vpiCallback
*obj
= new_vpi_callback();
251 obj
->cb_data
= *data
;
253 obj
->cb_time
= *(data
->time
);
254 obj
->cb_data
.time
= &obj
->cb_time
;
258 struct sync_cb
*cb
= new sync_cb
;
259 cb
->sync_flag
= false;
263 switch (obj
->cb_time
.type
) {
265 vvp_time64_t tv
= vpip_timestruct_to_time(&obj
->cb_time
);
266 schedule_generic(cb
, tv
, false);
271 fprintf(stderr
, "Unsupported time type %d.\n", obj
->cb_time
.type
);
280 * The following functions are the used for pre and post simulation
284 static struct __vpiCallback
*NextSimTime
= 0;
285 static struct __vpiCallback
*EndOfCompile
= NULL
;
286 static struct __vpiCallback
*StartOfSimulation
= NULL
;
287 static struct __vpiCallback
*EndOfSimulation
= NULL
;
289 void vpiEndOfCompile(void) {
290 struct __vpiCallback
* cur
;
293 * Walk the list of register callbacks, executing them and
294 * freeing them when done.
296 assert(vpi_mode_flag
== VPI_MODE_NONE
);
297 vpi_mode_flag
= VPI_MODE_RWSYNC
;
299 while (EndOfCompile
) {
301 EndOfCompile
= cur
->next
;
302 (cur
->cb_data
.cb_rtn
)(&cur
->cb_data
);
303 delete_vpi_callback(cur
);
306 vpi_mode_flag
= VPI_MODE_NONE
;
309 void vpiStartOfSim(void) {
310 struct __vpiCallback
* cur
;
313 * Walk the list of register callbacks, executing them and
314 * freeing them when done.
316 assert(vpi_mode_flag
== VPI_MODE_NONE
);
317 vpi_mode_flag
= VPI_MODE_RWSYNC
;
319 while (StartOfSimulation
) {
320 cur
= StartOfSimulation
;
321 StartOfSimulation
= cur
->next
;
322 (cur
->cb_data
.cb_rtn
)(&cur
->cb_data
);
323 delete_vpi_callback(cur
);
326 vpi_mode_flag
= VPI_MODE_NONE
;
329 void vpiPostsim(void) {
330 struct __vpiCallback
* cur
;
333 * Walk the list of register callbacks
335 assert(vpi_mode_flag
== VPI_MODE_NONE
);
336 vpi_mode_flag
= VPI_MODE_ROSYNC
;
338 while (EndOfSimulation
) {
339 cur
= EndOfSimulation
;
340 EndOfSimulation
= cur
->next
;
341 vpip_time_to_timestruct(cur
->cb_data
.time
, schedule_simtime());
342 (cur
->cb_data
.cb_rtn
)(&cur
->cb_data
);
343 delete_vpi_callback(cur
);
346 vpi_mode_flag
= VPI_MODE_NONE
;
350 * The scheduler invokes this to clear out callbacks for the next
353 void vpiNextSimTime(void)
355 struct __vpiCallback
* cur
;
357 while (NextSimTime
) {
359 NextSimTime
= cur
->next
;
360 (cur
->cb_data
.cb_rtn
)(&cur
->cb_data
);
361 delete_vpi_callback(cur
);
366 static struct __vpiCallback
* make_prepost(p_cb_data data
)
368 struct __vpiCallback
*obj
= new_vpi_callback();
369 obj
->cb_data
= *data
;
371 /* Insert at head of list */
372 switch (data
->reason
) {
374 obj
->next
= EndOfCompile
;
377 case cbStartOfSimulation
:
378 obj
->next
= StartOfSimulation
;
379 StartOfSimulation
= obj
;
381 case cbEndOfSimulation
:
382 obj
->next
= EndOfSimulation
;
383 EndOfSimulation
= obj
;
386 obj
->next
= NextSimTime
;
393 vpiHandle
vpi_register_cb(p_cb_data data
)
395 struct __vpiCallback
*obj
= 0;
398 switch (data
->reason
) {
401 obj
= make_value_change(data
);
404 case cbReadOnlySynch
:
405 obj
= make_sync(data
, true);
408 case cbReadWriteSynch
:
409 obj
= make_sync(data
, false);
413 obj
= make_afterdelay(data
);
417 case cbStartOfSimulation
:
418 case cbEndOfSimulation
:
420 obj
= make_prepost(data
);
424 fprintf(stderr
, "vpi error: vpi_register_cb invalid or "
425 "unsupported callback reason: %d\n",
430 return obj
? &obj
->base
: 0;
434 * Removing a callback doesn't really delete it right away. Instead,
435 * it clears the reference to the user callback function. This causes
436 * the callback to quietly reap itself.
438 PLI_INT32
vpi_remove_cb(vpiHandle ref
)
441 assert(ref
->vpi_type
);
442 assert(ref
->vpi_type
->type_code
== vpiCallback
);
444 struct __vpiCallback
*obj
= (struct __vpiCallback
*)ref
;
445 obj
->cb_data
.cb_rtn
= 0;
450 void callback_execute(struct __vpiCallback
*cur
)
452 const vpi_mode_t save_mode
= vpi_mode_flag
;
453 vpi_mode_flag
= VPI_MODE_RWSYNC
;
455 assert(cur
->cb_data
.cb_rtn
);
456 cur
->cb_data
.time
->type
= vpiSimTime
;
457 vpip_time_to_timestruct(cur
->cb_data
.time
, schedule_simtime());
458 (cur
->cb_data
.cb_rtn
)(&cur
->cb_data
);
460 vpi_mode_flag
= save_mode
;
463 vvp_vpi_callback::vvp_vpi_callback()
470 vvp_vpi_callback::~vvp_vpi_callback()
472 assert(vpi_callbacks_
== 0);
476 void vvp_vpi_callback::add_vpi_callback(__vpiCallback
*cb
)
478 cb
->next
= vpi_callbacks_
;
482 void vvp_vpi_callback::attach_as_word(vvp_array_t arr
, unsigned long addr
)
490 * A vvp_fun_signal uses this method to run its callbacks whenever it
491 * has a value change. If the cb_rtn is non-nil, then call the
492 * callback function. If the cb_rtn pointer is nil, then the object
493 * has been marked for deletion. Free it.
495 void vvp_vpi_callback::run_vpi_callbacks()
497 struct __vpiCallback
*next
= vpi_callbacks_
;
498 struct __vpiCallback
*prev
= 0;
500 if (array_
) array_word_change(array_
, array_word_
);
503 struct __vpiCallback
*cur
= next
;
506 if (cur
->cb_data
.cb_rtn
!= 0) {
507 if (cur
->cb_data
.value
)
508 get_value(cur
->cb_data
.value
);
510 callback_execute(cur
);
513 } else if (prev
== 0) {
515 vpi_callbacks_
= next
;
517 delete_vpi_callback(cur
);
520 assert(prev
->next
== cur
);
523 delete_vpi_callback(cur
);
528 void vvp_fun_signal::get_value(struct t_vpi_value
*vp
)
530 switch (vp
->format
) {
532 vp
->value
.scalar
= value(0);
537 fprintf(stderr
, "vpi_callback: value "
538 "format %d not supported (fun_signal)\n",
543 void vvp_fun_signal8::get_value(struct t_vpi_value
*vp
)
545 switch (vp
->format
) {
547 vp
->value
.scalar
= value(0);
552 fprintf(stderr
, "vpi_callback: value "
553 "format %d not supported (fun_signal8)\n",
558 void vvp_fun_signal_real::get_value(struct t_vpi_value
*vp
)
560 char*rbuf
= need_result_buf(64 + 1, RBUF_VAL
);
562 switch (vp
->format
) {
564 vp
->format
= vpiRealVal
;
567 vp
->value
.real
= real_value();
571 vp
->value
.integer
= (int)(real_value() + 0.5);
575 sprintf(rbuf
, "%0.0f", real_value());
576 vp
->value
.str
= rbuf
;
580 sprintf(rbuf
, "%lx", (long)real_value());
581 vp
->value
.str
= rbuf
;
585 unsigned long val
= (unsigned long)real_value();
593 val
= (unsigned long)real_value();
594 for (unsigned idx
= 0 ; idx
< len
; idx
+= 1) {
595 rbuf
[len
-idx
-1] = (val
& 1)? '1' : '0';
604 vp
->value
.str
= rbuf
;
609 fprintf(stderr
, "vpi_callback: value "
610 "format %d not supported (fun_signal_real)\n",