diff --git a/ivtest/gold/pr2800985b-vlog95.gold b/ivtest/gold/pr2800985b-vlog95.gold index 4a161da36..c2430ce23 100644 --- a/ivtest/gold/pr2800985b-vlog95.gold +++ b/ivtest/gold/pr2800985b-vlog95.gold @@ -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. diff --git a/ivtest/gold/pr2800985b.gold b/ivtest/gold/pr2800985b.gold index 9f626a7f9..25313bfb9 100644 --- a/ivtest/gold/pr2800985b.gold +++ b/ivtest/gold/pr2800985b.gold @@ -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. diff --git a/vpi/sys_fileio.c b/vpi/sys_fileio.c index 5375b9d67..43f685105 100644 --- a/vpi/sys_fileio.c +++ b/vpi/sys_fileio.c @@ -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; diff --git a/vpi/sys_priv.c b/vpi/sys_priv.c index 222970a81..c12a01512 100644 --- a/vpi/sys_priv.c +++ b/vpi/sys_priv.c @@ -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. diff --git a/vpi/sys_priv.h b/vpi/sys_priv.h index dea7d55ac..a596082c4 100644 --- a/vpi/sys_priv.h +++ b/vpi/sys_priv.h @@ -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,