2001-06-22 00:54:12 +02:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
|
|
|
|
*
|
|
|
|
|
* This source code is free software; you can redistribute it
|
|
|
|
|
* and/or modify it in source code form under the terms of the GNU
|
|
|
|
|
* General Public License as published by the Free Software
|
|
|
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
|
|
|
* any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
|
*/
|
2002-08-12 03:34:58 +02:00
|
|
|
#ifdef HAVE_CVS_IDENT
|
2003-02-10 06:20:10 +01:00
|
|
|
#ident "$Id: vpi_callback.cc,v 1.27 2003/02/10 05:20:10 steve Exp $"
|
2001-06-22 00:54:12 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Callbacks are objects that carry a function to be called when some
|
|
|
|
|
* event in the simulation occurs. The VPI code create a __vpiCallback
|
|
|
|
|
* object, and that object is put in some location that the simulation
|
|
|
|
|
* can look when the event in question is tripped.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
# include <vpi_user.h>
|
|
|
|
|
# include "vpi_priv.h"
|
|
|
|
|
# include "schedule.h"
|
2001-08-08 03:05:06 +02:00
|
|
|
# include "functor.h"
|
2001-11-06 04:07:21 +01:00
|
|
|
# include "event.h"
|
2001-06-22 00:54:12 +02:00
|
|
|
# include <stdio.h>
|
|
|
|
|
# include <assert.h>
|
2001-09-15 20:27:04 +02:00
|
|
|
#ifdef HAVE_MALLOC_H
|
2001-08-08 03:05:06 +02:00
|
|
|
# include <malloc.h>
|
2001-09-15 20:27:04 +02:00
|
|
|
#endif
|
|
|
|
|
# include <stdlib.h>
|
2001-06-22 00:54:12 +02:00
|
|
|
|
2002-05-04 05:17:29 +02:00
|
|
|
static int free_simple_callback(vpiHandle ref)
|
|
|
|
|
{
|
|
|
|
|
assert(ref);
|
|
|
|
|
assert(ref->vpi_type);
|
|
|
|
|
assert(ref->vpi_type->type_code == vpiCallback);
|
|
|
|
|
delete ref;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-22 00:54:12 +02:00
|
|
|
const struct __vpirt callback_rt = {
|
|
|
|
|
vpiCallback,
|
|
|
|
|
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
|
|
|
|
|
0,
|
|
|
|
|
0,
|
2002-05-04 05:17:29 +02:00
|
|
|
0,
|
|
|
|
|
|
|
|
|
|
&free_simple_callback
|
2001-06-22 00:54:12 +02:00
|
|
|
};
|
|
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
/*
|
|
|
|
|
* Callback handles are created when the VPI function registers a
|
|
|
|
|
* callback. The handle is stored by the run time, and it triggered
|
|
|
|
|
* when the run-time thing that it is waiting for happens.
|
2002-04-06 22:25:45 +02:00
|
|
|
*
|
|
|
|
|
* This is the thing that the VPI code references by the vpiHandle. It
|
|
|
|
|
* also points to callback data that the caller attached to the event,
|
|
|
|
|
* as well as the time structure to receive data.
|
|
|
|
|
*
|
|
|
|
|
* The cb_sync is a private member that points to the schedulable
|
|
|
|
|
* event that is triggered when the event happens. The sync_cb class
|
|
|
|
|
* represents the action to execute when the scheduler gets to this
|
|
|
|
|
* event. This member is only used for things like cbReadOnlySync.
|
2001-10-31 05:27:46 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
struct sync_cb : public vvp_gen_event_s {
|
|
|
|
|
struct __vpiCallback*handle;
|
|
|
|
|
};
|
|
|
|
|
|
2001-07-13 05:02:34 +02:00
|
|
|
|
2002-05-19 07:18:16 +02:00
|
|
|
struct __vpiCallback* new_vpi_callback()
|
2001-07-13 05:02:34 +02:00
|
|
|
{
|
|
|
|
|
struct __vpiCallback* obj;
|
2002-04-06 22:25:45 +02:00
|
|
|
|
|
|
|
|
obj = new __vpiCallback;
|
|
|
|
|
|
|
|
|
|
obj->base.vpi_type = &callback_rt;
|
|
|
|
|
obj->cb_sync = 0;
|
|
|
|
|
obj->next = 0;
|
2001-07-13 05:02:34 +02:00
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
2001-08-08 03:05:06 +02:00
|
|
|
/*
|
2002-04-06 22:25:45 +02:00
|
|
|
* The callback_functor_s functor is used to support cbValueChange
|
|
|
|
|
* callbacks. When a value change callback is created, instances of
|
|
|
|
|
* this functor are created to receive values and detect changes in
|
|
|
|
|
* the functor web at the right spot.
|
2001-08-08 03:05:06 +02:00
|
|
|
*/
|
2001-07-13 05:02:34 +02:00
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
struct callback_functor_s: public functor_s {
|
2001-11-06 04:07:21 +01:00
|
|
|
callback_functor_s();
|
|
|
|
|
virtual ~callback_functor_s();
|
2001-10-31 05:27:46 +01:00
|
|
|
virtual void set(vvp_ipoint_t i, bool push, unsigned val, unsigned str);
|
|
|
|
|
struct __vpiCallback *cb_handle;
|
|
|
|
|
};
|
|
|
|
|
|
2002-04-06 22:25:45 +02:00
|
|
|
callback_functor_s::callback_functor_s()
|
2001-11-06 04:07:21 +01:00
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
callback_functor_s::~callback_functor_s()
|
|
|
|
|
{}
|
|
|
|
|
|
2002-04-06 22:25:45 +02:00
|
|
|
/*
|
|
|
|
|
* Make the functors necessary to support an edge callback. This is a
|
|
|
|
|
* single event functor that is in turn fed by edge detector functors
|
|
|
|
|
* attached to all the input bit functors. (Just like an event-or.)
|
|
|
|
|
* This function creates the callback_functor and the necessary event
|
|
|
|
|
* functors, and attaches the event functors to the net.
|
|
|
|
|
*/
|
2001-10-31 05:27:46 +01:00
|
|
|
struct callback_functor_s *vvp_fvector_make_callback(vvp_fvector_t vec,
|
|
|
|
|
event_functor_s::edge_t edge)
|
2001-07-13 05:02:34 +02:00
|
|
|
{
|
2001-10-31 05:27:46 +01:00
|
|
|
// Let's make a callback functor.
|
|
|
|
|
struct callback_functor_s *obj = new callback_functor_s;
|
|
|
|
|
|
|
|
|
|
// We want to connect nvec inputs
|
2001-08-08 03:05:06 +02:00
|
|
|
unsigned nvec = vvp_fvector_size(vec);
|
|
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
// We require a total of nfun functors. If there's an edge to
|
|
|
|
|
// look for, then all inputs must go to extra event functors.
|
|
|
|
|
// Otherwise we just make sure we have one input left on the base
|
|
|
|
|
// functor to connect the extras to, if there are any.
|
|
|
|
|
unsigned nfun = (nvec+3)/4;
|
|
|
|
|
if (edge != vvp_edge_none)
|
2001-08-08 03:05:06 +02:00
|
|
|
nfun ++ ;
|
|
|
|
|
else if (nfun > 1 && 4*nfun == nvec)
|
|
|
|
|
nfun ++;
|
|
|
|
|
|
|
|
|
|
vvp_ipoint_t fdx = functor_allocate(nfun);
|
2001-10-31 05:27:46 +01:00
|
|
|
functor_define(fdx, obj);
|
|
|
|
|
|
|
|
|
|
for (unsigned i=1; i<nfun; i++) {
|
|
|
|
|
functor_t fu = new event_functor_s(edge);
|
|
|
|
|
functor_define(ipoint_index(fdx, i), fu);
|
|
|
|
|
fu->out = fdx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
if (edge != vvp_edge_none)
|
|
|
|
|
i = 4;
|
|
|
|
|
else if (nvec > 4)
|
|
|
|
|
i = 1;
|
|
|
|
|
else
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
|
|
for (unsigned vi = 0; vi < nvec; vi++, i++) {
|
|
|
|
|
vvp_ipoint_t vipt = vvp_fvector_get(vec, vi);
|
|
|
|
|
functor_t vfu = functor_index(vipt);
|
|
|
|
|
|
|
|
|
|
vvp_ipoint_t ipt = ipoint_input_index(fdx, i);
|
2001-08-08 03:05:06 +02:00
|
|
|
functor_t fu = functor_index(ipt);
|
2001-10-31 05:27:46 +01:00
|
|
|
unsigned pp = ipoint_port(ipt);
|
|
|
|
|
|
|
|
|
|
fu->port[pp] = vfu->out;
|
|
|
|
|
vfu->out = ipt;
|
2001-08-08 03:05:06 +02:00
|
|
|
}
|
2001-10-31 05:27:46 +01:00
|
|
|
|
2001-08-08 03:05:06 +02:00
|
|
|
obj->cb_handle = 0;
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
2001-07-13 05:02:34 +02:00
|
|
|
|
2001-06-22 00:54:12 +02:00
|
|
|
/*
|
|
|
|
|
* A value change callback is tripped when a bit of a signal
|
|
|
|
|
* changes. This function creates that value change callback and
|
2003-02-10 00:33:26 +01:00
|
|
|
* attaches it to the relevant vpiSignal object. Also, if the signal
|
2002-04-06 22:25:45 +02:00
|
|
|
* does not already have them, create some callback functors to do the
|
|
|
|
|
* actual value change detection.
|
2001-06-22 00:54:12 +02:00
|
|
|
*/
|
|
|
|
|
static struct __vpiCallback* make_value_change(p_cb_data data)
|
|
|
|
|
{
|
2001-07-13 05:02:34 +02:00
|
|
|
struct __vpiCallback*obj = new_vpi_callback();
|
2001-06-22 00:54:12 +02:00
|
|
|
obj->cb_data = *data;
|
2002-05-09 05:34:31 +02:00
|
|
|
if (data->time) {
|
|
|
|
|
obj->cb_time = *(data->time);
|
|
|
|
|
} else {
|
|
|
|
|
obj->cb_time.type = vpiSuppressTime;
|
|
|
|
|
}
|
2001-07-11 04:27:21 +02:00
|
|
|
obj->cb_data.time = &obj->cb_time;
|
2001-06-22 00:54:12 +02:00
|
|
|
|
2001-07-11 04:27:21 +02:00
|
|
|
assert(data->obj);
|
|
|
|
|
assert(data->obj->vpi_type);
|
2002-04-06 22:25:45 +02:00
|
|
|
|
2002-05-19 07:18:16 +02:00
|
|
|
switch (data->obj->vpi_type->type_code) {
|
|
|
|
|
|
|
|
|
|
case vpiReg:
|
|
|
|
|
case vpiNet:
|
2002-07-12 04:07:36 +02:00
|
|
|
case vpiIntegerVar:
|
2002-05-19 07:18:16 +02:00
|
|
|
struct __vpiSignal*sig;
|
|
|
|
|
sig = reinterpret_cast<__vpiSignal*>(data->obj);
|
|
|
|
|
|
|
|
|
|
/* Create callback functors, if necessary, to do the
|
|
|
|
|
value change detection and carry the callback
|
|
|
|
|
objects. */
|
|
|
|
|
if (sig->callback == 0) {
|
|
|
|
|
sig->callback = vvp_fvector_make_callback(sig->bits);
|
|
|
|
|
assert(sig->callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Attach the __vpiCallback object to the signals
|
|
|
|
|
callback functors. */
|
|
|
|
|
obj->next = sig->callback->cb_handle;
|
|
|
|
|
sig->callback->cb_handle = obj;
|
|
|
|
|
break;
|
|
|
|
|
|
2003-02-10 06:20:10 +01:00
|
|
|
case vpiRealVar:
|
|
|
|
|
vpip_real_value_change(obj, data->obj);
|
|
|
|
|
break;
|
|
|
|
|
|
2002-05-19 07:18:16 +02:00
|
|
|
case vpiNamedEvent:
|
|
|
|
|
struct __vpiNamedEvent*nev;
|
|
|
|
|
nev = reinterpret_cast<__vpiNamedEvent*>(data->obj);
|
|
|
|
|
obj->next = nev->callbacks;
|
|
|
|
|
nev->callbacks = obj;
|
|
|
|
|
break;
|
|
|
|
|
|
2002-06-11 05:47:34 +02:00
|
|
|
case vpiModule:
|
|
|
|
|
case vpiConstant:
|
|
|
|
|
/* These are constant, so there are no value change
|
|
|
|
|
lists to put them in. */
|
|
|
|
|
break;
|
|
|
|
|
|
2002-05-19 07:18:16 +02:00
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-06-22 00:54:12 +02:00
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
2001-07-11 04:27:21 +02:00
|
|
|
static void make_sync_run(vvp_gen_event_t obj, unsigned char)
|
|
|
|
|
{
|
|
|
|
|
struct sync_cb*cb = (struct sync_cb*)obj;
|
|
|
|
|
if (cb->handle == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
struct __vpiCallback*cur = cb->handle;
|
|
|
|
|
cur->cb_data.time->type = vpiSimTime;
|
2002-04-20 06:33:23 +02:00
|
|
|
vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime());
|
2002-05-18 04:34:11 +02:00
|
|
|
|
2002-09-07 06:54:51 +02:00
|
|
|
assert(cur->cb_data.cb_rtn != 0);
|
|
|
|
|
|
2002-05-18 04:34:11 +02:00
|
|
|
assert(vpi_mode_flag == VPI_MODE_NONE);
|
2002-07-31 05:22:23 +02:00
|
|
|
vpi_mode_flag = cb->sync_flag? VPI_MODE_ROSYNC : VPI_MODE_RWSYNC;
|
2001-07-11 04:27:21 +02:00
|
|
|
(cur->cb_data.cb_rtn)(&cur->cb_data);
|
2002-05-18 04:34:11 +02:00
|
|
|
vpi_mode_flag = VPI_MODE_NONE;
|
2001-07-11 04:27:21 +02:00
|
|
|
|
2002-05-04 05:17:29 +02:00
|
|
|
vpi_free_object(&cur->base);
|
2001-07-11 04:27:21 +02:00
|
|
|
}
|
|
|
|
|
|
2002-04-20 06:33:23 +02:00
|
|
|
static struct __vpiCallback* make_sync(p_cb_data data, bool readonly_flag)
|
2001-07-11 04:27:21 +02:00
|
|
|
{
|
2001-07-13 05:02:34 +02:00
|
|
|
struct __vpiCallback*obj = new_vpi_callback();
|
2001-07-11 04:27:21 +02:00
|
|
|
obj->cb_data = *data;
|
2002-05-09 05:34:31 +02:00
|
|
|
assert(data->time);
|
2001-07-11 04:27:21 +02:00
|
|
|
obj->cb_time = *(data->time);
|
|
|
|
|
obj->cb_data.time = &obj->cb_time;
|
|
|
|
|
|
|
|
|
|
obj->next = 0;
|
|
|
|
|
|
|
|
|
|
struct sync_cb*cb = new sync_cb;
|
2002-04-20 06:33:23 +02:00
|
|
|
cb->sync_flag = readonly_flag? true : false;
|
2001-07-11 04:27:21 +02:00
|
|
|
cb->run = &make_sync_run;
|
|
|
|
|
cb->handle = obj;
|
|
|
|
|
obj->cb_sync = cb;
|
|
|
|
|
|
2002-04-20 06:33:23 +02:00
|
|
|
switch (obj->cb_time.type) {
|
|
|
|
|
case vpiSuppressTime:
|
|
|
|
|
schedule_generic(cb, 0, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiSimTime:
|
|
|
|
|
{ vvp_time64_t tv = vpip_timestruct_to_time(&obj->cb_time);
|
|
|
|
|
vvp_time64_t tn = schedule_simtime();
|
|
|
|
|
if (tv < tn) {
|
|
|
|
|
schedule_generic(cb, 0, 0);
|
|
|
|
|
} else {
|
|
|
|
|
schedule_generic(cb, 0, tv - tn);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-07-11 04:27:21 +02:00
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-20 04:42:11 +02:00
|
|
|
static struct __vpiCallback* make_afterdelay(p_cb_data data)
|
|
|
|
|
{
|
|
|
|
|
struct __vpiCallback*obj = new_vpi_callback();
|
|
|
|
|
obj->cb_data = *data;
|
|
|
|
|
assert(data->time);
|
|
|
|
|
obj->cb_time = *(data->time);
|
|
|
|
|
obj->cb_data.time = &obj->cb_time;
|
|
|
|
|
|
|
|
|
|
obj->next = 0;
|
|
|
|
|
|
|
|
|
|
struct sync_cb*cb = new sync_cb;
|
|
|
|
|
cb->sync_flag = false;
|
|
|
|
|
cb->run = &make_sync_run;
|
|
|
|
|
cb->handle = obj;
|
|
|
|
|
obj->cb_sync = cb;
|
|
|
|
|
|
|
|
|
|
switch (obj->cb_time.type) {
|
|
|
|
|
case vpiSimTime: {
|
|
|
|
|
vvp_time64_t tv = vpip_timestruct_to_time(&obj->cb_time);
|
|
|
|
|
schedule_generic(cb, 0, tv);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-04 05:03:17 +02:00
|
|
|
/*
|
|
|
|
|
* The following functions are the used for pre and post simulation
|
|
|
|
|
* callbacks.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static struct __vpiCallback*EndOfCompile = NULL;
|
|
|
|
|
static struct __vpiCallback*StartOfSimulation = NULL;
|
|
|
|
|
static struct __vpiCallback*EndOfSimulation = NULL;
|
|
|
|
|
|
|
|
|
|
void vpiPresim() {
|
|
|
|
|
struct __vpiCallback* cur;
|
|
|
|
|
|
|
|
|
|
/*
|
2002-05-04 05:17:29 +02:00
|
|
|
* Walk the list of register callbacks, executing them and
|
|
|
|
|
* freeing them when done.
|
2002-05-04 05:03:17 +02:00
|
|
|
*/
|
2002-05-18 04:34:11 +02:00
|
|
|
assert(vpi_mode_flag == VPI_MODE_NONE);
|
|
|
|
|
vpi_mode_flag = VPI_MODE_RWSYNC;
|
|
|
|
|
|
2002-05-04 05:17:29 +02:00
|
|
|
while (EndOfCompile) {
|
|
|
|
|
cur = EndOfCompile;
|
|
|
|
|
EndOfCompile = cur->next;
|
|
|
|
|
(cur->cb_data.cb_rtn)(&cur->cb_data);
|
|
|
|
|
vpi_free_object(&cur->base);
|
2002-05-04 05:03:17 +02:00
|
|
|
}
|
2002-05-04 05:17:29 +02:00
|
|
|
|
|
|
|
|
while (StartOfSimulation) {
|
|
|
|
|
cur = StartOfSimulation;
|
|
|
|
|
StartOfSimulation = cur->next;
|
|
|
|
|
(cur->cb_data.cb_rtn)(&cur->cb_data);
|
|
|
|
|
vpi_free_object(&cur->base);
|
2002-05-04 05:03:17 +02:00
|
|
|
}
|
2002-05-18 04:34:11 +02:00
|
|
|
|
|
|
|
|
vpi_mode_flag = VPI_MODE_NONE;
|
2002-05-04 05:03:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void vpiPostsim() {
|
|
|
|
|
struct __vpiCallback* cur;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Walk the list of register callbacks
|
|
|
|
|
*/
|
2002-05-18 04:34:11 +02:00
|
|
|
assert(vpi_mode_flag == VPI_MODE_NONE);
|
|
|
|
|
vpi_mode_flag = VPI_MODE_ROSYNC;
|
|
|
|
|
|
2002-05-04 05:17:29 +02:00
|
|
|
while (EndOfSimulation) {
|
|
|
|
|
cur = EndOfSimulation;
|
|
|
|
|
EndOfSimulation = cur->next;
|
|
|
|
|
(cur->cb_data.cb_rtn)(&cur->cb_data);
|
|
|
|
|
vpi_free_object(&cur->base);
|
2002-05-04 05:03:17 +02:00
|
|
|
}
|
2002-05-18 04:34:11 +02:00
|
|
|
|
|
|
|
|
vpi_mode_flag = VPI_MODE_NONE;
|
2002-05-04 05:03:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct __vpiCallback* make_prepost(p_cb_data data)
|
|
|
|
|
{
|
|
|
|
|
struct __vpiCallback*obj = new_vpi_callback();
|
|
|
|
|
obj->cb_data = *data;
|
|
|
|
|
|
|
|
|
|
/* Insert at head of list */
|
|
|
|
|
switch (data->reason) {
|
|
|
|
|
case cbEndOfCompile:
|
|
|
|
|
obj->next = EndOfCompile;
|
|
|
|
|
EndOfCompile = obj;
|
|
|
|
|
break;
|
|
|
|
|
case cbStartOfSimulation:
|
|
|
|
|
obj->next = StartOfSimulation;
|
|
|
|
|
StartOfSimulation = obj;
|
|
|
|
|
break;
|
|
|
|
|
case cbEndOfSimulation:
|
|
|
|
|
obj->next = EndOfSimulation;
|
|
|
|
|
EndOfSimulation = obj;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-22 00:54:12 +02:00
|
|
|
vpiHandle vpi_register_cb(p_cb_data data)
|
|
|
|
|
{
|
|
|
|
|
struct __vpiCallback*obj = 0;
|
|
|
|
|
|
2002-06-02 21:05:50 +02:00
|
|
|
assert(data);
|
2001-06-22 00:54:12 +02:00
|
|
|
switch (data->reason) {
|
|
|
|
|
|
|
|
|
|
case cbValueChange:
|
|
|
|
|
obj = make_value_change(data);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-07-11 04:27:21 +02:00
|
|
|
case cbReadOnlySynch:
|
2002-04-20 06:33:23 +02:00
|
|
|
obj = make_sync(data, true);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case cbReadWriteSynch:
|
|
|
|
|
obj = make_sync(data, false);
|
2001-07-11 04:27:21 +02:00
|
|
|
break;
|
|
|
|
|
|
2002-09-20 04:42:11 +02:00
|
|
|
case cbAfterDelay:
|
|
|
|
|
obj = make_afterdelay(data);
|
|
|
|
|
break;
|
|
|
|
|
|
2002-05-04 05:03:17 +02:00
|
|
|
case cbEndOfCompile:
|
|
|
|
|
case cbStartOfSimulation:
|
|
|
|
|
case cbEndOfSimulation:
|
|
|
|
|
obj = make_prepost(data);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-06-22 00:54:12 +02:00
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "vpi error: vpi_register_cb invalid or "
|
|
|
|
|
"unsupported callback reason: %d\n",
|
|
|
|
|
data->reason);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return obj? &obj->base : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-07 06:54:51 +02:00
|
|
|
/*
|
|
|
|
|
* Removing a callback doesn't really delete it right away. Instead,
|
|
|
|
|
* it clears the reference to the user callback function. This causes
|
|
|
|
|
* the callback to quietly reap itself.
|
|
|
|
|
*/
|
2001-06-22 00:54:12 +02:00
|
|
|
int vpi_remove_cb(vpiHandle ref)
|
|
|
|
|
{
|
2001-07-11 04:27:21 +02:00
|
|
|
assert(ref);
|
|
|
|
|
assert(ref->vpi_type);
|
2001-06-22 00:54:12 +02:00
|
|
|
assert(ref->vpi_type->type_code == vpiCallback);
|
|
|
|
|
|
2002-09-07 06:54:51 +02:00
|
|
|
struct __vpiCallback*obj = (struct __vpiCallback*)ref;
|
|
|
|
|
obj->cb_data.cb_rtn = 0;
|
2001-06-22 00:54:12 +02:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-19 07:18:16 +02:00
|
|
|
void callback_execute(struct __vpiCallback*cur)
|
|
|
|
|
{
|
2002-05-29 00:55:20 +02:00
|
|
|
const vpi_mode_t save_mode = vpi_mode_flag;
|
2002-05-19 07:18:16 +02:00
|
|
|
vpi_mode_flag = VPI_MODE_RWSYNC;
|
|
|
|
|
|
2002-09-07 06:54:51 +02:00
|
|
|
assert(cur->cb_data.cb_rtn);
|
2002-05-19 07:18:16 +02:00
|
|
|
cur->cb_data.time->type = vpiSimTime;
|
|
|
|
|
vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime());
|
|
|
|
|
(cur->cb_data.cb_rtn)(&cur->cb_data);
|
|
|
|
|
|
2002-05-29 00:55:20 +02:00
|
|
|
vpi_mode_flag = save_mode;
|
2002-05-19 07:18:16 +02:00
|
|
|
}
|
|
|
|
|
|
2001-06-22 01:05:08 +02:00
|
|
|
/*
|
2002-04-06 22:25:45 +02:00
|
|
|
* A callback_functor_s functor uses its set method to detect value
|
|
|
|
|
* changes. When a value comes in, the __vpiCallback objects that are
|
|
|
|
|
* associated with this callback functor are all called.
|
2001-06-22 01:05:08 +02:00
|
|
|
*/
|
2001-06-22 00:54:12 +02:00
|
|
|
|
2001-10-31 05:27:46 +01:00
|
|
|
void callback_functor_s::set(vvp_ipoint_t, bool, unsigned val, unsigned)
|
2001-08-08 03:05:06 +02:00
|
|
|
{
|
|
|
|
|
struct __vpiCallback *next = cb_handle;
|
2002-09-07 06:54:51 +02:00
|
|
|
struct __vpiCallback *prev = 0;
|
2002-04-06 22:25:45 +02:00
|
|
|
|
2001-08-08 03:05:06 +02:00
|
|
|
while (next) {
|
|
|
|
|
struct __vpiCallback * cur = next;
|
|
|
|
|
next = cur->next;
|
2002-09-07 06:54:51 +02:00
|
|
|
|
|
|
|
|
if (cur->cb_data.cb_rtn != 0) {
|
|
|
|
|
if (cur->cb_data.value) {
|
|
|
|
|
switch (cur->cb_data.value->format) {
|
|
|
|
|
case vpiScalarVal:
|
|
|
|
|
cur->cb_data.value->value.scalar = val;
|
|
|
|
|
break;
|
|
|
|
|
case vpiSuppressVal:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "vpi_callback: value "
|
|
|
|
|
"format %d not supported\n",
|
|
|
|
|
cur->cb_data.value->format);
|
|
|
|
|
}
|
2001-10-25 06:19:53 +02:00
|
|
|
}
|
2002-09-07 06:54:51 +02:00
|
|
|
|
|
|
|
|
callback_execute(cur);
|
|
|
|
|
prev = cur;
|
|
|
|
|
|
|
|
|
|
} else if (prev == 0) {
|
|
|
|
|
|
|
|
|
|
cb_handle = next;
|
|
|
|
|
cur->next = 0;
|
|
|
|
|
vpi_free_object(&cur->base);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
assert(prev->next == cur);
|
|
|
|
|
prev->next = next;
|
|
|
|
|
cur->next = 0;
|
|
|
|
|
vpi_free_object(&cur->base);
|
2001-10-25 06:19:53 +02:00
|
|
|
}
|
2002-05-18 04:34:11 +02:00
|
|
|
|
2001-06-22 00:54:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-08-08 03:05:06 +02:00
|
|
|
|
2001-06-22 00:54:12 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* $Log: vpi_callback.cc,v $
|
2003-02-10 06:20:10 +01:00
|
|
|
* Revision 1.27 2003/02/10 05:20:10 steve
|
|
|
|
|
* Add value change callbacks to real variables.
|
|
|
|
|
*
|
2003-02-10 00:33:26 +01:00
|
|
|
* Revision 1.26 2003/02/09 23:33:26 steve
|
|
|
|
|
* Spelling fixes.
|
|
|
|
|
*
|
2002-09-20 04:42:11 +02:00
|
|
|
* Revision 1.25 2002/09/20 02:42:11 steve
|
|
|
|
|
* Add support for cbAfterDelay.
|
|
|
|
|
*
|
2002-09-07 06:54:51 +02:00
|
|
|
* Revision 1.24 2002/09/07 04:54:51 steve
|
|
|
|
|
* Implement vpi_remove_cb for cbValueChange.
|
|
|
|
|
*
|
2002-08-12 03:34:58 +02:00
|
|
|
* Revision 1.23 2002/08/12 01:35:08 steve
|
|
|
|
|
* conditional ident string using autoconfig.
|
|
|
|
|
*
|
2002-07-31 05:22:23 +02:00
|
|
|
* Revision 1.22 2002/07/31 03:22:23 steve
|
|
|
|
|
* Set vpi_mode_flag to represent cpReadOnlySync actions.
|
|
|
|
|
*
|
2002-07-12 04:07:36 +02:00
|
|
|
* Revision 1.21 2002/07/12 02:07:36 steve
|
|
|
|
|
* vpiIntegerVars can have callbacks.
|
|
|
|
|
*
|
2002-06-11 05:47:34 +02:00
|
|
|
* Revision 1.20 2002/06/11 03:47:34 steve
|
|
|
|
|
* Stub value change callbacks for consts and modules.
|
|
|
|
|
*
|
2002-06-02 21:05:50 +02:00
|
|
|
* Revision 1.19 2002/06/02 19:05:50 steve
|
|
|
|
|
* Check for null pointers from users.
|
|
|
|
|
*
|
2002-05-29 00:55:20 +02:00
|
|
|
* Revision 1.18 2002/05/28 22:55:20 steve
|
|
|
|
|
* Callbacks can happen during calltf functions.
|
|
|
|
|
*
|
2002-05-19 07:18:16 +02:00
|
|
|
* Revision 1.17 2002/05/19 05:18:16 steve
|
|
|
|
|
* Add callbacks for vpiNamedEvent objects.
|
|
|
|
|
*
|
2002-05-18 04:34:11 +02:00
|
|
|
* Revision 1.16 2002/05/18 02:34:11 steve
|
|
|
|
|
* Add vpi support for named events.
|
|
|
|
|
*
|
|
|
|
|
* Add vpi_mode_flag to track the mode of the
|
|
|
|
|
* vpi engine. This is for error checking.
|
|
|
|
|
*
|
2002-05-09 05:34:31 +02:00
|
|
|
* Revision 1.15 2002/05/09 03:34:31 steve
|
|
|
|
|
* Handle null time and calltf pointers.
|
|
|
|
|
*
|
2002-05-04 05:17:29 +02:00
|
|
|
* Revision 1.14 2002/05/04 03:17:29 steve
|
|
|
|
|
* Properly free vpi callback objects.
|
|
|
|
|
*
|
2002-05-04 05:03:17 +02:00
|
|
|
* Revision 1.13 2002/05/04 03:03:17 steve
|
|
|
|
|
* Add simulator event callbacks.
|
|
|
|
|
*
|
2002-04-20 06:33:23 +02:00
|
|
|
* Revision 1.12 2002/04/20 04:33:23 steve
|
|
|
|
|
* Support specified times in cbReadOnlySync, and
|
|
|
|
|
* add support for cbReadWriteSync.
|
|
|
|
|
* Keep simulation time in a 64bit number.
|
|
|
|
|
*
|
2002-04-06 22:25:45 +02:00
|
|
|
* Revision 1.11 2002/04/06 20:25:45 steve
|
|
|
|
|
* cbValueChange automatically replays.
|
2001-06-22 00:54:12 +02:00
|
|
|
*/
|
|
|
|
|
|