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 (cur
->cb_data
.cb_rtn
)(&cur
->cb_data
);
342 delete_vpi_callback(cur
);
345 vpi_mode_flag
= VPI_MODE_NONE
;
349 * The scheduler invokes this to clear out callbacks for the next
352 void vpiNextSimTime(void)
354 struct __vpiCallback
* cur
;
356 while (NextSimTime
) {
358 NextSimTime
= cur
->next
;
359 (cur
->cb_data
.cb_rtn
)(&cur
->cb_data
);
360 delete_vpi_callback(cur
);
365 static struct __vpiCallback
* make_prepost(p_cb_data data
)
367 struct __vpiCallback
*obj
= new_vpi_callback();
368 obj
->cb_data
= *data
;
370 /* Insert at head of list */
371 switch (data
->reason
) {
373 obj
->next
= EndOfCompile
;
376 case cbStartOfSimulation
:
377 obj
->next
= StartOfSimulation
;
378 StartOfSimulation
= obj
;
380 case cbEndOfSimulation
:
381 obj
->next
= EndOfSimulation
;
382 EndOfSimulation
= obj
;
385 obj
->next
= NextSimTime
;
392 vpiHandle
vpi_register_cb(p_cb_data data
)
394 struct __vpiCallback
*obj
= 0;
397 switch (data
->reason
) {
400 obj
= make_value_change(data
);
403 case cbReadOnlySynch
:
404 obj
= make_sync(data
, true);
407 case cbReadWriteSynch
:
408 obj
= make_sync(data
, false);
412 obj
= make_afterdelay(data
);
416 case cbStartOfSimulation
:
417 case cbEndOfSimulation
:
419 obj
= make_prepost(data
);
423 fprintf(stderr
, "vpi error: vpi_register_cb invalid or "
424 "unsupported callback reason: %d\n",
429 return obj
? &obj
->base
: 0;
433 * Removing a callback doesn't really delete it right away. Instead,
434 * it clears the reference to the user callback function. This causes
435 * the callback to quietly reap itself.
437 PLI_INT32
vpi_remove_cb(vpiHandle ref
)
440 assert(ref
->vpi_type
);
441 assert(ref
->vpi_type
->type_code
== vpiCallback
);
443 struct __vpiCallback
*obj
= (struct __vpiCallback
*)ref
;
444 obj
->cb_data
.cb_rtn
= 0;
449 void callback_execute(struct __vpiCallback
*cur
)
451 const vpi_mode_t save_mode
= vpi_mode_flag
;
452 vpi_mode_flag
= VPI_MODE_RWSYNC
;
454 assert(cur
->cb_data
.cb_rtn
);
455 cur
->cb_data
.time
->type
= vpiSimTime
;
456 vpip_time_to_timestruct(cur
->cb_data
.time
, schedule_simtime());
457 (cur
->cb_data
.cb_rtn
)(&cur
->cb_data
);
459 vpi_mode_flag
= save_mode
;
462 vvp_vpi_callback::vvp_vpi_callback()
469 vvp_vpi_callback::~vvp_vpi_callback()
471 assert(vpi_callbacks_
== 0);
475 void vvp_vpi_callback::add_vpi_callback(__vpiCallback
*cb
)
477 cb
->next
= vpi_callbacks_
;
481 void vvp_vpi_callback::attach_as_word(vvp_array_t arr
, unsigned long addr
)
489 * A vvp_fun_signal uses this method to run its callbacks whenever it
490 * has a value change. If the cb_rtn is non-nil, then call the
491 * callback function. If the cb_rtn pointer is nil, then the object
492 * has been marked for deletion. Free it.
494 void vvp_vpi_callback::run_vpi_callbacks()
496 struct __vpiCallback
*next
= vpi_callbacks_
;
497 struct __vpiCallback
*prev
= 0;
499 if (array_
) array_word_change(array_
, array_word_
);
502 struct __vpiCallback
*cur
= next
;
505 if (cur
->cb_data
.cb_rtn
!= 0) {
506 if (cur
->cb_data
.value
)
507 get_value(cur
->cb_data
.value
);
509 callback_execute(cur
);
512 } else if (prev
== 0) {
514 vpi_callbacks_
= next
;
516 delete_vpi_callback(cur
);
519 assert(prev
->next
== cur
);
522 delete_vpi_callback(cur
);
527 void vvp_fun_signal::get_value(struct t_vpi_value
*vp
)
529 switch (vp
->format
) {
531 vp
->value
.scalar
= value(0);
536 fprintf(stderr
, "vpi_callback: value "
537 "format %d not supported (fun_signal)\n",
542 void vvp_fun_signal8::get_value(struct t_vpi_value
*vp
)
544 switch (vp
->format
) {
546 vp
->value
.scalar
= value(0);
551 fprintf(stderr
, "vpi_callback: value "
552 "format %d not supported (fun_signal8)\n",
557 void vvp_fun_signal_real::get_value(struct t_vpi_value
*vp
)
559 char*rbuf
= need_result_buf(64 + 1, RBUF_VAL
);
561 switch (vp
->format
) {
563 vp
->format
= vpiRealVal
;
566 vp
->value
.real
= real_value();
570 vp
->value
.integer
= (int)(real_value() + 0.5);
574 sprintf(rbuf
, "%0.0f", real_value());
575 vp
->value
.str
= rbuf
;
579 sprintf(rbuf
, "%lx", (long)real_value());
580 vp
->value
.str
= rbuf
;
584 unsigned long val
= (unsigned long)real_value();
592 val
= (unsigned long)real_value();
593 for (unsigned idx
= 0 ; idx
< len
; idx
+= 1) {
594 rbuf
[len
-idx
-1] = (val
& 1)? '1' : '0';
603 vp
->value
.str
= rbuf
;
608 fprintf(stderr
, "vpi_callback: value "
609 "format %d not supported (fun_signal_real)\n",