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);
|
||||
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
free(fname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -429,6 +430,261 @@ static PLI_INT32 sys_fgets_calltf(PLI_BYTE8*name)
|
|||
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)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
|
|
@ -735,6 +991,16 @@ void sys_fileio_register()
|
|||
tf_data.user_data = "$fgets";
|
||||
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 */
|
||||
tf_data.type = vpiSysFunc;
|
||||
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
|
||||
* 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.user_data = "$ferror";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.tfname = "$fread";
|
||||
tf_data.user_data = "$fread";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue