From 34b5834a84c5b51fd761a0af05145c43fb9ece8e Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 1 Feb 2016 13:50:08 +0100 Subject: [PATCH] vhdlpp: Added file_open() variant that returns status. --- vhdlpp/std_funcs.cc | 11 +++++ vpi/vhdl_textio.c | 101 +++++++++++++++++++++++++++++++++----------- 2 files changed, 87 insertions(+), 25 deletions(-) diff --git a/vhdlpp/std_funcs.cc b/vhdlpp/std_funcs.cc index dfc0ce1f6..9129124e5 100644 --- a/vhdlpp/std_funcs.cc +++ b/vhdlpp/std_funcs.cc @@ -318,6 +318,17 @@ void preload_std_funcs(void) perm_string::literal("$ivlh_file_open"), args, NULL)); + /* procedure file_open (status: out file_open_status, file f: text; filename: in string, file_open_kind: in mode); + */ + args = new list(); + args->push_back(new InterfacePort(&type_FILE_OPEN_STATUS, PORT_OUT)); + args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN)); + args->push_back(new InterfacePort(&primitive_STRING, PORT_IN)); + args->push_back(new InterfacePort(&type_FILE_OPEN_KIND, PORT_IN)); + register_std_subprogram(new SubprogramBuiltin(perm_string::literal("file_open"), + perm_string::literal("$ivlh_file_open"), + args, NULL)); + /* std.textio library * procedure file_close (file f: text); */ diff --git a/vpi/vhdl_textio.c b/vpi/vhdl_textio.c index e6a9a8411..c0879cc64 100644 --- a/vpi/vhdl_textio.c +++ b/vpi/vhdl_textio.c @@ -48,6 +48,7 @@ # include # include # include +# include # include "ivl_alloc.h" /* additional parameter values to distinguish between integer, boolean and @@ -55,6 +56,7 @@ enum format_t { FORMAT_STD, FORMAT_BOOL, FORMAT_TIME, FORMAT_HEX, FORMAT_STRING }; enum file_mode_t { FILE_MODE_READ, FILE_MODE_WRITE, FILE_MODE_APPEND, FILE_MODE_LAST }; +enum file_open_status_t { FS_OPEN_OK, FS_STATUS_ERROR, FS_NAME_ERROR, FS_MODE_ERROR }; /* bits per vector, in a single s_vpi_vecval struct */ static const size_t BPW = 8 * sizeof(PLI_INT32); @@ -67,6 +69,11 @@ static int is_integer_var(vpiHandle obj) type == vpiIntVar || type == vpiLongIntVar); } +static int is_const(vpiHandle obj) +{ + return vpi_get(vpiType, obj) == vpiConstant; +} + static void show_error_line(vpiHandle callh) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -281,40 +288,44 @@ static int write_time(char *string, const s_vpi_value* val, static PLI_INT32 ivlh_file_open_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv; + vpiHandle argv, arg; assert(callh != 0); + int ok = 1; argv = vpi_iterate(vpiArgument, callh); /* Check that there is a file name argument and that it is a string. */ - if (argv == 0) { - show_error_line(callh); - vpi_printf("%s requires a string file name argument.\n", name); - vpi_control(vpiFinish, 1); - return 0; - } + if (argv == 0) + ok = 0; - if(!is_integer_var(vpi_scan(argv))) { - show_error_line(callh); - vpi_printf("%s's first argument has to be an integer variable (file handle).\n", name); - vpi_control(vpiFinish, 1); - } + arg = vpi_scan(argv); + if (!arg || !is_integer_var(arg)) + ok = 0; - if(!is_string_obj(vpi_scan(argv))) { - show_error_line(callh); - vpi_printf("%s's second argument argument must be a string (file name).\n", name); - vpi_control(vpiFinish, 1); - } + arg = vpi_scan(argv); + if (arg && is_integer_var(arg)) + arg = vpi_scan(argv); - /* When provided, the type argument must be a string. */ - if(!vpi_scan(argv)) { + // no vpi_scan() here, if we had both 'status' and 'file' arguments, + // then the next arg is read in the above if, otherwise we are going + // to check the second argument once again + if (!arg || !is_string_obj(arg)) + ok = 0; + + arg = vpi_scan(argv); + if (arg && !is_const(arg)) + ok = 0; + + if (!ok) { show_error_line(callh); - vpi_printf("%s's third argument must be an integer (open mode).\n", name); + vpi_printf("%s() function is available in following variants:\n", name); + vpi_printf("* (file f: text; filename: in string, file_open_kind: in mode)\n"); + vpi_printf("* (status: out file_open_status, file f: text; filename: in string, file_open_kind: in mode)\n"); vpi_control(vpiFinish, 1); } /* Make sure there are no extra arguments. */ - check_for_extra_args(argv, callh, name, "three arguments", 1); + check_for_extra_args(argv, callh, name, "four arguments", 1); return 0; } @@ -330,15 +341,25 @@ static PLI_INT32 ivlh_file_open_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) int mode; char *fname; + vpiHandle fstatush = vpi_scan(argv); vpiHandle fhandleh = vpi_scan(argv); vpiHandle fnameh = vpi_scan(argv); vpiHandle modeh = vpi_scan(argv); + if(!modeh) { + /* There are only three arguments, so rearrange handles */ + modeh = fnameh; + fnameh = fhandleh; + fhandleh = fstatush; + fstatush = 0; + } else { + vpi_free_object(argv); + } + /* Get the mode handle */ val.format = vpiIntVal; vpi_get_value(modeh, &val); mode = val.value.integer; - vpi_free_object(argv); if(mode < 0 || mode >= FILE_MODE_LAST) { show_error_line(callh); @@ -355,21 +376,51 @@ static PLI_INT32 ivlh_file_open_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) } /* Open file and save the handle */ + PLI_INT32 result = -1; switch(mode) { case FILE_MODE_READ: - val.value.integer = vpi_fopen(fname, "r"); + result = vpi_fopen(fname, "r"); break; case FILE_MODE_WRITE: - val.value.integer = vpi_fopen(fname, "w"); + result = vpi_fopen(fname, "w"); break; case FILE_MODE_APPEND: - val.value.integer = vpi_fopen(fname, "a"); + result = vpi_fopen(fname, "a"); break; } + if(fstatush) { + val.format = vpiIntVal; + + if(!result) { + switch(errno) { + case ENOENT: + case ENAMETOOLONG: + val.value.integer = FS_NAME_ERROR; + break; + + case EINVAL: + case EACCES: + case EEXIST: + case EISDIR: + val.value.integer = FS_MODE_ERROR; + break; + + default: + val.value.integer = FS_STATUS_ERROR; + break; + } + } else { + val.value.integer = FS_OPEN_OK; + } + + vpi_put_value(fstatush, &val, 0, vpiNoDelay); + } + val.format = vpiIntVal; + val.value.integer = result; vpi_put_value(fhandleh, &val, 0, vpiNoDelay); free(fname);