diff --git a/Makefile.in b/Makefile.in index 986427846..042f8ee23 100644 --- a/Makefile.in +++ b/Makefile.in @@ -117,7 +117,7 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \ net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \ pform_disciplines.o pform_dump.o pform_package.o pform_pclass.o \ pform_class_type.o pform_string_type.o pform_struct_type.o pform_types.o \ - symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \ + symbol_search.o sync.o sys_funcs.o verinum.o verireal.o vpi_modules.o target.o \ Attrib.o HName.o Module.o PClass.o PDelays.o PEvent.o PExpr.o PFunction.o \ PGate.o PGenerate.o PModport.o PNamedItem.o PPackage.o PScope.o PSpec.o \ PTask.o PUdp.o PWire.o Statement.o AStatement.o $M $(FF) $(TT) @@ -138,7 +138,7 @@ endif check: all $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true test -r check.conf || cp $(srcdir)/check.conf . - driver/iverilog -B. -BPivlpp -tcheck -ocheck.vvp $(srcdir)/examples/hello.vl + driver/iverilog -B. -BMvpi -BPivlpp -tcheck -ocheck.vvp $(srcdir)/examples/hello.vl ifeq (@WIN32@,yes) ifeq (@install_suffix@,) vvp/vvp -M- -M./vpi ./check.vvp | grep 'Hello, World' diff --git a/cadpli/Makefile.in b/cadpli/Makefile.in index 8d9af5a51..eac420b81 100644 --- a/cadpli/Makefile.in +++ b/cadpli/Makefile.in @@ -71,12 +71,12 @@ dep: $(CC) $(CPPFLAGS) $(CFLAGS) @DEPENDENCY_FLAG@ -c $< mv $*.d dep -SYSTEM_VPI_LDFLAGS = -L../vvp -lvpi +SYSTEM_VPI_LDFLAGS = -L../vpi -lvpi ifeq (@MINGW32@,yes) SYSTEM_VPI_LDFLAGS += @EXTRALIBS@ endif -cadpli.vpl: $O ../vvp/libvpi.a ../libveriuser/libveriuser.o +cadpli.vpl: $O ../vpi/libvpi.a ../libveriuser/libveriuser.o $(CC) @shared@ $(LDFLAGS) -o $@ $O ../libveriuser/libveriuser.o $(SYSTEM_VPI_LDFLAGS) install: all installdirs $(vpidir)/cadpli.vpl diff --git a/compiler.h b/compiler.h index 593955e65..441ad11d9 100644 --- a/compiler.h +++ b/compiler.h @@ -290,9 +290,16 @@ struct sfunc_return_type { bool override_flag; }; +extern void add_sys_func(const struct sfunc_return_type&ret_type); extern const struct sfunc_return_type* lookup_sys_func(const char*name); extern int load_sys_func_table(const char*path); extern void cleanup_sys_func_table(); +/* + * This temporarily loads a VPI module, to determine the return values + * of system functions provided by that module, and adds the return values + * to the system function table. + */ +extern bool load_vpi_module(const char*path); /* * In system Verilog it is allowed with a warning to call a function diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index 464a6acbf..190142d96 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -1,4 +1,4 @@ -.TH iverilog 1 "Oct 5th, 2019" "" "Version %M.%n%E" +.TH iverilog 1 "Oct 23rd, 2019" "" "Version %M.%n%E" .SH NAME iverilog - Icarus Verilog compiler @@ -7,8 +7,9 @@ iverilog - Icarus Verilog compiler [\-EiSuVv] [\-Bpath] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]] [\-Pparameter=value] [\-pflag=value] [\-dname] [\-g1995\:|\-g2001\:|\-g2005\:|\-g2005-sv\:|\-g2009\:|\-g2012\:|\-g] -[\-Iincludedir] [\-mmodule] [\-M[mode=]file] [\-Nfile] [\-ooutputfilename] -[\-stopmodule] [\-ttype] [\-Tmin/typ/max] [\-Wclass] [\-ypath] [\-lfile] +[\-Iincludedir] [\-Lmoduledir] [\-mmodule] [\-M[mode=]file] [\-Nfile] +[\-ooutputfilename] [\-stopmodule] [\-ttype] [\-Tmin/typ/max] [\-Wclass] +[\-ypath] [\-lfile] sourcefile .SH DESCRIPTION @@ -164,6 +165,12 @@ over that instantiation. It will also stop the compiler returning an error if there are no top level modules. This allows the compiler to be used to check incomplete designs for errors. .TP 8 +.B -L\fIpath\fP +This flag adds a directory to the path list used to locate VPI +modules. The default path includes only the install directory for the +system.vpi module, but this flag can add other directories. Multiple +paths are allowed, and the paths will be searched in order. +.TP 8 .B -l\fIfile\fP Add the specified file to the list of source files to be compiled, but mark it as a library file. All modules contained within that @@ -191,12 +198,12 @@ prefixed by "I " and other files are prefixed by "M ". Add this module to the list of VPI modules to be loaded by the simulation. Many modules can be specified, and all will be loaded, in the order specified. The system module is implicit and always included -(and loaded last). If a System Function Table file (.sft) -exists for the module it will be loaded automatically. +(and loaded last). If the specified name includes at least one directory character, it is assumed to be prefixed by the path to the module, otherwise the module -is assumed to be located in the \fIiverilog\fP base directory. +is searched for in the paths specified by preceding \fB-L\fP options, +and if not found there, in the \fIiverilog\fP base directory. .TP 8 .B -N\fIpath\fP This is used for debugging the compiler proper. Dump the final netlist @@ -406,13 +413,23 @@ sensitivity list. Although this behaviour is prescribed by the IEEE standard, it is not what might be expected and can have performance implications if the array is large. -.SH "SYSTEM FUNCTION TABLE FILES" -If the source file name as a \fB.sft\fP suffix, then it is taken to be -a system function table file. A System function table file is used to -describe to the compiler the return types for system functions. This +.SH "VPI MODULES" +If the source file name has a \fB.vpi\fP or \fB.vpl\fP suffix, then it +is taken to be a VPI module. VPI modules supplied by the user are scanned +to determine the return types of any system functions they provide. This is necessary because the compiler needs this information to elaborate -expressions that contain these system functions, but cannot run the -sizetf functions since it has no run-time. +expressions that contain these system functions. The module path/name is +passed on to the target to allow the VPI module to be automatically loaded +at the start of simulation. + +VPI modules may also be supplied using the \fB-L\fP and \fB-m\fP options. + +.SH "SYSTEM FUNCTION TABLE FILES [deprecated]" +If the source file name has a \fB.sft\fP suffix, then it is taken to be a +system function table file. A system function table file is the old method +used to describe to the compiler the return types for system functions. +Users are encouraged to switch to the new method of simply supplying the +VPI module. The format of the table is ASCII, one function per line. Empty lines are ignored, and lines that start with the '\fI#\fP' character are @@ -566,6 +583,24 @@ This is always defined when compiling with Icarus Verilog. .B __VAMS_ENABLE__ = 1 This is defined if Verilog\-AMS is enabled. +.SH ENVIRONMENT +.PP +\fIiverilog\fP also accepts some environment variables that control +its behavior. These can be used to make semi-permanent changes. + +.TP 8 +.B IVERILOG_ICONFIG=\fIfile-name\fP +This sets the name used for the temporary file that passes parameters +to the compiler proper, and prevents that file being deleted after the +compiler has exited. + +.TP 8 +.B IVERILOG_VPI_MODULE_PATH=\fI/some/path:/some/other/path\fP +This adds additional components to the VPI module search path. Paths +specified in this way are searched after paths specified with \fB-L\fP, +but before the default search path. Multiple paths can be separated with +colons (semicolons if using Windows). + .SH EXAMPLES These examples assume that you have a Verilog source file called hello.v in the current directory diff --git a/driver/main.c b/driver/main.c index 427c9d499..661e7604b 100644 --- a/driver/main.c +++ b/driver/main.c @@ -40,7 +40,7 @@ const char NOTICE[] = const char HELP[] = "Usage: iverilog [-EiSuvV] [-B base] [-c cmdfile|-f cmdfile]\n" " [-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012] [-g]\n" -" [-D macro[=defn]] [-I includedir]\n" +" [-D macro[=defn]] [-I includedir] [-L moduledir]\n" " [-M [mode=]depfile] [-m module]\n" " [-N file] [-o filename] [-p flag=value]\n" " [-s topmodule] [-t target] [-T min|typ|max]\n" @@ -99,13 +99,16 @@ extern const char*optarg; #ifdef __MINGW32__ const char sep = '\\'; +const char path_sep = ';'; #else const char sep = '/'; +const char path_sep = ':'; #endif extern void cfreset(FILE*fd, const char*path); const char*base = 0; +const char*vpi_dir = 0; const char*ivlpp_dir = 0; const char*vhdlpp_dir= 0; const char*vhdlpp_work = 0; @@ -169,6 +172,12 @@ char*compiled_defines_path = 0; static char iconfig_common_path[4096] = ""; +static const char**vpi_path_list = 0; +static unsigned vpi_path_list_size = 0; + +static const char**env_vpi_path_list = 0; +static unsigned env_vpi_path_list_size = 0; + int synth_flag = 0; int verbose_flag = 0; @@ -673,14 +682,19 @@ void process_timescale(const char*ts_string) /* * This function is called while processing a file name in a command * file, or a file name on the command line. Look to see if there is a - * .sft suffix, and if so pass that as a sys_func file. Otherwise, it - * is a Verilog source file to be written into the file list. + * .sft or .vpi suffix, and if so pass that as a sys_func or module + * file. Otherwise, it is a Verilog source file to be written into the + * file list. */ void process_file_name(const char*name, int lib_flag) { if (strlen(name) > 4 && strcasecmp(".sft", name+strlen(name)-4) == 0) { + fprintf(stderr, "SFT files are deprecated. Please pass the VPI module instead.\n"); fprintf(iconfig_file,"sys_func:%s\n", name); + } else if (strlen(name) > 4 && strcasecmp(".vpi", name+strlen(name)-4) == 0) { + fprintf(iconfig_file,"module:%s\n", name); + } else { fprintf(source_file, "%s\n", name); source_count += 1; @@ -856,25 +870,124 @@ static int process_depfile(const char*name) return 0; } -/* - * If it exists add the SFT file for the given module. - */ -static void add_sft_file(const char *module) +static void add_env_vpi_module_path(const char*path) { - char *file; + env_vpi_path_list_size += 1; + env_vpi_path_list = (const char**)realloc(env_vpi_path_list, + env_vpi_path_list_size*sizeof(char*)); + env_vpi_path_list[env_vpi_path_list_size-1] = path; +} - file = (char *) malloc(strlen(base)+1+strlen(module)+4+1); - // If the module name has at least one directory character - // in it, assume it includes the path, otherwise look in - // the base directory. - if (strchr(module, sep)) - sprintf(file, "%s.sft", module); - else - sprintf(file, "%s%c%s.sft", base, sep, module); +static void get_env_vpi_module_paths(void) +{ + char *var = getenv("IVERILOG_VPI_MODULE_PATH"); + char *ptr, *end; - if (access(file, R_OK) == 0) - fprintf(iconfig_file, "sys_func:%s\n", file); - free(file); + if (!var) + return; + + var = strdup(var); +#ifdef __MINGW32__ + convert_to_MS_path(var); +#endif + ptr = var; + end = var+strlen(var); + int len = 0; + while (ptr <= end) { + if (*ptr == 0 || *ptr == path_sep) { + *ptr = 0; + if (len > 0) { + add_env_vpi_module_path(var); + } + len = 0; + var = ptr+1; + } else { + len++; + } + ptr++; + } +} + +static void add_vpi_module_path(const char*path) +{ +#ifdef __MINGW32__ + char*tmp_path = strdup(path); + convert_to_MS_path(tmp_path); + path = tmp_path; +#endif + vpi_path_list_size += 1; + vpi_path_list = (const char**)realloc(vpi_path_list, + vpi_path_list_size*sizeof(char*)); + vpi_path_list[vpi_path_list_size-1] = path; +} + +static int probe_for_vpi_module(const char*base_path, const char*name, + char*path, unsigned path_size) +{ + snprintf(path, path_size, "%s%c%s.vpi", base_path, sep, name); + if (access(path, R_OK) == 0) + return 1; + + snprintf(path, path_size, "%s%c%s.vpl", base_path, sep, name); + if (access(path, R_OK) == 0) + return 1; + + return 0; +} + +/* + * If it exists add the VPI file for the given module. + */ +static void add_vpi_file(const char *name) +{ + const char*base_dir = vpi_dir ? vpi_dir : base; + + char path[4096]; + +#ifdef __MINGW32__ + char*tmp_name = strdup(name); + convert_to_MS_path(tmp_name); + name = tmp_name; +#endif + + int found = 0; + if (strchr(name, sep)) { + /* If the name has at least one directory character in it + then assume it is a complete name, maybe including any + possible .vpi or .vpl suffix. */ + found = access(name, R_OK) == 0; + if (!found) { + snprintf(path, sizeof(path), "%s.vpi", name); + found = access(path, R_OK) == 0; + if (!found) { + snprintf(path, sizeof(path), "%s.vpl", name); + found = access(path, R_OK) == 0; + } + } else { + strncpy(path, name, sizeof(path) - 1); + } + } else { + for (unsigned idx = 0; !found && (idx < vpi_path_list_size); idx += 1) { + found = probe_for_vpi_module(vpi_path_list[idx], name, + path, sizeof(path)); + } + for (unsigned idx = 0; !found && (idx < env_vpi_path_list_size); idx += 1) { + found = probe_for_vpi_module(env_vpi_path_list[idx], name, + path, sizeof(path)); + } + if (!found) { + found = probe_for_vpi_module(base_dir, name, + path, sizeof(path)); + } + } + if (found) { + fprintf(iconfig_file, "module:%s\n", path); + } else { + fprintf(stderr, "Unable to find VPI module '%s'\n", name); + } +#ifdef __MINGW32__ + free(tmp_name); +#endif } static void find_ivl_root_failed(const char *reason) @@ -979,6 +1092,8 @@ int main(int argc, char **argv) find_ivl_root(); base = ivl_root; + get_env_vpi_module_paths(); + /* Create a temporary file for communicating input parameters to the preprocessor. */ source_path = strdup(my_tempfile("ivrlg", &source_file)); @@ -1039,7 +1154,7 @@ int main(int argc, char **argv) } } - while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hl:I:iM:m:N:o:P:p:Ss:T:t:uvVW:y:Y:")) != EOF) { + while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hl:I:iL:M:m:N:o:P:p:Ss:T:t:uvVW:y:Y:")) != EOF) { switch (opt) { case 'B': @@ -1048,6 +1163,9 @@ int main(int argc, char **argv) character of the path indicates which path the user is specifying. */ switch (optarg[0]) { + case 'M': /* Path for the VPI modules */ + vpi_dir = optarg+1; + break; case 'P': /* Path for the ivlpp preprocessor */ ivlpp_dir = optarg+1; break; @@ -1098,6 +1216,10 @@ int main(int argc, char **argv) ignore_missing_modules = 1; break; + case 'L': + add_vpi_module_path(optarg); + break; + case 'l': process_file_name(optarg, 1); break; @@ -1108,8 +1230,7 @@ int main(int argc, char **argv) break; case 'm': - fprintf(iconfig_file, "module:%s\n", optarg); - add_sft_file(optarg); + add_vpi_file(optarg); break; case 'N': @@ -1180,6 +1301,8 @@ int main(int argc, char **argv) } } + if (vpi_dir == 0) + vpi_dir = base; if (ivlpp_dir == 0) ivlpp_dir = base; if (vhdlpp_dir == 0) @@ -1198,12 +1321,10 @@ int main(int argc, char **argv) /* Write values to the iconfig file. */ fprintf(iconfig_file, "basedir:%s\n", base); - /* Tell the core where to find the system.sft. This file - describes the system functions so that elaboration knows - how to handle them. */ - 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_textio.sft\n", base, sep); + /* Tell the core where to find the system VPI modules. */ + fprintf(iconfig_file, "module:%s%csystem.vpi\n", vpi_dir, sep); + fprintf(iconfig_file, "module:%s%cvhdl_sys.vpi\n", vpi_dir, sep); + fprintf(iconfig_file, "module:%s%cvhdl_textio.vpi\n", vpi_dir, sep); /* If verilog-2005/09/12 is enabled or icarus-misc or verilog-ams, * then include the v2005_math library. */ @@ -1212,23 +1333,20 @@ int main(int argc, char **argv) strcmp(generation, "2012") == 0 || strcmp(gen_icarus, "icarus-misc") == 0 || strcmp(gen_verilog_ams, "verilog-ams") == 0) { - fprintf(iconfig_file, "sys_func:%s%cv2005_math.sft\n", base, sep); - fprintf(iconfig_file, "module:v2005_math\n"); + fprintf(iconfig_file, "module:%s%cv2005_math.vpi\n", vpi_dir, sep); } /* If verilog-ams or icarus_misc is enabled, then include the * va_math module as well. */ if (strcmp(gen_verilog_ams,"verilog-ams") == 0 || strcmp(gen_icarus, "icarus-misc") == 0) { - fprintf(iconfig_file, "sys_func:%s%cva_math.sft\n", base, sep); - fprintf(iconfig_file, "module:va_math\n"); + fprintf(iconfig_file, "module:%s%cva_math.vpi\n", vpi_dir, sep); } /* If verilog-2009 (SystemVerilog) is enabled, then include the v2009 module. */ if (strcmp(generation, "2005-sv") == 0 || strcmp(generation, "2009") == 0 || strcmp(generation, "2012") == 0) { - fprintf(iconfig_file, "sys_func:%s%cv2009.sft\n", base, sep); - fprintf(iconfig_file, "module:v2009\n"); + fprintf(iconfig_file, "module:%s%cv2009.vpi\n", vpi_dir, sep); } if (mtm != 0) fprintf(iconfig_file, "-T:%s\n", mtm); diff --git a/main.cc b/main.cc index 60ec62e7e..6dc4988de 100644 --- a/main.cc +++ b/main.cc @@ -136,6 +136,7 @@ void add_vpi_module(const char*name) vpi_module_list = tmp; } flags["VPI_MODULE_LIST"] = vpi_module_list; + load_vpi_module(name); } map missing_modules; @@ -900,11 +901,6 @@ int main(int argc, char*argv[]) } library_suff.push_back(strdup(".v")); - // Start the module list with the base system module. - add_vpi_module("system"); - add_vpi_module("vhdl_sys"); - add_vpi_module("vhdl_textio"); - flags["-o"] = strdup("a.out"); min_typ_max_flag = TYP; min_typ_max_warn = 10; diff --git a/sys_funcs.cc b/sys_funcs.cc index a39585c70..93b0e14c4 100644 --- a/sys_funcs.cc +++ b/sys_funcs.cc @@ -29,16 +29,8 @@ * via the lookup_sys_func function. */ -static const struct sfunc_return_type sfunc_table[] = { - { "$realtime", IVL_VT_REAL, 1, false, false }, - { "$bitstoreal", IVL_VT_REAL, 1, false, false }, - { "$itor", IVL_VT_REAL, 1, false, false }, - { "$realtobits", IVL_VT_LOGIC, 64, false, false }, - { "$time", IVL_VT_LOGIC, 64, false, false }, - { "$stime", IVL_VT_LOGIC, 32, false, false }, - { "$simtime", IVL_VT_LOGIC, 64, false, false }, - { 0, IVL_VT_LOGIC, 32, false, false } -}; +static const struct sfunc_return_type default_return_type = + { 0, IVL_VT_LOGIC, 32, false, false }; struct sfunc_return_type_cell : sfunc_return_type { struct sfunc_return_type_cell*next; @@ -89,19 +81,26 @@ const struct sfunc_return_type* lookup_sys_func(const char*name) if (def) return def; - /* Next, look in the core table. */ - unsigned idx = 0; - while (sfunc_table[idx].name) { + /* No luck finding, so return the default description. */ + return &default_return_type; +} - if (strcmp(sfunc_table[idx].name, name) == 0) - return sfunc_table + idx; - - idx += 1; +void add_sys_func(const struct sfunc_return_type&ret_type) +{ + struct sfunc_return_type*def = find_in_sys_func_list(ret_type.name); + if (def) { + /* Keep the original definition, but flag that it + overrides a later definition. */ + def->override_flag = true; + return; } - - /* No luck finding, so return the trailer, which gives a - default description. */ - return sfunc_table + idx; + struct sfunc_return_type_cell*cell = new struct sfunc_return_type_cell; + cell->name = lex_strings.add(ret_type.name); + cell->type = ret_type.type; + cell->wid = ret_type.wid; + cell->signed_flag = ret_type.signed_flag; + cell->override_flag = ret_type.override_flag; + append_to_list(cell); } /* diff --git a/veriuser.h b/veriuser.h index 7614673db..6b958f39e 100644 --- a/veriuser.h +++ b/veriuser.h @@ -1,7 +1,7 @@ #ifndef VERIUSER_H #define VERIUSER_H /* - * Copyright (c) 2002-2018 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2019 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -152,6 +152,9 @@ typedef struct t_tfcell */ extern s_tfcell veriusertfs[]; extern void veriusertfs_register_table(p_tfcell vtable); +#if defined(__MINGW32__) || defined (__CYGWIN32__) +extern __declspec(dllexport) void (*vlog_startup_routines[])(void); +#endif #define usertask 1 #define userfunction 2 diff --git a/vpi.txt b/vpi.txt index 27cfb3830..d19a2f28a 100644 --- a/vpi.txt +++ b/vpi.txt @@ -4,13 +4,16 @@ HOW IT WORKS The VPI interface for Icarus Verilog works by creating from a collection of PLI applications a single vpi module. The vpi module includes compiled code for the applications linked together (with any -other libraries that the applications need) into a module with a -single exported symbol, the vlog_startup_routines array. +other libraries that the applications need) into a module with two +exported symbols, the vpip_set_callback function and the +vlog_startup_routines array. -The product that wishes to invoke the module (normally at run time) -loads the module, locates the vlog_startup_routines table, and calls -all the startup routines contained in that table. It is possible for a -product to link with many modules. In that case, all the modules are +The product that wishes to invoke the module (normally at run time) loads +the module, locates and calls the vpip_set_callback function to pass the +the module a jump table that allows the module to access the VPI routines +implemented by the product, then locates the vlog_startup_routines table +and calls all the startup routines contained in that table. It is possible +for a product to link with many modules. In that case, all the modules are linked in and startup routines are called in order. The product that uses vpi modules uses the environment variable @@ -19,9 +22,11 @@ module search path. When a module is specified by name (using whatever means the product supports) the module search path is scanned until the module is located. -The special module name "system.vpi" is part of the core Icarus -Verilog distribution and includes implementations of the standard -system tasks/functions. +The special module names "system.vpi", "v2005_math.vpi", "v2009.vpi", +and "va_math.vpi" are part of the core Icarus Verilog distribution and +include implementations of the standard system tasks/functions. The +additional special module names "vhdl_sys.vpi" and "vhdl_textio.vpi" +include implementations of private functions used to support VHDL. COMPILING A VPI MODULE @@ -40,4 +45,3 @@ This tracing is pretty verbose, so you don't want to run like this normally. Also, the format of the tracing messages will change according to my needs (and whim) so don't expect to be able to parse it in software. - diff --git a/vpi/Makefile.in b/vpi/Makefile.in index 70f045ce1..44ab8915d 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -33,6 +33,8 @@ vpidir = $(libdir)/ivl$(suffix) CC = @CC@ CXX = @CXX@ +AR = @AR@ +RANLIB = @RANLIB@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ @@ -69,10 +71,10 @@ O += sys_fst.o fstapi.o fastlz.o lz4.o endif # Object files for v2005_math.vpi -M = sys_clog2.o v2005_math.o +V2005 = sys_clog2.o v2005_math.o # Object files for va_math.vpi -V = va_math.o +VA_MATH = va_math.o V2009 = v2009_table.o v2009_array.o v2009_bitvec.o v2009_enum.o v2009_string.o \ sys_priv.o @@ -83,12 +85,12 @@ VHDL_TEXTIO = vhdl_textio.o sys_priv.o VPI_DEBUG = vpi_debug.o -all: dep system.vpi va_math.vpi v2005_math.vpi v2009.vpi vhdl_sys.vpi vhdl_textio.vpi vpi_debug.vpi $(ALL32) +all: dep libvpi.a system.vpi va_math.vpi v2005_math.vpi v2009.vpi vhdl_sys.vpi vhdl_textio.vpi vpi_debug.vpi $(ALL32) check: all clean: - rm -rf *.o sys_readmem_lex.c dep system.vpi + rm -rf *.o sys_readmem_lex.c dep libvpi.a system.vpi 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_lexor.c @@ -122,6 +124,12 @@ dep: $(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o mv $*.d dep +libvpi.a: libvpi.c ../vpi_user.h + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< + rm -f libvpi.a + $(AR) cqv libvpi.a libvpi.o + $(RANLIB) libvpi.a + LIBS = @LIBS@ SYSTEM_VPI_LDFLAGS = $(LIBS) VA_MATH_LDFLAGS = @@ -130,8 +138,8 @@ ifeq (@MINGW32@,yes) VA_MATH_LDFLAGS += @EXTRALIBS@ endif -system.vpi: $O $(OPP) ../vvp/libvpi.a - $(CXX) @shared@ -o $@ $O $(OPP) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) +system.vpi: $O $(OPP) libvpi.a + $(CXX) @shared@ -o $@ $O $(OPP) -L. $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) sys_readmem_lex.c: $(srcdir)/sys_readmem_lex.lex $(LEX) -t $< > $@ @@ -156,23 +164,23 @@ table_mod_parse.c: $(srcdir)/table_mod_parse.y $(YACC) --verbose -t -p tblmod -d -o $@ $< table_mod_parse.h: table_mod_parse.c -v2005_math.vpi: $M ../vvp/libvpi.a - $(CC) @shared@ -o $@ $M -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS) +v2005_math.vpi: $(V2005) libvpi.a + $(CC) @shared@ -o $@ $(V2005) -L. $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS) -v2009.vpi: $(V2009) ../vvp/libvpi.a - $(CC) @shared@ -o $@ $(V2009) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) +v2009.vpi: $(V2009) libvpi.a + $(CC) @shared@ -o $@ $(V2009) -L. $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) -va_math.vpi: $V ../vvp/libvpi.a - $(CC) @shared@ -o $@ $V -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS) +va_math.vpi: $(VA_MATH) libvpi.a + $(CC) @shared@ -o $@ $(VA_MATH) -L. $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS) -vhdl_sys.vpi: $(VHDL_SYS) ../vvp/libvpi.a - $(CC) @shared@ -o $@ $(VHDL_SYS) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) +vhdl_sys.vpi: $(VHDL_SYS) libvpi.a + $(CC) @shared@ -o $@ $(VHDL_SYS) -L. $(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) +vhdl_textio.vpi: $(VHDL_TEXTIO) libvpi.a + $(CC) @shared@ -o $@ $(VHDL_TEXTIO) -L. $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) -vpi_debug.vpi: $(VPI_DEBUG) ../vvp/libvpi.a - $(CC) @shared@ -o $@ $(VPI_DEBUG) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) +vpi_debug.vpi: $(VPI_DEBUG) libvpi.a + $(CC) @shared@ -o $@ $(VPI_DEBUG) -L. $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) stamp-vpi_config-h: $(srcdir)/vpi_config.h.in ../config.status @rm -f $@ @@ -180,50 +188,36 @@ stamp-vpi_config-h: $(srcdir)/vpi_config.h.in ../config.status vpi_config.h: stamp-vpi_config-h install: all installdirs \ - $(vpidir)/system.vpi $(vpidir)/system.sft \ - $(vpidir)/va_math.vpi $(vpidir)/va_math.sft \ - $(vpidir)/v2005_math.vpi $(vpidir)/v2005_math.sft \ - $(vpidir)/v2009.vpi $(vpidir)/v2009.sft \ - $(vpidir)/vhdl_sys.vpi $(vpidir)/vhdl_sys.sft \ - $(vpidir)/vhdl_textio.vpi $(vpidir)/vhdl_textio.sft \ + $(libdir)/libvpi$(suffix).a \ + $(vpidir)/system.vpi \ + $(vpidir)/va_math.vpi \ + $(vpidir)/v2005_math.vpi \ + $(vpidir)/v2009.vpi \ + $(vpidir)/vhdl_sys.vpi \ + $(vpidir)/vhdl_textio.vpi \ $(vpidir)/vpi_debug.vpi +$(libdir)/libvpi$(suffix).a : ./libvpi.a + $(INSTALL_DATA) libvpi.a "$(DESTDIR)$(libdir)/libvpi$(suffix).a" + $(vpidir)/system.vpi: ./system.vpi $(INSTALL_PROGRAM) ./system.vpi "$(DESTDIR)$(vpidir)/system.vpi" -$(vpidir)/system.sft: system.sft - $(INSTALL_DATA) $< "$(DESTDIR)$@" - $(vpidir)/va_math.vpi: ./va_math.vpi $(INSTALL_PROGRAM) ./va_math.vpi "$(DESTDIR)$(vpidir)/va_math.vpi" -$(vpidir)/va_math.sft: va_math.sft - $(INSTALL_DATA) $< "$(DESTDIR)$@" - $(vpidir)/v2005_math.vpi: ./v2005_math.vpi $(INSTALL_PROGRAM) ./v2005_math.vpi "$(DESTDIR)$(vpidir)/v2005_math.vpi" -$(vpidir)/v2005_math.sft: v2005_math.sft - $(INSTALL_DATA) $< "$(DESTDIR)$@" - $(vpidir)/v2009.vpi: ./v2009.vpi $(INSTALL_PROGRAM) ./v2009.vpi "$(DESTDIR)$(vpidir)/v2009.vpi" -$(vpidir)/v2009.sft: v2009.sft - $(INSTALL_DATA) $< "$(DESTDIR)$@" - $(vpidir)/vhdl_sys.vpi: ./vhdl_sys.vpi $(INSTALL_PROGRAM) ./vhdl_sys.vpi "$(DESTDIR)$(vpidir)/vhdl_sys.vpi" -$(vpidir)/vhdl_sys.sft: vhdl_sys.sft - $(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 $(INSTALL_PROGRAM) ./vpi_debug.vpi "$(DESTDIR)$(vpidir)/vpi_debug.vpi" @@ -231,21 +225,20 @@ installdirs: $(srcdir)/../mkinstalldirs $(srcdir)/../mkinstalldirs "$(DESTDIR)$(libdir)" "$(DESTDIR)$(vpidir)" uninstall: + rm -f "$(DESTDIR)$(libdir)/libvpi$(suffix).a" rm -f "$(DESTDIR)$(vpidir)/system.vpi" - rm -f "$(DESTDIR)$(vpidir)/system.sft" rm -f "$(DESTDIR)$(vpidir)/va_math.vpi" - rm -f "$(DESTDIR)$(vpidir)/va_math.sft" rm -f "$(DESTDIR)$(vpidir)/v2005_math.vpi" - rm -f "$(DESTDIR)$(vpidir)/v2005_math.sft" rm -f "$(DESTDIR)$(vpidir)/v2009.vpi" - rm -f "$(DESTDIR)$(vpidir)/v2009.sft" rm -f "$(DESTDIR)$(vpidir)/vhdl_sys.vpi" - 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" -include $(patsubst %.o, dep/%.d, $O) -include $(patsubst %.o, dep/%.d, $(OPP)) --include $(patsubst %.o, dep/%.d, $M) --include $(patsubst %.o, dep/%.d, $V) +-include $(patsubst %.o, dep/%.d, $(V2005)) +-include $(patsubst %.o, dep/%.d, $(VA_MATH)) +-include $(patsubst %.o, dep/%.d, $(V2009)) +-include $(patsubst %.o, dep/%.d, $(VHDL_SYS)) +-include $(patsubst %.o, dep/%.d, $(VHDL_TEXTIO)) +-include $(patsubst %.o, dep/%.d, $(VPI_DEBUG)) diff --git a/vpi/libvpi.c b/vpi/libvpi.c new file mode 100644 index 000000000..3780521c1 --- /dev/null +++ b/vpi/libvpi.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2019 Martin Whitaker (icarus@martin-whitaker.me.uk) + * + * 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. + */ + +#if defined(__MINGW32__) || defined (__CYGWIN32__) + +#include "vpi_user.h" +#include + +static vpip_routines_s*vpip_routines = 0; + +// callback related + +vpiHandle vpi_register_cb(p_cb_data data) +{ + assert(vpip_routines); + return vpip_routines->register_cb(data); +} +PLI_INT32 vpi_remove_cb(vpiHandle ref) +{ + assert(vpip_routines); + return vpip_routines->remove_cb(ref); +} + +vpiHandle vpi_register_systf(const struct t_vpi_systf_data*ss) +{ + assert(vpip_routines); + return vpip_routines->register_systf(ss); +} +void vpi_get_systf_info(vpiHandle obj, p_vpi_systf_data data) +{ + assert(vpip_routines); + vpip_routines->get_systf_info(obj, data); +} + +// for obtaining handles + +vpiHandle vpi_handle_by_name(const char*name, vpiHandle scope) +{ + assert(vpip_routines); + return vpip_routines->handle_by_name(name, scope); +} +vpiHandle vpi_handle_by_index(vpiHandle ref, PLI_INT32 idx) +{ + assert(vpip_routines); + return vpip_routines->handle_by_index(ref, idx); +} + +// for traversing relationships + +vpiHandle vpi_handle(PLI_INT32 type, vpiHandle ref) +{ + assert(vpip_routines); + return vpip_routines->handle(type, ref); +} +vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle ref) +{ + assert(vpip_routines); + return vpip_routines->iterate(type, ref); +} +vpiHandle vpi_scan(vpiHandle iter) +{ + assert(vpip_routines); + return vpip_routines->scan(iter); +} + +// for processing properties + +PLI_INT32 vpi_get(int property, vpiHandle ref) +{ + assert(vpip_routines); + return vpip_routines->get(property, ref); +} +char*vpi_get_str(PLI_INT32 property, vpiHandle ref) +{ + assert(vpip_routines); + return vpip_routines->get_str(property, ref); +} + +// delay processing + +void vpi_get_delays(vpiHandle expr, p_vpi_delay delays) +{ + assert(vpip_routines); + vpip_routines->get_delays(expr, delays); +} +void vpi_put_delays(vpiHandle expr, p_vpi_delay delays) +{ + assert(vpip_routines); + vpip_routines->put_delays(expr, delays); +} + +// value processing + +void vpi_get_value(vpiHandle expr, p_vpi_value value) +{ + assert(vpip_routines); + vpip_routines->get_value(expr, value); +} +vpiHandle vpi_put_value(vpiHandle obj, p_vpi_value value, p_vpi_time when, PLI_INT32 flags) +{ + assert(vpip_routines); + return vpip_routines->put_value(obj, value, when, flags); +} + +// time processing + +void vpi_get_time(vpiHandle obj, s_vpi_time*t) +{ + assert(vpip_routines); + vpip_routines->get_time(obj, t); +} + +// data processing + +void*vpi_get_userdata(vpiHandle obj) +{ + assert(vpip_routines); + return vpip_routines->get_userdata(obj); +} +PLI_INT32 vpi_put_userdata(vpiHandle obj, void*data) +{ + assert(vpip_routines); + return vpip_routines->put_userdata(obj, data); +} + +// I/O routines + +PLI_UINT32 vpi_mcd_open(char*name) +{ + assert(vpip_routines); + return vpip_routines->mcd_open(name); +} +PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) +{ + assert(vpip_routines); + return vpip_routines->mcd_close(mcd); +} +PLI_INT32 vpi_mcd_flush(PLI_UINT32 mcd) +{ + assert(vpip_routines); + return vpip_routines->mcd_flush(mcd); +} +char*vpi_mcd_name(PLI_UINT32 mcd) +{ + assert(vpip_routines); + return vpip_routines->mcd_name(mcd); +} +PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, const char*fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + assert(vpip_routines); + PLI_INT32 rv = vpip_routines->mcd_vprintf(mcd, fmt, ap); + va_end(ap); + return rv; +} +PLI_INT32 vpi_mcd_vprintf(PLI_UINT32 mcd, const char*fmt, va_list ap) +{ + assert(vpip_routines); + return vpip_routines->mcd_vprintf(mcd, fmt, ap); +} + +PLI_INT32 vpi_flush(void) +{ + assert(vpip_routines); + return vpip_routines->flush(); +} +PLI_INT32 vpi_printf(const char*fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + assert(vpip_routines); + PLI_INT32 rv = vpip_routines->vprintf(fmt, ap); + va_end(ap); + return rv; +} +PLI_INT32 vpi_vprintf(const char*fmt, va_list ap) +{ + assert(vpip_routines); + return vpip_routines->vprintf(fmt, ap); +} + +// utility routines + +PLI_INT32 vpi_chk_error(p_vpi_error_info info) +{ + assert(vpip_routines); + return vpip_routines->chk_error(info); +} +PLI_INT32 vpi_compare_objects(vpiHandle obj1, vpiHandle obj2) +{ + assert(vpip_routines); + return vpip_routines->compare_objects(obj1, obj2); +} +PLI_INT32 vpi_free_object(vpiHandle ref) +{ + assert(vpip_routines); + return vpip_routines->free_object(ref); +} +PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info info) +{ + assert(vpip_routines); + return vpip_routines->get_vlog_info(info); + +} + +// control routines + +void vpi_control(PLI_INT32 operation, ...) +{ + va_list ap; + va_start(ap, operation); + assert(vpip_routines); + vpip_routines->vcontrol(operation, ap); + va_end(ap); +} +void vpi_sim_control(PLI_INT32 operation, ...) +{ + va_list ap; + va_start(ap, operation); + assert(vpip_routines); + vpip_routines->vcontrol(operation, ap); + va_end(ap); +} + +// proposed standard extensions + +PLI_INT32 vpi_fopen(const char*name, const char*mode) +{ + assert(vpip_routines); + return vpip_routines->fopen(name, mode); +} +FILE*vpi_get_file(PLI_INT32 fd) +{ + assert(vpip_routines); + return vpip_routines->get_file(fd); +} + +// Icarus extensions + +s_vpi_vecval vpip_calc_clog2(vpiHandle arg) +{ + assert(vpip_routines); + return vpip_routines->calc_clog2(arg); +} +void vpip_count_drivers(vpiHandle ref, unsigned idx, unsigned counts[4]) +{ + assert(vpip_routines); + vpip_routines->count_drivers(ref, idx, counts); +} +void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit) +{ + assert(vpip_routines); + vpip_routines->format_strength(str, value, bit); +} +void vpip_make_systf_system_defined(vpiHandle ref) +{ + assert(vpip_routines); + vpip_routines->make_systf_system_defined(ref); +} +void vpip_mcd_rawwrite(PLI_UINT32 mcd, const char*buf, size_t count) +{ + assert(vpip_routines); + vpip_routines->mcd_rawwrite(mcd, buf, count); +} +void vpip_set_return_value(int value) +{ + assert(vpip_routines); + vpip_routines->set_return_value(value); +} + +DLLEXPORT PLI_UINT32 vpip_set_callback(vpip_routines_s*routines, PLI_UINT32 version) +{ + if (version != vpip_routines_version) + return 0; + + vpip_routines = routines; + return 1; +} + +#else + +void __libvpi_c_dummy_function(void) +{ +} + +#endif diff --git a/vpi/sys_convert.c b/vpi/sys_convert.c index 8f78fec5a..b9582de82 100644 --- a/vpi/sys_convert.c +++ b/vpi/sys_convert.c @@ -90,11 +90,6 @@ static void error_message(vpiHandle callh, const char* msg) vpi_control(vpiFinish, 1); } -static PLI_INT32 sizetf_32 (ICARUS_VPI_CONST PLI_BYTE8*name) -{ - (void)name; /* Parameter is not used. */ - return 32; -} static PLI_INT32 sizetf_64 (ICARUS_VPI_CONST PLI_BYTE8*name) { (void)name; /* Parameter is not used. */ @@ -252,39 +247,43 @@ void sys_convert_register(void) s_vpi_systf_data tf_data; vpiHandle res; - tf_data.type = vpiSysFunc; - tf_data.user_data = "$bitstoreal"; - tf_data.tfname = tf_data.user_data; - tf_data.sizetf = sizetf_64; - tf_data.compiletf = sys_convert_compiletf; - tf_data.calltf = sys_bitstoreal_calltf; + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiRealFunc; + tf_data.user_data = "$bitstoreal"; + tf_data.tfname = tf_data.user_data; + tf_data.sizetf = 0; + tf_data.compiletf = sys_convert_compiletf; + tf_data.calltf = sys_bitstoreal_calltf; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); - tf_data.type = vpiSysFunc; - tf_data.user_data = "$itor"; - tf_data.tfname = tf_data.user_data; - tf_data.sizetf = sizetf_64; - tf_data.compiletf = sys_convert_compiletf; - tf_data.calltf = sys_itor_calltf; + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiRealFunc; + tf_data.user_data = "$itor"; + tf_data.tfname = tf_data.user_data; + tf_data.sizetf = 0; + tf_data.compiletf = sys_convert_compiletf; + tf_data.calltf = sys_itor_calltf; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); - tf_data.type = vpiSysFunc; - tf_data.user_data = "$realtobits"; - tf_data.tfname = tf_data.user_data; - tf_data.sizetf = sizetf_64; - tf_data.compiletf = sys_convert_compiletf; - tf_data.calltf = sys_realtobits_calltf; + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiSizedFunc; + tf_data.user_data = "$realtobits"; + tf_data.tfname = tf_data.user_data; + tf_data.sizetf = sizetf_64; + tf_data.compiletf = sys_convert_compiletf; + tf_data.calltf = sys_realtobits_calltf; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); - tf_data.type = vpiSysFunc; - tf_data.user_data = "$rtoi"; - tf_data.tfname = tf_data.user_data; - tf_data.sizetf = sizetf_32; - tf_data.compiletf = sys_convert_compiletf; - tf_data.calltf = sys_rtoi_calltf; + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiIntFunc; + tf_data.user_data = "$rtoi"; + tf_data.tfname = tf_data.user_data; + tf_data.sizetf = 0; + tf_data.compiletf = sys_convert_compiletf; + tf_data.calltf = sys_rtoi_calltf; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); } diff --git a/vpi/sys_countdrivers.c b/vpi/sys_countdrivers.c index d4fbb8ea4..8499d5dc1 100644 --- a/vpi/sys_countdrivers.c +++ b/vpi/sys_countdrivers.c @@ -78,6 +78,12 @@ static void check_var_arg(vpiHandle arg, vpiHandle callh, const char *name, vpi_control(vpiFinish, 1); } +static PLI_INT32 sys_countdrivers_sizetf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + (void)name; /* Parameter is not used. */ + return 1; +} + /* * Check that the given $countdrivers() call has valid arguments. */ @@ -204,12 +210,13 @@ void sys_countdrivers_register(void) s_vpi_systf_data tf_data; vpiHandle res; - tf_data.type = vpiSysFunc; - tf_data.tfname = "$countdrivers"; - tf_data.calltf = sys_countdrivers_calltf; - tf_data.compiletf = sys_countdrivers_compiletf; - tf_data.sizetf = 0; - tf_data.user_data = "$countdrivers"; + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiSizedFunc; + tf_data.tfname = "$countdrivers"; + tf_data.calltf = sys_countdrivers_calltf; + tf_data.compiletf = sys_countdrivers_compiletf; + tf_data.sizetf = sys_countdrivers_sizetf; + tf_data.user_data = "$countdrivers"; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); } diff --git a/vpi/system.sft b/vpi/system.sft deleted file mode 100644 index be082c85f..000000000 --- a/vpi/system.sft +++ /dev/null @@ -1,28 +0,0 @@ -# -# This is the system function descriptor table for the -# builtin (system) functions. -# - -$random vpiSysFuncInt -$rtoi vpiSysFuncInt -$urandom vpiSysFuncSized 32 unsigned -$urandom_range vpiSysFuncSized 32 unsigned -$dist_uniform vpiSysFuncInt -$dist_normal vpiSysFuncInt -$dist_exponential vpiSysFuncInt -$dist_poisson vpiSysFuncInt -$dist_chi_square vpiSysFuncInt -$dist_t vpiSysFuncInt -$dist_erlang vpiSysFuncInt -$clog2 vpiSysFuncInt -$q_full vpiSysFuncInt - -$abstime vpiSysFuncReal -$simparam vpiSysFuncReal -$simparam$str vpiSysFuncSized 1024 unsigned -$table_model vpiSysFuncReal - -$ivl_string_method$len vpiSysFuncInt -$ivl_string_method$to_vec vpiSysFuncVoid - -$sformatf vpiSysFuncString diff --git a/vpi/v2005_math.sft b/vpi/v2005_math.sft deleted file mode 100644 index d772832b4..000000000 --- a/vpi/v2005_math.sft +++ /dev/null @@ -1,28 +0,0 @@ -# -# This is the system function descriptor table for the -# Verilog-2005 math functions. -# - -# Single argument functions. -$sqrt vpiSysFuncReal -$ln vpiSysFuncReal -$log10 vpiSysFuncReal -$exp vpiSysFuncReal -$ceil vpiSysFuncReal -$floor vpiSysFuncReal -$sin vpiSysFuncReal -$cos vpiSysFuncReal -$tan vpiSysFuncReal -$asin vpiSysFuncReal -$acos vpiSysFuncReal -$atan vpiSysFuncReal -$sinh vpiSysFuncReal -$cosh vpiSysFuncReal -$tanh vpiSysFuncReal -$asinh vpiSysFuncReal -$acosh vpiSysFuncReal -$atanh vpiSysFuncReal -# Double argument functions. -$pow vpiSysFuncReal -$atan2 vpiSysFuncReal -$hypot vpiSysFuncReal diff --git a/vpi/v2009.sft b/vpi/v2009.sft deleted file mode 100644 index e60c8cfdd..000000000 --- a/vpi/v2009.sft +++ /dev/null @@ -1,22 +0,0 @@ -# -# This is the system function descriptor table for the -# builtin (SystemVerilog) functions. -# - -$dimensions vpiSysFuncInt -$unpacked_dimensions vpiSysFuncInt -$left vpiSysFuncInt -$right vpiSysFuncInt -$low vpiSysFuncInt -$high vpiSysFuncInt -$increment vpiSysFuncInt -$size vpiSysFuncInt - -$countbits vpiSysFuncInt -$countones vpiSysFuncInt -$onehot vpiSysFuncSized 1 unsigned -$onehot0 vpiSysFuncSized 1 unsigned -$isunknown vpiSysFuncSized 1 unsigned - -$ivl_array_method$to_vec vpiSysFuncVoid -$ivl_array_method$from_vec vpiSysFuncVoid diff --git a/vpi/v2009_enum.c b/vpi/v2009_enum.c index 8c638ff22..f20e59b0e 100644 --- a/vpi/v2009_enum.c +++ b/vpi/v2009_enum.c @@ -505,6 +505,7 @@ void v2009_enum_register(void) vpiHandle res; tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiOtherFunc; tf_data.calltf = ivl_enum_method_name_calltf; tf_data.compiletf = ivl_enum_method_name_compiletf; tf_data.sizetf = 0; @@ -515,6 +516,7 @@ void v2009_enum_register(void) vpip_make_systf_system_defined(res); tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiOtherFunc; tf_data.calltf = ivl_enum_method_next_prev_calltf; tf_data.compiletf = ivl_enum_method_next_prev_compiletf; tf_data.sizetf = 0; @@ -525,6 +527,7 @@ void v2009_enum_register(void) vpip_make_systf_system_defined(res); tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiOtherFunc; tf_data.calltf = ivl_enum_method_next_prev_calltf; tf_data.compiletf = ivl_enum_method_next_prev_compiletf; tf_data.sizetf = 0; diff --git a/vpi/v2009_table.c b/vpi/v2009_table.c index 1a3f8ee2b..010801a84 100644 --- a/vpi/v2009_table.c +++ b/vpi/v2009_table.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2018 Stephen Williams (steve@icarus.com) + * Copyright (c) 2010-2019 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +# include "vpi_user.h" + extern void v2009_array_register(void); extern void v2009_bitvec_register(void); extern void v2009_enum_register(void); diff --git a/vpi/va_math.sft b/vpi/va_math.sft deleted file mode 100644 index 9544566aa..000000000 --- a/vpi/va_math.sft +++ /dev/null @@ -1,10 +0,0 @@ -# -# This is the system function descriptor table for the -# Verilog-A math functions. -# - -# Single argument functions. -$abs vpiSysFuncReal -# Double argument functions. -$min vpiSysFuncReal -$max vpiSysFuncReal diff --git a/vpi/vhdl_sys.sft b/vpi/vhdl_sys.sft deleted file mode 100644 index 86903476f..000000000 --- a/vpi/vhdl_sys.sft +++ /dev/null @@ -1,6 +0,0 @@ -$ivlh_attribute_event vpiSysFuncSized 1 unsigned -$ivlh_rising_edge vpiSysFuncSized 1 unsigned -$ivlh_falling_edge vpiSysFuncSized 1 unsigned - -$ivlh_shift_left vpiSysFuncSized 32 unsigned -$ivlh_shift_right vpiSysFuncSized 32 unsigned diff --git a/vpi/vhdl_textio.sft b/vpi/vhdl_textio.sft deleted file mode 100644 index f2fe46cf1..000000000 --- a/vpi/vhdl_textio.sft +++ /dev/null @@ -1,9 +0,0 @@ -$ivlh_file_open vpiSysFuncVoid - -$ivlh_readline vpiSysFuncVoid -$ivlh_writeline vpiSysFuncVoid - -$ivlh_read vpiSysFuncVoid -$ivlh_write vpiSysFuncVoid -$ivlh_hread vpiSysFuncVoid -$ivlh_hwrite vpiSysFuncVoid diff --git a/vpi_modules.cc b/vpi_modules.cc new file mode 100644 index 000000000..96eeef4a3 --- /dev/null +++ b/vpi_modules.cc @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2019 Martin Whitaker (icarus@martin-whitaker.me.uk) + * + * 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. + */ + +#include "config.h" +#include "compiler.h" +#include "vpi_user.h" +#include "sv_vpi_user.h" +#include "vvp/ivl_dlfcn.h" + +/* The only VPI routines that can be legally called when the functions in + the vlog_startup_routines[] array are executed are vpi_register_systf() + and vpi_register_cb(), so we can simply provide stubs for the rest. We + aren't going to execute any callbacks, so we can just provide a stub for + vpi_register_cb() too. + + Note that the Icarus system module illegally calls vpi_get_vlog_info() + during startup, so take care to fill in the data structure for that. +*/ + +// callback related + +vpiHandle vpi_register_cb(p_cb_data) { return 0; } +PLI_INT32 vpi_remove_cb(vpiHandle) { return 0; } + +void vpi_get_systf_info(vpiHandle, p_vpi_systf_data) { } + +// for obtaining handles + +vpiHandle vpi_handle_by_name(const char*, vpiHandle) { return 0; } +vpiHandle vpi_handle_by_index(vpiHandle, PLI_INT32) { return 0; } + +// for traversing relationships + +vpiHandle vpi_handle(PLI_INT32, vpiHandle) { return 0; } +vpiHandle vpi_iterate(PLI_INT32, vpiHandle) { return 0; } +vpiHandle vpi_scan(vpiHandle) { return 0; } + +// for processing properties + +PLI_INT32 vpi_get(int, vpiHandle) { return 0; } +char* vpi_get_str(PLI_INT32, vpiHandle) { return 0; } + +// delay processing + +void vpi_get_delays(vpiHandle, p_vpi_delay) { } +void vpi_put_delays(vpiHandle, p_vpi_delay) { } + +// value processing + +void vpi_get_value(vpiHandle, p_vpi_value) { } +vpiHandle vpi_put_value(vpiHandle, p_vpi_value, p_vpi_time, PLI_INT32) { return 0; } + +// time processing + +void vpi_get_time(vpiHandle, s_vpi_time*) { } + +// data processing + +void* vpi_get_userdata(vpiHandle) { return 0; } +PLI_INT32 vpi_put_userdata(vpiHandle, void*) { return 0; } + +// I/O routines + +PLI_UINT32 vpi_mcd_open(char *) { return 0; } +PLI_UINT32 vpi_mcd_close(PLI_UINT32) { return 0; } +PLI_INT32 vpi_mcd_flush(PLI_UINT32) { return 0; } +char* vpi_mcd_name(PLI_UINT32) { return 0; } +PLI_INT32 vpi_mcd_printf(PLI_UINT32, const char*, ...) { return 0; } +PLI_INT32 vpi_mcd_vprintf(PLI_UINT32, const char*, va_list) { return 0; } + +PLI_INT32 vpi_flush(void) { return 0; } +PLI_INT32 vpi_printf(const char*, ...) { return 0; } +PLI_INT32 vpi_vprintf(const char*, va_list) { return 0; } + +// utility routines + +PLI_INT32 vpi_chk_error(p_vpi_error_info) { return 0; } +PLI_INT32 vpi_compare_objects(vpiHandle, vpiHandle) { return 0; } +PLI_INT32 vpi_free_object(vpiHandle) { return 0; } +PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info info) +{ + info->argc = 0; + info->argv = 0; + info->product = 0; + info->version = 0; + return 0; +} + +// control routines + +void vpi_control(PLI_INT32, ...) { } +void vpi_sim_control(PLI_INT32, ...) { } + +// proposed standard extensions + +PLI_INT32 vpi_fopen(const char*, const char*) { return 0; } +FILE* vpi_get_file(PLI_INT32) { return 0; } + +// Icarus extensions + +s_vpi_vecval vpip_calc_clog2(vpiHandle) +{ + s_vpi_vecval val = { 0, 0 }; + return val; +} +void vpip_count_drivers(vpiHandle, unsigned, unsigned [4]) { } +void vpip_format_strength(char*, s_vpi_value*, unsigned) { } +void vpip_make_systf_system_defined(vpiHandle) { } +void vpip_mcd_rawwrite(PLI_UINT32, const char*, size_t) { } +void vpip_set_return_value(int) { } +void vpi_vcontrol(PLI_INT32, va_list) { } + + +/* When a module registers a system function, extract and save the return + type for use during elaboration. */ +vpiHandle vpi_register_systf(const struct t_vpi_systf_data*ss) +{ + if (ss->type != vpiSysFunc) + return 0; + + struct sfunc_return_type ret_type; + ret_type.name = ss->tfname; + switch (ss->sysfunctype) { + case vpiIntFunc: + ret_type.type = IVL_VT_LOGIC; + ret_type.wid = 32; + ret_type.signed_flag = true; + break; + case vpiRealFunc: + ret_type.type = IVL_VT_REAL; + ret_type.wid = 1; + ret_type.signed_flag = true; + break; + case vpiTimeFunc: + ret_type.type = IVL_VT_LOGIC; + ret_type.wid = 64; + ret_type.signed_flag = false; + break; + case vpiSizedFunc: + ret_type.type = IVL_VT_LOGIC; + ret_type.wid = ss->sizetf ? ss->sizetf(ss->user_data) : 32; + ret_type.signed_flag = false; + break; + case vpiSizedSignedFunc: + ret_type.type = IVL_VT_LOGIC; + ret_type.wid = ss->sizetf ? ss->sizetf(ss->user_data) : 32; + ret_type.signed_flag = true; + break; + case vpiStringFunc: + ret_type.type = IVL_VT_STRING; + ret_type.wid = 0; + ret_type.signed_flag = false; + break; + case vpiOtherFunc: + ret_type.type = IVL_VT_NO_TYPE; + ret_type.wid = 0; + ret_type.signed_flag = false; + break; + default: + cerr << "warning: " << ss->tfname << " has an unknown return type. " + "Assuming 32 bit unsigned." << endl; + ret_type.type = IVL_VT_LOGIC; + ret_type.wid = 32; + ret_type.signed_flag = false; + break; + } + ret_type.override_flag = false; + add_sys_func(ret_type); + return 0; +} + +#if defined(__MINGW32__) || defined (__CYGWIN32__) +vpip_routines_s vpi_routines = { + .register_cb = vpi_register_cb, + .remove_cb = vpi_remove_cb, + .register_systf = vpi_register_systf, + .get_systf_info = vpi_get_systf_info, + .handle_by_name = vpi_handle_by_name, + .handle_by_index = vpi_handle_by_index, + .handle = vpi_handle, + .iterate = vpi_iterate, + .scan = vpi_scan, + .get = vpi_get, + .get_str = vpi_get_str, + .get_delays = vpi_get_delays, + .put_delays = vpi_put_delays, + .get_value = vpi_get_value, + .put_value = vpi_put_value, + .get_time = vpi_get_time, + .get_userdata = vpi_get_userdata, + .put_userdata = vpi_put_userdata, + .mcd_open = vpi_mcd_open, + .mcd_close = vpi_mcd_close, + .mcd_flush = vpi_mcd_flush, + .mcd_name = vpi_mcd_name, + .mcd_vprintf = vpi_mcd_vprintf, + .flush = vpi_flush, + .vprintf = vpi_vprintf, + .chk_error = vpi_chk_error, + .compare_objects = vpi_compare_objects, + .free_object = vpi_free_object, + .get_vlog_info = vpi_get_vlog_info, + .vcontrol = vpi_vcontrol, + .fopen = vpi_fopen, + .get_file = vpi_get_file, + .calc_clog2 = vpip_calc_clog2, + .count_drivers = vpip_count_drivers, + .format_strength = vpip_format_strength, + .make_systf_system_defined = vpip_make_systf_system_defined, + .mcd_rawwrite = vpip_mcd_rawwrite, + .set_return_value = vpip_set_return_value, +}; + +typedef PLI_UINT32 (*vpip_set_callback_t)(vpip_routines_s*, PLI_UINT32); +#endif +typedef void (*vlog_startup_routines_t)(void); + +bool load_vpi_module(const char*path) +{ + ivl_dll_t dll = ivl_dlopen(path, false); + if (dll == 0) { + cerr << "error: Failed to open '" << path << "' because:" << endl; + cerr << " : " << dlerror() << endl; + return false; + } + +#if defined(__MINGW32__) || defined (__CYGWIN32__) + void*function = ivl_dlsym(dll, "vpip_set_callback"); + if (function == 0) { + cerr << "warning: '" << path << "' has no vpip_set_callback()" << endl; + ivl_dlclose(dll); + return true; + } + vpip_set_callback_t set_callback = (vpip_set_callback_t)function; + if (!set_callback(&vpi_routines, vpip_routines_version)) { + cerr << "error: Failed to link '" << path << "'. " + "Try rebuilding it with iverilog-vpi." << endl; + ivl_dlclose(dll); + return true; + } +#endif + + void*table = ivl_dlsym(dll, LU "vlog_startup_routines" TU); + if (table == 0) { + cerr << "warning: '" << path << "' has no vlog_startup_routines" << endl; + ivl_dlclose(dll); + return true; + } + + vlog_startup_routines_t*routines = (vlog_startup_routines_t*)table; + for (unsigned idx = 0; routines[idx]; idx += 1) { + (routines[idx])(); + } + + ivl_dlclose(dll); + return true; +} diff --git a/vpi_user.h b/vpi_user.h index 0be7fbfeb..05a3c3c4b 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -1,7 +1,7 @@ #ifndef VPI_USER_H #define VPI_USER_H /* - * Copyright (c) 1999-2018 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2019 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -675,6 +675,63 @@ extern void vpip_count_drivers(vpiHandle ref, unsigned idx, # define _vpi_at_APV 6 #endif +#if defined(__MINGW32__) || defined (__CYGWIN32__) +/* + * In Linux, when loaded, a shared library can automatically bind to functions + * provided by its client. In Windows, a DLL can only do this statically at + * link time, and is then tied to a specific client. So to enable VPI modules + * to be used by both the compiler and the simulator, we construct a jump table + * for the VPI routines that we can pass down to the VPI modules. + */ + +// Increment the version number any time vpip_routines_s is changed. +static const PLI_UINT32 vpip_routines_version = 1; + +typedef struct { + vpiHandle (*register_cb)(p_cb_data); + PLI_INT32 (*remove_cb)(vpiHandle); + vpiHandle (*register_systf)(const struct t_vpi_systf_data*ss); + void (*get_systf_info)(vpiHandle, p_vpi_systf_data); + vpiHandle (*handle_by_name)(const char*, vpiHandle); + vpiHandle (*handle_by_index)(vpiHandle, PLI_INT32); + vpiHandle (*handle)(PLI_INT32, vpiHandle); + vpiHandle (*iterate)(PLI_INT32, vpiHandle); + vpiHandle (*scan)(vpiHandle); + PLI_INT32 (*get)(int, vpiHandle); + char* (*get_str)(PLI_INT32, vpiHandle); + void (*get_delays)(vpiHandle, p_vpi_delay); + void (*put_delays)(vpiHandle, p_vpi_delay); + void (*get_value)(vpiHandle, p_vpi_value); + vpiHandle (*put_value)(vpiHandle, p_vpi_value, p_vpi_time, PLI_INT32); + void (*get_time)(vpiHandle, s_vpi_time*); + void* (*get_userdata)(vpiHandle); + PLI_INT32 (*put_userdata)(vpiHandle, void*); + PLI_UINT32 (*mcd_open)(char *); + PLI_UINT32 (*mcd_close)(PLI_UINT32); + PLI_INT32 (*mcd_flush)(PLI_UINT32); + char* (*mcd_name)(PLI_UINT32); + PLI_INT32 (*mcd_vprintf)(PLI_UINT32, const char*, va_list); + PLI_INT32 (*flush)(void); + PLI_INT32 (*vprintf)(const char*, va_list); + PLI_INT32 (*chk_error)(p_vpi_error_info); + PLI_INT32 (*compare_objects)(vpiHandle, vpiHandle); + PLI_INT32 (*free_object)(vpiHandle); + PLI_INT32 (*get_vlog_info)(p_vpi_vlog_info info) ; + void (*vcontrol)(PLI_INT32, va_list); + PLI_INT32 (*fopen)(const char*, const char*); + FILE* (*get_file)(PLI_INT32); + s_vpi_vecval(*calc_clog2)(vpiHandle); + void (*count_drivers)(vpiHandle, unsigned, unsigned [4]); + void (*format_strength)(char*, s_vpi_value*, unsigned); + void (*make_systf_system_defined)(vpiHandle); + void (*mcd_rawwrite)(PLI_UINT32, const char*, size_t); + void (*set_return_value)(int); +} vpip_routines_s; + +extern DLLEXPORT PLI_UINT32 vpip_set_callback(vpip_routines_s*routines, PLI_UINT32 version); + +#endif // defined(__MINGW32__) || defined (__CYGWIN32__) + EXTERN_C_END #endif /* VPI_USER_H */ diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 897aa6e17..8d5724abb 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -38,9 +38,6 @@ HOSTCFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@ BUILDCC = @CC_FOR_BUILD@ BUILDEXT = @BUILD_EXEEXT@ CXX = @CXX@ -DLLTOOL = @DLLTOOL@ -AR = @AR@ -RANLIB = @RANLIB@ INSTALL = @INSTALL@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ @@ -82,7 +79,7 @@ O = main.o parse.o parse_misc.o lexor.o arith.o array_common.o array.o bufif.o c vvp_object.o vvp_cobject.o vvp_darray.o event.o logic.o delay.o \ words.o island_tran.o $(VPI) -all: dep vvp@EXEEXT@ libvpi.a vvp.man +all: dep vvp@EXEEXT@ vvp.man check: all ifeq (@WIN32@,yes) @@ -101,13 +98,13 @@ endif clean: rm -f *.o *~ parse.cc parse.h lexor.cc tables.cc - rm -rf dep vvp@EXEEXT@ libvpi.a parse.output vvp.man vvp.ps vvp.pdf vvp.exp + rm -rf dep vvp@EXEEXT@ parse.output vvp.man vvp.ps vvp.pdf vvp.exp distclean: clean rm -f Makefile config.log rm -f stamp-config-h config.h -cppcheck: $(O:.o=.cc) libvpi.c draw_tt.c +cppcheck: $(O:.o=.cc) draw_tt.c cppcheck --enable=all --std=posix --std=c99 --std=c++03 -f \ --suppressions-list=$(srcdir)/cppcheck.sup \ -UMODULE_DIR1 -UMODULE_DIR2 -UYY_USER_INIT \ @@ -121,30 +118,8 @@ Makefile: $(srcdir)/Makefile.in dep: mkdir dep -ifeq (@WIN32@,yes) -# Under Windows (mingw) I need to make the vvp.exe in two steps. -# The first step makes an vvp.exe that dlltool can use to make an -# export and import library, and the last link makes a, vvp.exe -# that really exports the things that the import library imports. -# -# To get this to work correctly we must use the suffixed version of the -# executable to build the library. -vvp@EXEEXT@ libvpi.a: $O $(srcdir)/vvp.def - $(CXX) -o vvp$(suffix)@EXEEXT@ $(LDFLAGS) $O $(dllib) $(LIBS) - $(DLLTOOL) --dllname vvp$(suffix)@EXEEXT@ --def $(srcdir)/vvp.def \ - --output-lib libvpi.a --output-exp vvp.exp - rm -f vvp$(suffix)@EXEEXT@ - $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ vvp.exp $(LDFLAGS) $O $(dllib) $(LIBS) -else -libvpi.a: libvpi.c - $(CC) $(CPPFLAGS) $(CFLAGS) -c $< - rm -f libvpi.a - $(AR) cqv libvpi.a libvpi.o - $(RANLIB) libvpi.a - vvp@EXEEXT@: $O $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ $O $(LIBS) $(dllib) -endif %.o: %.cc config.h $(CXX) $(CPPFLAGS) -DIVL_SUFFIX='"$(suffix)"' $(MDIR1) $(MDIR2) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o @@ -207,14 +182,11 @@ stamp-config-h: $(srcdir)/config.h.in ../config.status cd ..; ./config.status --header=vvp/config.h config.h: stamp-config-h -install: all installdirs $(bindir)/vvp$(suffix)@EXEEXT@ $(libdir)/libvpi$(suffix).a $(INSTALL_DOC) +install: all installdirs $(bindir)/vvp$(suffix)@EXEEXT@ $(INSTALL_DOC) $(bindir)/vvp$(suffix)@EXEEXT@: ./vvp@EXEEXT@ $(INSTALL_PROGRAM) ./vvp@EXEEXT@ "$(DESTDIR)$(bindir)/vvp$(suffix)@EXEEXT@" -$(libdir)/libvpi$(suffix).a : ./libvpi.a - $(INSTALL_DATA) libvpi.a "$(DESTDIR)$(libdir)/libvpi$(suffix).a" - $(mandir)/man1/vvp$(suffix).1: vvp.man $(INSTALL_DATA) vvp.man "$(DESTDIR)$(mandir)/man1/vvp$(suffix).1" @@ -227,7 +199,6 @@ installdirs: $(srcdir)/../mkinstalldirs uninstall: $(UNINSTALL32) rm -f "$(DESTDIR)$(bindir)/vvp$(suffix)@EXEEXT@" - rm -f "$(DESTDIR)$(libdir)/libvpi$(suffix).a" rm -f "$(DESTDIR)$(mandir)/man1/vvp$(suffix).1" "$(DESTDIR)$(prefix)/vvp$(suffix).pdf" -include $(patsubst %.o, dep/%.d, $O) diff --git a/vvp/cppcheck.sup b/vvp/cppcheck.sup index 049c11041..911e1cb0a 100644 --- a/vvp/cppcheck.sup +++ b/vvp/cppcheck.sup @@ -2,10 +2,6 @@ // pool is defined there. uninitVar:vvp_net.cc:167 -// These functions are not used by Icarus -// __libvpi_c_dummy_function() -unusedFunction:libvpi.c:24 - // These functions are not used by Icarus // vpi_chk_error() unusedFunction:vpi_priv.cc:193 diff --git a/vvp/libvpi.c b/vvp/libvpi.c deleted file mode 100644 index df6388f17..000000000 --- a/vvp/libvpi.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2003 Stephen Williams (steve@icarus.com) - * - * 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. - */ - -/* - * Things that should be statically linked by VPI modules go here. - */ - -void __libvpi_c_dummy_function(void) -{ -} diff --git a/vvp/vpi_modules.cc b/vvp/vpi_modules.cc index e91bebe0a..fa35dd57f 100644 --- a/vvp/vpi_modules.cc +++ b/vvp/vpi_modules.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2018 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2019 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -30,6 +30,9 @@ static ivl_dll_t*dll_list = 0; static unsigned dll_list_cnt = 0; +#if defined(__MINGW32__) || defined (__CYGWIN32__) +typedef PLI_UINT32 (*vpip_set_callback_t)(vpip_routines_s*, PLI_UINT32); +#endif typedef void (*vlog_startup_routines_t)(void); # define VPIP_MODULE_PATH_MAX 64 @@ -215,13 +218,22 @@ void vpip_load_module(const char*name) return; } - -#ifdef __MINGW32__ - /* For this check MinGW does not want the leading underscore! */ - void*table = ivl_dlsym(dll, "vlog_startup_routines"); -#else - void*table = ivl_dlsym(dll, LU "vlog_startup_routines" TU); +#if defined(__MINGW32__) || defined (__CYGWIN32__) + void*function = ivl_dlsym(dll, "vpip_set_callback"); + if (function == 0) { + fprintf(stderr, "%s: no vpip_set_callback()\n", name); + ivl_dlclose(dll); + return; + } + vpip_set_callback_t set_callback = (vpip_set_callback_t)function; + if (!set_callback(&vpi_routines, vpip_routines_version)) { + fprintf(stderr, "Failed to link VPI module %s. Try rebuilding it with iverilog-vpi.\n", name); + ivl_dlclose(dll); + return; + } #endif + + void*table = ivl_dlsym(dll, LU "vlog_startup_routines" TU); if (table == 0) { fprintf(stderr, "%s: no vlog_startup_routines\n", name); ivl_dlclose(dll); diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 5d1fb4f95..b70449529 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1634,3 +1634,46 @@ extern "C" void vpip_count_drivers(vpiHandle ref, unsigned idx, assert(rfp); rfp->node->count_drivers(idx, counts); } + +#if defined(__MINGW32__) || defined (__CYGWIN32__) +vpip_routines_s vpi_routines = { + .register_cb = vpi_register_cb, + .remove_cb = vpi_remove_cb, + .register_systf = vpi_register_systf, + .get_systf_info = vpi_get_systf_info, + .handle_by_name = vpi_handle_by_name, + .handle_by_index = vpi_handle_by_index, + .handle = vpi_handle, + .iterate = vpi_iterate, + .scan = vpi_scan, + .get = vpi_get, + .get_str = vpi_get_str, + .get_delays = vpi_get_delays, + .put_delays = vpi_put_delays, + .get_value = vpi_get_value, + .put_value = vpi_put_value, + .get_time = vpi_get_time, + .get_userdata = vpi_get_userdata, + .put_userdata = vpi_put_userdata, + .mcd_open = vpi_mcd_open, + .mcd_close = vpi_mcd_close, + .mcd_flush = vpi_mcd_flush, + .mcd_name = vpi_mcd_name, + .mcd_vprintf = vpi_mcd_vprintf, + .flush = vpi_flush, + .vprintf = vpi_vprintf, + .chk_error = vpi_chk_error, + .compare_objects = vpi_compare_objects, + .free_object = vpi_free_object, + .get_vlog_info = vpi_get_vlog_info, + .vcontrol = vpi_sim_vcontrol, + .fopen = vpi_fopen, + .get_file = vpi_get_file, + .calc_clog2 = vpip_calc_clog2, + .count_drivers = vpip_count_drivers, + .format_strength = vpip_format_strength, + .make_systf_system_defined = vpip_make_systf_system_defined, + .mcd_rawwrite = vpip_mcd_rawwrite, + .set_return_value = vpip_set_return_value, +}; +#endif diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 3a841f3a0..213126183 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -48,6 +48,10 @@ typedef struct __vpiArray* vvp_array_t; * header file elsewhere. */ +#if defined(__MINGW32__) || defined (__CYGWIN32__) +extern vpip_routines_s vpi_routines; +#endif + /* * Routines/definitions used to build the file/line number tracing object. */ diff --git a/vvp/vvp.def b/vvp/vvp.def deleted file mode 100644 index c49f79400..000000000 --- a/vvp/vvp.def +++ /dev/null @@ -1,45 +0,0 @@ -EXPORTS - -vpi_chk_error -vpi_compare_objects -vpi_control -vpi_flush -vpi_fopen -vpi_free_object -vpi_get -vpi_get_delays -vpi_get_file -vpi_get_str -vpi_get_systf_info -vpi_get_time -vpi_get_userdata -vpi_get_value -vpi_get_vlog_info -vpi_handle -vpi_handle_by_index -vpi_handle_by_name -vpi_iterate -vpi_mcd_close -vpi_mcd_flush -vpi_mcd_name -vpi_mcd_open -vpi_mcd_printf -vpi_mcd_vprintf -vpi_printf -vpi_put_delays -vpi_put_userdata -vpi_put_value -vpi_register_cb -vpi_register_systf -vpi_remove_cb -vpi_scan -vpi_sim_control -vpi_sim_vcontrol -vpi_vprintf - -vpip_calc_clog2 -vpip_count_drivers -vpip_format_strength -vpip_make_systf_system_defined -vpip_mcd_rawwrite -vpip_set_return_value