diff --git a/ivtest/vpi/nextsimtime_cb.c b/ivtest/vpi/nextsimtime_cb.c new file mode 100644 index 000000000..62da1b18c --- /dev/null +++ b/ivtest/vpi/nextsimtime_cb.c @@ -0,0 +1,96 @@ +/* + * 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 + +#if defined(TEST_SIM_TIME) +#define TIME_TYPE vpiSimTime +#elif defined(TEST_SCALED_TIME) +#define TIME_TYPE vpiScaledRealTime +#else +#define TIME_TYPE vpiSuppressTime +#endif + +#ifndef TEST_NULL_TIME +static s_vpi_time cb_timerec = {TIME_TYPE, 0, 0, 0}; +#endif + +static PLI_INT32 register_nextsimtime(struct t_cb_data* cb); + + +static PLI_INT32 nextsimtime_cb(struct t_cb_data* cb) { + s_vpi_time timerec; + +#ifdef TEST_NULL_TIME + (void)cb; +#else + assert(cb->time && (cb->time->type == TIME_TYPE)); +#endif + +#if defined(TEST_SCALED_TIME) || defined(TEST_SIM_TIME) + timerec = *(cb->time); +#else + timerec.type = vpiSimTime; + vpi_get_time(NULL, &timerec); +#endif + + +#ifdef TEST_SCALED_TIME + vpi_printf("nextsimtime: %f\n", timerec.real); +#else + uint64_t time = ((uint64_t)timerec.high << 32) | timerec.low; + vpi_printf("nextsimtime: %" PLI_UINT64_FMT "\n", time); +#endif + register_nextsimtime(NULL); + return 0; +} + +static PLI_INT32 register_nextsimtime(struct t_cb_data* cb) { + (void)cb; /* unused */ + s_cb_data cb_data; +#ifdef TEST_NULL_TIME + cb_data.time = 0; +#else + cb_data.time = &cb_timerec; +#endif +#ifdef TEST_SCALED_TIME + cb_data.obj = vpi_handle_by_name("main", NULL); +#else + cb_data.obj = 0; +#endif + 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 +}; diff --git a/ivtest/vpi/nextsimtime_cb.v b/ivtest/vpi/nextsimtime_cb.v new file mode 100644 index 000000000..aec944aaa --- /dev/null +++ b/ivtest/vpi/nextsimtime_cb.v @@ -0,0 +1,31 @@ +/* + * 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 + */ + +`timescale 1s/1ms + +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 diff --git a/ivtest/vpi/nextsimtime_cb1.c b/ivtest/vpi/nextsimtime_cb1.c new file mode 100644 index 000000000..b90273b4b --- /dev/null +++ b/ivtest/vpi/nextsimtime_cb1.c @@ -0,0 +1,2 @@ +#define TEST_SIM_TIME +#include "nextsimtime_cb.c" diff --git a/ivtest/vpi/nextsimtime_cb1.v b/ivtest/vpi/nextsimtime_cb1.v new file mode 100644 index 000000000..d7c7cff1d --- /dev/null +++ b/ivtest/vpi/nextsimtime_cb1.v @@ -0,0 +1 @@ +`include "vpi/nextsimtime_cb.v" diff --git a/ivtest/vpi/nextsimtime_cb2.c b/ivtest/vpi/nextsimtime_cb2.c new file mode 100644 index 000000000..35d6dd690 --- /dev/null +++ b/ivtest/vpi/nextsimtime_cb2.c @@ -0,0 +1,2 @@ +#define TEST_SCALED_TIME +#include "nextsimtime_cb.c" diff --git a/ivtest/vpi/nextsimtime_cb2.v b/ivtest/vpi/nextsimtime_cb2.v new file mode 100644 index 000000000..d7c7cff1d --- /dev/null +++ b/ivtest/vpi/nextsimtime_cb2.v @@ -0,0 +1 @@ +`include "vpi/nextsimtime_cb.v" diff --git a/ivtest/vpi/nextsimtime_cb3.c b/ivtest/vpi/nextsimtime_cb3.c new file mode 100644 index 000000000..acf54664e --- /dev/null +++ b/ivtest/vpi/nextsimtime_cb3.c @@ -0,0 +1,2 @@ +#define TEST_SUPPRESS_TIME +#include "nextsimtime_cb.c" diff --git a/ivtest/vpi/nextsimtime_cb3.v b/ivtest/vpi/nextsimtime_cb3.v new file mode 100644 index 000000000..d7c7cff1d --- /dev/null +++ b/ivtest/vpi/nextsimtime_cb3.v @@ -0,0 +1 @@ +`include "vpi/nextsimtime_cb.v" diff --git a/ivtest/vpi/nextsimtime_cb4.c b/ivtest/vpi/nextsimtime_cb4.c new file mode 100644 index 000000000..8dae6b8f3 --- /dev/null +++ b/ivtest/vpi/nextsimtime_cb4.c @@ -0,0 +1,2 @@ +#define TEST_NULL_TIME +#include "nextsimtime_cb.c" diff --git a/ivtest/vpi/nextsimtime_cb4.v b/ivtest/vpi/nextsimtime_cb4.v new file mode 100644 index 000000000..d7c7cff1d --- /dev/null +++ b/ivtest/vpi/nextsimtime_cb4.v @@ -0,0 +1 @@ +`include "vpi/nextsimtime_cb.v" diff --git a/ivtest/vpi/pr686.c b/ivtest/vpi/pr686.c index dc68db901..720ef01f0 100644 --- a/ivtest/vpi/pr686.c +++ b/ivtest/vpi/pr686.c @@ -47,6 +47,7 @@ static PLI_INT32 test_next_compiletf(PLI_BYTE8 *name) static PLI_INT32 test_next_calltf(PLI_BYTE8 *name) { vpiHandle sys, argv, value; + static s_vpi_time dummy_time = {vpiSimTime, 0, 0, 0}; (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)) { s_cb_data cb; cb.reason = cbNextSimTime; + cb.time = &dummy_time; cb.cb_rtn = next_sim_time_callback; cb.user_data = (char*)value; vpi_register_cb(&cb); diff --git a/ivtest/vpi/sim_time_cb.c b/ivtest/vpi/sim_time_cb.c new file mode 100644 index 000000000..953905973 --- /dev/null +++ b/ivtest/vpi/sim_time_cb.c @@ -0,0 +1,183 @@ +#ifdef TEST_SCALED_TIME +#define TIME_TYPE vpiScaledRealTime +#else +#define TIME_TYPE vpiSimTime +#endif + +#include +#include +#include +#include + +static PLI_INT32 monitor_cb(p_cb_data cb_data) +{ + vpiHandle*var_list = (vpiHandle*)cb_data->user_data; + + s_vpi_time time; + s_vpi_value value; + PLI_INT32 index; + + time.type = vpiSimTime; + vpi_get_time(NULL, &time); + vpi_printf(" @ %04d :", time.low); + +#ifdef TEST_SCALED_TIME + vpi_printf(" cb_data.time = %1.1f :", cb_data->time->real); +#else + vpi_printf(" cb_data.time = %04d :", cb_data->time->low); +#endif + + value.format = vpiIntVal; + + index = 0; + while (var_list[index]) { + vpi_get_value(var_list[index], &value); + vpi_printf(" %s = %d", vpi_get_str(vpiName, var_list[index]), value.value.integer); + index++; + } + vpi_printf("\n"); + + return 0; +} + +static PLI_INT32 monitor_cb_start(p_cb_data cb_data) +{ + vpi_printf("cbStartOfSimTime"); + monitor_cb(cb_data); + return 0; +} + +static PLI_INT32 monitor_cb_delay(p_cb_data cb_data) +{ + vpi_printf("cbAfterDelay "); + monitor_cb(cb_data); + return 0; +} + +static PLI_INT32 monitor_cb_synch(p_cb_data cb_data) +{ + vpi_printf("cbReadWriteSynch"); + monitor_cb(cb_data); + return 0; +} + +static PLI_INT32 monitor_cb_end(p_cb_data cb_data) +{ + vpiHandle*var_list = (vpiHandle*)cb_data->user_data; + + vpi_printf("cbEndOfSimTime "); + monitor_cb(cb_data); + free(var_list); + return 0; +} + +static PLI_INT32 monitor_calltf(char*xx) +{ + vpiHandle sys = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, sys); + + vpiHandle*var_list = 0; + + vpiHandle handle; + PLI_INT32 index; + s_vpi_time time; + s_vpi_time delay; + s_vpi_value value; + s_cb_data cb_data; + + (void)xx; /* Parameter is not used. */ + + delay.type = TIME_TYPE; + delay.low = 0; + delay.high = 0; + delay.real = 0.0; + + assert(argv); + + handle = vpi_scan(argv); + assert(handle && (vpi_get(vpiType, handle) == vpiConstant)); +#ifdef TEST_SCALED_TIME + value.format = vpiRealVal; + vpi_get_value(handle, &value); + delay.real = value.value.real; +#else + value.format = vpiIntVal; + vpi_get_value(handle, &value); + delay.low = value.value.integer; +#endif + + index = 0; + while ((handle = vpi_scan(argv))) { + assert(vpi_get(vpiType, handle) == vpiReg); + var_list = realloc(var_list, (index + 1) * sizeof(vpiHandle)); + var_list[index++] = handle; + } + var_list = realloc(var_list, (index + 1) * sizeof(vpiHandle)); + var_list[index++] = 0; + + assert(index > 0); + + time.type = TIME_TYPE; + vpi_get_time(var_list[0], &time); + // cbAtStartOfSimTime and cbAtEndOfSimTime want an absolute time. + // We know the test is short, so can ignore the high part. +#ifdef TEST_SCALED_TIME + time.real += delay.real; +#else + time.low += delay.low; +#endif + + memset(&cb_data, 0, sizeof(cb_data)); + + cb_data.reason = cbAtStartOfSimTime; + cb_data.cb_rtn = monitor_cb_start; + cb_data.user_data = (char*)var_list; + cb_data.obj = var_list[0]; + cb_data.time = &time; + vpi_register_cb(&cb_data); + + cb_data.reason = cbAfterDelay; + cb_data.cb_rtn = monitor_cb_delay; + cb_data.user_data = (char*)var_list; + cb_data.obj = var_list[0]; + cb_data.time = &delay; + vpi_register_cb(&cb_data); + + // Add cbNBASynch when we support it + + cb_data.reason = cbReadWriteSynch; + cb_data.cb_rtn = monitor_cb_synch; + cb_data.user_data = (char*)var_list; + cb_data.obj = var_list[0]; + cb_data.time = &delay; + vpi_register_cb(&cb_data); + + cb_data.reason = cbAtEndOfSimTime; + cb_data.cb_rtn = monitor_cb_end; + cb_data.user_data = (char*)var_list; + cb_data.obj = var_list[0]; + cb_data.time = &time; + vpi_register_cb(&cb_data); + + memset(&cb_data, 0, sizeof(cb_data)); + memset(&time , 0, sizeof(time)); + + return 0; +} + +static void monitor_register(void) +{ + s_vpi_systf_data tf_data; + + tf_data.type = vpiSysTask; + tf_data.tfname = "$monitor_time_slot"; + tf_data.calltf = monitor_calltf; + tf_data.compiletf = 0; + tf_data.sizetf = 0; + vpi_register_systf(&tf_data); +} + +void (*vlog_startup_routines[])(void) = { + monitor_register, + 0 +}; diff --git a/ivtest/vpi/sim_time_cb1.c b/ivtest/vpi/sim_time_cb1.c new file mode 100644 index 000000000..d93ba2499 --- /dev/null +++ b/ivtest/vpi/sim_time_cb1.c @@ -0,0 +1,2 @@ +#define TEST_SIM_TIME +#include "sim_time_cb.c" diff --git a/ivtest/vpi/sim_time_cb1.v b/ivtest/vpi/sim_time_cb1.v new file mode 100644 index 000000000..e58741bf3 --- /dev/null +++ b/ivtest/vpi/sim_time_cb1.v @@ -0,0 +1,27 @@ +`timescale 1s/1ms + +module test; + +reg [7:0] a, b; + +initial begin + a = 0; b = 0; + $monitor_time_slot(2000, a, b); + $monitor_time_slot(5000, a, b); + #1; + a = 1; b <= 1; + #1; + a = 2; b <= 2; + #1; + a = 3; b <= 3; + #1; + a = 4; b <= 4; + #1; + a = 5; b <= 5; + #1; + a = 6; b <= 6; + #1; + $finish(0); +end + +endmodule diff --git a/ivtest/vpi/sim_time_cb2.c b/ivtest/vpi/sim_time_cb2.c new file mode 100644 index 000000000..dab1047ed --- /dev/null +++ b/ivtest/vpi/sim_time_cb2.c @@ -0,0 +1,2 @@ +#define TEST_SCALED_TIME +#include "sim_time_cb.c" diff --git a/ivtest/vpi/sim_time_cb2.v b/ivtest/vpi/sim_time_cb2.v new file mode 100644 index 000000000..171759ad0 --- /dev/null +++ b/ivtest/vpi/sim_time_cb2.v @@ -0,0 +1,35 @@ +`timescale 1s/1ms + +module dut; + +reg [7:0] a, b; + +endmodule + +`timescale 1ms/1ms + +module test; + +dut dut(); + +initial begin + dut.a = 0; dut.b = 0; + $monitor_time_slot(2.0, dut.a, dut.b); + $monitor_time_slot(5.0, dut.a, dut.b); + #1000; + dut.a = 1; dut.b <= 1; + #1000; + dut.a = 2; dut.b <= 2; + #1000; + dut.a = 3; dut.b <= 3; + #1000; + dut.a = 4; dut.b <= 4; + #1000; + dut.a = 5; dut.b <= 5; + #1000; + dut.a = 6; dut.b <= 6; + #1000; + $finish(0); +end + +endmodule diff --git a/ivtest/vpi/value_change_cb.c b/ivtest/vpi/value_change_cb.c new file mode 100644 index 000000000..2f6a2d26b --- /dev/null +++ b/ivtest/vpi/value_change_cb.c @@ -0,0 +1,137 @@ +#if defined(TEST_SCALED_TIME) +#define TIME_TYPE vpiScaledRealTime +#elif defined(TEST_SIM_TIME) +#define TIME_TYPE vpiSimTime +#else +#define TIME_TYPE vpiSuppressTime +#endif + +#include +#include +#include + +static PLI_INT32 report_change(p_cb_data cb) +{ + vpiHandle handle = (vpiHandle)(cb->user_data); + + s_vpi_time time; + +#ifndef TEST_NULL_TIME + assert(cb->time && (cb->time->type == TIME_TYPE)); +#endif + assert(cb->value); + +#if defined(TEST_SCALED_TIME) || defined(TEST_SIM_TIME) + time = *(cb->time); +#else + time.type = vpiSimTime; + vpi_get_time(NULL, &time); +#endif + + switch (cb->value->format) { + case vpiIntVal: +#if defined(TEST_SCALED_TIME) + vpi_printf("At time %f %s = %d\n", time.real, vpi_get_str(vpiName, handle), cb->value->value.integer); +#else + vpi_printf("At time %d %s = %d\n", time.low, vpi_get_str(vpiName, handle), cb->value->value.integer); +#endif + break; + case vpiRealVal: +#ifdef TEST_SCALED_TIME + vpi_printf("At time %f %s = %f\n", time.real, vpi_get_str(vpiName, handle), cb->value->value.real); +#else + vpi_printf("At time %d %s = %f\n", time.low, vpi_get_str(vpiName, handle), cb->value->value.real); +#endif + break; + case vpiSuppressVal: +#ifdef TEST_SCALED_TIME + vpi_printf("At time %f %s changed\n", time.real, vpi_get_str(vpiName, handle)); +#else + vpi_printf("At time %d %s changed\n", time.low, vpi_get_str(vpiName, handle)); +#endif + break; + default: + vpi_printf("ERROR: unexpected value format %d\n", cb->value->format); + break; + } + return 0; +} + +static s_cb_data cb; +static s_vpi_time time; +static s_vpi_value value; + +static PLI_INT32 my_monitor_calltf(PLI_BYTE8 *xx) +{ + (void)xx; /* Parameter is not used. */ + + vpiHandle sys = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, sys); + + vpiHandle handle; + + memset(&cb, 0, sizeof(cb)); + memset(&time, 0, sizeof(time)); + memset(&value, 0, sizeof(value)); + + time.type = TIME_TYPE; + + cb.reason = cbValueChange; + cb.cb_rtn = report_change; + cb.time = &time; + cb.value = &value; + + while ((handle = vpi_scan(argv))) { + PLI_INT32 type = vpi_get(vpiType, handle); + cb.obj = handle; + cb.user_data = (char *)handle; + switch (type) { + case vpiNet: + case vpiReg: + case vpiIntegerVar: + case vpiBitVar: + case vpiByteVar: + case vpiShortIntVar: + case vpiIntVar: + case vpiLongIntVar: + case vpiPartSelect: + case vpiMemoryWord: + case vpiMemory: + value.format = vpiIntVal; + break; + case vpiRealVar: + value.format = vpiRealVal; + break; + case vpiNamedEvent: + value.format = vpiSuppressVal; + break; + default: + vpi_printf("ERROR: unexpected object type %d\n", type); + break; + } + vpi_register_cb(&cb); + } + + memset(&cb, 0, sizeof(cb)); + memset(&time, 0, sizeof(time)); + memset(&value, 0, sizeof(value)); + + return 0; +} + +static void my_monitor_register(void) +{ + s_vpi_systf_data tf_data; + + tf_data.type = vpiSysTask; + tf_data.tfname = "$my_monitor"; + tf_data.calltf = my_monitor_calltf; + tf_data.compiletf = 0; + tf_data.sizetf = 0; + vpi_register_systf(&tf_data); +} + +void (*vlog_startup_routines[])(void) = { + my_monitor_register, + 0 +}; diff --git a/ivtest/vpi/value_change_cb.v b/ivtest/vpi/value_change_cb.v new file mode 100644 index 000000000..3ebf8e436 --- /dev/null +++ b/ivtest/vpi/value_change_cb.v @@ -0,0 +1,45 @@ +`timescale 1s/1ms + +module test; + +logic [3:0] v4; +wire [3:0] w4; +integer i4; + +bit [3:0] v2; +byte b2; +shortint s2; +int i2; +longint l2; + +real r; + +event e; + +logic [3:0] p4; + +logic [3:0] a4[3:0]; +bit [3:0] a2[3:0]; + +assign w4 = v4; + +initial begin + $my_monitor(v4, w4, i4, v2, b2, s2, i2, l2, r, e, p4[1:0], a4, a2[1]); + #1 v4 = 4'd1; + #1 i4 = 2; + #1 v2 = 4'd3; + #1 b2 = 4; + #1 s2 = 5; + #1 i2 = 6; + #1 l2 = 7; + #1 r = 8.0; + #1 ->e; + // NOTE: the value change callback on a part select returns the value of the entire variable. + #1 p4 = 4'd10; + #1 a4[0] = 4'd11; + #1 a4[1] = 4'd12; + #1 a2[0] = 4'd13; + #1 a2[1] = 4'd14; +end + +endmodule diff --git a/ivtest/vpi/value_change_cb1.c b/ivtest/vpi/value_change_cb1.c new file mode 100644 index 000000000..f1cf3b310 --- /dev/null +++ b/ivtest/vpi/value_change_cb1.c @@ -0,0 +1,2 @@ +#define TEST_SIM_TIME +#include "value_change_cb.c" diff --git a/ivtest/vpi/value_change_cb1.v b/ivtest/vpi/value_change_cb1.v new file mode 100644 index 000000000..98ad87dd4 --- /dev/null +++ b/ivtest/vpi/value_change_cb1.v @@ -0,0 +1 @@ +`include "vpi/value_change_cb.v" diff --git a/ivtest/vpi/value_change_cb2.c b/ivtest/vpi/value_change_cb2.c new file mode 100644 index 000000000..50d5529b9 --- /dev/null +++ b/ivtest/vpi/value_change_cb2.c @@ -0,0 +1,2 @@ +#define TEST_SCALED_TIME +#include "value_change_cb.c" diff --git a/ivtest/vpi/value_change_cb2.v b/ivtest/vpi/value_change_cb2.v new file mode 100644 index 000000000..98ad87dd4 --- /dev/null +++ b/ivtest/vpi/value_change_cb2.v @@ -0,0 +1 @@ +`include "vpi/value_change_cb.v" diff --git a/ivtest/vpi/value_change_cb3.c b/ivtest/vpi/value_change_cb3.c new file mode 100644 index 000000000..25047b1c4 --- /dev/null +++ b/ivtest/vpi/value_change_cb3.c @@ -0,0 +1,2 @@ +#define TEST_SUPPRESS_TIME +#include "value_change_cb.c" diff --git a/ivtest/vpi/value_change_cb3.v b/ivtest/vpi/value_change_cb3.v new file mode 100644 index 000000000..98ad87dd4 --- /dev/null +++ b/ivtest/vpi/value_change_cb3.v @@ -0,0 +1 @@ +`include "vpi/value_change_cb.v" diff --git a/ivtest/vpi/value_change_cb4.c b/ivtest/vpi/value_change_cb4.c new file mode 100644 index 000000000..005e36c68 --- /dev/null +++ b/ivtest/vpi/value_change_cb4.c @@ -0,0 +1,2 @@ +#define TEST_NULL_TIME +#include "value_change_cb.c" diff --git a/ivtest/vpi/value_change_cb4.v b/ivtest/vpi/value_change_cb4.v new file mode 100644 index 000000000..98ad87dd4 --- /dev/null +++ b/ivtest/vpi/value_change_cb4.v @@ -0,0 +1 @@ +`include "vpi/value_change_cb.v" diff --git a/ivtest/vpi_gold/nextsimtime_cb1.gold b/ivtest/vpi_gold/nextsimtime_cb1.gold new file mode 100644 index 000000000..c32082f43 --- /dev/null +++ b/ivtest/vpi_gold/nextsimtime_cb1.gold @@ -0,0 +1,8 @@ +Compiling vpi/nextsimtime_cb1.c... +Making nextsimtime_cb1.vpi from nextsimtime_cb1.o... +time 0: 0 +nextsimtime: 1000 +time 1: 1 +nextsimtime: 4000 +time 4: 4 +nextsimtime: 5000 diff --git a/ivtest/vpi_gold/nextsimtime_cb2.gold b/ivtest/vpi_gold/nextsimtime_cb2.gold new file mode 100644 index 000000000..5c68a4772 --- /dev/null +++ b/ivtest/vpi_gold/nextsimtime_cb2.gold @@ -0,0 +1,8 @@ +Compiling vpi/nextsimtime_cb2.c... +Making nextsimtime_cb2.vpi from nextsimtime_cb2.o... +time 0: 0 +nextsimtime: 1.000000 +time 1: 1 +nextsimtime: 4.000000 +time 4: 4 +nextsimtime: 5.000000 diff --git a/ivtest/vpi_gold/nextsimtime_cb3.gold b/ivtest/vpi_gold/nextsimtime_cb3.gold new file mode 100644 index 000000000..56d0f862e --- /dev/null +++ b/ivtest/vpi_gold/nextsimtime_cb3.gold @@ -0,0 +1,8 @@ +Compiling vpi/nextsimtime_cb3.c... +Making nextsimtime_cb3.vpi from nextsimtime_cb3.o... +time 0: 0 +nextsimtime: 1000 +time 1: 1 +nextsimtime: 4000 +time 4: 4 +nextsimtime: 5000 diff --git a/ivtest/vpi_gold/nextsimtime_cb4.gold b/ivtest/vpi_gold/nextsimtime_cb4.gold new file mode 100644 index 000000000..66c2b9cfd --- /dev/null +++ b/ivtest/vpi_gold/nextsimtime_cb4.gold @@ -0,0 +1,8 @@ +Compiling vpi/nextsimtime_cb4.c... +Making nextsimtime_cb4.vpi from nextsimtime_cb4.o... +time 0: 0 +nextsimtime: 1000 +time 1: 1 +nextsimtime: 4000 +time 4: 4 +nextsimtime: 5000 diff --git a/ivtest/vpi_gold/sim_time_cb1.gold b/ivtest/vpi_gold/sim_time_cb1.gold new file mode 100644 index 000000000..a479bac8b --- /dev/null +++ b/ivtest/vpi_gold/sim_time_cb1.gold @@ -0,0 +1,10 @@ +Compiling vpi/sim_time_cb1.c... +Making sim_time_cb1.vpi from sim_time_cb1.o... +cbStartOfSimTime @ 2000 : cb_data.time = 2000 : a = 1 b = 1 +cbAfterDelay @ 2000 : cb_data.time = 2000 : a = 1 b = 1 +cbReadWriteSynch @ 2000 : cb_data.time = 2000 : a = 2 b = 2 +cbEndOfSimTime @ 2000 : cb_data.time = 2000 : a = 2 b = 2 +cbStartOfSimTime @ 5000 : cb_data.time = 5000 : a = 4 b = 4 +cbAfterDelay @ 5000 : cb_data.time = 5000 : a = 4 b = 4 +cbReadWriteSynch @ 5000 : cb_data.time = 5000 : a = 5 b = 5 +cbEndOfSimTime @ 5000 : cb_data.time = 5000 : a = 5 b = 5 diff --git a/ivtest/vpi_gold/sim_time_cb2.gold b/ivtest/vpi_gold/sim_time_cb2.gold new file mode 100644 index 000000000..253377053 --- /dev/null +++ b/ivtest/vpi_gold/sim_time_cb2.gold @@ -0,0 +1,10 @@ +Compiling vpi/sim_time_cb2.c... +Making sim_time_cb2.vpi from sim_time_cb2.o... +cbStartOfSimTime @ 2000 : cb_data.time = 2.0 : a = 1 b = 1 +cbAfterDelay @ 2000 : cb_data.time = 2.0 : a = 1 b = 1 +cbReadWriteSynch @ 2000 : cb_data.time = 2.0 : a = 2 b = 2 +cbEndOfSimTime @ 2000 : cb_data.time = 2.0 : a = 2 b = 2 +cbStartOfSimTime @ 5000 : cb_data.time = 5.0 : a = 4 b = 4 +cbAfterDelay @ 5000 : cb_data.time = 5.0 : a = 4 b = 4 +cbReadWriteSynch @ 5000 : cb_data.time = 5.0 : a = 5 b = 5 +cbEndOfSimTime @ 5000 : cb_data.time = 5.0 : a = 5 b = 5 diff --git a/ivtest/vpi_gold/value_change_cb1.gold b/ivtest/vpi_gold/value_change_cb1.gold new file mode 100644 index 000000000..6b9ff85b5 --- /dev/null +++ b/ivtest/vpi_gold/value_change_cb1.gold @@ -0,0 +1,16 @@ +Compiling vpi/value_change_cb1.c... +Making value_change_cb1.vpi from value_change_cb1.o... +At time 1000 v4 = 1 +At time 1000 w4 = 1 +At time 2000 i4 = 2 +At time 3000 v2 = 3 +At time 4000 b2 = 4 +At time 5000 s2 = 5 +At time 6000 i2 = 6 +At time 7000 l2 = 7 +At time 8000 r = 8.000000 +At time 9000 e changed +At time 10000 p4[1:0] = 10 +At time 11000 a4 = 11 +At time 12000 a4 = 12 +At time 14000 a2[1] = 14 diff --git a/ivtest/vpi_gold/value_change_cb2.gold b/ivtest/vpi_gold/value_change_cb2.gold new file mode 100644 index 000000000..50d47629e --- /dev/null +++ b/ivtest/vpi_gold/value_change_cb2.gold @@ -0,0 +1,16 @@ +Compiling vpi/value_change_cb2.c... +Making value_change_cb2.vpi from value_change_cb2.o... +At time 1.000000 v4 = 1 +At time 1.000000 w4 = 1 +At time 2.000000 i4 = 2 +At time 3.000000 v2 = 3 +At time 4.000000 b2 = 4 +At time 5.000000 s2 = 5 +At time 6.000000 i2 = 6 +At time 7.000000 l2 = 7 +At time 8.000000 r = 8.000000 +At time 9.000000 e changed +At time 10.000000 p4[1:0] = 10 +At time 11.000000 a4 = 11 +At time 12.000000 a4 = 12 +At time 14.000000 a2[1] = 14 diff --git a/ivtest/vpi_gold/value_change_cb3.gold b/ivtest/vpi_gold/value_change_cb3.gold new file mode 100644 index 000000000..df70b959e --- /dev/null +++ b/ivtest/vpi_gold/value_change_cb3.gold @@ -0,0 +1,16 @@ +Compiling vpi/value_change_cb3.c... +Making value_change_cb3.vpi from value_change_cb3.o... +At time 1000 v4 = 1 +At time 1000 w4 = 1 +At time 2000 i4 = 2 +At time 3000 v2 = 3 +At time 4000 b2 = 4 +At time 5000 s2 = 5 +At time 6000 i2 = 6 +At time 7000 l2 = 7 +At time 8000 r = 8.000000 +At time 9000 e changed +At time 10000 p4[1:0] = 10 +At time 11000 a4 = 11 +At time 12000 a4 = 12 +At time 14000 a2[1] = 14 diff --git a/ivtest/vpi_gold/value_change_cb4.gold b/ivtest/vpi_gold/value_change_cb4.gold new file mode 100644 index 000000000..7ba3ee92b --- /dev/null +++ b/ivtest/vpi_gold/value_change_cb4.gold @@ -0,0 +1,16 @@ +Compiling vpi/value_change_cb4.c... +Making value_change_cb4.vpi from value_change_cb4.o... +At time 1000 v4 = 1 +At time 1000 w4 = 1 +At time 2000 i4 = 2 +At time 3000 v2 = 3 +At time 4000 b2 = 4 +At time 5000 s2 = 5 +At time 6000 i2 = 6 +At time 7000 l2 = 7 +At time 8000 r = 8.000000 +At time 9000 e changed +At time 10000 p4[1:0] = 10 +At time 11000 a4 = 11 +At time 12000 a4 = 12 +At time 14000 a2[1] = 14 diff --git a/ivtest/vpi_regress.list b/ivtest/vpi_regress.list index 4d9d5c951..982f61381 100644 --- a/ivtest/vpi_regress.list +++ b/ivtest/vpi_regress.list @@ -99,6 +99,10 @@ hello_tf normal hello_tf.c hello_tf.log hello_vpi normal hello_vpi.c hello.log hello_vpi2 normal hello_vpi2.c hello2.log vpi/hello_vpi1.c listparams normal listparams.c listparams.log +nextsimtime_cb1 normal nextsimtime_cb1.c nextsimtime_cb1.gold +nextsimtime_cb2 normal nextsimtime_cb2.c nextsimtime_cb2.gold +nextsimtime_cb3 normal nextsimtime_cb3.c nextsimtime_cb3.gold +nextsimtime_cb4 normal nextsimtime_cb4.c nextsimtime_cb4.gold memmon normal,-g1995 memmon.c memmon.log memwide normal memwide.cc memwide.log mipname normal mipname.c mipname.log @@ -128,9 +132,15 @@ scanmem normal scanmem.cc scanmem.log scanmem2 normal scanmem2.cc scanmem2.log scanmem3 normal scanmem3.cc scanmem3.log scopes normal scopes.c scopes.log +sim_time_cb1 normal sim_time_cb1.c sim_time_cb1.gold +sim_time_cb2 normal sim_time_cb2.c sim_time_cb2.gold spec_delays normal,-gspecify spec_delays.c spec_delays.log start_of_simtime1 normal start_of_simtime1.c start_of_simtime1.log timescale normal timescale.c timescale.log +value_change_cb1 normal,-g2009 value_change_cb1.c value_change_cb1.gold +value_change_cb2 normal,-g2009 value_change_cb2.c value_change_cb2.gold +value_change_cb3 normal,-g2009 value_change_cb3.c value_change_cb3.gold +value_change_cb4 normal,-g2009 value_change_cb4.c value_change_cb4.gold # Add new tests in alphabetic/numeric order. If the test needs # a compile option or a different log file to run with an older diff --git a/libveriuser/veriusertfs.c b/libveriuser/veriusertfs.c index c09503f49..71d47e537 100644 --- a/libveriuser/veriusertfs.c +++ b/libveriuser/veriusertfs.c @@ -385,9 +385,7 @@ PLI_INT32 tf_isynchronize(void*obj) vpiHandle sys = (vpiHandle)obj; p_pli_data pli = vpi_get_userdata(sys); s_cb_data cb; - s_vpi_time ti; - - ti.type = vpiSuppressTime; + s_vpi_time ti = {vpiSimTime, 0, 0, 0.0}; cb.reason = cbReadWriteSynch; cb.cb_rtn = callback; @@ -414,7 +412,7 @@ PLI_INT32 tf_irosynchronize(void*obj) vpiHandle sys = (vpiHandle)obj; p_pli_data pli = vpi_get_userdata(sys); s_cb_data cb; - s_vpi_time ti = {vpiSuppressTime, 0, 0, 0.0}; + s_vpi_time ti = {vpiSimTime, 0, 0, 0.0}; cb.reason = cbReadOnlySynch; cb.cb_rtn = callback; diff --git a/vvp/array.cc b/vvp/array.cc index 7b3d6699c..36d72c6fe 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2022 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2024 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 @@ -1319,11 +1319,29 @@ void __vpiArray::word_change(unsigned long addr) if (addr < vals->get_size()) vals->get_word(addr, val); vpip_real_get_value(val, cur->cb_data.value); - } else { + } else if (vals4) { vpip_vec4_get_value(vals4->get_word(addr), vals_width, signed_flag, cur->cb_data.value); + } else if (dynamic_cast*>(vals) + || dynamic_cast*>(vals) + || dynamic_cast*>(vals) + || dynamic_cast*>(vals) + || dynamic_cast*>(vals) + || dynamic_cast*>(vals) + || dynamic_cast*>(vals) + || dynamic_cast*>(vals) + || dynamic_cast(vals)) { + vvp_vector4_t val; + if (addr < vals->get_size()) + vals->get_word(addr, val); + vpip_vec4_get_value(val, + vals_width, + signed_flag, + cur->cb_data.value); + } else { + assert(0); } } diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index 3427f32f6..e18bf00c7 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2022 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2024 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 @@ -40,6 +40,119 @@ using namespace std; +static const char*cb_reason_name(PLI_INT32 reason) +{ + switch (reason) { + case cbValueChange: + return "cbValueChange"; + case cbStmt: + return "cbStmt"; + case cbForce: + return "cbForce"; + case cbRelease: + return "cbRelease"; + case cbAtStartOfSimTime: + return "cbAtStartOfSimTime"; + case cbReadWriteSynch: + return "cbReadWriteSynch"; + case cbReadOnlySynch: + return "cbReadOnlySynch"; + case cbNextSimTime: + return "cbNextSimTime"; + case cbAfterDelay: + return "cbAfterDelay"; + case cbEndOfCompile: + return "cbEndOfCompile"; + case cbStartOfSimulation: + return "cbStartOfSimulation"; + case cbEndOfSimulation: + return "cbEndOfSimulation"; + case cbError: + return "cbError"; + case cbTchkViolation: + return "cbTchkViolation"; + case cbStartOfSave: + return "cbStartOfSave"; + case cbEndOfSave: + return "cbEndOfSave"; + case cbStartOfRestart: + return "cbStartOfRestart"; + case cbEndOfRestart: + return "cbEndOfRestart"; + case cbStartOfReset: + return "cbStartOfReset"; + case cbEndOfReset: + return "cbEndOfReset"; + case cbEnterInteractive: + return "cbEnterInteractive"; + case cbExitInteractive: + return "cbExitInteractive"; + case cbInteractiveScopeChange: + return "cbInteractiveScopeChange"; + case cbUnresolvedSystf: + return "cbUnresolvedSystf"; + case cbAtEndOfSimTime: + return "cbAtEndOfSimTime"; + default: + return "unrecognised"; + } +} + +static bool check_callback_time(p_cb_data data, bool allow_suppress) +{ + assert(data); + if (!data->time) { + if (!allow_suppress) { + fprintf(stderr, "VPI error: null value passed in cb_data.time " + "when registering %s callback\n.", + cb_reason_name(data->reason)); + return false; + } + return true; + } + switch (data->time->type) { + case vpiSimTime: + break; + case vpiScaledRealTime: + break; + case vpiSuppressTime: + if (!allow_suppress) { + fprintf(stderr, "VPI error: vpiSuppressTime is not valid " + "when registering %s callback\n.", + cb_reason_name(data->reason)); + return false; + } + break; + default: + fprintf(stderr, "VPI error: invalid type passed in cb_data time " + "structure when registering %s callback\n.", + cb_reason_name(data->reason)); + return false; + } + return true; +} + +static void set_callback_time(p_cb_data data) +{ + assert(data && data->time); + data->time->low = 0; + data->time->high = 0; + data->time->real = 0.0; + switch (data->time->type) { + case vpiSimTime: + vpip_time_to_timestruct(data->time, schedule_simtime()); + break; + case vpiScaledRealTime: + data->time->real = vpip_scaled_time_from_handle(schedule_simtime(), data->obj); + break; + case vpiSuppressTime: + break; + default: + assert(0); + break; + } +} + /* * Callback handles are created when the VPI function registers a * callback. The handle is stored by the run time, and it triggered @@ -203,6 +316,9 @@ static value_callback*make_value_change_part(p_cb_data data) */ static value_callback* make_value_change(p_cb_data data) { + if (!check_callback_time(data, true)) + return 0; + if (vpi_get(vpiAutomatic, data->obj)) { fprintf(stderr, "vpi error: cannot place value change " "callback on automatically allocated " @@ -314,13 +430,12 @@ void sync_cb::run_run() return; sync_callback*cur = handle; - cur->cb_data.time->type = vpiSimTime; - vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime()); /* Run the callback. If the cb_rtn function pointer is set to null, then just skip the whole thing and free it. This is the usual way to cancel one-time callbacks of this sort. */ if (cur->cb_data.cb_rtn != 0) { + set_callback_time(&cur->cb_data); assert(vpi_mode_flag == VPI_MODE_NONE); vpi_mode_flag = sync_flag? VPI_MODE_ROSYNC : VPI_MODE_RWSYNC; (cur->cb_data.cb_rtn)(&cur->cb_data); @@ -330,8 +445,33 @@ void sync_cb::run_run() delete cur; } +static vvp_time64_t get_sync_cb_time(sync_callback*obj) +{ + vvp_time64_t tv = 0; + switch (obj->cb_time.type) { + case vpiSimTime: + tv = vpip_timestruct_to_time(&obj->cb_time); + break; + + case vpiScaledRealTime: + tv = vpip_scaled_real_to_time64(obj->cb_time.real, + vpip_timescale_scope_from_handle(obj->cb_data.obj)); + break; + + default: + fprintf(stderr, "get_sync_cb_time: Unsupported time type %d.\n", + (int)obj->cb_time.type); + assert(0); + break; + } + return tv; +} + static sync_callback* make_sync(p_cb_data data, bool readonly_flag) { + if (!check_callback_time(data, false)) + return 0; + sync_callback*obj = new sync_callback(data); struct sync_cb*cb = new sync_cb; @@ -339,46 +479,24 @@ static sync_callback* make_sync(p_cb_data data, bool readonly_flag) cb->handle = obj; obj->cb_sync = cb; - vvp_time64_t tv = 0; - switch (obj->cb_time.type) { - case vpiSuppressTime: - break; - - 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 tv = get_sync_cb_time(obj); schedule_generic(cb, tv, true, readonly_flag); + return obj; } static struct __vpiCallback* make_afterdelay(p_cb_data data) { + if (!check_callback_time(data, false)) + return 0; + 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 tv = get_sync_cb_time(obj); schedule_generic(cb, tv, false); return obj; @@ -386,25 +504,16 @@ static struct __vpiCallback* make_afterdelay(p_cb_data data) static struct __vpiCallback* make_at_start_of_sim_time(p_cb_data data) { + if (!check_callback_time(data, false)) + return 0; + 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 tv = get_sync_cb_time(obj); vvp_time64_t cur = schedule_simtime(); if (cur > tv) { tv = 0; @@ -421,25 +530,16 @@ static struct __vpiCallback* make_at_start_of_sim_time(p_cb_data data) static struct __vpiCallback* make_at_end_of_sim_time(p_cb_data data) { + if (!check_callback_time(data, false)) + return 0; + 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 tv = get_sync_cb_time(obj); vvp_time64_t cur = schedule_simtime(); if (cur > tv) { tv = 0; @@ -461,12 +561,25 @@ static struct __vpiCallback* make_at_end_of_sim_time(p_cb_data data) class simulator_callback : public __vpiCallback { public: - inline explicit simulator_callback(const struct t_cb_data*data) - { cb_data = *data; } + explicit simulator_callback(const struct t_cb_data*data); public: + struct t_vpi_time cb_time; }; +inline simulator_callback::simulator_callback(const struct t_cb_data*data) +{ + cb_data = *data; + if ((data->reason == cbNextSimTime) && data->time) { + cb_time = *(data->time); + } else if (data->reason == cbEndOfSimulation) { + cb_time.type = vpiSimTime; + } else { + cb_time.type = vpiSuppressTime; + } + cb_data.time = &cb_time; +} + static simulator_callback*NextSimTime = 0; static simulator_callback*EndOfCompile = 0; static simulator_callback*StartOfSimulation = 0; @@ -516,7 +629,7 @@ void vpiEndOfCompile(void) { cur = EndOfCompile; EndOfCompile = dynamic_cast(cur->next); if (cur->cb_data.cb_rtn != 0) { - (cur->cb_data.cb_rtn)(&cur->cb_data); + (cur->cb_data.cb_rtn)(&cur->cb_data); } delete cur; } @@ -538,7 +651,7 @@ void vpiStartOfSim(void) { cur = StartOfSimulation; StartOfSimulation = dynamic_cast(cur->next); if (cur->cb_data.cb_rtn != 0) { - (cur->cb_data.cb_rtn)(&cur->cb_data); + (cur->cb_data.cb_rtn)(&cur->cb_data); } delete cur; } @@ -559,10 +672,8 @@ void vpiPostsim(void) { cur = EndOfSimulation; EndOfSimulation = dynamic_cast(cur->next); if (cur->cb_data.cb_rtn != 0) { - /* Only set the time if it is not NULL. */ - if (cur->cb_data.time) - vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime()); - (cur->cb_data.cb_rtn)(&cur->cb_data); + set_callback_time(&cur->cb_data); + (cur->cb_data.cb_rtn)(&cur->cb_data); } delete cur; } @@ -577,17 +688,20 @@ void vpiPostsim(void) { void vpiNextSimTime(void) { simulator_callback* cur; + simulator_callback* next = NextSimTime; + NextSimTime = 0; assert(vpi_mode_flag == VPI_MODE_NONE); vpi_mode_flag = VPI_MODE_RWSYNC; - while (NextSimTime) { - cur = NextSimTime; - NextSimTime = dynamic_cast(cur->next); - if (cur->cb_data.cb_rtn != 0) { - (cur->cb_data.cb_rtn)(&cur->cb_data); - } - delete cur; + while (next) { + cur = next; + next = dynamic_cast(cur->next); + if (cur->cb_data.cb_rtn != 0) { + set_callback_time(&cur->cb_data); + (cur->cb_data.cb_rtn)(&cur->cb_data); + } + delete cur; } vpi_mode_flag = VPI_MODE_NONE; @@ -595,6 +709,9 @@ void vpiNextSimTime(void) static simulator_callback* make_prepost(p_cb_data data) { + if ((data->reason == cbNextSimTime) && !check_callback_time(data, true)) + return 0; + simulator_callback*obj = new simulator_callback(data); /* Insert at head of list */ @@ -614,6 +731,7 @@ static simulator_callback* make_prepost(p_cb_data data) case cbNextSimTime: obj->next = NextSimTime; NextSimTime = obj; + break; } return obj; @@ -687,25 +805,7 @@ void callback_execute(struct __vpiCallback*cur) vpi_mode_flag = VPI_MODE_RWSYNC; assert(cur->cb_data.cb_rtn); - switch (cur->cb_data.time->type) { - case vpiSimTime: - vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime()); - break; - case vpiScaledRealTime: { - cur->cb_data.time->real = - vpip_time_to_scaled_real(schedule_simtime(), - static_cast<__vpiScope *>(vpi_handle(vpiScope, - cur->cb_data.obj))); - break; - } - case vpiSuppressTime: - break; - default: - fprintf(stderr, "Unsupported time format %d.\n", - (int)cur->cb_data.time->type); - assert(0); - break; - } + set_callback_time(&cur->cb_data); (cur->cb_data.cb_rtn)(&cur->cb_data); vpi_mode_flag = save_mode; diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 26d59ac55..27fe86210 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2023 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2024 Stephen Williams (steve@icarus.com) * Copyright (c) 2023 Leo Moser (leo.moser@pm.me) * * This source code is free software; you can redistribute it @@ -495,79 +495,89 @@ char* vpi_get_str(PLI_INT32 property, vpiHandle ref) return res; } -int vpip_time_units_from_handle(vpiHandle obj) +__vpiScope*vpip_timescale_scope_from_handle(vpiHandle obj) { struct __vpiSysTaskCall*task; - __vpiScope*scope; struct __vpiSignal*signal; + struct __vpiRealVar*real; __vpiNamedEvent*event; - if (obj == 0) - return vpip_get_time_precision(); - switch (obj->get_type_code()) { case vpiSysTaskCall: task = dynamic_cast<__vpiSysTaskCall*>(obj); - return task->scope->time_units; + return task->scope; case vpiModule: - scope = dynamic_cast<__vpiScope*>(obj); - return scope->time_units; + return dynamic_cast<__vpiScope*>(obj); case vpiNet: case vpiReg: + case vpiIntegerVar: + case vpiBitVar: + case vpiByteVar: + case vpiShortIntVar: + case vpiIntVar: + case vpiLongIntVar: signal = dynamic_cast<__vpiSignal*>(obj); - scope = vpip_scope(signal); - return scope->time_units; + return vpip_scope(signal); + + case vpiRealVar: + real = dynamic_cast<__vpiRealVar*>(obj); + return vpip_scope(real); case vpiNamedEvent: event = dynamic_cast<__vpiNamedEvent*>(obj); - scope = event->get_scope(); - return scope->time_units; + return event->get_scope(); + + case vpiMemory: + case vpiMemoryWord: + case vpiPartSelect: + return dynamic_cast<__vpiScope*>(obj->vpi_handle(vpiScope)); default: - fprintf(stderr, "ERROR: vpip_time_units_from_handle called with " + fprintf(stderr, "ERROR: vpip_scope_from_handle called with " "object handle type=%d\n", obj->get_type_code()); assert(0); return 0; } } -int vpip_time_precision_from_handle(vpiHandle obj) +int vpip_time_units_from_handle(vpiHandle obj) { - struct __vpiSysTaskCall*task; - __vpiScope*scope; - struct __vpiSignal*signal; - if (obj == 0) return vpip_get_time_precision(); - switch (obj->get_type_code()) { - case vpiSysTaskCall: - task = dynamic_cast<__vpiSysTaskCall*>(obj); - return task->scope->time_precision; + __vpiScope*scope = vpip_timescale_scope_from_handle(obj); + if (scope == 0) + return vpip_get_time_precision(); - case vpiModule: - scope = dynamic_cast<__vpiScope*>(obj); - return scope->time_precision; + return scope->time_units; +} - case vpiNet: - case vpiReg: - signal = dynamic_cast<__vpiSignal*>(obj); - scope = vpip_scope(signal); - return scope->time_precision; +int vpip_time_precision_from_handle(vpiHandle obj) +{ + if (obj == 0) + return vpip_get_time_precision(); - default: - fprintf(stderr, "ERROR: vpip_time_precision_from_handle called " - "with object handle type=%d\n", obj->get_type_code()); - assert(0); - return 0; - } + __vpiScope*scope = vpip_timescale_scope_from_handle(obj); + if (scope == 0) + return vpip_get_time_precision(); + + return scope->time_precision; +} + +double vpip_scaled_time_from_handle(vvp_time64_t time, vpiHandle obj) +{ + int scale = vpip_get_time_precision() - + vpip_time_units_from_handle(obj); + if (scale >= 0) + return (double)time * pow(10.0, scale); + else + return (double)time / pow(10.0, -scale); } void vpi_get_time(vpiHandle obj, s_vpi_time*vp) { - int scale; vvp_time64_t time; assert(vp); @@ -581,10 +591,7 @@ void vpi_get_time(vpiHandle obj, s_vpi_time*vp) break; case vpiScaledRealTime: - scale = vpip_get_time_precision() - - vpip_time_units_from_handle(obj); - if (scale >= 0) vp->real = (double)time * pow(10.0, scale); - else vp->real = (double)time / pow(10.0, -scale); + vp->real = vpip_scaled_time_from_handle(time, obj); break; default: diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 1c5f01652..55b26d5d3 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -1076,9 +1076,13 @@ vpiHandle vpip_sim_realtime(__vpiScope*scope); extern int vpip_get_time_precision(void); extern void vpip_set_time_precision(int pres); +extern __vpiScope*vpip_timescale_scope_from_handle(vpiHandle obj); + extern int vpip_time_units_from_handle(vpiHandle obj); extern int vpip_time_precision_from_handle(vpiHandle obj); +extern double vpip_scaled_time_from_handle(vvp_time64_t time, vpiHandle obj); + extern void vpip_time_to_timestruct(struct t_vpi_time*ts, vvp_time64_t ti); extern vvp_time64_t vpip_timestruct_to_time(const struct t_vpi_time*ts);