Free memory at EOS and convert to C code (vhdl_table.cc).

This patch converts the vhdl_table.cc file to C code and adds
code to free the allocated memory at the end of simulation to
make valgrind happy.
This commit is contained in:
Cary R 2011-10-05 18:49:02 -07:00 committed by Stephen Williams
parent 82e946b51a
commit 7f65f3b157
2 changed files with 66 additions and 26 deletions

View File

@ -151,7 +151,7 @@ va_math.vpi: $V ../vvp/libvpi.a
$(CC) @shared@ -o $@ $V -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS)
vhdl_sys.vpi: $(VHDL_SYS) ../vvp/libvpi.a
$(CXX) @shared@ -o $@ $(VHDL_SYS) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS)
$(CC) @shared@ -o $@ $(VHDL_SYS) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS)
stamp-vpi_config-h: $(srcdir)/vpi_config.h.in ../config.status
@rm -f $@

View File

@ -19,7 +19,8 @@
# include "vpi_config.h"
# include "vpi_user.h"
# include <cassert>
# include <assert.h>
# include "ivl_alloc.h"
/*
* The $ivlh_attribute_event implements the VHDL <varname>'event
@ -32,14 +33,28 @@ struct monitor_data {
struct t_vpi_time last_event;
};
/*
* All the following are called from C so define them for C linkage.
*/
extern "C" {
static struct monitor_data **mdata = 0;
static unsigned mdata_count = 0;
/* To keep valgrind happy free the allocated memory. */
static PLI_INT32 cleanup_mdata(p_cb_data cause)
{
unsigned idx;
(void) cause; /* Unused argument. */
for (idx= 0; idx < mdata_count; idx += 1) {
free(mdata[idx]);
}
free(mdata);
mdata = 0;
mdata_count = 0;
return 0;
}
static PLI_INT32 monitor_events(struct t_cb_data*cb)
{
struct monitor_data*mon = reinterpret_cast<monitor_data*> (cb->user_data);
struct monitor_data*mon = (struct monitor_data*)(cb->user_data);
assert(cb->time);
assert(cb->time->type == vpiSimTime);
@ -48,56 +63,71 @@ static PLI_INT32 monitor_events(struct t_cb_data*cb)
return 0;
}
static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*)
static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle arg;
struct monitor_data*mon;
struct t_cb_data cb;
struct t_vpi_time tb;
// Check that there is at least 1 argument...
/* Check that there are arguments. */
if (argv == 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), vpi_get(vpiLineNo, sys));
vpi_printf("Call to %s missing its argument\n", vpi_get_str(vpiName,sys));
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys),
(int)vpi_get(vpiLineNo, sys));
vpi_printf("(compiler error) %s requires a single argument.\n",
name);
vpi_control(vpiFinish, 1);
return 0;
}
/* Icarus either returns 0 above or has one argument. */
arg = vpi_scan(argv);
assert(arg);
struct monitor_data*monitor_handle = new struct monitor_data;
mon = malloc(sizeof(struct monitor_data));
/* Add this to the list of data. */
mdata_count += 1;
mdata = (struct monitor_data **) realloc(mdata,
sizeof(struct monitor_data **) *
mdata_count);
mdata[mdata_count-1] = mon;
struct t_cb_data cb;
struct t_vpi_time tb;
tb.type = vpiSimTime;
cb.reason = cbValueChange;
cb.cb_rtn = monitor_events;
cb.obj = arg;
cb.time = &tb;
cb.value = 0;
cb.user_data = reinterpret_cast<char*>(monitor_handle);
cb.user_data = (char*) (mon);
vpi_register_cb(&cb);
vpi_put_userdata(sys, monitor_handle);
vpi_put_userdata(sys, mon);
// check that there is no more then 1 argument
/* Check that there are no more then one argument. */
arg = vpi_scan(argv);
if (arg != 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), vpi_get(vpiLineNo, sys));
vpi_printf("Too many arguments for call to %s.\n", vpi_get_str(vpiName,sys));
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys),
(int)vpi_get(vpiLineNo, sys));
vpi_printf("(compiler error) %s only takes a single argument.\n",
name);
vpi_free_object(argv);
vpi_control(vpiFinish, 1);
}
return 0;
}
static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*)
static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
struct t_vpi_value rval;
struct monitor_data*mon;
(void) name;
rval.format = vpiScalarVal;
struct monitor_data*mon = reinterpret_cast<monitor_data*>(vpi_get_userdata(sys));
mon = (struct monitor_data*) (vpi_get_userdata(sys));
if (mon->last_event.type == 0) {
rval.value.scalar = vpi0;
@ -105,7 +135,7 @@ static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*)
} else {
struct t_vpi_time tnow;
tnow.type = vpiSimTime;
vpi_get_time(0,&tnow);
vpi_get_time(0, &tnow);
rval.value.scalar = vpi1;
if (mon->last_event.high != tnow.high)
@ -119,14 +149,16 @@ static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*)
return 0;
}
static PLI_INT32 ivlh_attribute_event_sizetf(ICARUS_VPI_CONST PLI_BYTE8*)
static PLI_INT32 ivlh_attribute_event_sizetf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
(void) name;
return 1;
}
static void vhdl_register(void)
{
s_vpi_systf_data tf_data;
s_cb_data cb;
vpiHandle res;
tf_data.type = vpiSysFunc;
@ -138,11 +170,19 @@ static void vhdl_register(void)
tf_data.user_data = (PLI_BYTE8 *) "$ivlh_attribute_event";
res = vpi_register_systf(&tf_data);
vpip_make_systf_system_defined(res);
/* Create a callback to clear the monitor data memory when the
* simulator finishes. */
cb.time = NULL;
cb.reason = cbEndOfSimulation;
cb.cb_rtn = cleanup_mdata;
cb.user_data = NULL;
cb.obj = NULL;
vpi_register_cb(&cb);
}
void (*vlog_startup_routines[])() = {
vhdl_register,
0
};
} /* extern "C" */