vhdlpp: Added file_open() variant that returns status.

This commit is contained in:
Maciej Suminski 2016-02-01 13:50:08 +01:00
parent 0f3f8907c3
commit 34b5834a84
2 changed files with 87 additions and 25 deletions

View File

@ -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<InterfacePort*>();
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);
*/

View File

@ -48,6 +48,7 @@
# include <assert.h>
# include <string.h>
# include <ctype.h>
# include <errno.h>
# 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);