Rework libveriuser to make vpiSysTfCall handles available in callbacks.
PLI 1.0 callbacks are directly associated with the instance of the system
task/function that initiated them, allowing them to access the task/function
arguments. However, we implement them using VPI callbacks, which are not so
associated. So we need to pass the VPI handle for the associated task/function
instance to the callback routine via the VPI callback user_data pointer,
because vpi_handle(vpiSysTfCall, 0) will return null when called from the
callback function.
This is the first step to a proper fix for issue #141, to replace the
problematic fix that was reverted in commit 8da8261f.
This commit is contained in:
parent
df72e1d362
commit
3f9a49ae01
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003 Stephen Williams (steve@icarus.com)
|
* Copyright (c) 2003-2020 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -21,6 +21,8 @@
|
||||||
# include <string.h>
|
# include <string.h>
|
||||||
# include <assert.h>
|
# include <assert.h>
|
||||||
|
|
||||||
|
vpiHandle cur_instance = 0;
|
||||||
|
|
||||||
FILE* pli_trace = 0;
|
FILE* pli_trace = 0;
|
||||||
|
|
||||||
static char string_buffer[8192];
|
static char string_buffer[8192];
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef IVL_priv_H
|
#ifndef IVL_priv_H
|
||||||
#define IVL_priv_H
|
#define IVL_priv_H
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003-2014 Stephen Williams (steve@icarus.com)
|
* Copyright (c) 2003-2020 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -20,6 +20,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
# include <stdio.h>
|
# include <stdio.h>
|
||||||
|
# include "vpi_user.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The VPI handle for the current task/function instance. This is the
|
||||||
|
* handle returned by vpi_handle(vpiSysTfCall, 0) when the task/function
|
||||||
|
* is compiled or called, but we also need it when executing a callback.
|
||||||
|
*/
|
||||||
|
extern vpiHandle cur_instance;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function implements the acc_ string buffer, by adding the
|
* This function implements the acc_ string buffer, by adding the
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2002-2018 Michael Ruff (mruff at chiaro.com)
|
* Copyright (c) 2002-2020 Michael Ruff (mruff at chiaro.com)
|
||||||
* Michael Runyan (mrunyan at chiaro.com)
|
* Michael Runyan (mrunyan at chiaro.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
|
|
@ -34,11 +34,12 @@
|
||||||
# include "ivl_alloc.h"
|
# include "ivl_alloc.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* local structure used to hold the persistent veriusertfs data
|
* Data to be passed to the callback function via the VPI callback
|
||||||
* and anything else we decide to put in here, like workarea data.
|
* user data pointer.
|
||||||
*/
|
*/
|
||||||
typedef struct t_pli_data {
|
typedef struct t_pli_data {
|
||||||
p_tfcell tf; /* pointer to veriusertfs cell */
|
p_tfcell tf; /* pointer to veriusertfs cell */
|
||||||
|
vpiHandle call_handle; /* handle returned by vpiSysTfCall */
|
||||||
int paramvc; /* parameter number for misctf */
|
int paramvc; /* parameter number for misctf */
|
||||||
} s_pli_data, *p_pli_data;
|
} s_pli_data, *p_pli_data;
|
||||||
|
|
||||||
|
|
@ -54,6 +55,21 @@ static PLI_INT32 callback(p_cb_data);
|
||||||
static p_pli_data* udata_store = 0;
|
static p_pli_data* udata_store = 0;
|
||||||
static unsigned udata_count = 0;
|
static unsigned udata_count = 0;
|
||||||
|
|
||||||
|
static p_pli_data new_pli_data(p_tfcell tf, vpiHandle call_handle, int paramvc)
|
||||||
|
{
|
||||||
|
p_pli_data data = calloc(1, sizeof(s_pli_data));
|
||||||
|
data->tf = tf;
|
||||||
|
data->call_handle = call_handle;
|
||||||
|
data->paramvc = paramvc;
|
||||||
|
|
||||||
|
udata_count += 1;
|
||||||
|
udata_store = (p_pli_data*)realloc(udata_store,
|
||||||
|
udata_count*sizeof(p_pli_data*));
|
||||||
|
udata_store[udata_count-1] = data;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
static PLI_INT32 sys_end_of_simulation(p_cb_data cb_data)
|
static PLI_INT32 sys_end_of_simulation(p_cb_data cb_data)
|
||||||
{
|
{
|
||||||
unsigned idx;
|
unsigned idx;
|
||||||
|
|
@ -80,7 +96,6 @@ void veriusertfs_register_table(p_tfcell vtable)
|
||||||
const char*path;
|
const char*path;
|
||||||
p_tfcell tf;
|
p_tfcell tf;
|
||||||
s_vpi_systf_data tf_data;
|
s_vpi_systf_data tf_data;
|
||||||
p_pli_data data;
|
|
||||||
|
|
||||||
if (!pli_trace && (path = getenv("PLI_TRACE"))) {
|
if (!pli_trace && (path = getenv("PLI_TRACE"))) {
|
||||||
static char trace_buf[1024];
|
static char trace_buf[1024];
|
||||||
|
|
@ -106,12 +121,6 @@ void veriusertfs_register_table(p_tfcell vtable)
|
||||||
tf->tfname);
|
tf->tfname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* squirrel away veriusertfs in persistent user_data */
|
|
||||||
data = calloc(1, sizeof(s_pli_data));
|
|
||||||
udata_count += 1;
|
|
||||||
udata_store = (p_pli_data*)realloc(udata_store,
|
|
||||||
udata_count*sizeof(p_pli_data*));
|
|
||||||
udata_store[udata_count-1] = data;
|
|
||||||
if (need_EOS_cb) {
|
if (need_EOS_cb) {
|
||||||
s_cb_data cb_data;
|
s_cb_data cb_data;
|
||||||
|
|
||||||
|
|
@ -123,7 +132,6 @@ void veriusertfs_register_table(p_tfcell vtable)
|
||||||
|
|
||||||
need_EOS_cb = 0;
|
need_EOS_cb = 0;
|
||||||
}
|
}
|
||||||
data->tf = tf;
|
|
||||||
|
|
||||||
/* Build a VPI system task/function structure, and point
|
/* Build a VPI system task/function structure, and point
|
||||||
it to the pli_data that represents this
|
it to the pli_data that represents this
|
||||||
|
|
@ -152,7 +160,7 @@ void veriusertfs_register_table(p_tfcell vtable)
|
||||||
tf_data.compiletf = compiletf;
|
tf_data.compiletf = compiletf;
|
||||||
tf_data.calltf = calltf;
|
tf_data.calltf = calltf;
|
||||||
tf_data.sizetf = sizetf;
|
tf_data.sizetf = sizetf;
|
||||||
tf_data.user_data = (char *)data;
|
tf_data.user_data = (PLI_BYTE8*)tf;
|
||||||
|
|
||||||
if (pli_trace) {
|
if (pli_trace) {
|
||||||
fprintf(pli_trace, "Registering system %s:\n",
|
fprintf(pli_trace, "Registering system %s:\n",
|
||||||
|
|
@ -183,50 +191,49 @@ void veriusertfs_register_table(p_tfcell vtable)
|
||||||
*/
|
*/
|
||||||
static PLI_INT32 compiletf(ICARUS_VPI_CONST PLI_BYTE8*data)
|
static PLI_INT32 compiletf(ICARUS_VPI_CONST PLI_BYTE8*data)
|
||||||
{
|
{
|
||||||
p_pli_data pli;
|
|
||||||
p_tfcell tf;
|
p_tfcell tf;
|
||||||
|
p_pli_data pli;
|
||||||
s_cb_data cb_data;
|
s_cb_data cb_data;
|
||||||
vpiHandle call_h, arg_i, arg_h;
|
vpiHandle arg_i, arg_h;
|
||||||
int rtn = 0;
|
int rtn = 0;
|
||||||
|
|
||||||
/* cast back from opaque */
|
/* cast back from opaque */
|
||||||
pli = (p_pli_data)data;
|
tf = (p_tfcell)data;
|
||||||
tf = pli->tf;
|
|
||||||
|
|
||||||
/* get call handle */
|
/* get call handle */
|
||||||
call_h = vpi_handle(vpiSysTfCall, NULL);
|
cur_instance = vpi_handle(vpiSysTfCall, NULL);
|
||||||
|
|
||||||
/* Attach the pli_data structure to the vpi handle of the
|
/* build callback user data for this instance */
|
||||||
|
pli = new_pli_data(tf, cur_instance, 0);
|
||||||
|
|
||||||
|
/* Attach the pli_data structure to the VPI handle of the
|
||||||
system task. This is how I manage the map from vpiHandle to
|
system task. This is how I manage the map from vpiHandle to
|
||||||
PLI1 pli data. We do it here (instead of during register)
|
PLI1 user data. We do it here (instead of during register)
|
||||||
because this is the first that I have both the vpiHandle
|
because this is the first that I have both the vpiHandle
|
||||||
and the pli_data. */
|
and the user data. */
|
||||||
vpi_put_userdata(call_h, pli);
|
vpi_put_userdata(cur_instance, pli);
|
||||||
|
|
||||||
/* default cb_data */
|
/* default cb_data */
|
||||||
memset(&cb_data, 0, sizeof(s_cb_data));
|
memset(&cb_data, 0, sizeof(s_cb_data));
|
||||||
cb_data.cb_rtn = callback;
|
cb_data.cb_rtn = callback;
|
||||||
cb_data.user_data = data;
|
cb_data.user_data = (PLI_BYTE8*)pli;
|
||||||
|
|
||||||
/* register EOS misctf callback */
|
/* register EOS misctf callback */
|
||||||
cb_data.reason = cbEndOfSimulation;
|
cb_data.reason = cbEndOfSimulation;
|
||||||
cb_data.obj = call_h;
|
|
||||||
vpi_register_cb(&cb_data);
|
vpi_register_cb(&cb_data);
|
||||||
|
|
||||||
/* If there is a misctf function, then create a value change
|
/* If there is a misctf function, then create a value change
|
||||||
callback for all the arguments. In the tf_* API, misctf
|
callback for all the arguments. In the tf_* API, misctf
|
||||||
functions get value change callbacks, controlled by the
|
functions get value change callbacks, controlled by the
|
||||||
tf_asyncon and tf_asyncoff functions. */
|
tf_asyncon and tf_asyncoff functions. */
|
||||||
if (tf->misctf && ((arg_i = vpi_iterate(vpiArgument, call_h)) != NULL)) {
|
if (tf->misctf && ((arg_i = vpi_iterate(vpiArgument, cur_instance)) != NULL)) {
|
||||||
int paramvc = 1;
|
int paramvc = 1;
|
||||||
|
|
||||||
cb_data.reason = cbValueChange;
|
cb_data.reason = cbValueChange;
|
||||||
while ((arg_h = vpi_scan(arg_i)) != NULL) {
|
while ((arg_h = vpi_scan(arg_i)) != NULL) {
|
||||||
/* replicate user_data for each instance */
|
/* replicate user_data for each instance */
|
||||||
p_pli_data dp = calloc(1, sizeof(s_pli_data));
|
p_pli_data dp = new_pli_data(tf, cur_instance, paramvc++);
|
||||||
memcpy(dp, cb_data.user_data, sizeof(s_pli_data));
|
cb_data.user_data = (PLI_BYTE8*)dp;
|
||||||
dp->paramvc = paramvc++;
|
|
||||||
cb_data.user_data = (char *)dp;
|
|
||||||
cb_data.obj = arg_h;
|
cb_data.obj = arg_h;
|
||||||
vpi_register_cb(&cb_data);
|
vpi_register_cb(&cb_data);
|
||||||
}
|
}
|
||||||
|
|
@ -255,6 +262,7 @@ static PLI_INT32 compiletf(ICARUS_VPI_CONST PLI_BYTE8*data)
|
||||||
tf->misctf(tf->data, reason_endofcompile, 0);
|
tf->misctf(tf->data, reason_endofcompile, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cur_instance = 0;
|
||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,12 +272,13 @@ static PLI_INT32 compiletf(ICARUS_VPI_CONST PLI_BYTE8*data)
|
||||||
static PLI_INT32 calltf(ICARUS_VPI_CONST PLI_BYTE8*data)
|
static PLI_INT32 calltf(ICARUS_VPI_CONST PLI_BYTE8*data)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
p_pli_data pli;
|
|
||||||
p_tfcell tf;
|
p_tfcell tf;
|
||||||
|
|
||||||
/* cast back from opaque */
|
/* cast back from opaque */
|
||||||
pli = (p_pli_data)data;
|
tf = (p_tfcell)data;
|
||||||
tf = pli->tf;
|
|
||||||
|
/* get call handle */
|
||||||
|
cur_instance = vpi_handle(vpiSysTfCall, NULL);
|
||||||
|
|
||||||
/* execute calltf */
|
/* execute calltf */
|
||||||
if (tf->calltf) {
|
if (tf->calltf) {
|
||||||
|
|
@ -281,6 +290,7 @@ static PLI_INT32 calltf(ICARUS_VPI_CONST PLI_BYTE8*data)
|
||||||
rc = tf->calltf(tf->data, reason_calltf);
|
rc = tf->calltf(tf->data, reason_calltf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cur_instance = 0;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -290,12 +300,13 @@ static PLI_INT32 calltf(ICARUS_VPI_CONST PLI_BYTE8*data)
|
||||||
static PLI_INT32 sizetf(ICARUS_VPI_CONST PLI_BYTE8*data)
|
static PLI_INT32 sizetf(ICARUS_VPI_CONST PLI_BYTE8*data)
|
||||||
{
|
{
|
||||||
int rc = 32;
|
int rc = 32;
|
||||||
p_pli_data pli;
|
|
||||||
p_tfcell tf;
|
p_tfcell tf;
|
||||||
|
|
||||||
/* cast back from opaque */
|
/* cast back from opaque */
|
||||||
pli = (p_pli_data)data;
|
tf = (p_tfcell)data;
|
||||||
tf = pli->tf;
|
|
||||||
|
/* get call handle */
|
||||||
|
cur_instance = vpi_handle(vpiSysTfCall, NULL);
|
||||||
|
|
||||||
/* execute sizetf */
|
/* execute sizetf */
|
||||||
if (tf->sizetf) {
|
if (tf->sizetf) {
|
||||||
|
|
@ -307,6 +318,7 @@ static PLI_INT32 sizetf(ICARUS_VPI_CONST PLI_BYTE8*data)
|
||||||
rc = tf->sizetf(tf->data, reason_sizetf);
|
rc = tf->sizetf(tf->data, reason_sizetf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cur_instance = 0;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -329,7 +341,9 @@ static PLI_INT32 callback(p_cb_data data)
|
||||||
|
|
||||||
/* cast back from opaque */
|
/* cast back from opaque */
|
||||||
pli = (p_pli_data)data->user_data;
|
pli = (p_pli_data)data->user_data;
|
||||||
|
|
||||||
tf = pli->tf;
|
tf = pli->tf;
|
||||||
|
cur_instance = pli->call_handle;
|
||||||
|
|
||||||
switch (data->reason) {
|
switch (data->reason) {
|
||||||
case cbValueChange:
|
case cbValueChange:
|
||||||
|
|
@ -362,6 +376,7 @@ static PLI_INT32 callback(p_cb_data data)
|
||||||
/* execute misctf */
|
/* execute misctf */
|
||||||
rc = (tf->misctf) ? tf->misctf(tf->data, reason, paramvc) : 0;
|
rc = (tf->misctf) ? tf->misctf(tf->data, reason, paramvc) : 0;
|
||||||
|
|
||||||
|
cur_instance = 0;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -378,7 +393,7 @@ PLI_INT32 tf_isynchronize(void*obj)
|
||||||
cb.cb_rtn = callback;
|
cb.cb_rtn = callback;
|
||||||
cb.obj = sys;
|
cb.obj = sys;
|
||||||
cb.time = &ti;
|
cb.time = &ti;
|
||||||
cb.user_data = (char *)pli;
|
cb.user_data = (PLI_BYTE8*)pli;
|
||||||
|
|
||||||
vpi_register_cb(&cb);
|
vpi_register_cb(&cb);
|
||||||
|
|
||||||
|
|
@ -405,7 +420,7 @@ PLI_INT32 tf_irosynchronize(void*obj)
|
||||||
cb.cb_rtn = callback;
|
cb.cb_rtn = callback;
|
||||||
cb.obj = sys;
|
cb.obj = sys;
|
||||||
cb.time = &ti;
|
cb.time = &ti;
|
||||||
cb.user_data = (char *)pli;
|
cb.user_data = (PLI_BYTE8*)pli;
|
||||||
|
|
||||||
vpi_register_cb(&cb);
|
vpi_register_cb(&cb);
|
||||||
|
|
||||||
|
|
@ -439,7 +454,7 @@ PLI_INT32 tf_isetrealdelay(double dly, void*obj)
|
||||||
cb.cb_rtn = callback;
|
cb.cb_rtn = callback;
|
||||||
cb.obj = sys;
|
cb.obj = sys;
|
||||||
cb.time = &ti;
|
cb.time = &ti;
|
||||||
cb.user_data = (char *)pli;
|
cb.user_data = (PLI_BYTE8*)pli;
|
||||||
|
|
||||||
vpi_register_cb(&cb);
|
vpi_register_cb(&cb);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue