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

This commit is contained in:
Cary R
2023-07-19 00:30:50 -07:00
parent ceb07dc9db
commit 3aafa1333b
5 changed files with 98 additions and 41 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
ERROR: vlog95.v:18: $ferror's fd (first) argument must be numeric. 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:19: $ferror requires a second (variable) argument.
ERROR: vlog95.v:20: $ferror's second argument must be a reg (>=640 bits). 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:21: $ferror's second argument must have 640 bit or more.
ERROR: vlog95.v:22: $ferror takes two arguments. ERROR: vlog95.v:22: $ferror takes two arguments.
Found 1 extra argument. Found 1 extra argument.
+2 -2
View File
@@ -1,6 +1,6 @@
ERROR: ./ivltests/pr2800985b.v:11: $ferror's fd (first) argument must be numeric. 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:12: $ferror requires a second (variable) argument.
ERROR: ./ivltests/pr2800985b.v:13: $ferror's second argument must be a reg (>=640 bits). 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:14: $ferror's second argument must have 640 bit or more.
ERROR: ./ivltests/pr2800985b.v:15: $ferror takes two arguments. ERROR: ./ivltests/pr2800985b.v:15: $ferror takes two arguments.
Found 1 extra argument. Found 1 extra argument.
+66 -35
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003-2021 Stephen Williams ([email protected]) * Copyright (c) 2003-2023 Stephen Williams ([email protected])
* *
* 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
@@ -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 * 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) { if (argv == 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), 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; 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), vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, 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); vpip_set_return_value(1);
vpi_control(vpiFinish, 1); vpi_control(vpiFinish, 1);
} }
@@ -377,21 +377,30 @@ static PLI_INT32 sys_fgets_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
return 0; 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) static PLI_INT32 sys_fgets_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{ {
vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle regh; vpiHandle varh;
vpiHandle arg; vpiHandle arg;
s_vpi_value val; s_vpi_value val;
PLI_UINT32 fd_mcd; PLI_UINT32 fd_mcd;
FILE *fp; FILE *fp;
PLI_INT32 reg_size; PLI_INT32 var_size;
char*text; char*text;
errno = 0; errno = 0;
/* Get the register handle. */ /* Get the variable handle. */
regh = vpi_scan(argv); varh = vpi_scan(argv);
/* Get the file/MCD descriptor. */ /* Get the file/MCD descriptor. */
arg = vpi_scan(argv); arg = vpi_scan(argv);
@@ -414,17 +423,34 @@ static PLI_INT32 sys_fgets_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
return 0; return 0;
} }
/* Get the register size in bytes and allocate the buffer. */ if (vpi_get(vpiType, varh) == vpiStringVar) {
reg_size = vpi_get(vpiSize, regh) / 8; PLI_INT32 base_size = 1024;
text = malloc(reg_size + 1); 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. */ /* Read in the bytes. Return 0 if there was an error. */
if (fgets(text, reg_size+1, fp) == 0) { if (fgets(text, var_size+1, fp) == 0) {
val.format = vpiIntVal; return_zero(callh);
val.value.integer = 0; free(text);
vpi_put_value(callh, &val, 0, vpiNoDelay); return 0;
free(text); }
return 0;
} }
/* Return the number of character read. */ /* 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. */ /* Return the characters to the register. */
val.format = vpiStringVal; val.format = vpiStringVal;
val.value.str = text; val.value.str = text;
vpi_put_value(regh, &val, 0, vpiNoDelay); vpi_put_value(varh, &val, 0, vpiNoDelay);
free(text); free(text);
return 0; 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 * 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, * The parser requires that a function have at least one argument,
* so argv should always be defined with 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 /* Check that the second argument is given and that it is a 640 bit
* or larger register. */ * or larger variable. */
arg = vpi_scan(argv); arg = vpi_scan(argv);
if (! arg) { if (! arg) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, 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); vpip_set_return_value(1);
vpi_control(vpiFinish, 1); vpi_control(vpiFinish, 1);
return 0; return 0;
} }
if (vpi_get(vpiType, arg) != vpiReg) { if (! is_variable(arg)) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, 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); name);
vpip_set_return_value(1); vpip_set_return_value(1);
vpi_control(vpiFinish, 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), vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's second argument must have 640 bit or more.\n", 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 callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle reg; vpiHandle var;
s_vpi_value val; s_vpi_value val;
char *msg; char *msg;
PLI_INT32 size; 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); vpi_get_value(vpi_scan(argv), &val);
fd_mcd = val.value.integer; 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. */ * characters it will hold. */
reg = vpi_scan(argv); var = vpi_scan(argv);
size = vpi_get(vpiSize, reg); size = vpi_get(vpiSize, var);
chars = size / 8; chars = size / 8;
vpi_free_object(argv); vpi_free_object(argv);
@@ -1061,14 +1087,19 @@ static PLI_INT32 sys_ferror_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
val.value.integer = errno; val.value.integer = errno;
vpi_put_value(callh, &val, 0, vpiNoDelay); vpi_put_value(callh, &val, 0, vpiNoDelay);
/* Only return the number of characters that will fit in the reg. */ /* Only return the number of characters that will fit in the variable. */
msg = (char *) malloc(chars); if (vpi_get(vpiType, var) == vpiStringVar) {
if (errno != 0) strncpy(msg, strerror(errno), chars-1); if (errno != 0) msg = strdup(strerror(errno));
else strncpy(msg, "", chars-1); else msg = strdup("");
msg[chars-1] = '\0'; } 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.format = vpiStringVal;
val.value.str = msg; val.value.str = msg;
vpi_put_value(reg, &val, 0, vpiNoDelay); vpi_put_value(var, &val, 0, vpiNoDelay);
free(msg); free(msg);
return 0; return 0;
+26 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003-2021 Stephen Williams ([email protected]) * Copyright (c) 2003-2023 Stephen Williams ([email protected])
* *
* 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
@@ -257,6 +257,31 @@ unsigned is_string_obj(vpiHandle obj)
return rtn; 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. * Check if the file descriptor or MCD is valid.
+2 -1
View File
@@ -1,7 +1,7 @@
#ifndef IVL_sys_priv_H #ifndef IVL_sys_priv_H
#define IVL_sys_priv_H #define IVL_sys_priv_H
/* /*
* Copyright (c) 2002-2020 Stephen Williams ([email protected]) * Copyright (c) 2002-2023 Stephen Williams ([email protected])
* *
* 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
@@ -58,6 +58,7 @@ extern struct timeformat_info_s timeformat_info;
extern unsigned is_constant_obj(vpiHandle obj); extern unsigned is_constant_obj(vpiHandle obj);
extern unsigned is_numeric_obj(vpiHandle obj); extern unsigned is_numeric_obj(vpiHandle obj);
extern unsigned is_string_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 is_valid_fd_mcd(PLI_UINT32 fd_mcd);
extern unsigned get_fd_mcd_from_arg(PLI_UINT32 *fd_mcd, vpiHandle arg, extern unsigned get_fd_mcd_from_arg(PLI_UINT32 *fd_mcd, vpiHandle arg,