iverilog/vpi/vhdl_textio.c

944 lines
27 KiB
C

/*
* Copyright (c) 2015 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* The following VPI module implements some of the functions available
* in std.textio library.
*
* Type counterparts:
* VHDL SystemVerilog
* ------------------------------
* LINE string (line of text, in VHDL it is a pointer to string)
* TEXT int (file handle)
*
* Some of functions offered by std.textio library are not implemented here,
* as they can be directly replaced with SystemVerilog system functions.
*
* VHDL SystemVerilog
* --------------------------------------
* FILE_CLOSE(file F: TEXT) $fclose(fd)
* ENDFILE(file F: TEXT) $feof(fd)
*
* Procedures:
* HREAD (L: inout LINE; VALUE: out BIT_VECTOR)
* HWRITE (L: inout LINE; VALUE: out BIT_VECTOR)
* are handled with $ivlh_read/write() using FORMAT_HEX parameter (see format_t enum).
*/
# include "sys_priv.h"
# include "vpi_config.h"
# include "vpi_user.h"
# include <assert.h>
# include <string.h>
# include <ctype.h>
# include "ivl_alloc.h"
/* additional parameter values to distinguish between integer, boolean and
* time types or to use hex format */
enum format_t { FORMAT_STD, FORMAT_BOOL, FORMAT_TIME, FORMAT_HEX, FORMAT_STRING };
enum file_mode_t { FILE_MODE_READ, FILE_MODE_WRITE, FILE_MODE_APPEND, FILE_MODE_LAST };
/* bits per vector, in a single s_vpi_vecval struct */
static const size_t BPW = 8 * sizeof(PLI_INT32);
static int is_integer_var(vpiHandle obj)
{
PLI_INT32 type = vpi_get(vpiType, obj);
return (type == vpiIntegerVar || type == vpiShortIntVar ||
type == vpiIntVar || type == vpiLongIntVar);
}
static void show_error_line(vpiHandle callh) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
}
static void show_warning_line(vpiHandle callh) {
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
}
/* sets a single bit value in a bit/logic vector */
static int set_vec_val(s_vpi_vecval* vector, char value, int idx) {
s_vpi_vecval*v = &vector[idx / BPW];
PLI_INT32 bit = idx % BPW;
switch(toupper(value)) {
case '0':
v->bval &= ~(1 << bit);
v->aval &= ~(1 << bit);
break;
case '1':
v->bval &= ~(1 << bit);
v->aval |= (1 << bit);
break;
case 'Z':
v->bval |= (1 << bit);
v->aval &= ~(1 << bit);
break;
case 'X':
v->bval |= (1 << bit);
v->aval |= (1 << bit);
break;
default:
return 1;
}
return 0;
}
/* Converts a string of characters to a vector in s_vpi_value struct.
* Returns number of processed characters, 0 in case of failure.
* string is the data to be converted.
* val is the target s_vpi_value struct.
* var is the variable that is converted (to obtain size & type [2/4-state]).
*/
static int read_vector(const char *string, s_vpi_value *val, vpiHandle var)
{
#if 0
/* It could be easier to simply use val.format = vpiBinStrVal
* but there is no way to check if processing went fine */
val.format = vpiBinStrVal;
val.value.str = string;
processed_chars = size;
#endif
/* Vector size (==1 for scalars) */
int size = vpi_get(vpiSize, var);
/* Number of required s_vpi_vecval structs to store the result */
int words = (size + BPW - 1) / BPW; /* == ceil(size / BPW) */
int len = strlen(string);
val->format = vpiVectorVal; /* it also covers scalars */
val->value.vector = calloc(words, sizeof(s_vpi_vecval));
/* Skip spaces in the beginning */
int skipped = 0;
while(*string && *string == ' ') {
--len;
++string;
++skipped;
}
/* Process bits */
int p;
for(p = 0; p < size && p < len; ++p) {
if(set_vec_val(val->value.vector, string[p], size - p - 1)) {
free(val->value.vector); /* error */
return 0;
}
}
/* 2-logic variables cannot hold X or Z values, so change them to 0 */
if(vpi_get(vpiType, var) == vpiBitVar) {
for(int i = 0; i < words; ++i) {
val->value.vector[i].aval &= ~val->value.vector[i].bval;
val->value.vector[i].bval = 0;
}
}
return p + skipped;
}
/* Converts a string of characters to a time value, stored in vector filed of
* s_vpi_value struct.
* Returns number of processed characters, 0 in case of failure.
* string is the data to be converted.
* val is the target s_vpi_value struct.
* scope_unit is the time unit used in the scope (-3 for millisecond,
* -6 for microsecond, etc.)
*/
static int read_time(const char *string, s_vpi_value *val, PLI_INT32 scope_unit) {
PLI_UINT64 period;
char units[2];
int time_unit, processed_chars;
if(sscanf(string, "%ld %2s%n", &period, units, &processed_chars) != 2)
return 0;
if(!strncasecmp(units, "fs", 2))
time_unit = -15;
else if(!strncasecmp(units, "ps", 2))
time_unit = -12;
else if(!strncasecmp(units, "ns", 2))
time_unit = -9;
else if(!strncasecmp(units, "us", 2))
time_unit = -6;
else if(!strncasecmp(units, "ms", 2))
time_unit = -3;
else if(!strncasecmp(units, "s", 1))
time_unit = 0;
else
return 0;
/* Scale the time units to the one used in the scope */
int scale_diff = time_unit - scope_unit;
if(scale_diff > 0) {
for(int i = 0; i < scale_diff; ++i)
period *= 10;
} else {
for(int i = 0; i < -scale_diff; ++i)
period /= 10;
}
/* vpiTimeVal format is not handled at the moment,
* so return the read value as a vector*/
val->format = vpiVectorVal;
val->value.vector = calloc(2, sizeof(s_vpi_vecval));
memset(val->value.vector, 0, 2 * sizeof(s_vpi_vecval));
val->value.vector[1].aval = (PLI_UINT32) (period >> 32);
val->value.vector[0].aval = (PLI_UINT32) period;
return processed_chars;
}
static int read_string(const char *string, s_vpi_value *val) {
char buf[1024];
int processed_chars;
if(sscanf(string, "%1024s%n", buf, &processed_chars) != 1)
return 0;
val->format = vpiStringVal;
val->value.str = strndup(buf, processed_chars);
return processed_chars;
}
static int write_time(char *string, const s_vpi_value* val,
size_t width, PLI_INT32 scope_unit) {
char prefix = 0;
PLI_UINT64 period;
switch(val->format) {
case vpiIntVal:
period = val->value.integer;
break;
case vpiVectorVal:
period = val->value.vector[0].aval;
if(width > BPW)
period |= (PLI_UINT64)(val->value.vector[1].aval) << 32;
break;
default:
return 1;
}
/* Handle the case when the time unit base is 10 or 100 */
int remainder = scope_unit % -3;
if(remainder) {
remainder += 3;
scope_unit -= remainder;
while(remainder--)
period *= 10;
}
switch(scope_unit) {
case -15: prefix = 'f'; break;
case -12: prefix = 'p'; break;
case -9: prefix = 'n'; break;
case -6: prefix = 'u'; break;
case -3: prefix = 'm'; break;
}
if(prefix)
sprintf(string, "%ld %cs", period, prefix);
else
sprintf(string, "%ld s", period);
return 0;
}
/* slightly modified sys_fopen_compiletf */
static PLI_INT32 ivlh_file_open_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv;
assert(callh != 0);
argv = vpi_iterate(vpiArgument, callh);
/* Check that there is a file name argument and that it is a string. */
if (argv == 0) {
show_error_line(callh);
vpi_printf("%s requires a string file name argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
if(!is_integer_var(vpi_scan(argv))) {
show_error_line(callh);
vpi_printf("%s's first argument has to be an integer variable (file handle).\n", name);
vpi_control(vpiFinish, 1);
}
if(!is_string_obj(vpi_scan(argv))) {
show_error_line(callh);
vpi_printf("%s's second argument argument must be a string (file name).\n", name);
vpi_control(vpiFinish, 1);
}
/* When provided, the type argument must be a string. */
if(!vpi_scan(argv)) {
show_error_line(callh);
vpi_printf("%s's third argument must be an integer (open mode).\n", name);
vpi_control(vpiFinish, 1);
}
/* Make sure there are no extra arguments. */
check_for_extra_args(argv, callh, name, "three arguments", 1);
return 0;
}
/* procedure FILE_MODE(file F: TEXT; External_Name; in STRING;
Open_Kind: in FILE_MODE_KIND := READ_MODE); */
/* slightly modified sys_fopen_calltf */
static PLI_INT32 ivlh_file_open_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
s_vpi_value val;
int mode;
char *fname;
vpiHandle fhandleh = vpi_scan(argv);
vpiHandle fnameh = vpi_scan(argv);
vpiHandle modeh = vpi_scan(argv);
/* Get the mode handle */
val.format = vpiIntVal;
vpi_get_value(modeh, &val);
mode = val.value.integer;
vpi_free_object(argv);
if(mode < 0 || mode >= FILE_MODE_LAST) {
show_error_line(callh);
vpi_printf("%s's file open mode argument is invalid.\n", name);
return 0;
}
fname = get_filename(callh, name, fnameh);
if(fname == 0) {
show_error_line(callh);
vpi_printf("%s's could not obtain the file name.\n", name);
return 0;
}
/* Open file and save the handle */
switch(mode) {
case FILE_MODE_READ:
val.value.integer = vpi_fopen(fname, "r");
break;
case FILE_MODE_WRITE:
val.value.integer = vpi_fopen(fname, "w");
break;
case FILE_MODE_APPEND:
val.value.integer = vpi_fopen(fname, "a");
break;
}
val.format = vpiIntVal;
vpi_put_value(fhandleh, &val, 0, vpiNoDelay);
free(fname);
return 0;
}
static PLI_INT32 ivlh_readwriteline_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
/* Check that there are two arguments and that the first is an
integer (file handle) and that the second is string. */
if(argv == 0) {
show_error_line(callh);
vpi_printf("%s requires two arguments.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
arg = vpi_scan(argv);
if(!arg || !is_integer_var(arg)) {
show_error_line(callh);
vpi_printf("%s's first argument must be an integer variable (file handle).\n", name);
vpi_control(vpiFinish, 1);
}
arg = vpi_scan(argv);
if(!arg || !is_string_obj(arg)) {
show_error_line(callh);
vpi_printf("%s's second argument must be a string.\n", name);
vpi_control(vpiFinish, 1);
}
/* Make sure there are no extra arguments. */
check_for_extra_args(argv, callh, name, "two arguments", 0);
return 0;
}
/* procedure READLINE (file F: TEXT; L: inout LINE); */
/* slightly modified sys_fgets_calltf */
static PLI_INT32 ivlh_readline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle stringh, arg;
s_vpi_value val;
PLI_UINT32 fd;
FILE *fp;
char *text;
const int BUF_SIZE = 1024;
char buf[BUF_SIZE];
/* Get the file descriptor. */
arg = vpi_scan(argv);
val.format = vpiIntVal;
vpi_get_value(arg, &val);
fd = val.value.integer;
/* Get the string handle. */
stringh = vpi_scan(argv);
vpi_free_object(argv);
/* Return zero if this is not a valid fd. */
fp = vpi_get_file(fd);
if(!fp) {
show_warning_line(callh);
vpi_printf("invalid file descriptor (0x%x) given to %s.\n",
(unsigned int)fd, name);
return 0;
}
/* Read in the bytes. Return 0 if there was an error. */
if(fgets(buf, BUF_SIZE, fp) == 0) {
show_error_line(callh);
vpi_printf("%s reading past the end of file.\n", name);
return 0;
}
int len = strlen(buf);
if(len == 0) {
show_error_line(callh);
vpi_printf("%s read 0 bytes.\n", name);
return 0;
} else if(len == BUF_SIZE - 1) {
show_warning_line(callh);
vpi_printf("%s has reached the buffer limit, part of the "
"processed string might have been skipped.\n", name);
}
/* Return the characters to the register. */
text = strndup(buf, len - 1); /* skip the newline character */
val.format = vpiStringVal;
val.value.str = text;
vpi_put_value(stringh, &val, 0, vpiNoDelay);
free(text);
return 0;
}
/* procedure WRITELINE (file F: TEXT; L: inout LINE); */
/* slightly modified sys_fgets_calltf */
static PLI_INT32 ivlh_writeline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle stringh, arg;
s_vpi_value val;
PLI_UINT32 fd;
FILE *fp;
char *empty;
/* Get the file descriptor. */
arg = vpi_scan(argv);
val.format = vpiIntVal;
vpi_get_value(arg, &val);
fd = val.value.integer;
/* Get the string contents. */
stringh = vpi_scan(argv);
val.format = vpiStringVal;
vpi_get_value(stringh, &val);
vpi_free_object(argv);
/* Return zero if this is not a valid fd. */
fp = vpi_get_file(fd);
if(!fp) {
show_warning_line(callh);
vpi_printf("invalid file descriptor (0x%x) given to %s.\n",
(unsigned int)fd, name);
return 0;
}
fprintf(fp, "%s\n", val.value.str);
/* Clear the written string */
empty = strdup("");
val.format = vpiStringVal;
val.value.str = empty;
vpi_put_value(stringh, &val, 0, vpiNoDelay);
free(empty);
return 0;
}
static PLI_INT32 ivlh_read_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
if(argv == 0) {
show_error_line(callh);
vpi_printf("%s requires three arguments.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
arg = vpi_scan(argv);
if(!arg || !is_string_obj(arg)) {
show_error_line(callh);
vpi_printf("%s's first argument must be a string.\n", name);
vpi_control(vpiFinish, 1);
}
arg = vpi_scan(argv);
if(!arg || is_constant_obj(arg)) {
show_error_line(callh);
vpi_printf("%s's second argument must be a variable.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
arg = vpi_scan(argv);
if(!arg) {
show_error_line(callh);
vpi_printf("%s's third argument must be an integer.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
/* Make sure there are no extra arguments. */
check_for_extra_args(argv, callh, name, "three arguments", 0);
return 0;
}
/* procedure READ (L: inout LINE;
VALUE: out BIT/BIT_VECTOR/BOOLEAN/CHARACTER/INTEGER/REAL/STRING/TIME); */
static PLI_INT32 ivlh_read_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle stringh, varh, formath;
s_vpi_value val;
PLI_INT32 type, format;
char *string = 0;
int processed_chars = 0, fail = 0;
/* Get the string */
stringh = vpi_scan(argv);
val.format = vpiStringVal;
vpi_get_value(stringh, &val);
/* Get the destination variable */
varh = vpi_scan(argv);
type = vpi_get(vpiType, varh);
if(strlen(val.value.str) == 0) {
show_error_line(callh);
vpi_printf("%s cannot read from an empty string.\n", name);
return 0;
}
string = strdup(val.value.str);
/* Get the format (see enum format_t) */
formath = vpi_scan(argv);
val.format = vpiIntVal;
vpi_get_value(formath, &val);
format = val.value.integer;
vpi_free_object(argv);
switch(format) {
case FORMAT_STD:
switch(type) {
/* TODO longint is 64-bit, so it has to be handled by vector */
/*case vpiLongIntVar:*/
case vpiShortIntVar:
case vpiIntVar:
case vpiByteVar:
case vpiIntegerVar:
val.format = vpiIntVal;
if(sscanf(string, "%d%n", &val.value.integer, &processed_chars) != 1)
fail = 1;
break;
case vpiBitVar: /* bit, bit vector */
case vpiLogicVar: /* ==vpiReg time, logic, logic vector */
processed_chars = read_vector(string, &val, varh);
break;
case vpiRealVar:
val.format = vpiRealVal;
if(sscanf(string, "%lf%n", &val.value.real, &processed_chars) != 1)
fail = 1;
break;
case vpiStringVar:
processed_chars = read_string(string, &val);
break;
default:
fail = 1;
show_warning_line(callh);
vpi_printf("%s does not handle such type (%d).\n", name, type);
break;
}
break;
case FORMAT_BOOL:
{
char buf[5];
val.format = vpiIntVal;
if(sscanf(string, "%5s%n", buf, &processed_chars) == 1)
{
if(!strncasecmp(buf, "true", 4))
val.value.integer = 1;
else if(!strncasecmp(buf, "false", 5))
val.value.integer = 0;
else
fail = 1;
}
}
break;
case FORMAT_TIME:
val.format = vpiIntVal;
processed_chars = read_time(string, &val, vpi_get(vpiTimeUnit, callh));
break;
case FORMAT_HEX:
val.format = vpiIntVal;
if(sscanf(string, "%x%n", &val.value.integer, &processed_chars) != 1)
fail = 1;
break;
case FORMAT_STRING:
processed_chars = read_string(string, &val);
break;
}
if(processed_chars == 0) {
show_error_line(callh);
vpi_printf("%s could not read a valid value.\n", name);
fail = 1;
} else if(val.format == vpiStringVar && processed_chars == 1024) {
show_warning_line(callh);
vpi_printf("%s has reached the buffer limit, part of the "
"processed string might have been skipped.\n", name);
}
if(!fail) {
assert(processed_chars > 0);
/* Store the read value */
vpi_put_value(varh, &val, 0, vpiNoDelay);
/* Clean up */
if(val.format == vpiStringVar)
free(val.value.str);
else if(val.format == vpiVectorVal)
free(val.value.vector);
/* Strip the read token from the string */
char* tmp = strdup(&string[processed_chars]);
val.format = vpiStringVal;
val.value.str = tmp;
vpi_put_value(stringh, &val, 0, vpiNoDelay);
free(tmp);
} else {
show_error_line(callh);
vpi_printf("%s failed.\n", name);
/*vpi_control(vpiFinish, 1);*/
}
free(string);
return 0;
}
static PLI_INT32 ivlh_write_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
if(argv == 0) {
show_error_line(callh);
vpi_printf("%s requires three arguments.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
arg = vpi_scan(argv);
if(!arg || !is_string_obj(arg)) {
show_error_line(callh);
vpi_printf("%s's first argument must be a string.\n", name);
vpi_control(vpiFinish, 1);
}
arg = vpi_scan(argv);
if(!arg) {
show_error_line(callh);
vpi_printf("%s requires three arguments.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
arg = vpi_scan(argv);
if(!arg) {
show_error_line(callh);
vpi_printf("%s's third argument must be an integer.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
/* Make sure there are no extra arguments. */
check_for_extra_args(argv, callh, name, "three arguments", 0);
return 0;
}
/*procedure WRITE (L: inout LINE;
VALUE: in BIT/BIT_VECTOR/BOOLEAN/CHARACTER/INTEGER/REAL/STRING/TIME);
JUSTIFIED: in SIDE:= RIGHT; FIELD: in WIDTH := 0); */
/* JUSTIFIED & FIELD are not handled at the moment */
static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle stringh, varh, formath;
s_vpi_value val;
PLI_INT32 type, format;
char *string = 0;
int fail = 0, res = 0;
const int BUF_SIZE = 1024;
char buf[BUF_SIZE];
/* Get the string */
stringh = vpi_scan(argv);
val.format = vpiStringVal;
vpi_get_value(stringh, &val);
string = strdup(val.value.str);
/* Get the destination variable */
varh = vpi_scan(argv);
type = vpi_get(vpiType, varh);
/* Get the format (see enum format_t) */
formath = vpi_scan(argv);
val.format = vpiIntVal;
vpi_get_value(formath, &val);
format = val.value.integer;
vpi_free_object(argv);
/* Convert constant types to variable types */
if(type == vpiConstant) {
type = vpi_get(vpiConstType, varh);
switch(type) {
case vpiRealConst:
type = vpiRealVar;
break;
case vpiStringConst:
type = vpiStringVar;
break;
case vpiDecConst:
case vpiBinaryConst:
case vpiOctConst:
case vpiHexConst:
type = vpiIntVar;
break;
}
}
switch(format) {
case FORMAT_STD:
switch(type) {
/* TODO longint is 64-bit, so it has to be handled by vector */
/*case vpiLongIntVar:*/
case vpiShortIntVar:
case vpiIntVar:
case vpiByteVar:
case vpiIntegerVar:
val.format = vpiIntVal;
vpi_get_value(varh, &val);
res = snprintf(buf, BUF_SIZE, "%s%d", string, val.value.integer);
break;
case vpiBitVar: /* bit, bit vector */
case vpiLogicVar: /* ==vpiReg time, logic, logic vector */
val.format = vpiBinStrVal;
vpi_get_value(varh, &val);
/* VHDL stores X/Z values uppercase, so follow the rule */
for(size_t i = 0; i< strlen(val.value.str); ++i)
val.value.str[i] = toupper(val.value.str[i]);
res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str);
break;
case vpiRealVar:
val.format = vpiRealVal;
vpi_get_value(varh, &val);
res = snprintf(buf, BUF_SIZE, "%s%lf", string, val.value.real);
break;
case vpiStringVar:
val.format = vpiStringVal;
vpi_get_value(varh, &val);
res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str);
break;
default:
fail = 1;
show_warning_line(callh);
vpi_printf("%s does not handle such type (%d).\n", name, type);
break;
}
break;
case FORMAT_BOOL:
val.format = vpiIntVal;
vpi_get_value(varh, &val);
res = snprintf(buf, BUF_SIZE, "%s%s", string,
val.value.integer ? "TRUE" : "FALSE");
break;
case FORMAT_TIME:
{
char tmp[64];
val.format = vpiIntVal;
vpi_get_value(varh, &val);
if(write_time(tmp, &val, vpi_get(vpiSize, varh), vpi_get(vpiTimeUnit, callh))) {
fail = 1;
break;
}
res = snprintf(buf, BUF_SIZE, "%s%s", string, tmp);
}
break;
case FORMAT_HEX:
val.format = vpiIntVal;
vpi_get_value(varh, &val);
res = snprintf(buf, BUF_SIZE, "%s%X", string, val.value.integer);
break;
case FORMAT_STRING:
val.format = vpiStringVal;
vpi_get_value(varh, &val);
res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str);
break;
}
if(res > BUF_SIZE)
fail = 1;
if(!fail) {
/* Strip the read token from the string */
char* tmp = strndup(buf, BUF_SIZE);
val.format = vpiStringVal;
val.value.str = tmp;
vpi_put_value(stringh, &val, 0, vpiNoDelay);
free(tmp);
} else {
show_error_line(callh);
vpi_printf("%s failed.\n", name);
/*vpi_control(vpiFinish, 1);*/
}
free(string);
return 0;
}
static void vhdl_register(void)
{
vpiHandle res;
s_vpi_systf_data tf_data[] = {
{ vpiSysTask, 0, "$ivlh_file_open",
ivlh_file_open_calltf, ivlh_file_open_compiletf, 0,
"$ivlh_file_open" },
{ vpiSysTask, 0, "$ivlh_readline",
ivlh_readline_calltf, ivlh_readwriteline_compiletf, 0,
"$ivlh_readline" },
{ vpiSysTask, 0, "$ivlh_writeline",
ivlh_writeline_calltf, ivlh_readwriteline_compiletf, 0,
"$ivlh_writeline" },
{ vpiSysTask, 0, "$ivlh_read",
ivlh_read_calltf, ivlh_read_compiletf, 0,
"$ivlh_read" },
{ vpiSysTask, 0, "$ivlh_write",
ivlh_write_calltf, ivlh_write_compiletf, 0,
"$ivlh_write" },
};
for(unsigned int i = 0; i < sizeof(tf_data) / sizeof(s_vpi_systf_data); ++i) {
res = vpi_register_systf(&tf_data[i]);
vpip_make_systf_system_defined(res);
}
}
void (*vlog_startup_routines[])(void) = {
vhdl_register,
0
};