From 11812d80744b2b2caefd004f1292aa045c21f462 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 2 Aug 2009 10:10:45 -0700 Subject: [PATCH 1/4] LXT2 file size limit can be set by environment variable. The LXT2 writer allows for splitting the output file into multiple output files. The size of that output file was fixed, but needs to be controlled by an environment variable. --- vpi/sys_lxt2.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/vpi/sys_lxt2.c b/vpi/sys_lxt2.c index 5eddf6ad4..868133d6d 100644 --- a/vpi/sys_lxt2.c +++ b/vpi/sys_lxt2.c @@ -440,10 +440,24 @@ static void *close_dumpfile(void) static void open_dumpfile(vpiHandle callh) { + off_t use_file_size_limit = lxt2_file_size_limit; if (dump_path == 0) dump_path = strdup("dump.lx2"); dump_file = lxt2_wr_init(dump_path); + if (getenv("LXT_FILE_SIZE_LIMIT")) { + const char*limit_string = getenv("LXT_FILE_SIZE_LIMIT"); + char*ep; + use_file_size_limit = strtoul(limit_string,&ep,0); + if (use_file_size_limit == 0 || ep[0] != 0) { + vpi_printf("LXT2 Warning: %s:%d: LXT_FILE_SIZE_LIMIT is invalid: %s\n", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh), + limit_string); + use_file_size_limit = lxt2_file_size_limit; + } + } + if (dump_file == 0) { vpi_printf("LXT2 Error: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -462,7 +476,7 @@ static void open_dumpfile(vpiHandle callh) lxt2_wr_set_initial_value(dump_file, 'x'); lxt2_wr_set_compression_depth(dump_file, 4); lxt2_wr_set_partial_on(dump_file, 1); - lxt2_wr_set_break_size(dump_file, lxt2_file_size_limit); + lxt2_wr_set_break_size(dump_file, use_file_size_limit); atexit((void(*)(void))close_dumpfile); } From 52fbb3f734218ea7dbe60cbbf7a6628cb0c6bdc8 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 29 Jul 2009 14:46:47 -0700 Subject: [PATCH 2/4] Fix memory leak, unneeded argument. Very minor issues dosify was not closing files so memory leaks could show up and vpi/sys_readmem.c was passing the file after it was closed to the lexor cleanup code. The lexor cleanup code does not need an argument. --- dosify.c | 28 ++++------------------------ vpi/sys_readmem.c | 2 +- 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/dosify.c b/dosify.c index 7a3245bde..77fa81be7 100644 --- a/dosify.c +++ b/dosify.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2009 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 @@ -16,9 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: dosify.c,v 1.5 2003/07/15 16:17:47 steve Exp $" -#endif /* * This is a simple program to make a dosified copy of the @@ -51,6 +48,7 @@ int main(int argc, char*argv[]) ofile = fopen(argv[2], "wb"); if (ofile == 0) { fprintf(stderr, "Unable to open %s for output.\n", argv[2]); + fclose(ifile); return 2; } @@ -64,25 +62,7 @@ int main(int argc, char*argv[]) pr = ch; } + fclose(ifile); + fclose(ofile); return 0; } - -/* - * $Log: dosify.c,v $ - * Revision 1.5 2003/07/15 16:17:47 steve - * Fix spelling of ifdef. - * - * Revision 1.4 2003/07/15 03:49:22 steve - * Spelling fixes. - * - * Revision 1.3 2002/08/12 01:34:58 steve - * conditional ident string using autoconfig. - * - * Revision 1.2 2002/08/11 23:47:04 steve - * Add missing Log and Ident strings. - * - * Revision 1.1 2001/08/03 17:06:47 steve - * Add install of examples for Windows. - * - */ - diff --git a/vpi/sys_readmem.c b/vpi/sys_readmem.c index 9adc062b9..14976d253 100644 --- a/vpi/sys_readmem.c +++ b/vpi/sys_readmem.c @@ -401,7 +401,7 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name) free(value.value.vector); free(fname); fclose(file); - destroy_readmem_lexor(file); + destroy_readmem_lexor(); return 0; } From b0ac550791595a1261b85647643b18b090501481 Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 30 Jul 2009 17:51:09 -0700 Subject: [PATCH 3/4] Add a warning when we reach 1024 files. It's not too likely we will ever reach this, but we should be nice and print a message instead of just failing. We could set errno, but for now the warning will have to be enough. --- vvp/vpi_mcd.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vvp/vpi_mcd.cc b/vvp/vpi_mcd.cc index 9a0a71139..a10fc539f 100644 --- a/vvp/vpi_mcd.cc +++ b/vvp/vpi_mcd.cc @@ -258,7 +258,10 @@ extern "C" PLI_INT32 vpi_fopen(const char*name, const char*mode) } /* We need to allocate more table entries, but to keep things */ /* sane we'll hard limit this to 1024 file descriptors total. */ - if (fd_table_len >= 1024) return 0; + if (fd_table_len >= 1024) { + vpi_printf("WARNING: Icarus only supports 1024 open files!\n"); + return 0; + } fd_table_len += FD_INCR; fd_table = (mcd_entry_s *) realloc(fd_table, fd_table_len*sizeof(mcd_entry_s)); From ce89a687352eb019a690f52bd9b3361465efaf13 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 31 Jul 2009 13:06:49 -0700 Subject: [PATCH 4/4] Add full $ferror() support, bug fixes, etc. This patch adds $ferror() support. This is enhanced over what the standard says needs to be supported. All file I/O routines set/clear the errno flag, This allows $ferror() to check when an invalid fd/MCD is passed to a system task. The $ferror() fd is only checked if errno is not set since all the other routines will set EBADF when they are called. This allows us to test the output from $fopen() which sets the fd to zero (an invalid fd) when it has a problem. The following bugs (changes) are also fixed: Fix $fdisplay*, $fwrite*, $fstrobe*, $fflush, $fclose to not accept 0 as a valid MCD. For the $fdisplay*, $fwrite* and $fstrobe tasks an invalid fd/MCD is now a warning instead of an error like the other file I/O routines. Modify $fputc() to be a function and return a value like $ungetc(). Modify $ungetc() to return a value like the standard dictates (-1 on error else 0) and pass the value as a full int to get EOF as an error. Remove some extra checks that could not happen in $fseek() and to be safe convert the numeric codes to the system symbolic values. Skip $fstrobe callback when the fd/MCD is closed. The standard says we need to cancel the callback, but we currently do not have the ability to do that so just skipping this will work for now. Free the argument handle when $fscanf() is called with an invalid fd (memory leak). --- vpi/sys_display.c | 47 +++++++---- vpi/sys_fileio.c | 208 +++++++++++++++++++++++++++++++++++++++------- vpi/sys_icarus.c | 20 ----- vpi/sys_scanf.c | 4 + 4 files changed, 213 insertions(+), 66 deletions(-) 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; }