vhdlpp: std.textio & ieee.std_logic_textio functions implemented using VPI.
This commit is contained in:
parent
6fee37a640
commit
b414733f34
|
|
@ -1072,6 +1072,7 @@ int main(int argc, char **argv)
|
||||||
how to handle them. */
|
how to handle them. */
|
||||||
fprintf(iconfig_file, "sys_func:%s%csystem.sft\n", base, sep);
|
fprintf(iconfig_file, "sys_func:%s%csystem.sft\n", base, sep);
|
||||||
fprintf(iconfig_file, "sys_func:%s%cvhdl_sys.sft\n", base, sep);
|
fprintf(iconfig_file, "sys_func:%s%cvhdl_sys.sft\n", base, sep);
|
||||||
|
fprintf(iconfig_file, "sys_func:%s%cvhdl_textio.sft\n", base, sep);
|
||||||
|
|
||||||
/* If verilog-2005/09/12 is enabled or icarus-misc or verilog-ams,
|
/* If verilog-2005/09/12 is enabled or icarus-misc or verilog-ams,
|
||||||
* then include the v2005_math library. */
|
* then include the v2005_math library. */
|
||||||
|
|
|
||||||
1
main.cc
1
main.cc
|
|
@ -832,6 +832,7 @@ int main(int argc, char*argv[])
|
||||||
// Start the module list with the base system module.
|
// Start the module list with the base system module.
|
||||||
add_vpi_module("system");
|
add_vpi_module("system");
|
||||||
add_vpi_module("vhdl_sys");
|
add_vpi_module("vhdl_sys");
|
||||||
|
add_vpi_module("vhdl_textio");
|
||||||
|
|
||||||
flags["-o"] = strdup("a.out");
|
flags["-o"] = strdup("a.out");
|
||||||
min_typ_max_flag = TYP;
|
min_typ_max_flag = TYP;
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,8 @@ rm -rf $RPM_BUILD_ROOT
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/v2009.vpi
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/v2009.vpi
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_sys.sft
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_sys.sft
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_sys.vpi
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_sys.vpi
|
||||||
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_textio.sft
|
||||||
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_textio.vpi
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/vpi_debug.vpi
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vpi_debug.vpi
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/cadpli.vpl
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/cadpli.vpl
|
||||||
%attr(-,root,root) %{_libdir}/libvpi%{suff}.a
|
%attr(-,root,root) %{_libdir}/libvpi%{suff}.a
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,11 @@ V2009 = v2009_table.o v2009_array.o v2009_enum.o v2009_string.o
|
||||||
|
|
||||||
VHDL_SYS = vhdl_table.o
|
VHDL_SYS = vhdl_table.o
|
||||||
|
|
||||||
|
VHDL_TEXTIO = vhdl_textio.o sys_priv.o
|
||||||
|
|
||||||
VPI_DEBUG = vpi_debug.o
|
VPI_DEBUG = vpi_debug.o
|
||||||
|
|
||||||
all: dep system.vpi va_math.vpi v2005_math.vpi v2009.vpi vhdl_sys.vpi vpi_debug.vpi $(ALL32)
|
all: dep system.vpi va_math.vpi v2005_math.vpi v2009.vpi vhdl_sys.vpi vhdl_textio.vpi vpi_debug.vpi $(ALL32)
|
||||||
|
|
||||||
check: all
|
check: all
|
||||||
|
|
||||||
|
|
@ -88,7 +90,7 @@ clean:
|
||||||
rm -f sdf_lexor.c sdf_parse.c sdf_parse.output sdf_parse.h
|
rm -f sdf_lexor.c sdf_parse.c sdf_parse.output sdf_parse.h
|
||||||
rm -f table_mod_parse.c table_mod_parse.h table_mod_parse.output
|
rm -f table_mod_parse.c table_mod_parse.h table_mod_parse.output
|
||||||
rm -f table_mod_lexor.c
|
rm -f table_mod_lexor.c
|
||||||
rm -f va_math.vpi v2005_math.vpi v2009.vpi vhdl_sys.vpi vpi_debug.vpi
|
rm -f va_math.vpi v2005_math.vpi v2009.vpi vhdl_sys.vpi vhdl_textio.vpi vpi_debug.vpi
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f Makefile config.log
|
rm -f Makefile config.log
|
||||||
|
|
@ -163,6 +165,9 @@ va_math.vpi: $V ../vvp/libvpi.a
|
||||||
vhdl_sys.vpi: $(VHDL_SYS) ../vvp/libvpi.a
|
vhdl_sys.vpi: $(VHDL_SYS) ../vvp/libvpi.a
|
||||||
$(CC) @shared@ -o $@ $(VHDL_SYS) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS)
|
$(CC) @shared@ -o $@ $(VHDL_SYS) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS)
|
||||||
|
|
||||||
|
vhdl_textio.vpi: $(VHDL_TEXTIO) ../vvp/libvpi.a
|
||||||
|
$(CC) @shared@ -o $@ $(VHDL_TEXTIO) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS)
|
||||||
|
|
||||||
vpi_debug.vpi: $(VPI_DEBUG) ../vvp/libvpi.a
|
vpi_debug.vpi: $(VPI_DEBUG) ../vvp/libvpi.a
|
||||||
$(CC) @shared@ -o $@ $(VPI_DEBUG) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS)
|
$(CC) @shared@ -o $@ $(VPI_DEBUG) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS)
|
||||||
|
|
||||||
|
|
@ -177,6 +182,7 @@ install: all installdirs \
|
||||||
$(vpidir)/v2005_math.vpi $(vpidir)/v2005_math.sft \
|
$(vpidir)/v2005_math.vpi $(vpidir)/v2005_math.sft \
|
||||||
$(vpidir)/v2009.vpi $(vpidir)/v2009.sft \
|
$(vpidir)/v2009.vpi $(vpidir)/v2009.sft \
|
||||||
$(vpidir)/vhdl_sys.vpi $(vpidir)/vhdl_sys.sft \
|
$(vpidir)/vhdl_sys.vpi $(vpidir)/vhdl_sys.sft \
|
||||||
|
$(vpidir)/vhdl_textio.vpi $(vpidir)/vhdl_textio.sft \
|
||||||
$(vpidir)/vpi_debug.vpi
|
$(vpidir)/vpi_debug.vpi
|
||||||
|
|
||||||
$(vpidir)/system.vpi: ./system.vpi
|
$(vpidir)/system.vpi: ./system.vpi
|
||||||
|
|
@ -209,6 +215,12 @@ $(vpidir)/vhdl_sys.vpi: ./vhdl_sys.vpi
|
||||||
$(vpidir)/vhdl_sys.sft: vhdl_sys.sft
|
$(vpidir)/vhdl_sys.sft: vhdl_sys.sft
|
||||||
$(INSTALL_DATA) $< "$(DESTDIR)$@"
|
$(INSTALL_DATA) $< "$(DESTDIR)$@"
|
||||||
|
|
||||||
|
$(vpidir)/vhdl_textio.vpi: ./vhdl_textio.vpi
|
||||||
|
$(INSTALL_PROGRAM) ./vhdl_textio.vpi "$(DESTDIR)$(vpidir)/vhdl_textio.vpi"
|
||||||
|
|
||||||
|
$(vpidir)/vhdl_textio.sft: vhdl_textio.sft
|
||||||
|
$(INSTALL_DATA) $< "$(DESTDIR)$@"
|
||||||
|
|
||||||
$(vpidir)/vpi_debug.vpi: ./vpi_debug.vpi
|
$(vpidir)/vpi_debug.vpi: ./vpi_debug.vpi
|
||||||
$(INSTALL_PROGRAM) ./vpi_debug.vpi "$(DESTDIR)$(vpidir)/vpi_debug.vpi"
|
$(INSTALL_PROGRAM) ./vpi_debug.vpi "$(DESTDIR)$(vpidir)/vpi_debug.vpi"
|
||||||
|
|
||||||
|
|
@ -226,6 +238,8 @@ uninstall:
|
||||||
rm -f "$(DESTDIR)$(vpidir)/v2009.sft"
|
rm -f "$(DESTDIR)$(vpidir)/v2009.sft"
|
||||||
rm -f "$(DESTDIR)$(vpidir)/vhdl_sys.vpi"
|
rm -f "$(DESTDIR)$(vpidir)/vhdl_sys.vpi"
|
||||||
rm -f "$(DESTDIR)$(vpidir)/vhdl_sys.sft"
|
rm -f "$(DESTDIR)$(vpidir)/vhdl_sys.sft"
|
||||||
|
rm -f "$(DESTDIR)$(vpidir)/vhdl_textio.vpi"
|
||||||
|
rm -f "$(DESTDIR)$(vpidir)/vhdl_textio.sft"
|
||||||
rm -f "$(DESTDIR)$(vpidir)/vpi_debug.vpi"
|
rm -f "$(DESTDIR)$(vpidir)/vpi_debug.vpi"
|
||||||
|
|
||||||
-include $(patsubst %.o, dep/%.d, $O)
|
-include $(patsubst %.o, dep/%.d, $O)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,943 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015 CERN
|
||||||
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||||
|
*
|
||||||
|
* This source code is free software; you can redistribute it
|
||||||
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
* General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 2 of the License, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The following VPI module implements some of the functions available
|
||||||
|
* in std.textio library.
|
||||||
|
*
|
||||||
|
* Type counterparts:
|
||||||
|
* VHDL SystemVerilog
|
||||||
|
* ------------------------------
|
||||||
|
* LINE string (line of text, in VHDL it is a pointer to string)
|
||||||
|
* TEXT int (file handle)
|
||||||
|
*
|
||||||
|
* Some of functions offered by std.textio library are not implemented here,
|
||||||
|
* as they can be directly replaced with SystemVerilog system functions.
|
||||||
|
*
|
||||||
|
* VHDL SystemVerilog
|
||||||
|
* --------------------------------------
|
||||||
|
* FILE_CLOSE(file F: TEXT) $fclose(fd)
|
||||||
|
* ENDFILE(file F: TEXT) $feof(fd)
|
||||||
|
*
|
||||||
|
* Procedures:
|
||||||
|
* HREAD (L: inout LINE; VALUE: out BIT_VECTOR)
|
||||||
|
* HWRITE (L: inout LINE; VALUE: out BIT_VECTOR)
|
||||||
|
* are handled with $ivlh_read/write() using FORMAT_HEX parameter (see format_t enum).
|
||||||
|
*/
|
||||||
|
|
||||||
|
# include "sys_priv.h"
|
||||||
|
# include "vpi_config.h"
|
||||||
|
# include "vpi_user.h"
|
||||||
|
# include <assert.h>
|
||||||
|
# include <string.h>
|
||||||
|
# include <ctype.h>
|
||||||
|
# include "ivl_alloc.h"
|
||||||
|
|
||||||
|
/* additional parameter values to distinguish between integer, boolean and
|
||||||
|
* time types or to use hex format */
|
||||||
|
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 };
|
||||||
|
|
||||||
|
/* bits per vector, in a single s_vpi_vecval struct */
|
||||||
|
static const size_t BPW = 8 * sizeof(PLI_INT32);
|
||||||
|
|
||||||
|
static int is_integer_var(vpiHandle obj)
|
||||||
|
{
|
||||||
|
PLI_INT32 type = vpi_get(vpiType, obj);
|
||||||
|
|
||||||
|
return (type == vpiIntegerVar || type == vpiShortIntVar ||
|
||||||
|
type == vpiIntVar || type == vpiLongIntVar);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_error_line(vpiHandle callh) {
|
||||||
|
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_warning_line(vpiHandle callh) {
|
||||||
|
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sets a single bit value in a bit/logic vector */
|
||||||
|
static int set_vec_val(s_vpi_vecval* vector, char value, int idx) {
|
||||||
|
s_vpi_vecval*v = &vector[idx / BPW];
|
||||||
|
PLI_INT32 bit = idx % BPW;
|
||||||
|
|
||||||
|
switch(toupper(value)) {
|
||||||
|
case '0':
|
||||||
|
v->bval &= ~(1 << bit);
|
||||||
|
v->aval &= ~(1 << bit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '1':
|
||||||
|
v->bval &= ~(1 << bit);
|
||||||
|
v->aval |= (1 << bit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Z':
|
||||||
|
v->bval |= (1 << bit);
|
||||||
|
v->aval &= ~(1 << bit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'X':
|
||||||
|
v->bval |= (1 << bit);
|
||||||
|
v->aval |= (1 << bit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Converts a string of characters to a vector in s_vpi_value struct.
|
||||||
|
* Returns number of processed characters, 0 in case of failure.
|
||||||
|
* string is the data to be converted.
|
||||||
|
* val is the target s_vpi_value struct.
|
||||||
|
* var is the variable that is converted (to obtain size & type [2/4-state]).
|
||||||
|
*/
|
||||||
|
static int read_vector(const char *string, s_vpi_value *val, vpiHandle var)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
/* It could be easier to simply use val.format = vpiBinStrVal
|
||||||
|
* but there is no way to check if processing went fine */
|
||||||
|
val.format = vpiBinStrVal;
|
||||||
|
val.value.str = string;
|
||||||
|
processed_chars = size;
|
||||||
|
#endif
|
||||||
|
/* Vector size (==1 for scalars) */
|
||||||
|
int size = vpi_get(vpiSize, var);
|
||||||
|
|
||||||
|
/* Number of required s_vpi_vecval structs to store the result */
|
||||||
|
int words = (size + BPW - 1) / BPW; /* == ceil(size / BPW) */
|
||||||
|
int len = strlen(string);
|
||||||
|
|
||||||
|
val->format = vpiVectorVal; /* it also covers scalars */
|
||||||
|
val->value.vector = calloc(words, sizeof(s_vpi_vecval));
|
||||||
|
|
||||||
|
/* Skip spaces in the beginning */
|
||||||
|
int skipped = 0;
|
||||||
|
while(*string && *string == ' ') {
|
||||||
|
--len;
|
||||||
|
++string;
|
||||||
|
++skipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process bits */
|
||||||
|
int p;
|
||||||
|
for(p = 0; p < size && p < len; ++p) {
|
||||||
|
if(set_vec_val(val->value.vector, string[p], size - p - 1)) {
|
||||||
|
free(val->value.vector); /* error */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2-logic variables cannot hold X or Z values, so change them to 0 */
|
||||||
|
if(vpi_get(vpiType, var) == vpiBitVar) {
|
||||||
|
for(int i = 0; i < words; ++i) {
|
||||||
|
val->value.vector[i].aval &= ~val->value.vector[i].bval;
|
||||||
|
val->value.vector[i].bval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p + skipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Converts a string of characters to a time value, stored in vector filed of
|
||||||
|
* s_vpi_value struct.
|
||||||
|
* Returns number of processed characters, 0 in case of failure.
|
||||||
|
* string is the data to be converted.
|
||||||
|
* val is the target s_vpi_value struct.
|
||||||
|
* scope_unit is the time unit used in the scope (-3 for millisecond,
|
||||||
|
* -6 for microsecond, etc.)
|
||||||
|
*/
|
||||||
|
static int read_time(const char *string, s_vpi_value *val, PLI_INT32 scope_unit) {
|
||||||
|
PLI_UINT64 period;
|
||||||
|
char units[2];
|
||||||
|
int time_unit, processed_chars;
|
||||||
|
|
||||||
|
if(sscanf(string, "%ld %2s%n", &period, units, &processed_chars) != 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(!strncasecmp(units, "fs", 2))
|
||||||
|
time_unit = -15;
|
||||||
|
else if(!strncasecmp(units, "ps", 2))
|
||||||
|
time_unit = -12;
|
||||||
|
else if(!strncasecmp(units, "ns", 2))
|
||||||
|
time_unit = -9;
|
||||||
|
else if(!strncasecmp(units, "us", 2))
|
||||||
|
time_unit = -6;
|
||||||
|
else if(!strncasecmp(units, "ms", 2))
|
||||||
|
time_unit = -3;
|
||||||
|
else if(!strncasecmp(units, "s", 1))
|
||||||
|
time_unit = 0;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Scale the time units to the one used in the scope */
|
||||||
|
int scale_diff = time_unit - scope_unit;
|
||||||
|
|
||||||
|
if(scale_diff > 0) {
|
||||||
|
for(int i = 0; i < scale_diff; ++i)
|
||||||
|
period *= 10;
|
||||||
|
} else {
|
||||||
|
for(int i = 0; i < -scale_diff; ++i)
|
||||||
|
period /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vpiTimeVal format is not handled at the moment,
|
||||||
|
* so return the read value as a vector*/
|
||||||
|
val->format = vpiVectorVal;
|
||||||
|
val->value.vector = calloc(2, sizeof(s_vpi_vecval));
|
||||||
|
memset(val->value.vector, 0, 2 * sizeof(s_vpi_vecval));
|
||||||
|
|
||||||
|
val->value.vector[1].aval = (PLI_UINT32) (period >> 32);
|
||||||
|
val->value.vector[0].aval = (PLI_UINT32) period;
|
||||||
|
|
||||||
|
return processed_chars;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_string(const char *string, s_vpi_value *val) {
|
||||||
|
char buf[1024];
|
||||||
|
int processed_chars;
|
||||||
|
|
||||||
|
if(sscanf(string, "%1024s%n", buf, &processed_chars) != 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
val->format = vpiStringVal;
|
||||||
|
val->value.str = strndup(buf, processed_chars);
|
||||||
|
|
||||||
|
return processed_chars;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_time(char *string, const s_vpi_value* val,
|
||||||
|
size_t width, PLI_INT32 scope_unit) {
|
||||||
|
char prefix = 0;
|
||||||
|
PLI_UINT64 period;
|
||||||
|
|
||||||
|
switch(val->format) {
|
||||||
|
case vpiIntVal:
|
||||||
|
period = val->value.integer;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiVectorVal:
|
||||||
|
period = val->value.vector[0].aval;
|
||||||
|
|
||||||
|
if(width > BPW)
|
||||||
|
period |= (PLI_UINT64)(val->value.vector[1].aval) << 32;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle the case when the time unit base is 10 or 100 */
|
||||||
|
int remainder = scope_unit % -3;
|
||||||
|
if(remainder) {
|
||||||
|
remainder += 3;
|
||||||
|
scope_unit -= remainder;
|
||||||
|
|
||||||
|
while(remainder--)
|
||||||
|
period *= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(scope_unit) {
|
||||||
|
case -15: prefix = 'f'; break;
|
||||||
|
case -12: prefix = 'p'; break;
|
||||||
|
case -9: prefix = 'n'; break;
|
||||||
|
case -6: prefix = 'u'; break;
|
||||||
|
case -3: prefix = 'm'; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(prefix)
|
||||||
|
sprintf(string, "%ld %cs", period, prefix);
|
||||||
|
else
|
||||||
|
sprintf(string, "%ld s", period);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* slightly modified sys_fopen_compiletf */
|
||||||
|
static PLI_INT32 ivlh_file_open_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv;
|
||||||
|
assert(callh != 0);
|
||||||
|
|
||||||
|
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(!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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When provided, the type argument must be a string. */
|
||||||
|
if(!vpi_scan(argv)) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's third argument must be an integer (open mode).\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure there are no extra arguments. */
|
||||||
|
check_for_extra_args(argv, callh, name, "three arguments", 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* procedure FILE_MODE(file F: TEXT; External_Name; in STRING;
|
||||||
|
Open_Kind: in FILE_MODE_KIND := READ_MODE); */
|
||||||
|
/* slightly modified sys_fopen_calltf */
|
||||||
|
static PLI_INT32 ivlh_file_open_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
s_vpi_value val;
|
||||||
|
int mode;
|
||||||
|
char *fname;
|
||||||
|
|
||||||
|
vpiHandle fhandleh = vpi_scan(argv);
|
||||||
|
vpiHandle fnameh = vpi_scan(argv);
|
||||||
|
vpiHandle modeh = vpi_scan(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);
|
||||||
|
vpi_printf("%s's file open mode argument is invalid.\n", name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fname = get_filename(callh, name, fnameh);
|
||||||
|
|
||||||
|
if(fname == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's could not obtain the file name.\n", name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open file and save the handle */
|
||||||
|
switch(mode) {
|
||||||
|
case FILE_MODE_READ:
|
||||||
|
val.value.integer = vpi_fopen(fname, "r");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FILE_MODE_WRITE:
|
||||||
|
val.value.integer = vpi_fopen(fname, "w");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FILE_MODE_APPEND:
|
||||||
|
val.value.integer = vpi_fopen(fname, "a");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_put_value(fhandleh, &val, 0, vpiNoDelay);
|
||||||
|
free(fname);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PLI_INT32 ivlh_readwriteline_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle arg;
|
||||||
|
|
||||||
|
/* Check that there are two arguments and that the first is an
|
||||||
|
integer (file handle) and that the second is string. */
|
||||||
|
if(argv == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s requires two arguments.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg || !is_integer_var(arg)) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's first argument must be an integer variable (file handle).\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg || !is_string_obj(arg)) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's second argument must be a string.\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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* procedure READLINE (file F: TEXT; L: inout LINE); */
|
||||||
|
/* slightly modified sys_fgets_calltf */
|
||||||
|
static PLI_INT32 ivlh_readline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle stringh, arg;
|
||||||
|
s_vpi_value val;
|
||||||
|
PLI_UINT32 fd;
|
||||||
|
FILE *fp;
|
||||||
|
char *text;
|
||||||
|
const int BUF_SIZE = 1024;
|
||||||
|
char buf[BUF_SIZE];
|
||||||
|
|
||||||
|
/* Get the file descriptor. */
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(arg, &val);
|
||||||
|
fd = val.value.integer;
|
||||||
|
|
||||||
|
/* Get the string handle. */
|
||||||
|
stringh = vpi_scan(argv);
|
||||||
|
vpi_free_object(argv);
|
||||||
|
|
||||||
|
/* Return zero if this is not a valid fd. */
|
||||||
|
fp = vpi_get_file(fd);
|
||||||
|
if(!fp) {
|
||||||
|
show_warning_line(callh);
|
||||||
|
vpi_printf("invalid file descriptor (0x%x) given to %s.\n",
|
||||||
|
(unsigned int)fd, name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read in the bytes. Return 0 if there was an error. */
|
||||||
|
if(fgets(buf, BUF_SIZE, fp) == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s reading past the end of file.\n", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = strlen(buf);
|
||||||
|
|
||||||
|
if(len == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s read 0 bytes.\n", name);
|
||||||
|
return 0;
|
||||||
|
} else if(len == BUF_SIZE - 1) {
|
||||||
|
show_warning_line(callh);
|
||||||
|
vpi_printf("%s has reached the buffer limit, part of the "
|
||||||
|
"processed string might have been skipped.\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the characters to the register. */
|
||||||
|
text = strndup(buf, len - 1); /* skip the newline character */
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
val.value.str = text;
|
||||||
|
vpi_put_value(stringh, &val, 0, vpiNoDelay);
|
||||||
|
free(text);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* procedure WRITELINE (file F: TEXT; L: inout LINE); */
|
||||||
|
/* slightly modified sys_fgets_calltf */
|
||||||
|
static PLI_INT32 ivlh_writeline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle stringh, arg;
|
||||||
|
s_vpi_value val;
|
||||||
|
PLI_UINT32 fd;
|
||||||
|
FILE *fp;
|
||||||
|
char *empty;
|
||||||
|
|
||||||
|
/* Get the file descriptor. */
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(arg, &val);
|
||||||
|
fd = val.value.integer;
|
||||||
|
|
||||||
|
/* Get the string contents. */
|
||||||
|
stringh = vpi_scan(argv);
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
vpi_get_value(stringh, &val);
|
||||||
|
|
||||||
|
vpi_free_object(argv);
|
||||||
|
|
||||||
|
/* Return zero if this is not a valid fd. */
|
||||||
|
fp = vpi_get_file(fd);
|
||||||
|
if(!fp) {
|
||||||
|
show_warning_line(callh);
|
||||||
|
vpi_printf("invalid file descriptor (0x%x) given to %s.\n",
|
||||||
|
(unsigned int)fd, name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "%s\n", val.value.str);
|
||||||
|
|
||||||
|
/* Clear the written string */
|
||||||
|
empty = strdup("");
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
val.value.str = empty;
|
||||||
|
vpi_put_value(stringh, &val, 0, vpiNoDelay);
|
||||||
|
free(empty);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PLI_INT32 ivlh_read_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle arg;
|
||||||
|
|
||||||
|
if(argv == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s requires three arguments.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg || !is_string_obj(arg)) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's first argument must be a string.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg || is_constant_obj(arg)) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's second argument must be a variable.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's third argument must be an integer.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Make sure there are no extra arguments. */
|
||||||
|
check_for_extra_args(argv, callh, name, "three arguments", 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* procedure READ (L: inout LINE;
|
||||||
|
VALUE: out BIT/BIT_VECTOR/BOOLEAN/CHARACTER/INTEGER/REAL/STRING/TIME); */
|
||||||
|
static PLI_INT32 ivlh_read_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle stringh, varh, formath;
|
||||||
|
s_vpi_value val;
|
||||||
|
PLI_INT32 type, format;
|
||||||
|
char *string = 0;
|
||||||
|
int processed_chars = 0, fail = 0;
|
||||||
|
|
||||||
|
/* Get the string */
|
||||||
|
stringh = vpi_scan(argv);
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
vpi_get_value(stringh, &val);
|
||||||
|
|
||||||
|
/* Get the destination variable */
|
||||||
|
varh = vpi_scan(argv);
|
||||||
|
type = vpi_get(vpiType, varh);
|
||||||
|
|
||||||
|
if(strlen(val.value.str) == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s cannot read from an empty string.\n", name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
string = strdup(val.value.str);
|
||||||
|
|
||||||
|
/* Get the format (see enum format_t) */
|
||||||
|
formath = vpi_scan(argv);
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(formath, &val);
|
||||||
|
format = val.value.integer;
|
||||||
|
vpi_free_object(argv);
|
||||||
|
|
||||||
|
switch(format) {
|
||||||
|
case FORMAT_STD:
|
||||||
|
switch(type) {
|
||||||
|
/* TODO longint is 64-bit, so it has to be handled by vector */
|
||||||
|
/*case vpiLongIntVar:*/
|
||||||
|
case vpiShortIntVar:
|
||||||
|
case vpiIntVar:
|
||||||
|
case vpiByteVar:
|
||||||
|
case vpiIntegerVar:
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
if(sscanf(string, "%d%n", &val.value.integer, &processed_chars) != 1)
|
||||||
|
fail = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiBitVar: /* bit, bit vector */
|
||||||
|
case vpiLogicVar: /* ==vpiReg time, logic, logic vector */
|
||||||
|
processed_chars = read_vector(string, &val, varh);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiRealVar:
|
||||||
|
val.format = vpiRealVal;
|
||||||
|
if(sscanf(string, "%lf%n", &val.value.real, &processed_chars) != 1)
|
||||||
|
fail = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiStringVar:
|
||||||
|
processed_chars = read_string(string, &val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fail = 1;
|
||||||
|
show_warning_line(callh);
|
||||||
|
vpi_printf("%s does not handle such type (%d).\n", name, type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_BOOL:
|
||||||
|
{
|
||||||
|
char buf[5];
|
||||||
|
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
if(sscanf(string, "%5s%n", buf, &processed_chars) == 1)
|
||||||
|
{
|
||||||
|
if(!strncasecmp(buf, "true", 4))
|
||||||
|
val.value.integer = 1;
|
||||||
|
else if(!strncasecmp(buf, "false", 5))
|
||||||
|
val.value.integer = 0;
|
||||||
|
else
|
||||||
|
fail = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_TIME:
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
processed_chars = read_time(string, &val, vpi_get(vpiTimeUnit, callh));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_HEX:
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
if(sscanf(string, "%x%n", &val.value.integer, &processed_chars) != 1)
|
||||||
|
fail = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_STRING:
|
||||||
|
processed_chars = read_string(string, &val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(processed_chars == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s could not read a valid value.\n", name);
|
||||||
|
fail = 1;
|
||||||
|
} else if(val.format == vpiStringVar && processed_chars == 1024) {
|
||||||
|
show_warning_line(callh);
|
||||||
|
vpi_printf("%s has reached the buffer limit, part of the "
|
||||||
|
"processed string might have been skipped.\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!fail) {
|
||||||
|
assert(processed_chars > 0);
|
||||||
|
|
||||||
|
/* Store the read value */
|
||||||
|
vpi_put_value(varh, &val, 0, vpiNoDelay);
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
if(val.format == vpiStringVar)
|
||||||
|
free(val.value.str);
|
||||||
|
else if(val.format == vpiVectorVal)
|
||||||
|
free(val.value.vector);
|
||||||
|
|
||||||
|
/* Strip the read token from the string */
|
||||||
|
char* tmp = strdup(&string[processed_chars]);
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
val.value.str = tmp;
|
||||||
|
vpi_put_value(stringh, &val, 0, vpiNoDelay);
|
||||||
|
free(tmp);
|
||||||
|
} else {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s failed.\n", name);
|
||||||
|
/*vpi_control(vpiFinish, 1);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
free(string);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PLI_INT32 ivlh_write_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle arg;
|
||||||
|
|
||||||
|
if(argv == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s requires three arguments.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg || !is_string_obj(arg)) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's first argument must be a string.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s requires three arguments.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's third argument must be an integer.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Make sure there are no extra arguments. */
|
||||||
|
check_for_extra_args(argv, callh, name, "three arguments", 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*procedure WRITE (L: inout LINE;
|
||||||
|
VALUE: in BIT/BIT_VECTOR/BOOLEAN/CHARACTER/INTEGER/REAL/STRING/TIME);
|
||||||
|
JUSTIFIED: in SIDE:= RIGHT; FIELD: in WIDTH := 0); */
|
||||||
|
/* JUSTIFIED & FIELD are not handled at the moment */
|
||||||
|
static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle stringh, varh, formath;
|
||||||
|
s_vpi_value val;
|
||||||
|
PLI_INT32 type, format;
|
||||||
|
char *string = 0;
|
||||||
|
int fail = 0, res = 0;
|
||||||
|
const int BUF_SIZE = 1024;
|
||||||
|
char buf[BUF_SIZE];
|
||||||
|
|
||||||
|
/* Get the string */
|
||||||
|
stringh = vpi_scan(argv);
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
vpi_get_value(stringh, &val);
|
||||||
|
string = strdup(val.value.str);
|
||||||
|
|
||||||
|
/* Get the destination variable */
|
||||||
|
varh = vpi_scan(argv);
|
||||||
|
type = vpi_get(vpiType, varh);
|
||||||
|
|
||||||
|
/* Get the format (see enum format_t) */
|
||||||
|
formath = vpi_scan(argv);
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(formath, &val);
|
||||||
|
format = val.value.integer;
|
||||||
|
vpi_free_object(argv);
|
||||||
|
|
||||||
|
/* Convert constant types to variable types */
|
||||||
|
if(type == vpiConstant) {
|
||||||
|
type = vpi_get(vpiConstType, varh);
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case vpiRealConst:
|
||||||
|
type = vpiRealVar;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiStringConst:
|
||||||
|
type = vpiStringVar;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiDecConst:
|
||||||
|
case vpiBinaryConst:
|
||||||
|
case vpiOctConst:
|
||||||
|
case vpiHexConst:
|
||||||
|
type = vpiIntVar;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(format) {
|
||||||
|
case FORMAT_STD:
|
||||||
|
switch(type) {
|
||||||
|
/* TODO longint is 64-bit, so it has to be handled by vector */
|
||||||
|
/*case vpiLongIntVar:*/
|
||||||
|
case vpiShortIntVar:
|
||||||
|
case vpiIntVar:
|
||||||
|
case vpiByteVar:
|
||||||
|
case vpiIntegerVar:
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%d", string, val.value.integer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiBitVar: /* bit, bit vector */
|
||||||
|
case vpiLogicVar: /* ==vpiReg time, logic, logic vector */
|
||||||
|
val.format = vpiBinStrVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
|
||||||
|
/* VHDL stores X/Z values uppercase, so follow the rule */
|
||||||
|
for(size_t i = 0; i< strlen(val.value.str); ++i)
|
||||||
|
val.value.str[i] = toupper(val.value.str[i]);
|
||||||
|
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiRealVar:
|
||||||
|
val.format = vpiRealVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%lf", string, val.value.real);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiStringVar:
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fail = 1;
|
||||||
|
show_warning_line(callh);
|
||||||
|
vpi_printf("%s does not handle such type (%d).\n", name, type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_BOOL:
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%s", string,
|
||||||
|
val.value.integer ? "TRUE" : "FALSE");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_TIME:
|
||||||
|
{
|
||||||
|
char tmp[64];
|
||||||
|
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
|
||||||
|
if(write_time(tmp, &val, vpi_get(vpiSize, varh), vpi_get(vpiTimeUnit, callh))) {
|
||||||
|
fail = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%s", string, tmp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_HEX:
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%X", string, val.value.integer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_STRING:
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(res > BUF_SIZE)
|
||||||
|
fail = 1;
|
||||||
|
|
||||||
|
if(!fail) {
|
||||||
|
/* Strip the read token from the string */
|
||||||
|
char* tmp = strndup(buf, BUF_SIZE);
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
val.value.str = tmp;
|
||||||
|
vpi_put_value(stringh, &val, 0, vpiNoDelay);
|
||||||
|
free(tmp);
|
||||||
|
} else {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s failed.\n", name);
|
||||||
|
/*vpi_control(vpiFinish, 1);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
free(string);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vhdl_register(void)
|
||||||
|
{
|
||||||
|
vpiHandle res;
|
||||||
|
|
||||||
|
s_vpi_systf_data tf_data[] = {
|
||||||
|
{ vpiSysTask, 0, "$ivlh_file_open",
|
||||||
|
ivlh_file_open_calltf, ivlh_file_open_compiletf, 0,
|
||||||
|
"$ivlh_file_open" },
|
||||||
|
|
||||||
|
{ vpiSysTask, 0, "$ivlh_readline",
|
||||||
|
ivlh_readline_calltf, ivlh_readwriteline_compiletf, 0,
|
||||||
|
"$ivlh_readline" },
|
||||||
|
|
||||||
|
{ vpiSysTask, 0, "$ivlh_writeline",
|
||||||
|
ivlh_writeline_calltf, ivlh_readwriteline_compiletf, 0,
|
||||||
|
"$ivlh_writeline" },
|
||||||
|
|
||||||
|
{ vpiSysTask, 0, "$ivlh_read",
|
||||||
|
ivlh_read_calltf, ivlh_read_compiletf, 0,
|
||||||
|
"$ivlh_read" },
|
||||||
|
|
||||||
|
{ vpiSysTask, 0, "$ivlh_write",
|
||||||
|
ivlh_write_calltf, ivlh_write_compiletf, 0,
|
||||||
|
"$ivlh_write" },
|
||||||
|
};
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < sizeof(tf_data) / sizeof(s_vpi_systf_data); ++i) {
|
||||||
|
res = vpi_register_systf(&tf_data[i]);
|
||||||
|
vpip_make_systf_system_defined(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*vlog_startup_routines[])(void) = {
|
||||||
|
vhdl_register,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
$ivlh_file_open vpiSysFuncVoid
|
||||||
|
|
||||||
|
$ivlh_readline vpiSysFuncVoid
|
||||||
|
$ivlh_writeline vpiSysFuncVoid
|
||||||
|
|
||||||
|
$ivlh_read vpiSysFuncVoid
|
||||||
|
$ivlh_write vpiSysFuncVoid
|
||||||
|
$ivlh_hread vpiSysFuncVoid
|
||||||
|
$ivlh_hwrite vpiSysFuncVoid
|
||||||
Loading…
Reference in New Issue