Merge pull request #1098 from steveicarus/vpi-callback-improvements
VPI callback improvements
This commit is contained in:
commit
202d41a60c
|
|
@ -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 <assert.h>
|
||||
|
||||
#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
|
||||
};
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#define TEST_SIM_TIME
|
||||
#include "nextsimtime_cb.c"
|
||||
|
|
@ -0,0 +1 @@
|
|||
`include "vpi/nextsimtime_cb.v"
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#define TEST_SCALED_TIME
|
||||
#include "nextsimtime_cb.c"
|
||||
|
|
@ -0,0 +1 @@
|
|||
`include "vpi/nextsimtime_cb.v"
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#define TEST_SUPPRESS_TIME
|
||||
#include "nextsimtime_cb.c"
|
||||
|
|
@ -0,0 +1 @@
|
|||
`include "vpi/nextsimtime_cb.v"
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#define TEST_NULL_TIME
|
||||
#include "nextsimtime_cb.c"
|
||||
|
|
@ -0,0 +1 @@
|
|||
`include "vpi/nextsimtime_cb.v"
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,183 @@
|
|||
#ifdef TEST_SCALED_TIME
|
||||
#define TIME_TYPE vpiScaledRealTime
|
||||
#else
|
||||
#define TIME_TYPE vpiSimTime
|
||||
#endif
|
||||
|
||||
#include <vpi_user.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
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
|
||||
};
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#define TEST_SIM_TIME
|
||||
#include "sim_time_cb.c"
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#define TEST_SCALED_TIME
|
||||
#include "sim_time_cb.c"
|
||||
|
|
@ -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
|
||||
|
|
@ -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 <sv_vpi_user.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
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
|
||||
};
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#define TEST_SIM_TIME
|
||||
#include "value_change_cb.c"
|
||||
|
|
@ -0,0 +1 @@
|
|||
`include "vpi/value_change_cb.v"
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#define TEST_SCALED_TIME
|
||||
#include "value_change_cb.c"
|
||||
|
|
@ -0,0 +1 @@
|
|||
`include "vpi/value_change_cb.v"
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#define TEST_SUPPRESS_TIME
|
||||
#include "value_change_cb.c"
|
||||
|
|
@ -0,0 +1 @@
|
|||
`include "vpi/value_change_cb.v"
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#define TEST_NULL_TIME
|
||||
#include "value_change_cb.c"
|
||||
|
|
@ -0,0 +1 @@
|
|||
`include "vpi/value_change_cb.v"
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
22
vvp/array.cc
22
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<vvp_darray_atom<int8_t>*>(vals)
|
||||
|| dynamic_cast<vvp_darray_atom<int16_t>*>(vals)
|
||||
|| dynamic_cast<vvp_darray_atom<int32_t>*>(vals)
|
||||
|| dynamic_cast<vvp_darray_atom<int64_t>*>(vals)
|
||||
|| dynamic_cast<vvp_darray_atom<uint8_t>*>(vals)
|
||||
|| dynamic_cast<vvp_darray_atom<uint16_t>*>(vals)
|
||||
|| dynamic_cast<vvp_darray_atom<uint32_t>*>(vals)
|
||||
|| dynamic_cast<vvp_darray_atom<uint64_t>*>(vals)
|
||||
|| dynamic_cast<vvp_darray_vec2*>(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<simulator_callback*>(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<simulator_callback*>(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<simulator_callback*>(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<simulator_callback*>(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<simulator_callback*>(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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue