diff --git a/vvp/Makefile.in b/vvp/Makefile.in index d391685d1..eef2f82c5 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -16,7 +16,7 @@ # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # -#ident "$Id: Makefile.in,v 1.3 2001/03/14 19:26:01 steve Exp $" +#ident "$Id: Makefile.in,v 1.4 2001/03/16 01:44:34 steve Exp $" # # SHELL = /bin/sh @@ -43,6 +43,9 @@ CPPFLAGS = @CPPFLAGS@ @DEFS@ CXXFLAGS = @CXXFLAGS@ -I. -I$(srcdir) LDFLAGS = @LDFLAGS@ +dllib=@DLLIB@ +rdynamic=@rdynamic@ + all: vvp clean: @@ -51,11 +54,13 @@ clean: distclean: clean rm -f config.h Makefile config.cache config.log config.status +V = vpi_modules.o vpi_iter.o vpi_mcd.o vpi_priv.o vpi_tasks.o + O = main.o parse.o parse_misc.o lexor.o compile.o functor.o symbols.o \ -codes.o vthread.o schedule.o tables.o +codes.o vthread.o schedule.o tables.o $V vvp: $O - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o vvp $O + $(CXX) $(rdynamic) $(CXXFLAGS) $(LDFLAGS) -o vvp $O $(dllib) %.o: %.cc diff --git a/vvp/codes.h b/vvp/codes.h index 8e10c6b6d..2fbd7ce3b 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: codes.h,v 1.2 2001/03/11 23:06:49 steve Exp $" +#ident "$Id: codes.h,v 1.3 2001/03/16 01:44:34 steve Exp $" #endif @@ -40,6 +40,7 @@ extern bool of_DELAY(vthread_t thr, vvp_code_t code); extern bool of_END(vthread_t thr, vvp_code_t code); extern bool of_SET(vthread_t thr, vvp_code_t code); extern bool of_NOOP(vthread_t thr, vvp_code_t code); +extern bool of_VPI_CALL(vthread_t thr, vvp_code_t code); /* * This is the format of a machine code instruction. @@ -51,6 +52,7 @@ struct vvp_code_s { unsigned number; vvp_ipoint_t iptr; vvp_cpoint_t cptr; + struct __vpiHandle*handle; }; unsigned short bit_idx1; @@ -83,6 +85,10 @@ extern void codespace_dump(FILE*fd); /* * $Log: codes.h,v $ + * Revision 1.3 2001/03/16 01:44:34 steve + * Add structures for VPI support, and all the %vpi_call + * instruction. Get linking of VPI modules to work. + * * Revision 1.2 2001/03/11 23:06:49 steve * Compact the vvp_code_s structure. * diff --git a/vvp/compile.cc b/vvp/compile.cc index 7301ff0b2..cc6aa8399 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: compile.cc,v 1.3 2001/03/11 23:06:49 steve Exp $" +#ident "$Id: compile.cc,v 1.4 2001/03/16 01:44:34 steve Exp $" #endif # include "compile.h" @@ -25,6 +25,7 @@ # include "symbols.h" # include "codes.h" # include "schedule.h" +# include "vpi_priv.h" # include "vthread.h" # include "parse_misc.h" # include @@ -297,6 +298,30 @@ void compile_code(char*label, char*mnem, comp_operands_t opa) free(mnem); } +void compile_vpi_call(char*label, char*name) +{ + vvp_cpoint_t ptr = codespace_allocate(); + + /* First, I can give the label a value that is the current + codespace pointer. Don't need the text of the label after + this is done. */ + if (label) { + sym_set_value(sym_codespace, label, ptr); + free(label); + } + + /* Create an instruction in the code space. */ + vvp_code_t code = codespace_index(ptr); + code->opcode = &of_VPI_CALL; + + /* Create a vpiHandle that bundles the call information, and + store that handle in the instruction. */ + code->handle = vpip_build_vpi_call(name); + + /* Done with the lexor-allocated name string. */ + free(name); +} + /* * When the parser finds a thread statement, I create a new thread * with the start address referenced by the program symbol passed to @@ -391,6 +416,10 @@ void compile_dump(FILE*fd) /* * $Log: compile.cc,v $ + * Revision 1.4 2001/03/16 01:44:34 steve + * Add structures for VPI support, and all the %vpi_call + * instruction. Get linking of VPI modules to work. + * * Revision 1.3 2001/03/11 23:06:49 steve * Compact the vvp_code_s structure. * diff --git a/vvp/compile.h b/vvp/compile.h index 34434a7e6..a4d894494 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: compile.h,v 1.2 2001/03/11 22:42:11 steve Exp $" +#ident "$Id: compile.h,v 1.3 2001/03/16 01:44:34 steve Exp $" #endif # include @@ -77,6 +77,7 @@ struct comp_operands_s { typedef struct comp_operands_s*comp_operands_t; extern void compile_code(char*label, char*mnem, comp_operands_t opa); +extern void compile_vpi_call(char*label, char*name); /* * The parser uses this function to declare a thread. The start_sym is @@ -97,6 +98,10 @@ extern void compile_dump(FILE*fd); /* * $Log: compile.h,v $ + * Revision 1.3 2001/03/16 01:44:34 steve + * Add structures for VPI support, and all the %vpi_call + * instruction. Get linking of VPI modules to work. + * * Revision 1.2 2001/03/11 22:42:11 steve * Functor values and propagation. * diff --git a/vvp/config.h.in b/vvp/config.h.in index 72eca6a6d..27ae13224 100644 --- a/vvp/config.h.in +++ b/vvp/config.h.in @@ -19,15 +19,24 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: config.h.in,v 1.1 2001/03/11 00:29:38 steve Exp $" +#ident "$Id: config.h.in,v 1.2 2001/03/16 01:44:34 steve Exp $" #endif # define SIZEOF_UNSIGNED_LONG 0 # define SIZEOF_UNSIGNED 0 +# undef HAVE_DLFCN_H +# undef HAVE_DL_H + +# define LU "" +# define TU "" /* * $Log: config.h.in,v $ + * Revision 1.2 2001/03/16 01:44:34 steve + * Add structures for VPI support, and all the %vpi_call + * instruction. Get linking of VPI modules to work. + * * Revision 1.1 2001/03/11 00:29:38 steve * Add the vvp engine to cvs. * diff --git a/vvp/configure.in b/vvp/configure.in index c01410f44..9cce1504a 100644 --- a/vvp/configure.in +++ b/vvp/configure.in @@ -10,4 +10,45 @@ AC_PROG_INSTALL AC_CHECK_SIZEOF(unsigned long) AC_CHECK_SIZEOF(unsigned) +# -- +# Look for a dl library to use. First look for the standard dlopen +# functions, and failing that look for the HP specific shl_load function. + +AC_CHECK_HEADERS(dlfcn.h dl.h, break) + +DLLIB='' +AC_CHECK_LIB(dl,dlopen,[DLLIB=-ldl]) +if test -z "$DLLIB" ; then +AC_CHECK_LIB(dld,shl_load,[DLLIB=-ldld]) +fi +AC_SUBST(DLLIB) + + +# The -rdynamic flag is used by iverilog when compiling the target, +# to know how to export symbols of the main program to loadable modules +# that are brought in by -ldl. VPI support requires this. +AC_MSG_CHECKING("for -rdynamic compiler flag") + +rdynamic=-rdynamic +case "${host}" in + + *-*-netbsd*) + rdynamic="-Wl,--export-dynamic" + ;; + + *-*-solaris*) + rdynamic="" + ;; + + *-*-cygwin*) + rdynamic="" + ;; + + *-*-hpux*) + rdynamic="-E" + ;; +esac +AC_SUBST(rdynamic) +AC_MSG_RESULT($rdynamic) + AC_OUTPUT(Makefile) diff --git a/vvp/ivl_dlfcn.h b/vvp/ivl_dlfcn.h new file mode 100644 index 000000000..72f11ffde --- /dev/null +++ b/vvp/ivl_dlfcn.h @@ -0,0 +1,71 @@ +#ifndef __ivl_dlfcn_H +#define __ivl_dlfcn_H +/* + * Copyright (c) 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined(WINNT) && !defined(macintosh) +#ident "$Id: ivl_dlfcn.h,v 1.1 2001/03/16 01:44:34 steve Exp $" +#endif + +#if defined(HAVE_DLFCN_H) +# include +typedef void* ivl_dll_t; +#elif defined(HAVE_DL_H) +# include +typedef shl_t ivl_dll_t; +#endif + +#if defined(HAVE_DLFCN_H) +inline ivl_dll_t ivl_dlopen(const char*name) +{ return dlopen(name,RTLD_NOW); } + +inline void* ivl_dlsym(ivl_dll_t dll, const char*nm) +{ return dlsym(dll, nm); } + +inline void ivl_dlclose(ivl_dll_t dll) +{ dlclose(dll); } + +#elif defined(HAVE_DL_H) +inline ivl_dll_t ivl_dlopen(const char*name) +{ return shl_load(name, BIND_IMMEDIATE, 0); } + +inline void* ivl_dlsym(ivl_dll_t dll, const char*nm) +{ + void*sym; + int rc = shl_findsym(&dll, nm, TYPE_PROCEDURE, &sym); + return (rc == 0) ? sym : 0; +} + +inline void ivl_dlclose(ivl_dll_t dll) +{ shl_unload(dll); } + +inline const char*dlerror(void) +{ return strerror( errno ); } +#endif + +/* + * $Log: ivl_dlfcn.h,v $ + * Revision 1.1 2001/03/16 01:44:34 steve + * Add structures for VPI support, and all the %vpi_call + * instruction. Get linking of VPI modules to work. + * + * Revision 1.1 2001/01/14 17:12:59 steve + * possible HP/UX portability support. + * + */ +#endif diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 897bcf420..950853a78 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -13,6 +13,13 @@ yylval.text = strdup(yytext); return T_LABEL; } + /* String tokens are parsed here. Return as the token value the + contents of the string without the enclosing quotes. */ +\"[^\"]*\" { + yytext[strlen(yytext)-1] = 0; + yylval.text = strdup(yytext+1); + return T_STRING; } + /* These are some keywords that are recognized. */ ".functor" { return K_FUNCTOR; } @@ -21,7 +28,12 @@ /* instructions start with a % character. The compiler decides what - kind of instruction this really is. */ + kind of instruction this really is. The few exceptions (that have + exceptional parameter requirements) are listed first. */ + +"%vpi_call" { + return K_vpi_call; } + "%"[.$_/a-zA-Z0-9]+ { yylval.text = strdup(yytext); return T_INSTR; } diff --git a/vvp/main.cc b/vvp/main.cc index 0ef2d984f..5f6523149 100644 --- a/vvp/main.cc +++ b/vvp/main.cc @@ -17,17 +17,22 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: main.cc,v 1.1 2001/03/11 00:29:38 steve Exp $" +#ident "$Id: main.cc,v 1.2 2001/03/16 01:44:34 steve Exp $" #endif # include "config.h" # include "parse_misc.h" # include "compile.h" # include "schedule.h" +# include "vpi_priv.h" # include # include +const char*module_path = "."; +unsigned module_cnt = 0; +const char*module_tab[64]; + int main(int argc, char*argv[]) { int opt; @@ -35,10 +40,16 @@ int main(int argc, char*argv[]) const char*dump_path = 0; const char*design_path = 0; - while ((opt = getopt(argc, argv, "D:")) != EOF) switch (opt) { + while ((opt = getopt(argc, argv, "D:M:m:")) != EOF) switch (opt) { case 'D': dump_path = optarg; break; + case 'M': + module_path = optarg; + break; + case 'm': + module_tab[module_cnt++] = optarg; + break; default: flag_errors += 1; } @@ -54,6 +65,7 @@ int main(int argc, char*argv[]) design_path = argv[optind]; compile_init(); + vpip_load_modules(module_cnt, module_tab, module_path); compile_design(design_path); compile_cleanup(); @@ -69,6 +81,10 @@ int main(int argc, char*argv[]) /* * $Log: main.cc,v $ + * Revision 1.2 2001/03/16 01:44:34 steve + * Add structures for VPI support, and all the %vpi_call + * instruction. Get linking of VPI modules to work. + * * Revision 1.1 2001/03/11 00:29:38 steve * Add the vvp engine to cvs. * diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index ca9f0355c..92021bc8d 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -34,6 +34,16 @@ value. Once the set completes, the value is immediately available to be read out of the variable. The is the address of the thread register that contains the bit value to assign. +* %vpi_call [, ...] + +This instruction makes a call to a system task or function that was +declared using VPI. The name is given in the source as a string. It is +not yet defined how arguments are to be passed. + * %waitfor -XXXX +When a thread executes this instruction, it places itself in the +sensitive list for the addressed functor. The functor holds all the +threads that await the functor. When the defined sort of event occurs +on the functor, a thread schedule event is created for all the threads +in its list and the list is cleared. diff --git a/vvp/parse.y b/vvp/parse.y index 737352440..e0663d7a8 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -21,11 +21,12 @@ extern FILE*yyin; }; -%token K_FUNCTOR K_THREAD K_VAR +%token K_FUNCTOR K_THREAD K_VAR K_vpi_call %token T_INSTR %token T_LABEL %token T_NUMBER +%token T_STRING %token T_SYMBOL %type symbols @@ -69,6 +70,15 @@ statement { compile_code(0, $1, $2); } + /* %vpi_call statements are instructions that have unusual operand + requirements so are handled by their own rules. */ + + | T_LABEL K_vpi_call T_STRING ';' + { compile_vpi_call($1, $3); } + + | K_vpi_call T_STRING ';' + { compile_vpi_call(0, $2); } + /* Thread statements declare a thread with its starting address. The starting address must already be defined. */ diff --git a/vvp/vpi.txt b/vvp/vpi.txt index a1b81ad75..d8d2c30fd 100644 --- a/vvp/vpi.txt +++ b/vvp/vpi.txt @@ -1,7 +1,7 @@ /* * Copyright (c) 2001 Stephen Williams (steve@icarus.com) * - * $Id: vpi.txt,v 1.1 2001/03/14 19:26:58 steve Exp $ + * $Id: vpi.txt,v 1.2 2001/03/16 01:44:34 steve Exp $ */ @@ -47,16 +47,43 @@ access to the system task call by calling back the VPI requesting the handle. It uses the handle, in turn, to get hold of the operands for the task. -In VPI Land, there is a vpiHandle for each system task call. However, -since only one is accessible at a time, there is no need for more then -the one that is active. Therefore, vvp will construct the vpiHande for -the task call at the time the call is made. - All that vvp needs to know about a system task call is the handle of -the system task (created by the vpi_register_systf function) and the -arguments of the actual call. The arguments are tricky because the -list has no bound, even though each particular call in the Verilog -source has a specific set of parameters. +the system task definitions (created by the vpi_register_systf +function) and the arguments of the actual call. The arguments are +tricky because the list has no bound, even though each particular call +in the Verilog source has a specific set of parameters. + +Since each call takes a fixed number of parameters, the input source +can include in the statement the list of arguments. The argument list +will not fit in a single generated instruction, but a vpiHandle that +refers to a vpiSysTfCall does. Therefore, the compiler can take the +long argument list and form a vpiSysTaskCall object. The generated +instruction then only needs to be a %vpi_call with the single parameter +that is the vpiHandle for the call. + + +SYSTEM FUNCTION CALLS + +System function calls are similar to system tasks. The only +differences are that all the arguments are input only, and there is a +single magic output that is the return value. The same %vpi_call can +even be used to call a function. + +System functions, like system tasks, can only be called from thread +code. However, they can appear in expressions, even when that +expression is entirely structural. The desired effect is achieved by +writing a wrapper thread that calls the function when inputs change, +and that writes the output into the containing expression. + + +SYSTEM TASK/FUNCTION ARGUMENTS + +The arguments to each system task or call are not stored in the +instruction op-code, but in the vpiSysTfCall object that the compiler +creates and that the %vpi_call instruction ultimately refers to. All +the arguments must be some sort of object that can be represented by a +vpiHandle at compile time. + /* * Copyright (c) 2001 Stephen Williams (steve@icarus.com) diff --git a/vvp/vpi_iter.cc b/vvp/vpi_iter.cc new file mode 100644 index 000000000..4f950c5dc --- /dev/null +++ b/vvp/vpi_iter.cc @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1999-2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined(WINNT) && !defined(macintosh) +#ident "$Id: vpi_iter.cc,v 1.1 2001/03/16 01:44:34 steve Exp $" +#endif + +/* + * Find here the methods functions in support of iterator objects. + */ + +# include "vpi_priv.h" +# include +# include + +static const struct __vpirt vpip_iterator_rt = { + vpiIterator, + 0, + 0, + 0, + 0, + 0, + 0 +}; + +vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args) +{ + struct __vpiIterator*res = (struct __vpiIterator*) + calloc(1, sizeof(struct __vpiIterator)); + res->base.vpi_type = &vpip_iterator_rt; + res->args = args; + res->nargs = nargs; + res->next = 0; + + return &(res->base); +} + +/* + * The vpi_scan function only applies to iterators. It returns the + * next vpiHandle in the iterated list. + */ +vpiHandle vpi_scan(vpiHandle ref) +{ + struct __vpiIterator*hp = (struct __vpiIterator*)ref; + assert(ref->vpi_type->type_code == vpiIterator); + + if (hp->next == hp->nargs) { + vpi_free_object(ref); + return 0; + } + + return hp->args[hp->next++]; +} + +/* + * $Log: vpi_iter.cc,v $ + * Revision 1.1 2001/03/16 01:44:34 steve + * Add structures for VPI support, and all the %vpi_call + * instruction. Get linking of VPI modules to work. + * + */ + diff --git a/vvp/vpi_mcd.cc b/vvp/vpi_mcd.cc new file mode 100644 index 000000000..5b4b40d89 --- /dev/null +++ b/vvp/vpi_mcd.cc @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2000 Stephen G. Tell + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined(WINNT) && !defined(macintosh) +#ident "$Id: vpi_mcd.cc,v 1.1 2001/03/16 01:44:34 steve Exp $" +#endif + +# include "vpi_priv.h" +# include +# include +# include +# include +# include + +struct mcd_entry { + FILE *fp; + char *filename; +}; + +static struct mcd_entry mcd_table[32]; + +/* Initialize mcd portion of vpi. Must be called before + * any vpi_mcd routines can be used. + */ +void vpi_mcd_init(void) +{ + mcd_table[0].fp = stdout; + mcd_table[0].filename = ""; + mcd_table[1].fp = stderr; + mcd_table[1].filename = ""; + mcd_table[2].fp = stdout; /* TODO: initialize this to log file */ + mcd_table[2].filename = ""; +} + +/* + * close one or more channels. we silently refuse to close the preopened ones. + */ +unsigned int vpi_mcd_close(unsigned int mcd) +{ + int i; + int rc; + rc = 0; + for(i = 3; i < 31; i++) { + if( ((mcd>>i) & 1) && mcd_table[i].filename) { + if(fclose(mcd_table[i].fp) != 0) + rc |= 1<>i) & 1) + return mcd_table[i].filename; + } + return NULL; +} + +unsigned int vpi_mcd_open(char *name) +{ + int i; + for(i = 0; i < 31; i++) { + if(mcd_table[i].filename == NULL) + goto got_entry; + } + return 0; /* too many open mcd's */ + +got_entry: + mcd_table[i].fp = fopen(name, "w"); + if(mcd_table[i].fp == NULL) + return 0; + mcd_table[i].filename = strdup(name); + return 1<>i) & 1) { + if(mcd_table[i].fp) + len = vfprintf(mcd_table[i].fp, fmt, ap); + else + rc = EOF; + } + } + va_end(ap); + + if(rc) + return rc; + else + return len; +} + diff --git a/vvp/vpi_modules.cc b/vvp/vpi_modules.cc new file mode 100644 index 000000000..6473550fe --- /dev/null +++ b/vvp/vpi_modules.cc @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined(WINNT) +#ident "$Id: vpi_modules.cc,v 1.1 2001/03/16 01:44:34 steve Exp $" +#endif + +# include "config.h" +# include "vpi_priv.h" +# include "ivl_dlfcn.h" +# include + +typedef void (*vlog_startup_routines_t)(void); + +void vpip_load_modules(unsigned cnt, const char*mod[], const char*path) +{ + for (unsigned idx = 0 ; idx < cnt ; idx += 1) { + char buf[4096]; + sprintf(buf, "%s/%s.vpi", path, mod[idx]); + printf("Load %s...\n", buf); + + ivl_dll_t dll = ivl_dlopen(buf); + if (dll == 0) { + fprintf(stderr, "%s: %s\n", mod[idx], dlerror()); + continue; + } + + void*table = ivl_dlsym(dll, LU "vlog_startup_routines" TU); + if (table == 0) { + fprintf(stderr, "%s: no vlog_startup_routines\n", mod[idx]); + ivl_dlclose(dll); + continue; + } + + vlog_startup_routines_t*routines = (vlog_startup_routines_t*)table; + for (unsigned tmp = 0 ; routines[tmp] ; tmp += 1) + (routines[tmp])(); + + } +} + +/* + * $Log: vpi_modules.cc,v $ + * Revision 1.1 2001/03/16 01:44:34 steve + * Add structures for VPI support, and all the %vpi_call + * instruction. Get linking of VPI modules to work. + * + */ + diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc new file mode 100644 index 000000000..450475499 --- /dev/null +++ b/vvp/vpi_priv.cc @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined(WINNT) +#ident "$Id: vpi_priv.cc,v 1.1 2001/03/16 01:44:34 steve Exp $" +#endif + +# include "vpi_priv.h" +# include +# include +# include +# include + +/* + * When a task is called, this value is set so that vpi_handle can + * fathom the vpi_handle(vpiSysTfCall,0) function. + */ +struct __vpiSysTaskCall*vpip_cur_task = 0; + +int vpi_free_object(vpiHandle ref) +{ + free(ref); + return 0; +} + +static int vpip_get_global(int property) +{ + switch (property) { + + default: + assert(0); + return -1; + } +} + +int vpi_get(int property, vpiHandle ref) +{ + if (property == vpiType) + return ref->vpi_type->type_code; + + if (ref == 0) + return vpip_get_global(property); + + if (ref->vpi_type->vpi_get_ == 0) + return -1; + + return (ref->vpi_type->vpi_get_)(property, ref); +} + +char* vpi_get_str(int property, vpiHandle ref) +{ + if (ref->vpi_type->vpi_get_str_ == 0) + return 0; + + return (ref->vpi_type->vpi_get_str_)(property, ref); +} + +void vpi_get_time(vpiHandle obj, s_vpi_time*t) +{ + assert(0); +} + +void vpi_get_value(vpiHandle expr, s_vpi_value*vp) +{ + if (expr->vpi_type->vpi_get_value_) { + (expr->vpi_type->vpi_get_value_)(expr, vp); + return; + } + + vp->format = vpiSuppressVal; +} + +vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, + s_vpi_time*tp, int flags) +{ + if (obj->vpi_type->vpi_put_value_) + return (obj->vpi_type->vpi_put_value_)(obj, vp, tp, flags); + else + return 0; +} + +vpiHandle vpi_handle(int type, vpiHandle ref) +{ + if (type == vpiSysTfCall) { + assert(ref == 0); + return &vpip_cur_task->base; + } + + assert(ref->vpi_type->handle_); + return (ref->vpi_type->handle_)(type, ref); +} + +/* + * This function asks the object to return an iterator for + * the specified reference. It is up to the iterate_ method to + * allocate a properly formed iterator. + */ +vpiHandle vpi_iterate(int type, vpiHandle ref) +{ + assert(ref->vpi_type->iterate_); + return (ref->vpi_type->iterate_)(type, ref); +} + +vpiHandle vpi_handle_by_index(vpiHandle ref, int idx) +{ + assert(ref->vpi_type->index_); + return (ref->vpi_type->index_)(ref, idx); +} + +void vpi_printf(const char*fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + + +/* STUBS */ + +vpiHandle vpi_register_cb(p_cb_data data) +{ + assert(0); + return 0; +} + + +int vpi_remove_cb(vpiHandle ref) +{ + assert(0); + return 0; +} + +void vpi_sim_control(int operation, ...) +{ + assert(0); +} + +/* + * $Log: vpi_priv.cc,v $ + * Revision 1.1 2001/03/16 01:44:34 steve + * Add structures for VPI support, and all the %vpi_call + * instruction. Get linking of VPI modules to work. + * + */ + diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h new file mode 100644 index 000000000..08a643581 --- /dev/null +++ b/vvp/vpi_priv.h @@ -0,0 +1,129 @@ +#ifndef __vpi_priv_H +#define __vpi_priv_H +/* + * Copyright (c) 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined(WINNT) +#ident "$Id: vpi_priv.h,v 1.1 2001/03/16 01:44:34 steve Exp $" +#endif + +# include "vpi_user.h" + +/* + * This header file contains the internal definitions that the vvp + * program uses to implement the public interface in the vpi_user.h + * header file elsewhere. + */ + + + +/* + * This structure is the very base of a vpiHandle. Every handle + * structure starts with this structure, so that the library can + * internally pass the derived types as pointers to one of these. + */ +struct __vpiHandle { + const struct __vpirt *vpi_type; +}; + +/* + * Objects with this structure are used to represent a type of + * vpiHandle. A specific object becomes of this type by holding a + * pointer to an instance of this structure. + */ +struct __vpirt { + int type_code; + + /* These methods extract information from the handle. */ + int (*vpi_get_)(int, vpiHandle); + char* (*vpi_get_str_)(int, vpiHandle); + void (*vpi_get_value_)(vpiHandle, p_vpi_value); + vpiHandle (*vpi_put_value_)(vpiHandle, p_vpi_value, p_vpi_time, int); + + /* These methods follow references. */ + vpiHandle (*handle_)(int, vpiHandle); + vpiHandle (*iterate_)(int, vpiHandle); + vpiHandle (*index_)(vpiHandle, int); +}; + +/* + * The vpiHandle for an iterator has this structure. The definition of + * the methods lives in vpi_iter.c + */ +struct __vpiIterator { + struct __vpiHandle base; + vpiHandle *args; + unsigned nargs; + unsigned next; +}; + +/* + * When a loaded VPI module announces a system task/function, one + * __vpiUserSystf object is created to hold the definition of that + * task/function. + * + * When the compiler encounters a %vpi_call statement, it creates a + * __vpiSysTaskCall to represent that particular call. The call refers + * to the definition handle so that when the %vpi_call instruction is + * encountered at run-time, the definition can be located and used. + */ +struct __vpiUserSystf { + struct __vpiHandle base; + s_vpi_systf_data info; +}; + +struct __vpiSysTaskCall { + struct __vpiHandle base; + struct __vpiUserSystf*defn; + unsigned nargs; + vpiHandle*args; +}; + +extern struct __vpiSysTaskCall*vpip_cur_task; + +/* + * This function is called before any compilation to load VPI + * modules. This gives the modules a chance to announce their + * contained functions before compilation commences. It is called only + * once. + */ +extern void vpip_load_modules(unsigned cnt, const char*tab[], const char*path); + +/* + * The vpip_build_vpi_call function creates a __vpiSysTaskCall object + * and returns the handle. The compiler uses this function when it + * encounters a %vpi_call statement. + * + * The %vpi_call instruction has as its only parameter the handle that + * is returned by the vpip_build_vpi_call. This includes all the + * information needed by vpip_execute_vpi_call to actually execute the + * call. + */ +extern vpiHandle vpip_build_vpi_call(const char*name); + +extern void vpip_execute_vpi_call(vpiHandle obj); + + +/* + * $Log: vpi_priv.h,v $ + * Revision 1.1 2001/03/16 01:44:34 steve + * Add structures for VPI support, and all the %vpi_call + * instruction. Get linking of VPI modules to work. + * + */ +#endif diff --git a/vvp/vpi_tasks.cc b/vvp/vpi_tasks.cc new file mode 100644 index 000000000..b1ed496a5 --- /dev/null +++ b/vvp/vpi_tasks.cc @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined(WINNT) +#ident "$Id: vpi_tasks.cc,v 1.1 2001/03/16 01:44:34 steve Exp $" +#endif + +/* + * This file keeps the table of system/task definitions. This table is + * built up before the input source file is parsed, and is used by the + * compiler when %vpi_call statements are encountered. + */ +# include "vpi_priv.h" +# include +# include +# include +# include + +static vpiHandle systask_handle(int type, vpiHandle ref) +{ + return 0; +} + +/* + * the iter function only supports getting an iterator of the + * arguments. This works equally well for tasks and functions. + */ +static vpiHandle systask_iter(int type, vpiHandle ref) +{ + struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; + assert((ref->vpi_type->type_code == vpiSysTaskCall) + || (ref->vpi_type->type_code == vpiSysFuncCall)); + + if (rfp->nargs == 0) + return 0; + +#if 0 + return vpip_make_iterator(rfp->nargs, rfp->args); +#else + return 0; +#endif +} + +static const struct __vpirt vpip_systask_rt = { + vpiSysTaskCall, + 0, + 0, + 0, + 0, + systask_handle, + systask_iter +}; + + +/* + * A value *can* be put to a vpiSysFuncCall object. This is how the + * return value is set. The value that is given should be converted to + * bits and set into the return value bit array. + */ +static vpiHandle sysfunc_put_value(vpiHandle ref, p_vpi_value val, + p_vpi_time t, int flag) +{ + assert(0); + return 0; +} + +static const struct __vpirt vpip_sysfunc_rt = { + vpiSysFuncCall, + 0, + 0, + 0, + sysfunc_put_value, + 0, + systask_iter +}; + + /* **** Manipulate the internal datastructures. **** */ + +static struct __vpiUserSystf**def_table = 0; +static unsigned def_count = 0; + +static struct __vpiUserSystf* allocate_def(void) +{ + if (def_table == 0) { + def_table = (struct __vpiUserSystf**) + malloc(sizeof (struct __vpiUserSystf*)); + + def_table[0] = (struct __vpiUserSystf*) + calloc(1, sizeof(struct __vpiUserSystf)); + + def_count = 1; + return def_table[0]; + } + + def_table = (struct __vpiUserSystf**) + realloc(def_table, (def_count+1)*sizeof (struct __vpiUserSystf*)); + + def_table[def_count] = (struct __vpiUserSystf*) + calloc(1, sizeof(struct __vpiUserSystf)); + + return def_table[def_count++]; +} + + +static struct __vpiUserSystf* vpip_find_systf(const char*name) +{ + for (unsigned idx = 0 ; idx < def_count ; idx += 1) + if (strcmp(def_table[idx]->info.tfname, name) == 0) + return def_table[idx]; + + return 0; +} + +/* + * A vpi_call is actually built up into a vpiSysTaskCall VPI object + * that refers back to the vpiUserSystf VPI object that is the + * definition. So this function is called by the compiler when a + * %vpi_call statement is encountered. Create here a vpiHandle that + * describes the call, and return it. The %vpi_call instruction will + * store this handle for when it is executed. + */ +vpiHandle vpip_build_vpi_call(const char*name) +{ + struct __vpiSysTaskCall*obj = (struct __vpiSysTaskCall*) + calloc(1, sizeof (struct __vpiSysTaskCall)); + + obj->base.vpi_type = &vpip_systask_rt; + obj->defn = vpip_find_systf(name); + obj->nargs = 0; + obj->args = 0; + + /* If there is a compiletf function, call it here. */ + if (obj->defn->info.compiletf) + obj->defn->info.compiletf (obj->defn->info.user_data); + + return &obj->base; +} + + +/* + * This function is used by the %vpi_call instruction to actually + * place the call to the system task/function. For now, only support + * calls to system tasks. + */ +void vpip_execute_vpi_call(vpiHandle ref) +{ + assert(ref->vpi_type->type_code == vpiSysTaskCall); + + vpip_cur_task = (struct __vpiSysTaskCall*)ref; + + assert(vpip_cur_task->defn->info.calltf); + vpip_cur_task->defn->info.calltf (vpip_cur_task->defn->info.user_data); +} + +/* + * This is the entry function that a VPI module uses to hook a new + * task/function into the simulator. The function creates a new + * __vpi_userSystf to represent the definition for the calls that come + * to pass later. + */ +void vpi_register_systf(const struct t_vpi_systf_data*ss) +{ + struct __vpiUserSystf*cur = allocate_def(); + cur->info = *ss; + cur->info.tfname = strdup(ss->tfname); +} + +/* + * $Log: vpi_tasks.cc,v $ + * Revision 1.1 2001/03/16 01:44:34 steve + * Add structures for VPI support, and all the %vpi_call + * instruction. Get linking of VPI modules to work. + * + */ + diff --git a/vvp/vthread.cc b/vvp/vthread.cc index da74eb802..6004b9b31 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -17,13 +17,14 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vthread.cc,v 1.3 2001/03/11 23:06:49 steve Exp $" +#ident "$Id: vthread.cc,v 1.4 2001/03/16 01:44:34 steve Exp $" #endif # include "vthread.h" # include "codes.h" # include "schedule.h" # include "functor.h" +# include "vpi_priv.h" # include struct vthread_s { @@ -53,6 +54,7 @@ void vthread_run(vthread_t thr) vvp_code_t cp = codespace_index(thr->pc); thr->pc += 1; + assert(cp->opcode); bool rc = (cp->opcode)(thr, cp); if (rc == false) return; @@ -110,8 +112,19 @@ bool of_SET(vthread_t thr, vvp_code_t cp) return true; } +bool of_VPI_CALL(vthread_t thr, vvp_code_t cp) +{ + printf("thread %p: %%vpi_call\n", thr); + vpip_execute_vpi_call(cp->handle); + return true; +} + /* * $Log: vthread.cc,v $ + * Revision 1.4 2001/03/16 01:44:34 steve + * Add structures for VPI support, and all the %vpi_call + * instruction. Get linking of VPI modules to work. + * * Revision 1.3 2001/03/11 23:06:49 steve * Compact the vvp_code_s structure. *