VPI cbNextSimTime: Fill out time and don't call newly generated CBs

Fill out cb_data.time and require it is non-NULL.

Record the last NextSimTime CB so we don't call CBs added during this timestep.

(cherry picked from PR #740)
This commit is contained in:
Jevin Sweval 2022-07-05 12:24:43 -07:00 committed by Martin Whitaker
parent 2299fc1b2b
commit 53e8a139b0
16 changed files with 236 additions and 21 deletions

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2022 Jevin Sweval (jevinsweval@gmail.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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "vpi_user.h"
# include <assert.h>
#if defined(TEST_SCALED) || defined(TEST_SUPPRESS)
#if defined(TEST_SCALED)
#define TIME_TYPE vpiScaledRealTime
#elif defined(TEST_SUPPRESS)
#define TIME_TYPE vpiSuppressTime
#endif
static s_vpi_time cb_timerec = {TIME_TYPE, 0, 0, 0};
#endif
static PLI_INT32 dummy_cb(struct t_cb_data* cb) {
(void)cb; /* unused */
return 0;
}
static PLI_INT32 register_nextsimtime(struct t_cb_data* cb) {
(void)cb; /* unused */
s_cb_data cb_data;
#if defined(TEST_SCALED) || defined(TEST_SUPPRESS)
cb_data.time = &cb_timerec;
#elif defined(TEST_NULL)
cb_data.time = NULL;
#endif
cb_data.reason = cbNextSimTime;
cb_data.cb_rtn = dummy_cb;
vpiHandle hndl = NULL;
assert((hndl = vpi_register_cb(&cb_data)) && vpi_free_object(hndl));
return 0;
}
static void register_functions(void)
{
s_cb_data cb_data;
cb_data.reason = cbEndOfCompile;
cb_data.cb_rtn = register_nextsimtime;
vpi_register_cb(&cb_data);
}
void (*vlog_startup_routines[])(void) = {
register_functions,
NULL
};

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2022 Jevin Sweval (jevinsweval@gmail.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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "vpi_user.h"
# include <assert.h>
static s_vpi_time cb_timerec = {vpiSimTime, 0, 0, 0};
static PLI_INT32 register_nextsimtime(struct t_cb_data* cb);
static PLI_INT32 nextsimtime_cb(struct t_cb_data* cb) {
uint64_t nextsimtime = ((uint64_t)cb->time->high << 32) | cb->time->low;
s_vpi_time timerec;
timerec.type = vpiSimTime;
vpi_get_time(NULL, &timerec);
uint64_t time = ((uint64_t)timerec.high << 32) | timerec.low;
vpi_printf("nextsimtime: %" PLI_UINT64_FMT " vpi_get_time: %" PLI_UINT64_FMT "\n",
nextsimtime, time);
register_nextsimtime(NULL);
return 0;
}
static PLI_INT32 register_nextsimtime(struct t_cb_data* cb) {
(void)cb; /* unused */
s_cb_data cb_data;
cb_data.time = &cb_timerec;
cb_data.reason = cbNextSimTime;
cb_data.cb_rtn = nextsimtime_cb;
vpiHandle hndl = NULL;
assert((hndl = vpi_register_cb(&cb_data)) && vpi_free_object(hndl));
return 0;
}
static void register_functions(void)
{
s_cb_data cb_data;
cb_data.reason = cbEndOfCompile;
cb_data.cb_rtn = register_nextsimtime;
vpi_register_cb(&cb_data);
}
void (*vlog_startup_routines[])(void) = {
register_functions,
NULL
};

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2022 Jevin Sweval (jevinsweval@gmail.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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
module main;
initial begin
$display("time 0: %0d", $time);
#1 $display("time 1: %0d", $time);
#3 $display("time 4: %0d", $time);
#1;
end
endmodule // main

View File

@ -0,0 +1,2 @@
#define TEST_NULL
#include "nextsimtime_errors.c"

View File

@ -0,0 +1 @@
`include "vpi/nextsimtime_fill_time.v"

View File

@ -0,0 +1,2 @@
#define TEST_SCALED
#include "nextsimtime_errors.c"

View File

@ -0,0 +1 @@
`include "vpi/nextsimtime_fill_time.v"

View File

@ -0,0 +1,2 @@
#define TEST_SUPPRESS
#include "nextsimtime_errors.c"

View File

@ -0,0 +1 @@
`include "vpi/nextsimtime_fill_time.v"

View File

@ -47,6 +47,7 @@ static PLI_INT32 test_next_compiletf(PLI_BYTE8 *name)
static PLI_INT32 test_next_calltf(PLI_BYTE8 *name) static PLI_INT32 test_next_calltf(PLI_BYTE8 *name)
{ {
vpiHandle sys, argv, value; vpiHandle sys, argv, value;
static s_vpi_time dummy_time = {vpiSimTime, 0, 0, 0};
(void)name; /* Parameter is not used. */ (void)name; /* Parameter is not used. */
@ -59,6 +60,7 @@ static PLI_INT32 test_next_calltf(PLI_BYTE8 *name)
for (value = vpi_scan(argv) ; value ; value = vpi_scan(argv)) { for (value = vpi_scan(argv) ; value ; value = vpi_scan(argv)) {
s_cb_data cb; s_cb_data cb;
cb.reason = cbNextSimTime; cb.reason = cbNextSimTime;
cb.time = &dummy_time;
cb.cb_rtn = next_sim_time_callback; cb.cb_rtn = next_sim_time_callback;
cb.user_data = (char*)value; cb.user_data = (char*)value;
vpi_register_cb(&cb); vpi_register_cb(&cb);

View File

@ -0,0 +1,8 @@
Compiling vpi/nextsimtime_fill_time.c...
Making nextsimtime_fill_time.vpi from nextsimtime_fill_time.o...
time 0: 0
nextsimtime: 1 vpi_get_time: 1
time 1: 1
nextsimtime: 4 vpi_get_time: 4
time 4: 4
nextsimtime: 5 vpi_get_time: 5

View File

@ -0,0 +1,3 @@
Compiling vpi/nextsimtime_null_time.c...
Making nextsimtime_null_time.vpi from nextsimtime_null_time.o...
ERROR: VPI: cbNextSimTime time pointer must be valid.

View File

@ -0,0 +1,3 @@
Compiling vpi/nextsimtime_scaled_time.c...
Making nextsimtime_scaled_time.vpi from nextsimtime_scaled_time.o...
ERROR: VPI: cbNextSimTime time type vpiScaledRealTime is not implemented.

View File

@ -0,0 +1,3 @@
Compiling vpi/nextsimtime_suppress_time.c...
Making nextsimtime_suppress_time.vpi from nextsimtime_suppress_time.o...
ERROR: VPI: cbNextSimTime time type cannot be vpiSuppressTime.

View File

@ -99,6 +99,10 @@ hello_tf normal hello_tf.c hello_tf.log
hello_vpi normal hello_vpi.c hello.log hello_vpi normal hello_vpi.c hello.log
hello_vpi2 normal hello_vpi2.c hello2.log vpi/hello_vpi1.c hello_vpi2 normal hello_vpi2.c hello2.log vpi/hello_vpi1.c
listparams normal listparams.c listparams.log listparams normal listparams.c listparams.log
nextsimtime_fill_time normal nextsimtime_fill_time.c nextsimtime_fill_time.gold
nextsimtime_null_time normal nextsimtime_null_time.c nextsimtime_null_time.gold
nextsimtime_scaled_time normal nextsimtime_scaled_time.c nextsimtime_scaled_time.gold
nextsimtime_suppress_time normal nextsimtime_suppress_time.c nextsimtime_suppress_time.gold
memmon normal,-g1995 memmon.c memmon.log memmon normal,-g1995 memmon.c memmon.log
memwide normal memwide.cc memwide.log memwide normal memwide.cc memwide.log
mipname normal mipname.c mipname.log mipname normal mipname.c mipname.log

View File

@ -577,17 +577,30 @@ void vpiPostsim(void) {
void vpiNextSimTime(void) void vpiNextSimTime(void)
{ {
simulator_callback* cur; simulator_callback* cur;
simulator_callback* last_cb = NextSimTime;
assert(vpi_mode_flag == VPI_MODE_NONE); assert(vpi_mode_flag == VPI_MODE_NONE);
vpi_mode_flag = VPI_MODE_RWSYNC; vpi_mode_flag = VPI_MODE_RWSYNC;
/* Find the last event currently in the list. Remember this callback so
* we don't call additional NextSimTime CB's generated during this timestep.
*/
while (last_cb && last_cb->next) {
last_cb = dynamic_cast<simulator_callback*>(last_cb->next);
}
while (NextSimTime) { while (NextSimTime) {
cur = NextSimTime; cur = NextSimTime;
NextSimTime = dynamic_cast<simulator_callback*>(cur->next); NextSimTime = dynamic_cast<simulator_callback*>(cur->next);
if (cur->cb_data.cb_rtn != 0) { if (cur->cb_data.cb_rtn != 0) {
(cur->cb_data.cb_rtn)(&cur->cb_data); // only vpiSimTime implemented right now
} vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime());
delete cur; (cur->cb_data.cb_rtn)(&cur->cb_data);
}
delete cur;
if (cur == last_cb) {
break;
}
} }
vpi_mode_flag = VPI_MODE_NONE; vpi_mode_flag = VPI_MODE_NONE;
@ -599,21 +612,37 @@ static simulator_callback* make_prepost(p_cb_data data)
/* Insert at head of list */ /* Insert at head of list */
switch (data->reason) { switch (data->reason) {
case cbEndOfCompile: case cbEndOfCompile:
obj->next = EndOfCompile; obj->next = EndOfCompile;
EndOfCompile = obj; EndOfCompile = obj;
break; break;
case cbStartOfSimulation: case cbStartOfSimulation:
obj->next = StartOfSimulation; obj->next = StartOfSimulation;
StartOfSimulation = obj; StartOfSimulation = obj;
break; break;
case cbEndOfSimulation: case cbEndOfSimulation:
obj->next = EndOfSimulation; obj->next = EndOfSimulation;
EndOfSimulation = obj; EndOfSimulation = obj;
break; break;
case cbNextSimTime: case cbNextSimTime:
obj->next = NextSimTime; if (!data->time) {
NextSimTime = obj; vpi_printf("ERROR: VPI: cbNextSimTime time pointer must be valid.\n");
vpi_control(vpiFinish, 1);
break;
}
if (data->time->type == vpiSuppressTime) {
vpi_printf("ERROR: VPI: cbNextSimTime time type cannot be vpiSuppressTime.\n");
vpi_control(vpiFinish, 1);
break;
}
if (data->time->type == vpiScaledRealTime) {
vpi_printf("ERROR: VPI: cbNextSimTime time type vpiScaledRealTime is not implemented.\n");
vpi_control(vpiFinish, 1);
break;
}
obj->next = NextSimTime;
NextSimTime = obj;
break;
} }
return obj; return obj;