mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-22 05:47:31 +02:00
Update $ferror() and $fgets() to support SV strings
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user