diff --git a/vvp/arith.cc b/vvp/arith.cc index 6eaf6c726..aa3c0c721 100644 --- a/vvp/arith.cc +++ b/vvp/arith.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: arith.cc,v 1.9 2001/07/07 02:57:33 steve Exp $" +#ident "$Id: arith.cc,v 1.10 2001/07/11 02:27:21 steve Exp $" #endif # include "arith.h" @@ -110,8 +110,6 @@ vvp_arith_sum::~vvp_arith_sum() void vvp_arith_sum::set(vvp_ipoint_t i, functor_t f, bool push) { - assert(wid_ <= 8*sizeof(unsigned long)); - unsigned page = 0; unsigned pbit = 0; unsigned long carry = 0; @@ -468,6 +466,9 @@ void vvp_shiftr::set(vvp_ipoint_t i, functor_t f, bool push) /* * $Log: arith.cc,v $ + * Revision 1.10 2001/07/11 02:27:21 steve + * Add support for REadOnlySync and monitors. + * * Revision 1.9 2001/07/07 02:57:33 steve * Add the .shift/r functor. * diff --git a/vvp/memory.cc b/vvp/memory.cc index 35e4b7c43..d8051287a 100644 --- a/vvp/memory.cc +++ b/vvp/memory.cc @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: memory.cc,v 1.4 2001/06/15 03:28:31 steve Exp $" +#ident "$Id: memory.cc,v 1.5 2001/07/11 02:27:21 steve Exp $" #endif #include "memory.h" @@ -437,6 +437,8 @@ inline static struct mem_assign_s* ma_alloc() cur = (struct mem_assign_s*) malloc(sizeof(struct mem_assign_s)); else ma_free_list = cur->next; + + cur->sync_flag = false; return cur; } diff --git a/vvp/schedule.cc b/vvp/schedule.cc index 74d5830c0..486d35dbd 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: schedule.cc,v 1.10 2001/05/30 03:02:35 steve Exp $" +#ident "$Id: schedule.cc,v 1.11 2001/07/11 02:27:21 steve Exp $" #endif # include "schedule.h" @@ -27,6 +27,7 @@ # include # include +# include /* * The event queue is arranged as a skip list, with the simulation * time the key to the list. The simulation time is stored in each @@ -90,9 +91,20 @@ inline static void e_free(struct event_s* cur) } /* - * This is the head of the list of pending events. + * This is the head of the list of pending events. This includes all + * the events that have not been executed yet, and reaches into the + * future. */ -static struct event_s* list = 0; +static struct event_s* sched_list = 0; + +/* + * At the current time, events that are marked as synch events are put + * into this list and held off until the time step is about to + * advance. Then the events in this list are run and the clock is + * allowed to advance. + */ +static struct event_s* synch_list = 0; + /* * This flag is true until a VPI task or function finishes the @@ -122,20 +134,20 @@ static void schedule_event_(struct event_s*cur) /* If the list is completely empty, then start the list with this the only event. */ - if (list == 0) { - list = cur; + if (sched_list == 0) { + sched_list = cur; cur->next = 0; return; } - struct event_s*idx = list; + struct event_s*idx = sched_list; if (cur->delay < idx->delay) { /* If this new event is earlier then even the first event, then insert it in front. Adjust the delay of the next event, and set the start to me. */ idx->delay -= cur->delay; cur->next = idx; - list = cur; + sched_list = cur; } else { @@ -173,6 +185,43 @@ static void schedule_event_(struct event_s*cur) } } +/* + * The synch_list is managed as a doubly-linked circular list. There is + * no need for the skip capabilities, so use the "last" member as a + * prev pointer. This function appends the event to the synch_list. + */ +static void postpone_sync_event(struct event_s*cur) +{ + if (synch_list == 0) { + synch_list = cur; + cur->next = cur; + cur->last = cur; + return; + } + + cur->next = synch_list; + cur->last = synch_list->last; + cur->next->last = cur; + cur->last->next = cur; +} + +static struct event_s* pull_sync_event(void) +{ + if (synch_list == 0) + return 0; + + struct event_s*cur = synch_list; + synch_list = cur->next; + if (cur == synch_list) { + synch_list = 0; + } else { + cur->next->last = cur->last; + cur->last->next = cur->next; + } + + return cur; +} + void schedule_vthread(vthread_t thr, unsigned delay) { struct event_s*cur = e_alloc(); @@ -228,30 +277,47 @@ void schedule_simulate(void) { schedule_time = 0; - while (schedule_runnable && list) { + while (schedule_runnable && sched_list) { /* Pull the first item off the list. Fixup the last pointer in the next cell, if necessary. */ - struct event_s*cur = list; - list = cur->next; + struct event_s*cur = sched_list; + sched_list = cur->next; if (cur->last != cur) { - assert(list); - assert(list->delay == 0); - list->last = cur->last; + assert(sched_list); + assert(sched_list->delay == 0); + sched_list->last = cur->last; } - schedule_time += cur->delay; - //printf("TIME: %u\n", schedule_time); + /* If the time is advancing, then first run the + postponed sync events. Run them all. */ + if (cur->delay > 0) { + struct event_s*sync_cur; + while ( (sync_cur = pull_sync_event()) ) { + assert(sync_cur->type == TYPE_GEN); + if (sync_cur->obj && sync_cur->obj->run) { + assert(sync_cur->obj->sync_flag); + sync_cur->obj->run(sync_cur->obj, sync_cur->val); + } + e_free(sync_cur); + } + + + schedule_time += cur->delay; + //printf("TIME: %u\n", schedule_time); + } switch (cur->type) { case TYPE_THREAD: vthread_run(cur->thr); + e_free(cur); break; case TYPE_PROP: //printf("Propagate %p\n", cur->fun); functor_propagate(cur->fun); + e_free(cur); break; case TYPE_ASSIGN: @@ -269,21 +335,31 @@ void schedule_simulate(void) functor_set(cur->fun, cur->val, HiZ, false); break; } + e_free(cur); break; case TYPE_GEN: - if (cur->obj && cur->obj->run) - cur->obj->run(cur->obj, cur->val); + if (cur->obj && cur->obj->run) { + if (cur->obj->sync_flag == false) { + cur->obj->run(cur->obj, cur->val); + e_free(cur); + + } else { + postpone_sync_event(cur); + } + } break; } - e_free(cur); } } /* * $Log: schedule.cc,v $ + * Revision 1.11 2001/07/11 02:27:21 steve + * Add support for REadOnlySync and monitors. + * * Revision 1.10 2001/05/30 03:02:35 steve * Propagate strength-values instead of drive strengths. * diff --git a/vvp/schedule.h b/vvp/schedule.h index 14ee8e072..083e94de6 100644 --- a/vvp/schedule.h +++ b/vvp/schedule.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: schedule.h,v 1.6 2001/05/02 01:38:13 steve Exp $" +#ident "$Id: schedule.h,v 1.7 2001/07/11 02:27:21 steve Exp $" #endif # include "vthread.h" @@ -63,7 +63,8 @@ extern void schedule_generic(vvp_gen_event_t obj, unsigned char val, struct vvp_gen_event_s { - void (*run)(vvp_gen_event_t obj, unsigned char val); + void (*run)(vvp_gen_event_t obj, unsigned char val); + bool sync_flag; }; /* @@ -94,6 +95,9 @@ extern bool schedule_finished(void); /* * $Log: schedule.h,v $ + * Revision 1.7 2001/07/11 02:27:21 steve + * Add support for REadOnlySync and monitors. + * * Revision 1.6 2001/05/02 01:38:13 steve * Describe a generic event a bit. * diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index fe2972717..18ec7cdb2 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vpi_callback.cc,v 1.2 2001/06/21 23:05:08 steve Exp $" +#ident "$Id: vpi_callback.cc,v 1.3 2001/07/11 02:27:21 steve Exp $" #endif /* @@ -58,7 +58,11 @@ static struct __vpiCallback* make_value_change(p_cb_data data) struct __vpiCallback*obj = new __vpiCallback; obj->base.vpi_type = &callback_rt; obj->cb_data = *data; + obj->cb_time = *(data->time); + obj->cb_data.time = &obj->cb_time; + assert(data->obj); + assert(data->obj->vpi_type); assert((data->obj->vpi_type->type_code == vpiReg) || (data->obj->vpi_type->type_code == vpiNet)); struct __vpiSignal*sig = reinterpret_cast<__vpiSignal*>(data->obj); @@ -81,6 +85,45 @@ static struct __vpiCallback* make_value_change(p_cb_data data) return obj; } +struct sync_cb : public vvp_gen_event_s { + struct __vpiCallback*handle; +}; + +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; + cur->cb_data.time->low = schedule_simtime(); + cur->cb_data.time->high = 0; + (cur->cb_data.cb_rtn)(&cur->cb_data); + + delete cur; +} + +static struct __vpiCallback* make_sync(p_cb_data data) +{ + struct __vpiCallback*obj = new __vpiCallback; + obj->base.vpi_type = &callback_rt; + obj->cb_data = *data; + 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 = true; + cb->run = &make_sync_run; + cb->handle = obj; + obj->cb_sync = cb; + + schedule_generic(cb, 0, 0); + return obj; +} + vpiHandle vpi_register_cb(p_cb_data data) { struct __vpiCallback*obj = 0; @@ -91,6 +134,10 @@ vpiHandle vpi_register_cb(p_cb_data data) obj = make_value_change(data); break; + case cbReadOnlySynch: + obj = make_sync(data); + break; + default: fprintf(stderr, "vpi error: vpi_register_cb invalid or " "unsupported callback reason: %d\n", @@ -104,6 +151,8 @@ vpiHandle vpi_register_cb(p_cb_data data) int vpi_remove_cb(vpiHandle ref) { + assert(ref); + assert(ref->vpi_type); assert(ref->vpi_type->type_code == vpiCallback); struct __vpiCallback*obj = reinterpret_cast<__vpiCallback*>(ref); @@ -150,6 +199,9 @@ void vpip_trip_monitor_callbacks(void) /* * $Log: vpi_callback.cc,v $ + * Revision 1.3 2001/07/11 02:27:21 steve + * Add support for REadOnlySync and monitors. + * * Revision 1.2 2001/06/21 23:05:08 steve * Some documentation of callback behavior. * diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index ee33a41b5..5f6923a39 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vpi_priv.cc,v 1.7 2001/06/30 23:03:17 steve Exp $" +#ident "$Id: vpi_priv.cc,v 1.8 2001/07/11 02:27:21 steve Exp $" #endif # include "vpi_priv.h" @@ -55,12 +55,12 @@ static int vpip_get_global(int property) int vpi_get(int property, vpiHandle ref) { - if (property == vpiType) - return ref->vpi_type->type_code; - if (ref == 0) return vpip_get_global(property); + if (property == vpiType) + return ref->vpi_type->type_code; + if (ref->vpi_type->vpi_get_ == 0) return -1; @@ -151,6 +151,9 @@ extern "C" void vpi_sim_vcontrol(int operation, va_list ap) /* * $Log: vpi_priv.cc,v $ + * Revision 1.8 2001/07/11 02:27:21 steve + * Add support for REadOnlySync and monitors. + * * Revision 1.7 2001/06/30 23:03:17 steve * support fast programming by only writing the bits * that are listed in the input file. diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 6151d3a28..994d387bf 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vpi_priv.h,v 1.18 2001/06/30 23:03:17 steve Exp $" +#ident "$Id: vpi_priv.h,v 1.19 2001/07/11 02:27:21 steve Exp $" #endif # include "vpi_user.h" @@ -125,10 +125,15 @@ extern struct __vpiSignal*vpip_sig_from_ptr(vvp_ipoint_t ptr); * callback. The handle is stored by the run time, and it triggered * when the run-time thing that it is waiting for happens. */ + +struct sync_cb; struct __vpiCallback { struct __vpiHandle base; struct t_cb_data cb_data; + struct t_vpi_time cb_time; + + struct sync_cb* cb_sync; struct __vpiCallback*next; }; @@ -254,6 +259,9 @@ extern void vpip_set_time_precision(int pres); /* * $Log: vpi_priv.h,v $ + * Revision 1.19 2001/07/11 02:27:21 steve + * Add support for REadOnlySync and monitors. + * * Revision 1.18 2001/06/30 23:03:17 steve * support fast programming by only writing the bits * that are listed in the input file.