Add the $fread() system function.
This patch adds the $fread() system function. Icarus does not currently allow missing arguments in functions so the following standard specified functionality is not supported: res = $fread(mem, fd,,count); It also fixes a memory leak in fopen related to the get_filename refactoring I recently did.
This commit is contained in:
parent
327e8d0ec0
commit
036c176e8b
266
vpi/sys_fileio.c
266
vpi/sys_fileio.c
|
|
@ -164,6 +164,7 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name)
|
||||||
val.value.integer = vpi_mcd_open(fname);
|
val.value.integer = vpi_mcd_open(fname);
|
||||||
|
|
||||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||||
|
free(fname);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -429,6 +430,261 @@ static PLI_INT32 sys_fgets_calltf(PLI_BYTE8*name)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PLI_INT32 sys_fread_compiletf(PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle arg;
|
||||||
|
PLI_INT32 type;
|
||||||
|
|
||||||
|
/* We must have at least two arguments. */
|
||||||
|
if (argv == 0) {
|
||||||
|
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
vpi_printf("%s requires two arguments.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the first required argument is a register or memory. */
|
||||||
|
type = vpi_get(vpiType, vpi_scan(argv));
|
||||||
|
if (type != vpiReg && type != vpiMemory) {
|
||||||
|
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 or memory.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the second required argument is numeric (a fd). */
|
||||||
|
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 (file descriptor) argument.\n",
|
||||||
|
name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If given check that the third argument is numeric (start).
|
||||||
|
*
|
||||||
|
* Technically you can give the fourth argument (count) with
|
||||||
|
* out a third argument (start), but Icarus does not currently
|
||||||
|
* support missing function arguments!
|
||||||
|
*/
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if (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);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If given check that the fourth argument is numeric (count). */
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if (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 fourth argument must be numeric.\n",
|
||||||
|
name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure there are no extra arguments. */
|
||||||
|
check_for_extra_args(argv, callh, name, "four arguments", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The pattern here is get the current vector, load the new bits on
|
||||||
|
* top of the old ones and then put the modified vector. We need the
|
||||||
|
* "get" first so that if we run out of bits in the file we keep the
|
||||||
|
* original ones.
|
||||||
|
*/
|
||||||
|
static unsigned fread_word(FILE *fp, vpiHandle word,
|
||||||
|
unsigned words, unsigned bpe, s_vpi_vecval *vector)
|
||||||
|
{
|
||||||
|
unsigned rtn, clr_mask, bnum;
|
||||||
|
int bidx, byte;
|
||||||
|
s_vpi_value val;
|
||||||
|
struct t_vpi_vecval *cur = &vector[words-1];
|
||||||
|
|
||||||
|
rtn = 0;
|
||||||
|
|
||||||
|
/* Get the current bits from the register and copy them to
|
||||||
|
* my local vector. */
|
||||||
|
val.format = vpiVectorVal;
|
||||||
|
vpi_get_value(word, &val);
|
||||||
|
for (bidx = 0; bidx < words; bidx += 1) {
|
||||||
|
vector[bidx].aval = val.value.vector[bidx].aval;
|
||||||
|
vector[bidx].bval = val.value.vector[bidx].bval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the bytes to the local vector MSByte first. */
|
||||||
|
for (bidx = bpe-1; bidx >= 0; bidx -= 1) {
|
||||||
|
byte = fgetc(fp);
|
||||||
|
if (byte == EOF) break;
|
||||||
|
/* Clear the current byte and load the new value. */
|
||||||
|
bnum = bidx % 4;
|
||||||
|
clr_mask = ~(0xff << bnum*8);
|
||||||
|
cur->aval &= clr_mask;
|
||||||
|
cur->bval &= clr_mask;
|
||||||
|
cur->aval |= byte << bnum*8;
|
||||||
|
rtn += 1;
|
||||||
|
if (bnum == 0) cur -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Put the updated bits into the register. */
|
||||||
|
val.value.vector = vector;
|
||||||
|
vpi_put_value(word, &val, 0, vpiNoDelay);
|
||||||
|
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PLI_INT32 sys_fread_calltf(PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle arg, mem_reg;
|
||||||
|
s_vpi_value val;
|
||||||
|
PLI_UINT32 fd_mcd;
|
||||||
|
PLI_INT32 start, count, width, rtn;
|
||||||
|
unsigned is_mem, idx, bpe, words;
|
||||||
|
FILE *fp;
|
||||||
|
s_vpi_vecval *vector;
|
||||||
|
|
||||||
|
/* Get the register/memory. */
|
||||||
|
mem_reg = vpi_scan(argv);
|
||||||
|
|
||||||
|
/* Get the file descriptor. */
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(arg, &val);
|
||||||
|
fd_mcd = val.value.integer;
|
||||||
|
|
||||||
|
/* Return 0 if this is not a valid fd. */
|
||||||
|
fp = vpi_get_file(fd_mcd);
|
||||||
|
if (!fp) {
|
||||||
|
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);
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
val.value.integer = 0;
|
||||||
|
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||||
|
vpi_free_object(argv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Are we reading into a memory? */
|
||||||
|
if (vpi_get(vpiType, mem_reg) == vpiReg) is_mem = 0;
|
||||||
|
else is_mem = 1;
|
||||||
|
|
||||||
|
/* We only need to get these for memories. */
|
||||||
|
if (is_mem) {
|
||||||
|
PLI_INT32 left, right, max, min;
|
||||||
|
|
||||||
|
/* Get the left and right memory address. */
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(vpi_handle(vpiLeftRange, mem_reg), &val);
|
||||||
|
left = val.value.integer;
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(vpi_handle(vpiRightRange, mem_reg), &val);
|
||||||
|
right = val.value.integer;
|
||||||
|
max = (left > right) ? left : right;
|
||||||
|
min = (left < right) ? left : right;
|
||||||
|
|
||||||
|
/* Get the starting address (optional). */
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if (arg) {
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(arg, &val);
|
||||||
|
start = val.value.integer;
|
||||||
|
if (start < min || start > max) {
|
||||||
|
vpi_printf("WARNING: %s:%d: ",
|
||||||
|
vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
vpi_printf("%s's start argument (%d) is outside "
|
||||||
|
"memory range [%d:%d].\n", name, start,
|
||||||
|
left, right);
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
val.value.integer = 0;
|
||||||
|
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||||
|
vpi_free_object(argv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the count (optional). */
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if (arg) {
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(arg, &val);
|
||||||
|
count = val.value.integer;
|
||||||
|
if (count > max-start) {
|
||||||
|
vpi_printf("WARNING: %s:%d: ",
|
||||||
|
vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
vpi_printf("%s's count argument (%d) is too "
|
||||||
|
"large for start (%d) and memory "
|
||||||
|
"range [%d:%d].\n", name, count,
|
||||||
|
start, left, right);
|
||||||
|
count = max - start + 1;
|
||||||
|
}
|
||||||
|
vpi_free_object(argv);
|
||||||
|
} else {
|
||||||
|
count = max - start + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
start = min;
|
||||||
|
count = max - min + 1;
|
||||||
|
}
|
||||||
|
width = vpi_get(vpiSize, vpi_handle_by_index(mem_reg, start));
|
||||||
|
} else {
|
||||||
|
start = 0;
|
||||||
|
count = 1;
|
||||||
|
width = vpi_get(vpiSize, mem_reg);
|
||||||
|
vpi_free_object(argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
words = (width+31)/32;
|
||||||
|
vector = calloc(words, sizeof(s_vpi_vecval));
|
||||||
|
bpe = (width+7)/8;
|
||||||
|
|
||||||
|
if (is_mem) {
|
||||||
|
rtn = 0;
|
||||||
|
for (idx = 0; idx < count; idx += 1) {
|
||||||
|
vpiHandle word;
|
||||||
|
word = vpi_handle_by_index(mem_reg, start+(signed)idx);
|
||||||
|
rtn += fread_word(fp, word, words, bpe, vector);
|
||||||
|
if (feof(fp)) break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rtn = fread_word(fp, mem_reg, words, bpe, vector);
|
||||||
|
}
|
||||||
|
free(vector);
|
||||||
|
|
||||||
|
/* Return the number of bytes read. */
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
val.value.integer = rtn;
|
||||||
|
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name)
|
static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name)
|
||||||
{
|
{
|
||||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
|
@ -735,6 +991,16 @@ void sys_fileio_register()
|
||||||
tf_data.user_data = "$fgets";
|
tf_data.user_data = "$fgets";
|
||||||
vpi_register_systf(&tf_data);
|
vpi_register_systf(&tf_data);
|
||||||
|
|
||||||
|
/*============================== fread */
|
||||||
|
tf_data.type = vpiSysFunc;
|
||||||
|
tf_data.sysfunctype = vpiIntFunc;
|
||||||
|
tf_data.tfname = "$fread";
|
||||||
|
tf_data.calltf = sys_fread_calltf;
|
||||||
|
tf_data.compiletf = sys_fread_compiletf;
|
||||||
|
tf_data.sizetf = 0;
|
||||||
|
tf_data.user_data = "$fread";
|
||||||
|
vpi_register_systf(&tf_data);
|
||||||
|
|
||||||
/*============================== ungetc */
|
/*============================== ungetc */
|
||||||
tf_data.type = vpiSysFunc;
|
tf_data.type = vpiSysFunc;
|
||||||
tf_data.sysfunctype = vpiIntFunc;
|
tf_data.sysfunctype = vpiIntFunc;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2008 Cary R. (cygcary@yahoo.com)
|
* Copyright (C) 2008-2009 Cary R. (cygcary@yahoo.com)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|
@ -193,8 +193,4 @@ void sys_special_register(void)
|
||||||
tf_data.tfname = "$ferror";
|
tf_data.tfname = "$ferror";
|
||||||
tf_data.user_data = "$ferror";
|
tf_data.user_data = "$ferror";
|
||||||
vpi_register_systf(&tf_data);
|
vpi_register_systf(&tf_data);
|
||||||
|
|
||||||
tf_data.tfname = "$fread";
|
|
||||||
tf_data.user_data = "$fread";
|
|
||||||
vpi_register_systf(&tf_data);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue