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.
This commit is contained in:
Stephen Williams 2019-11-25 17:57:10 -08:00
parent b25df08c99
commit 7f95abc6ab
4 changed files with 93 additions and 16 deletions

View File

@ -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);

View File

@ -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; }

View File

@ -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);

View File

@ -357,7 +357,33 @@ 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;
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;
}
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;
@ -378,7 +404,6 @@ 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;
@ -389,10 +414,42 @@ static struct __vpiCallback* make_afterdelay(p_cb_data data, bool simtime_flag)
tv -= cur;
}
schedule_at_start_of_simtime(cb, tv);
} else {
schedule_generic(cb, tv, false);
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: