159 lines
3.5 KiB
C
159 lines
3.5 KiB
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <vpi_user.h>
|
|
|
|
/*
|
|
* This file exercises an error
|
|
*/
|
|
|
|
static int chkvpierr(void)
|
|
{
|
|
s_vpi_error_info info;
|
|
int level;
|
|
|
|
if ((level = vpi_chk_error(&info)) != 0) {
|
|
fprintf(stderr, "+++ VPI ERROR +++ level %d\n", level);
|
|
fprintf(stderr, "+++ MESS: %s\n", info.message);
|
|
fprintf(stderr, "+++ PROD: %s\n", info.product);
|
|
fprintf(stderr, "+++ CODE: %s\n", info.code);
|
|
fprintf(stderr, "+++ FILE: %s\n", info.file);
|
|
fprintf(stderr, "+++\n");
|
|
}
|
|
return level;
|
|
}
|
|
|
|
#ifdef IVERILOG_V0_8
|
|
static PLI_INT32 xxx_compiletf(char *user_data)
|
|
#else
|
|
static PLI_INT32 xxx_compiletf(PLI_BYTE8 *user_data)
|
|
#endif
|
|
{
|
|
(void)user_data; /* Parameter is not used. */
|
|
return 0;
|
|
}
|
|
|
|
char charbuf[100];
|
|
|
|
#ifdef IVERILOG_V0_8
|
|
static PLI_INT32 xxx_calltf(char *user_data)
|
|
#else
|
|
static PLI_INT32 xxx_calltf(PLI_BYTE8 *user_data)
|
|
#endif
|
|
{
|
|
vpiHandle systf_h;
|
|
s_vpi_value vpival; /* get/set register values */
|
|
s_vpi_time t;
|
|
vpiHandle arg_iterator;
|
|
int i;
|
|
vpiHandle argi[100];
|
|
|
|
(void)user_data; /* Parameter is not used. */
|
|
|
|
/* Get handle to this instance, look up our workarea */
|
|
systf_h = vpi_handle(vpiSysTfCall, NULL);
|
|
chkvpierr();
|
|
|
|
arg_iterator = vpi_iterate(vpiArgument, systf_h);
|
|
chkvpierr();
|
|
i = 0;
|
|
|
|
if (arg_iterator == NULL) {
|
|
fprintf(stderr, "ERROR: missing argument list to $example(...)");
|
|
}
|
|
|
|
/* Copy args pointers into argi array */
|
|
while ((argi[i] = vpi_scan(arg_iterator)) != NULL) {
|
|
chkvpierr();
|
|
i++;
|
|
}
|
|
/* iterator is exhausted, no need to free */
|
|
|
|
/* Fill in the time struct */
|
|
t.type = vpiScaledRealTime;
|
|
t.high = 0;
|
|
t.low = 0;
|
|
t.real = 10.0;
|
|
|
|
/* Fill in the value struct */
|
|
vpival.format = vpiBinStrVal;
|
|
vpival.value.str = charbuf;
|
|
|
|
/*
|
|
* This is where the real work happens. We are called in an intial
|
|
* block and we schedule three "set-values" at times 10, 20 and 30
|
|
* to args 0, 1 and 2. The charbuf gets shared among the three
|
|
* calls, even though it shouldn't and the values are not distinct.
|
|
*/
|
|
|
|
/* Write this value to argi[0] at time 10.0 */
|
|
strcpy(charbuf, "01010101");
|
|
vpi_put_value(argi[0], &vpival, &t, vpiTransportDelay);
|
|
|
|
/* Write this value to argi[1] at time 20.0 */
|
|
strcpy(charbuf, "x1x1x1x1");
|
|
t.real = 20.0;
|
|
vpi_put_value(argi[1], &vpival, &t, vpiTransportDelay);
|
|
|
|
/* Write this value to argi[2] at time 30.0 */
|
|
strcpy(charbuf, "0xz101xz");
|
|
t.real = 30.0;
|
|
vpi_put_value(argi[2], &vpival, &t, vpiTransportDelay);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void xxx_register(void)
|
|
{
|
|
s_vpi_systf_data tfdata;
|
|
|
|
vpi_printf("+++ in XXX_REGISTER\n");
|
|
|
|
tfdata.type = vpiSysFunc;
|
|
|
|
/*
|
|
* TOM: sysfunctype field seems to be problematic for different simulators!
|
|
* some simulators simply don't register callback if subtype missing.
|
|
*
|
|
* Icarus - doesn't implement vpiSizedFunc, so use vpiIntFunct.
|
|
* CVER - use vpiIntFunc
|
|
* MTI - use vpiSizedFunc or vpiIntFunc.
|
|
* XL/NC - doesn't matter
|
|
* VCS - doesn't matter
|
|
*
|
|
*/
|
|
|
|
tfdata.sysfunctype = vpiIntFunc;
|
|
/* tfdata.sysfunctype = vpiSizedFunc; */
|
|
|
|
tfdata.tfname = "$example";
|
|
tfdata.calltf = xxx_calltf;
|
|
tfdata.compiletf = xxx_compiletf;
|
|
/* tfdata.sizetf = xxx_sizetf; */
|
|
tfdata.sizetf = 0;
|
|
tfdata.user_data = 0;
|
|
|
|
vpi_register_systf(&tfdata);
|
|
chkvpierr();
|
|
}
|
|
|
|
|
|
|
|
|
|
static void xxx_startup(void)
|
|
{
|
|
vpi_printf("*** Registering XXX PLI functions.\n");
|
|
xxx_register();
|
|
}
|
|
|
|
/**
|
|
*
|
|
*
|
|
**/
|
|
|
|
void (*vlog_startup_routines[])(void) = {
|
|
xxx_startup,
|
|
0
|
|
};
|