From 7f95abc6ab6b9428cf2e5c3c2360eace1cfc6be3 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 25 Nov 2019 17:57:10 -0800 Subject: [PATCH] Make a pass at implementing cbAtEndOfSimTime. In Icarus Verilog, AtEndOfSimTime is practically the same as cbReadWriteSync, since the latter is after non-blocking events in Icarus Verilog. --- vpi_user.h | 1 + vvp/schedule.cc | 14 +++++++ vvp/schedule.h | 1 + vvp/vpi_callback.cc | 93 +++++++++++++++++++++++++++++++++++++-------- 4 files changed, 93 insertions(+), 16 deletions(-) diff --git a/vpi_user.h b/vpi_user.h index fd2cf4190..03f9c7c84 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -495,6 +495,7 @@ typedef struct t_cb_data { #define cbExitInteractive 22 #define cbInteractiveScopeChange 23 #define cbUnresolvedSystf 24 +#define cbAtEndOfSimTime 31 extern vpiHandle vpi_register_cb(p_cb_data data); extern PLI_INT32 vpi_remove_cb(vpiHandle ref); diff --git a/vvp/schedule.cc b/vvp/schedule.cc index e2a49e126..b9cbde7d5 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -1029,6 +1029,20 @@ void schedule_at_start_of_simtime(vvp_gen_event_t obj, vvp_time64_t delay) schedule_event_(cur, delay, SEQ_START); } +/* + * In the vvp runtime of Icarus Verilog, the SEQ_RWSYNC time step is + * after all of the non-blocking assignments, so is effectively the + * same as the ReadWriteSync time. + */ +void schedule_at_end_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_RWSYNC); +} + static vvp_time64_t schedule_time; vvp_time64_t schedule_simtime(void) { return schedule_time; } diff --git a/vvp/schedule.h b/vvp/schedule.h index d60748d04..3d75400ce 100644 --- a/vvp/schedule.h +++ b/vvp/schedule.h @@ -148,6 +148,7 @@ extern void schedule_generic(vvp_gen_event_t obj, vvp_time64_t delay, extern void schedule_functor(vvp_gen_event_t obj); extern void schedule_at_start_of_simtime(vvp_gen_event_t obj, vvp_time64_t delay); +extern void schedule_at_end_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 b6d980ccb..a3637b47e 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -357,7 +357,7 @@ static sync_callback* make_sync(p_cb_data data, bool readonly_flag) return obj; } -static struct __vpiCallback* make_afterdelay(p_cb_data data, bool simtime_flag) +static struct __vpiCallback* make_afterdelay(p_cb_data data) { sync_callback*obj = new sync_callback(data); struct sync_cb*cb = new sync_cb; @@ -378,21 +378,78 @@ static struct __vpiCallback* make_afterdelay(p_cb_data data, bool simtime_flag) 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); + schedule_generic(cb, tv, false); + + return obj; +} + +static struct __vpiCallback* make_at_start_of_sim_time(p_cb_data data) +{ + sync_callback*obj = new sync_callback(data); + struct sync_cb*cb = new sync_cb; + cb->sync_flag = false; + cb->handle = obj; + obj->cb_sync = cb; + + vvp_time64_t tv = 0; + switch (obj->cb_time.type) { + case vpiSimTime: + tv = vpip_timestruct_to_time(&obj->cb_time); + break; + + default: + fprintf(stderr, "Unsupported time type %d.\n", + (int)obj->cb_time.type); + assert(0); + break; } + 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); + + return obj; +} + +static struct __vpiCallback* make_at_end_of_sim_time(p_cb_data data) +{ + sync_callback*obj = new sync_callback(data); + struct sync_cb*cb = new sync_cb; + cb->sync_flag = false; + cb->handle = obj; + obj->cb_sync = cb; + + vvp_time64_t tv = 0; + switch (obj->cb_time.type) { + case vpiSimTime: + tv = vpip_timestruct_to_time(&obj->cb_time); + break; + + default: + fprintf(stderr, "Unsupported time type %d.\n", + (int)obj->cb_time.type); + assert(0); + break; + } + + vvp_time64_t cur = schedule_simtime(); + if (cur > tv) { + tv = 0; + assert(0); + } else if (cur == tv) { + tv = 0; + } else { + tv -= cur; + } + schedule_at_end_of_simtime(cb, tv); + return obj; } @@ -573,11 +630,15 @@ vpiHandle vpi_register_cb(p_cb_data data) break; case cbAtStartOfSimTime: - obj = make_afterdelay(data, true); + obj = make_at_start_of_sim_time(data); + break; + + case cbAtEndOfSimTime: + obj = make_at_end_of_sim_time(data); break; case cbAfterDelay: - obj = make_afterdelay(data, false); + obj = make_afterdelay(data); break; case cbEndOfCompile: