diff --git a/vvp/schedule.cc b/vvp/schedule.cc index aa5416b07..5e176ac14 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -1038,6 +1038,10 @@ extern void vpiStartOfSim(); extern void vpiPostsim(); extern void vpiNextSimTime(void); +static bool sim_at_rosync = false; +bool schedule_at_rosync(void) +{ return sim_at_rosync; } + /* * The scheduler uses this function to drain the rosync events of the * current time. The ctim object is still in the event queue, because @@ -1050,6 +1054,7 @@ extern void vpiNextSimTime(void); */ static void run_rosync(struct event_time_s*ctim) { + sim_at_rosync = true; while (ctim->rosync) { struct event_s*cur = ctim->rosync->next; if (cur->next == cur) { @@ -1061,6 +1066,7 @@ static void run_rosync(struct event_time_s*ctim) cur->run_run(); delete cur; } + sim_at_rosync = false; while (ctim->del_thr) { struct event_s*cur = ctim->del_thr->next; diff --git a/vvp/schedule.h b/vvp/schedule.h index cd0deb79c..f47057060 100644 --- a/vvp/schedule.h +++ b/vvp/schedule.h @@ -164,6 +164,13 @@ extern void schedule_simulate(void); */ extern vvp_time64_t schedule_simtime(void); +/* + * Indicate that the simulator is running the rosync callbacks. This is + * used to prevent the callbacks from performing any write operations + * in the current simulation time slot. + */ +extern bool schedule_at_rosync(void); + /* * This function is the equivalent of the $finish system task. It * tells the simulator that simulation is done, the current thread diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index b914a73eb..c77ebee37 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2016 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 @@ -1067,13 +1067,13 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, vvp_time64_t dly; int scale; - if (vpi_get(vpiAutomatic, obj)) { - fprintf(stderr, "vpi error: cannot put a value with " - "a delay on automatically allocated " - "variable '%s'\n", - vpi_get_str(vpiName, obj)); - return 0; - } + if (vpi_get(vpiAutomatic, obj)) { + fprintf(stderr, "VPI error: cannot put a value with " + "a delay on automatically allocated " + "variable '%s'.\n", + vpi_get_str(vpiName, obj)); + return 0; + } assert(when != 0); @@ -1095,6 +1095,13 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, break; } + if ((dly == 0) && schedule_at_rosync()) { + fprintf(stderr, "VPI error: attempted to put a value to " + "variable '%s' during a read-only synch " + "callback.\n", vpi_get_str(vpiName, obj)); + return 0; + } + vpip_put_value_event*put = new vpip_put_value_event; put->handle = obj; put->value = *vp; @@ -1132,6 +1139,13 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, return 0; } + if (schedule_at_rosync()) { + fprintf(stderr, "VPI error: attempted to put a value to " + "variable '%s' during a read-only synch " + "callback.\n", vpi_get_str(vpiName, obj)); + return 0; + } + obj->vpi_put_value(vp, flags); return 0;