diff --git a/vpi/sys_display.c b/vpi/sys_display.c index fbbbcc768..c0f116290 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -23,6 +23,7 @@ # include "sys_priv.h" # include # include +# include # include # include # include @@ -1120,18 +1121,20 @@ static PLI_INT32 sys_display_calltf(PLI_BYTE8 *name) /* Get the file/MC descriptor and verify it is valid. */ if(name[1] == 'f') { + errno = 0; vpiHandle arg = vpi_scan(argv); s_vpi_value val; val.format = vpiIntVal; vpi_get_value(arg, &val); fd_mcd = val.value.integer; if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) || - ( IS_MCD(fd_mcd) && my_mcd_printf(fd_mcd, "") == EOF)) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + ( IS_MCD(fd_mcd) && my_mcd_printf(fd_mcd, "") == EOF) || + (! fd_mcd)) { + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor/MCD (0x%x) given " "to %s.\n", fd_mcd, name); - vpi_control(vpiFinish, 1); + errno = EBADF; vpi_free_object(argv); return 0; } @@ -1180,23 +1183,29 @@ static PLI_INT32 sys_display_calltf(PLI_BYTE8 *name) */ static PLI_INT32 strobe_cb(p_cb_data cb) { - char* result; + char* result = NULL; unsigned int size, location=0; struct strobe_cb_info*info = (struct strobe_cb_info*)cb->user_data; - /* Because %u and %z may put embedded NULL characters into the - * returned string strlen() may not match the real size! */ - result = get_display(&size, info); - while (location < size) { - if (result[location] == '\0') { - my_mcd_printf(info->fd_mcd, "%c", '\0'); - location += 1; - } else { - my_mcd_printf(info->fd_mcd, "%s", &result[location]); - location += strlen(&result[location]); + /* We really need to cancel any $fstrobe() calls for a file when it + * is closed, but for now we will just skip processing the result. + * Which has the same basic effect. */ + if ((! IS_MCD(info->fd_mcd) && vpi_get_file(info->fd_mcd) != NULL) || + ( IS_MCD(info->fd_mcd) && my_mcd_printf(info->fd_mcd, "") != EOF)) { + /* Because %u and %z may put embedded NULL characters into the + * returned string strlen() may not match the real size! */ + result = get_display(&size, info); + while (location < size) { + if (result[location] == '\0') { + my_mcd_printf(info->fd_mcd, "%c", '\0'); + location += 1; + } else { + my_mcd_printf(info->fd_mcd, "%s", &result[location]); + location += strlen(&result[location]); + } } + my_mcd_printf(info->fd_mcd, "\n"); } - my_mcd_printf(info->fd_mcd, "\n"); free(info->filename); free(info->items); @@ -1226,18 +1235,20 @@ static PLI_INT32 sys_strobe_calltf(PLI_BYTE8*name) /* Get the file/MC descriptor and verify it is valid. */ if(name[1] == 'f') { + errno = 0; vpiHandle arg = vpi_scan(argv); s_vpi_value val; val.format = vpiIntVal; vpi_get_value(arg, &val); fd_mcd = val.value.integer; if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) || - ( IS_MCD(fd_mcd) && my_mcd_printf(fd_mcd, "") == EOF)) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + ( IS_MCD(fd_mcd) && my_mcd_printf(fd_mcd, "") == EOF) || + (! fd_mcd)) { + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor/MCD (0x%x) given " "to %s.\n", fd_mcd, name); - vpi_control(vpiFinish, 1); + errno = EBADF; vpi_free_object(argv); return 0; } diff --git a/vpi/sys_fileio.c b/vpi/sys_fileio.c index 35d6a0c06..f65331f7b 100644 --- a/vpi/sys_fileio.c +++ b/vpi/sys_fileio.c @@ -21,13 +21,13 @@ # include "sys_priv.h" # include # include +# include # include # include # include #define IS_MCD(mcd) !((mcd)>>31&1) - /* * Implement the $fopen system function. */ @@ -83,6 +83,8 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name) vpiHandle fileh = vpi_scan(argv); char *fname; vpiHandle mode = vpi_scan(argv); + errno = 0; + /* Get the mode handle if it exists. */ if (mode) { char *esc_md; @@ -180,7 +182,7 @@ static PLI_INT32 sys_fopenrwa_calltf(PLI_BYTE8*name) vpiHandle argv = vpi_iterate(vpiArgument, callh); s_vpi_value val; char *mode, *fname; - + errno = 0; /* Get the mode. */ mode = name + strlen(name) - 1; @@ -210,6 +212,7 @@ static PLI_INT32 sys_fclose_calltf(PLI_BYTE8*name) s_vpi_value val; PLI_UINT32 fd_mcd; char *str = ""; /* This prevents the compiler from complaining. */ + errno = 0; vpi_free_object(argv); @@ -219,15 +222,19 @@ static PLI_INT32 sys_fclose_calltf(PLI_BYTE8*name) fd_mcd = val.value.integer; if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) || - ( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, str) == EOF)) { + ( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, str) == EOF) || + (! fd_mcd)) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor/MCD (0x%x) given to %s.\n", fd_mcd, name); + errno = EBADF; return 0; } - /* We need to cancel any active $fstrobe()'s for this FD/MCD. */ + /* We need to cancel any active $fstrobe()'s for this FD/MCD. + * For now we check in the strobe callback and skip the output + * generation when needed. */ vpi_mcd_close(fd_mcd); return 0; @@ -245,6 +252,7 @@ static PLI_INT32 sys_fflush_calltf(PLI_BYTE8*name) PLI_UINT32 fd_mcd; FILE *fp; char *str = ""; /* This prevents the compiler from complaining. */ + errno = 0; /* If we have no argument then flush all the streams. */ if (argv == 0) { @@ -260,11 +268,13 @@ static PLI_INT32 sys_fflush_calltf(PLI_BYTE8*name) fd_mcd = val.value.integer; if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) || - ( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, str) == EOF)) { + ( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, str) == EOF) || + (! fd_mcd)) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor/MCD (0x%x) given to %s.\n", fd_mcd, name); + errno = EBADF; return 0; } @@ -288,7 +298,7 @@ static PLI_INT32 sys_fputc_calltf(PLI_BYTE8*name) PLI_UINT32 fd_mcd; FILE *fp; unsigned char chr; - (void) name; /* Not used! */ + errno = 0; /* Get the character. */ arg = vpi_scan(argv); @@ -312,9 +322,12 @@ static PLI_INT32 sys_fputc_calltf(PLI_BYTE8*name) (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, name); + errno = EBADF; val.value.integer = EOF; - } else + } else { val.value.integer = fputc(chr, fp); + if (val.value.integer != EOF) val.value.integer = 0; + } vpi_put_value(callh, &val, 0, vpiNoDelay); return 0; @@ -378,7 +391,7 @@ static PLI_INT32 sys_fgets_calltf(PLI_BYTE8*name) FILE *fp; PLI_INT32 reg_size; char*text; - (void) name; /* Not used! */ + errno = 0; /* Get the register handle. */ regh = vpi_scan(argv); @@ -397,6 +410,7 @@ static PLI_INT32 sys_fgets_calltf(PLI_BYTE8*name) (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, name); + errno = EBADF; val.format = vpiIntVal; val.value.integer = 0; vpi_put_value(callh, &val, 0, vpiNoDelay); @@ -566,6 +580,7 @@ static PLI_INT32 sys_fread_calltf(PLI_BYTE8*name) unsigned is_mem, idx, bpe, words; FILE *fp; s_vpi_vecval *vector; + errno = 0; /* Get the register/memory. */ mem_reg = vpi_scan(argv); @@ -583,6 +598,7 @@ static PLI_INT32 sys_fread_calltf(PLI_BYTE8*name) (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, name); + errno = EBADF; val.format = vpiIntVal; val.value.integer = 0; vpi_put_value(callh, &val, 0, vpiNoDelay); @@ -693,8 +709,8 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name) s_vpi_value val; PLI_UINT32 fd_mcd; FILE *fp; - unsigned char chr; - (void) name; /* Not used! */ + int chr; + errno = 0; /* Get the character. */ arg = vpi_scan(argv); @@ -716,6 +732,7 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name) (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, name); + errno = EBADF; val.format = vpiIntVal; val.value.integer = EOF; vpi_put_value(callh, &val, 0, vpiNoDelay); @@ -725,6 +742,7 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name) /* ungetc the character and return the result. */ val.format = vpiIntVal; val.value.integer = ungetc(chr, fp); + if (val.value.integer != EOF) val.value.integer = 0; vpi_put_value(callh, &val, 0, vpiNoDelay); return 0; @@ -763,7 +781,7 @@ static PLI_INT32 sys_fseek_compiletf(PLI_BYTE8*name) return 0; } - if (!arg || !is_numeric_obj(arg)) { + if (! is_numeric_obj(arg)) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's second argument must be numeric.\n", name); @@ -780,7 +798,7 @@ static PLI_INT32 sys_fseek_compiletf(PLI_BYTE8*name) return 0; } - if (!arg || !is_numeric_obj(arg)) { + if (! is_numeric_obj(arg)) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's third argument must be numeric.\n", name); @@ -802,7 +820,7 @@ static PLI_INT32 sys_fseek_calltf(PLI_BYTE8*name) PLI_UINT32 fd_mcd; PLI_INT32 offset, oper; FILE *fp; - + errno = 0; /* Get the file pointer. */ arg = vpi_scan(argv); @@ -824,15 +842,22 @@ static PLI_INT32 sys_fseek_calltf(PLI_BYTE8*name) oper = val.value.integer; /* Check that the operation is in the valid range. */ - if ((oper < 0) || (oper > 2)) { + switch (oper) { + case 0: + oper = SEEK_SET; + break; + case 1: + oper = SEEK_CUR; + break; + case 2: + oper = SEEK_END; + break; + default: vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's operation must be 0, 1 or 2 given %d.\n", name, oper); - val.format = vpiIntVal; - val.value.integer = EOF; - vpi_put_value(callh, &val, 0, vpiNoDelay); - return 0; + oper = -1; /* An invalid argument value. */ } /* Return EOF if this is not a valid fd. */ @@ -842,6 +867,7 @@ static PLI_INT32 sys_fseek_calltf(PLI_BYTE8*name) (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, name); + errno = EBADF; val.format = vpiIntVal; val.value.integer = EOF; vpi_put_value(callh, &val, 0, vpiNoDelay); @@ -863,6 +889,7 @@ static PLI_INT32 sys_common_fd_calltf(PLI_BYTE8*name) s_vpi_value val; PLI_UINT32 fd_mcd; FILE *fp; + errno = 0; /* Get the file pointer. */ arg = vpi_scan(argv); @@ -878,6 +905,7 @@ static PLI_INT32 sys_common_fd_calltf(PLI_BYTE8*name) (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, name); + errno = EBADF; val.format = vpiIntVal; val.value.integer = EOF; vpi_put_value(callh, &val, 0, vpiNoDelay); @@ -910,6 +938,119 @@ static PLI_INT32 sys_common_fd_calltf(PLI_BYTE8*name) return 0; } +/* + * Implement the $ferror system function. + */ +static PLI_INT32 sys_ferror_compiletf(PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + vpiHandle arg; + + argv = vpi_iterate(vpiArgument, callh); + + /* + * Check that there are two arguments and that the first is + * numeric and that the second is a 640 bit or larger register. + * + * The parser requires that a function have at least one argument, + * so argv should always be defined with one argument. + */ + assert(argv); + + if (! is_numeric_obj(vpi_scan(argv))) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's fd (first) argument must be numeric.\n", name); + vpi_control(vpiFinish, 1); + } + + /* Check that the second argument is given and that it is a 640 bit + * or larger register. */ + 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_control(vpiFinish, 1); + return 0; + } + + if (vpi_get(vpiType, arg) != vpiReg) { + 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", + name); + vpi_control(vpiFinish, 1); + } else if (vpi_get(vpiSize, arg) < 640) { + 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", + name); + vpi_control(vpiFinish, 1); + } + + /* Make sure there are no extra arguments. */ + check_for_extra_args(argv, callh, name, "two arguments", 0); + + return 0; +} + +static PLI_INT32 sys_ferror_calltf(PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle reg; + s_vpi_value val; + char *msg; + PLI_INT32 size; + unsigned chars; + PLI_UINT32 fd_mcd; + + /* Get the file pointer. */ + val.format = vpiIntVal; + 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 + * characters it will hold. */ + reg = vpi_scan(argv); + size = vpi_get(vpiSize, reg); + chars = size / 8; + vpi_free_object(argv); + + /* If we do not already have an error check that the fd is valid. + * The assumption is that the other routines have set errno to + * EBADF when they encounter a bad file descriptor, so we do not + * need to check here. We also need to special case this since + * $fopen() will return 0 (a bad file descriptor) when it has a + * problem (sets errno). */ + if (!errno && !vpi_get_file(fd_mcd) ) { + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd, + name); + errno = EBADF; + } + + /* Return the error code. */ + val.format = vpiIntVal; + 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'; + val.format = vpiStringVal; + val.value.str = msg; + vpi_put_value(reg, &val, 0, vpiNoDelay); + free(msg); + + return 0; +} + void sys_fileio_register() { s_vpi_systf_data tf_data; @@ -962,15 +1103,6 @@ void sys_fileio_register() tf_data.user_data = "$fflush"; vpi_register_systf(&tf_data); - /*============================== fputc */ - tf_data.type = vpiSysTask; - tf_data.tfname = "$fputc"; - tf_data.calltf = sys_fputc_calltf; - tf_data.compiletf = sys_two_numeric_args_compiletf; - tf_data.sizetf = 0; - tf_data.user_data = "$fputc"; - vpi_register_systf(&tf_data); - /*============================== fgetc */ tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiIntFunc; @@ -1041,7 +1173,17 @@ void sys_fileio_register() tf_data.user_data = "$rewind"; vpi_register_systf(&tf_data); -/* $feof() is from 1364-2005. */ + /*============================== ferror */ + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiIntFunc; + tf_data.tfname = "$ferror"; + tf_data.calltf = sys_ferror_calltf; + tf_data.compiletf = sys_ferror_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$ferror"; + vpi_register_systf(&tf_data); + + /* $feof() is from 1364-2005. */ /*============================== feof */ tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiIntFunc; @@ -1052,4 +1194,14 @@ void sys_fileio_register() tf_data.user_data = "$feof"; vpi_register_systf(&tf_data); + /* Icarus specific. */ + /*============================== fputc */ + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiIntFunc; + tf_data.tfname = "$fputc"; + tf_data.calltf = sys_fputc_calltf; + tf_data.compiletf = sys_two_numeric_args_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$fputc"; + vpi_register_systf(&tf_data); } diff --git a/vpi/sys_icarus.c b/vpi/sys_icarus.c index 74e4456ad..8551057a8 100644 --- a/vpi/sys_icarus.c +++ b/vpi/sys_icarus.c @@ -53,17 +53,6 @@ static PLI_INT32 task_not_implemented_compiletf(PLI_BYTE8* name) return 0; } -static PLI_INT32 function_not_implemented_compiletf(PLI_BYTE8* name) -{ - vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - - vpi_printf("%s:%d: SORRY: function %s() is not currently implemented.\n", - vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh), - name); - vpi_control(vpiFinish, 1); - return 0; -} - /* * This is used to warn the user that the specified optional system * task/function is not available (from Annex C 1364-2005). @@ -222,15 +211,6 @@ void sys_special_register(void) tf_data.tfname = "$dumpportsflush"; tf_data.user_data = "$dumpportsflush"; - vpi_register_systf(&tf_data); - - /* These functions are not currently implemented. */ - tf_data.compiletf = function_not_implemented_compiletf; - tf_data.type = vpiSysFunc; - tf_data.sysfunctype = vpiIntFunc; - - tf_data.tfname = "$ferror"; - tf_data.user_data = "$ferror"; vpi_register_systf(&tf_data); /* The following optional system tasks/functions are not implemented diff --git a/vpi/sys_scanf.c b/vpi/sys_scanf.c index b523d2d60..db64fc35e 100644 --- a/vpi/sys_scanf.c +++ b/vpi/sys_scanf.c @@ -24,6 +24,7 @@ # include "vpi_user.h" # include "sys_priv.h" # include +# include # include # include # include @@ -639,6 +640,7 @@ static PLI_INT32 sys_fscanf_calltf(PLI_BYTE8*name) s_vpi_value val; struct byte_source src; FILE *fd; + errno = 0; val.format = vpiIntVal; vpi_get_value(vpi_scan(argv), &val); @@ -648,9 +650,11 @@ static PLI_INT32 sys_fscanf_calltf(PLI_BYTE8*name) (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor (0x%x) given to %s.\n", val.value.integer, name); + errno = EBADF; val.format = vpiIntVal; val.value.integer = EOF; vpi_put_value(callh, &val, 0, vpiNoDelay); + vpi_free_object(argv); return 0; }