Update $ferror() and $fgets() to support SV strings

This commit is contained in:
Cary R 2023-07-19 00:29:08 -07:00
parent ceb07dc9db
commit 3aafa1333b
5 changed files with 98 additions and 41 deletions

View File

@ -1,6 +1,6 @@
ERROR: vlog95.v:18: $ferror's fd (first) argument must be numeric.
ERROR: vlog95.v:19: $ferror requires a second (register) argument.
ERROR: vlog95.v:20: $ferror's second argument must be a reg (>=640 bits).
ERROR: vlog95.v:19: $ferror requires a second (variable) argument.
ERROR: vlog95.v:20: $ferror's second argument must be a variable (>=640 bits).
ERROR: vlog95.v:21: $ferror's second argument must have 640 bit or more.
ERROR: vlog95.v:22: $ferror takes two arguments.
Found 1 extra argument.

View File

@ -1,6 +1,6 @@
ERROR: ./ivltests/pr2800985b.v:11: $ferror's fd (first) argument must be numeric.
ERROR: ./ivltests/pr2800985b.v:12: $ferror requires a second (register) argument.
ERROR: ./ivltests/pr2800985b.v:13: $ferror's second argument must be a reg (>=640 bits).
ERROR: ./ivltests/pr2800985b.v:12: $ferror requires a second (variable) argument.
ERROR: ./ivltests/pr2800985b.v:13: $ferror's second argument must be a variable (>=640 bits).
ERROR: ./ivltests/pr2800985b.v:14: $ferror's second argument must have 640 bit or more.
ERROR: ./ivltests/pr2800985b.v:15: $ferror takes two arguments.
Found 1 extra argument.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003-2021 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-2023 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
@ -334,7 +334,7 @@ static PLI_INT32 sys_fgets_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
/*
* Check that there are two arguments and that the first is a
* register and that the second is numeric.
* variable and that the second is numeric.
*/
if (argv == 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
@ -345,10 +345,10 @@ static PLI_INT32 sys_fgets_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
return 0;
}
if (vpi_get(vpiType, vpi_scan(argv)) != vpiReg) {
if (! is_variable(vpi_scan(argv))) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's first argument must be a reg.\n", name);
vpi_printf("%s's first argument must be a variable.\n", name);
vpip_set_return_value(1);
vpi_control(vpiFinish, 1);
}
@ -377,21 +377,30 @@ static PLI_INT32 sys_fgets_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
return 0;
}
static void return_zero(vpiHandle callh)
{
s_vpi_value val;
val.format = vpiIntVal;
val.value.integer = 0;
assert(callh);
vpi_put_value(callh, &val, 0, vpiNoDelay);
}
static PLI_INT32 sys_fgets_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle regh;
vpiHandle varh;
vpiHandle arg;
s_vpi_value val;
PLI_UINT32 fd_mcd;
FILE *fp;
PLI_INT32 reg_size;
PLI_INT32 var_size;
char*text;
errno = 0;
/* Get the register handle. */
regh = vpi_scan(argv);
/* Get the variable handle. */
varh = vpi_scan(argv);
/* Get the file/MCD descriptor. */
arg = vpi_scan(argv);
@ -414,17 +423,34 @@ static PLI_INT32 sys_fgets_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
return 0;
}
/* Get the register size in bytes and allocate the buffer. */
reg_size = vpi_get(vpiSize, regh) / 8;
text = malloc(reg_size + 1);
if (vpi_get(vpiType, varh) == vpiStringVar) {
PLI_INT32 base_size = 1024;
size_t txt_len;
var_size = 0;
text = 0;
do {
var_size += base_size;
text = realloc(text, var_size+1);
/* Read in the bytes. Return 0 if there was an error.
* Assume an error can only occur when reading the first group of bytes. */
if ((fgets(text+var_size-base_size, base_size+1, fp) == 0) && (var_size == base_size)) {
return_zero(callh);
free(text);
return 0;
}
txt_len = strlen(text);
} while (((PLI_INT32) txt_len == var_size) && (text[txt_len-1] != '\n'));
} else {
/* Get the register size in bytes and allocate the buffer. */
var_size = vpi_get(vpiSize, varh) / 8;
text = malloc(var_size + 1);
/* Read in the bytes. Return 0 if there was an error. */
if (fgets(text, reg_size+1, fp) == 0) {
val.format = vpiIntVal;
val.value.integer = 0;
vpi_put_value(callh, &val, 0, vpiNoDelay);
free(text);
return 0;
/* Read in the bytes. Return 0 if there was an error. */
if (fgets(text, var_size+1, fp) == 0) {
return_zero(callh);
free(text);
return 0;
}
}
/* Return the number of character read. */
@ -435,7 +461,7 @@ static PLI_INT32 sys_fgets_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
/* Return the characters to the register. */
val.format = vpiStringVal;
val.value.str = text;
vpi_put_value(regh, &val, 0, vpiNoDelay);
vpi_put_value(varh, &val, 0, vpiNoDelay);
free(text);
return 0;
@ -970,7 +996,7 @@ static PLI_INT32 sys_ferror_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name)
/*
* Check that there are two arguments and that the first is
* numeric and that the second is a 640 bit or larger register.
* numeric and that the second is a 640 bit or larger variable.
*
* The parser requires that a function have at least one argument,
* so argv should always be defined with one argument.
@ -986,25 +1012,25 @@ static PLI_INT32 sys_ferror_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name)
}
/* Check that the second argument is given and that it is a 640 bit
* or larger register. */
* or larger variable. */
arg = vpi_scan(argv);
if (! arg) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires a second (register) argument.\n", name);
vpi_printf("%s requires a second (variable) argument.\n", name);
vpip_set_return_value(1);
vpi_control(vpiFinish, 1);
return 0;
}
if (vpi_get(vpiType, arg) != vpiReg) {
if (! is_variable(arg)) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's second argument must be a reg (>=640 bits).\n",
vpi_printf("%s's second argument must be a variable (>=640 bits).\n",
name);
vpip_set_return_value(1);
vpi_control(vpiFinish, 1);
} else if (vpi_get(vpiSize, arg) < 640) {
} else if ((vpi_get(vpiSize, arg) < 640) && (vpi_get(vpiType, arg) != vpiStringVar)) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's second argument must have 640 bit or more.\n",
@ -1023,7 +1049,7 @@ static PLI_INT32 sys_ferror_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle reg;
vpiHandle var;
s_vpi_value val;
char *msg;
PLI_INT32 size;
@ -1035,10 +1061,10 @@ static PLI_INT32 sys_ferror_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
vpi_get_value(vpi_scan(argv), &val);
fd_mcd = val.value.integer;
/* Get the register to put the string result and figure out how many
/* Get the variable to put the string result and figure out how many
* characters it will hold. */
reg = vpi_scan(argv);
size = vpi_get(vpiSize, reg);
var = vpi_scan(argv);
size = vpi_get(vpiSize, var);
chars = size / 8;
vpi_free_object(argv);
@ -1061,14 +1087,19 @@ static PLI_INT32 sys_ferror_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
val.value.integer = errno;
vpi_put_value(callh, &val, 0, vpiNoDelay);
/* Only return the number of characters that will fit in the reg. */
msg = (char *) malloc(chars);
if (errno != 0) strncpy(msg, strerror(errno), chars-1);
else strncpy(msg, "", chars-1);
msg[chars-1] = '\0';
/* Only return the number of characters that will fit in the variable. */
if (vpi_get(vpiType, var) == vpiStringVar) {
if (errno != 0) msg = strdup(strerror(errno));
else msg = strdup("");
} else {
msg = (char *) malloc(chars);
if (errno != 0) strncpy(msg, strerror(errno), chars-1);
else strncpy(msg, "", chars-1);
msg[chars-1] = '\0';
}
val.format = vpiStringVal;
val.value.str = msg;
vpi_put_value(reg, &val, 0, vpiNoDelay);
vpi_put_value(var, &val, 0, vpiNoDelay);
free(msg);
return 0;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003-2021 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-2023 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
@ -257,6 +257,31 @@ unsigned is_string_obj(vpiHandle obj)
return rtn;
}
/*
* This routine returns 1 if the argument supports a valid string value,
* otherwise it returns 0.
*/
unsigned is_variable(vpiHandle obj)
{
unsigned rtn = 0;
assert(obj);
switch(vpi_get(vpiType, obj)) {
case vpiIntegerVar:
case vpiBitVar:
case vpiByteVar:
case vpiShortIntVar:
case vpiIntVar:
case vpiLongIntVar:
case vpiReg:
case vpiTimeVar:
case vpiStringVar:
rtn = 1;
break;
}
return rtn;
}
/*
* Check if the file descriptor or MCD is valid.

View File

@ -1,7 +1,7 @@
#ifndef IVL_sys_priv_H
#define IVL_sys_priv_H
/*
* Copyright (c) 2002-2020 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-2023 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
@ -58,6 +58,7 @@ extern struct timeformat_info_s timeformat_info;
extern unsigned is_constant_obj(vpiHandle obj);
extern unsigned is_numeric_obj(vpiHandle obj);
extern unsigned is_string_obj(vpiHandle obj);
extern unsigned is_variable(vpiHandle obj);
extern unsigned is_valid_fd_mcd(PLI_UINT32 fd_mcd);
extern unsigned get_fd_mcd_from_arg(PLI_UINT32 *fd_mcd, vpiHandle arg,