diff --git a/vvp/schedule.cc b/vvp/schedule.cc index aca2ba308..104ed30d5 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -56,9 +56,18 @@ struct event_s { }; struct event_time_s { - event_time_s() { count_time_events += 1; } + event_time_s() { + count_time_events += 1; + start = 0; + active = 0; + nbassign = 0; + rwsync = 0; + rosync = 0; + del_thr = 0; + } vvp_time64_t delay; + struct event_s*start; struct event_s*active; struct event_s*nbassign; struct event_s*rwsync; @@ -383,8 +392,8 @@ static void signals_revert(void) * itself, and the structure is placed in the right place in the * queue. */ -typedef enum event_queue_e { SEQ_ACTIVE, SEQ_NBASSIGN, SEQ_RWSYNC, SEQ_ROSYNC, - DEL_THREAD } event_queue_t; +typedef enum event_queue_e { SEQ_START, SEQ_ACTIVE, SEQ_NBASSIGN, + SEQ_RWSYNC, SEQ_ROSYNC, DEL_THREAD } event_queue_t; static void schedule_event_(struct event_s*cur, vvp_time64_t delay, event_queue_t select_queue) @@ -397,11 +406,6 @@ static void schedule_event_(struct event_s*cur, vvp_time64_t delay, /* Is the event_time list completely empty? Create the first event_time object. */ ctim = new struct event_time_s; - ctim->active = 0; - ctim->nbassign = 0; - ctim->rwsync = 0; - ctim->rosync = 0; - ctim->del_thr = 0; ctim->delay = delay; ctim->next = 0; sched_list = ctim; @@ -411,11 +415,6 @@ static void schedule_event_(struct event_s*cur, vvp_time64_t delay, /* Am I looking for an event before the first event_time? If so, create a new event_time to go in front. */ struct event_time_s*tmp = new struct event_time_s; - tmp->active = 0; - tmp->nbassign = 0; - tmp->rwsync = 0; - tmp->rosync = 0; - tmp->del_thr = 0; tmp->delay = delay; tmp->next = ctim; ctim->delay -= delay; @@ -433,11 +432,6 @@ static void schedule_event_(struct event_s*cur, vvp_time64_t delay, if (ctim->delay > delay) { struct event_time_s*tmp = new struct event_time_s; - tmp->active = 0; - tmp->nbassign = 0; - tmp->rwsync = 0; - tmp->rosync = 0; - tmp->del_thr = 0; tmp->delay = delay; tmp->next = prev->next; prev->next = tmp; @@ -450,11 +444,6 @@ static void schedule_event_(struct event_s*cur, vvp_time64_t delay, } else { assert(ctim->next == 0); struct event_time_s*tmp = new struct event_time_s; - tmp->active = 0; - tmp->nbassign = 0; - tmp->rwsync = 0; - tmp->rosync = 0; - tmp->del_thr = 0; tmp->delay = delay - ctim->delay; tmp->next = 0; ctim->next = tmp; @@ -469,6 +458,16 @@ static void schedule_event_(struct event_s*cur, vvp_time64_t delay, switch (select_queue) { + case SEQ_START: + if (ctim->start == 0) { + ctim->start = cur; + } else { + cur->next = ctim->active->next; + ctim->active->next = cur; + ctim->active = cur; + } + break; + case SEQ_ACTIVE: if (ctim->active == 0) { ctim->active = cur; @@ -550,7 +549,6 @@ static void schedule_event_push_(struct event_s*cur) ctim->active->next = cur; } - void schedule_vthread(vthread_t thr, vvp_time64_t delay, bool push_flag) { struct vthread_event_s*cur = new vthread_event_s; @@ -673,6 +671,15 @@ void schedule_generic(vvp_gen_event_t obj, vvp_time64_t delay, sync_flag? (ro_flag?SEQ_ROSYNC:SEQ_RWSYNC) : SEQ_ACTIVE); } +void schedule_at_start_of_simtime(vvp_gen_event_t obj, vvp_time64_t delay) +{ + struct generic_event_s*cur = new generic_event_s; + + cur->obj = obj; + cur->delete_obj_when_done = false; + schedule_event_(cur, delay, SEQ_START); +} + static vvp_time64_t schedule_time; vvp_time64_t schedule_simtime(void) { return schedule_time; } @@ -767,6 +774,17 @@ void schedule_simulate(void) ctim->delay = 0; vpiNextSimTime(); + // Process the cbAtStartOfSimTime callbacks. + while (ctim->start) { + struct event_s*cur = ctim->start->next; + if (cur->next == cur) { + ctim->start = 0; + } else { + ctim->start->next = cur->next; + } + cur->run_run(); + delete (cur); + } } diff --git a/vvp/schedule.h b/vvp/schedule.h index 391643d2f..4267441ce 100644 --- a/vvp/schedule.h +++ b/vvp/schedule.h @@ -103,6 +103,8 @@ extern void schedule_generic(vvp_gen_event_t obj, vvp_time64_t delay, bool sync_flag, bool ro_flag =true, bool delete_obj_when_done =false); +extern void schedule_at_start_of_simtime(vvp_gen_event_t obj, vvp_time64_t delay); + /* Use this is schedule thread deletion (after rosync). */ extern void schedule_del_thr(vthread_t thr); diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index bafc05745..f5c702330 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -266,7 +266,7 @@ static struct __vpiCallback* make_sync(p_cb_data data, bool readonly_flag) return obj; } -static struct __vpiCallback* make_afterdelay(p_cb_data data) +static struct __vpiCallback* make_afterdelay(p_cb_data data, bool simtime_flag) { struct __vpiCallback*obj = new_vpi_callback(); obj->cb_data = *data; @@ -281,19 +281,34 @@ static struct __vpiCallback* make_afterdelay(p_cb_data data) cb->handle = obj; obj->cb_sync = cb; + vvp_time64_t tv; switch (obj->cb_time.type) { - case vpiSimTime: { - vvp_time64_t tv = vpip_timestruct_to_time(&obj->cb_time); - schedule_generic(cb, tv, false); - break; - } + case vpiSimTime: + tv = vpip_timestruct_to_time(&obj->cb_time); + break; default: fprintf(stderr, "Unsupported time type %d.\n", obj->cb_time.type); assert(0); + tv = 0; break; } + if (simtime_flag) { + vvp_time64_t cur = schedule_simtime(); + if (cur > tv) { + tv = 0; + assert(0); + } else if (cur == tv) { + tv = 0; + } else { + tv -= cur; + } + schedule_at_start_of_simtime(cb, tv); + } else { + schedule_generic(cb, tv, false); + } + return obj; } @@ -432,8 +447,12 @@ vpiHandle vpi_register_cb(p_cb_data data) obj = make_sync(data, false); break; + case cbAtStartOfSimTime: + obj = make_afterdelay(data, true); + break; + case cbAfterDelay: - obj = make_afterdelay(data); + obj = make_afterdelay(data, false); break; case cbEndOfCompile: