From 2d0e11283dbd70760b5382832aabd26c80b689f0 Mon Sep 17 00:00:00 2001 From: steve Date: Sun, 15 Aug 1999 01:23:56 +0000 Subject: [PATCH] Convert vvm to implement system tasks with vpi. --- Makefile.in | 5 +- configure.in | 2 +- t-vvm.cc | 88 +++++-- vpi.txt | 56 +++++ vpi/.cvsignore | 3 + vpi/Makefile.in | 86 +++++++ vpi/sys_display.c | 226 ++++++++++++++++++ vpi/sys_finish.c | 50 ++++ vpi/sys_table.c | 39 ++++ vpi/veriuser.h | 47 ++++ vpi/vpi_user.h | 147 ++++++++++++ vvm.txt | 16 +- vvm/Makefile.in | 7 +- vvm/display.cc | 264 --------------------- vvm/vpi_priv.h | 97 ++++++++ vvm/vvm.h | 13 +- vvm/vvm_calltf.cc | 564 +++++++++++++++++++++++++++++++++++---------- vvm/vvm_calltf.h | 78 +++---- vvm/vvm_monitor.cc | 7 +- 19 files changed, 1323 insertions(+), 472 deletions(-) create mode 100644 vpi.txt create mode 100644 vpi/.cvsignore create mode 100644 vpi/Makefile.in create mode 100644 vpi/sys_display.c create mode 100644 vpi/sys_finish.c create mode 100644 vpi/sys_table.c create mode 100644 vpi/veriuser.h create mode 100644 vpi/vpi_user.h delete mode 100644 vvm/display.cc create mode 100644 vvm/vpi_priv.h diff --git a/Makefile.in b/Makefile.in index 0d9775674..5591c0312 100644 --- a/Makefile.in +++ b/Makefile.in @@ -18,7 +18,7 @@ # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # -#ident "$Id: Makefile.in,v 1.11 1999/08/07 20:05:51 steve Exp $" +#ident "$Id: Makefile.in,v 1.12 1999/08/15 01:23:56 steve Exp $" # # SHELL = /bin/sh @@ -46,11 +46,13 @@ CXXFLAGS = @CXXFLAGS@ LDFLAGS = @LDFLAGS@ all: ivl + cd vpi ; make all cd vvm ; make all cd ivlpp ; make all clean: rm *.o parse.cc parse.cc.output parse.h dep/*.d lexor.cc + cd vpi ; make clean cd vvm ; make clean cd ivlpp ; make clean @@ -87,6 +89,7 @@ lexor.cc: lexor.lex flex -PVL -s -olexor.cc lexor.lex install: all installdirs $(bindir)/ivl + cd vpi ; make install cd vvm ; make install cd ivlpp ; make install diff --git a/configure.in b/configure.in index 2604e282d..a24720eb4 100644 --- a/configure.in +++ b/configure.in @@ -6,4 +6,4 @@ AC_PROG_CC AC_PROG_CXX AC_PROG_INSTALL -AC_OUTPUT(Makefile ivlpp/Makefile vvm/Makefile) +AC_OUTPUT(Makefile vpi/Makefile ivlpp/Makefile vvm/Makefile) diff --git a/t-vvm.cc b/t-vvm.cc index f92b3b30b..7d4fe259a 100644 --- a/t-vvm.cc +++ b/t-vvm.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: t-vvm.cc,v 1.34 1999/08/02 00:19:16 steve Exp $" +#ident "$Id: t-vvm.cc,v 1.35 1999/08/15 01:23:56 steve Exp $" #endif # include @@ -306,6 +306,14 @@ static string emit_proc_rval(ostream&os, unsigned indent, const NetExpr*expr) return scan.result; } +/* + * The vvm_parm_rval class scans expressions for the purpose of making + * parameters for system tasks/functions. Thus, the generated code is + * geared towards making the handles needed to make the call. + * + * The result of any parm rval scan is a vpiHandle, or a string that + * automatically converts to a vpiHandle on assignment. + */ class vvm_parm_rval : public expr_scan_t { public: @@ -326,8 +334,11 @@ class vvm_parm_rval : public expr_scan_t { void vvm_parm_rval::expr_const(const NetEConst*expr) { if (expr->value().is_string()) { - result = "\""; - result = result + expr->value().as_string() + "\""; + result = make_temp(); + os_ << " struct __vpiHandle " << result << ";" << endl; + os_ << " vvm_make_vpi_parm(&" << result << ", \"" + << expr->value().as_string() << "\");" << endl; + result = "&" + result; return; } @@ -353,16 +364,19 @@ void vvm_parm_rval::expr_const(const NetEConst*expr) os_ << ";" << endl; } - result = tname; + result = make_temp(); + os_ << " struct __vpiHandle " << result << ";" << endl; + os_ << " vvm_make_vpi_parm(&" << result << ", &" << tname + << ");" << endl; + result = "&" + result; } void vvm_parm_rval::expr_ident(const NetEIdent*expr) { if (expr->name() == "$time") { - string res = make_temp(); - os_ << " vvm_calltf_parm " << res << - "(vvm_calltf_parm::TIME);" << endl; - result = res; + os_ << " system_time.val.time.low " + "= sim_->get_sim_time();" << endl; + result = string("&system_time"); } else { cerr << "Unhandled identifier: " << expr->name() << endl; } @@ -370,12 +384,7 @@ void vvm_parm_rval::expr_ident(const NetEIdent*expr) void vvm_parm_rval::expr_signal(const NetESignal*expr) { - string res = make_temp(); - os_ << " vvm_calltf_parm::SIG " << res << ";" << endl; - os_ << " " << res << ".bits = &" << - mangle(expr->name()) << "_bits;" << endl; - os_ << " " << res << ".mon = &" << - mangle(expr->name()) << ";" << endl; + string res = string("&") + mangle(expr->name()) + "_vpi"; result = res; } @@ -393,11 +402,16 @@ void target_vvm::start_design(ostream&os, const Design*mod) os << "# include \"vvm_func.h\"" << endl; os << "# include \"vvm_calltf.h\"" << endl; os << "# include \"vvm_thread.h\"" << endl; + os << "# include \"vpi_user.h\"" << endl; + os << "# include \"vpi_priv.h\"" << endl; + + os << "static struct __vpiHandle system_time;" << endl; process_counter = 0; init_code << "static void design_init(vvm_simulation&sim)" << endl; init_code << "{" << endl; - + init_code << " vvm_init_vpi_timevar(&system_time, \"$time\");" + << endl; start_code << "static void design_start(vvm_simulation&sim)" << endl; start_code << "{" << endl; } @@ -414,6 +428,7 @@ void target_vvm::end_design(ostream&os, const Design*mod) os << start_code.str(); os << "main()" << endl << "{" << endl; + os << " vvm_load_vpi_module(\"system.vpi\");" << endl; os << " vvm_simulation sim;" << endl; os << " design_init(sim);" << endl; os << " design_start(sim);" << endl; @@ -818,6 +833,14 @@ void target_vvm::net_esignal(ostream&os, const NetESignal*net) os << "static vvm_signal_t<" << net->pin_count() << "> " << mangle(net->name()) << "(\"" << net->name() << "\", &" << mangle(net->name()) << "_bits);" << endl; + + os << "static struct __vpiHandle " << mangle(net->name()) << + "_vpi;" << endl; + + init_code << " vvm_init_vpi_handle(&" << + mangle(net->name()) << "_vpi, &" << mangle(net->name()) << + "_bits, &" << mangle(net->name()) << ");" << endl; + } /* @@ -1139,16 +1162,42 @@ void target_vvm::proc_repeat(ostream&os, const NetRepeat*net) void target_vvm::proc_stask(ostream&os, const NetSTask*net) { string ptmp = make_temp(); - os << " struct vvm_calltf_parm " << ptmp << "[" << + +#if 0 + os << " struct __vpiHandle " << ptmp << "[" << net->nparms() << "];" << endl; for (unsigned idx = 0 ; idx < net->nparms() ; idx += 1) if (net->parm(idx)) { string val = emit_parm_rval(os, net->parm(idx)); - os << " " << ptmp << "[" << idx << "] = " << - val << ";" << endl; + os << " vvm_make_vpi_parm(&" << ptmp << "[" + << idx << "], " << val << ");" << endl; + } else { + os << " vvm_make_vpi_parm(&" << ptmp << "[" + << idx << "]);" << endl; } +#else + os << " vpiHandle " << ptmp << "[" << net->nparms() << + "];" << endl; + for (unsigned idx = 0 ; idx < net->nparms() ; idx += 1) { + string val; + if (net->parm(idx)) { + val = emit_parm_rval(os, net->parm(idx)); + + } else { + val = make_temp(); + os << " struct __vpiHandle " << val << ";" << endl; + os << " vvm_make_vpi_parm(&" << val << ");" << endl; + val = string("&") + val; + } + + os << " " << ptmp << "[" << idx << "] = " << val << ";" + << endl; + } +#endif + os << " vvm_calltask(sim_, \"" << net->name() << "\", " << net->nparms() << ", " << ptmp << ");" << endl; + } void target_vvm::proc_utask(ostream&os, const NetUTask*net) @@ -1308,6 +1357,9 @@ extern const struct target tgt_vvm = { }; /* * $Log: t-vvm.cc,v $ + * Revision 1.35 1999/08/15 01:23:56 steve + * Convert vvm to implement system tasks with vpi. + * * Revision 1.34 1999/08/02 00:19:16 steve * Get rid of excess set/init of NetESignal objects. * diff --git a/vpi.txt b/vpi.txt new file mode 100644 index 000000000..525d69dcd --- /dev/null +++ b/vpi.txt @@ -0,0 +1,56 @@ + +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. + +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 +linked in and startup routines are called in order. + +The product that uses vpi modules uses the environment variable +VPI_MODULE_PATH as a ':' separated list of directories. This is the +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. + +COMPILING A VPI MODULE (LINUX) + +To compile a module, first compile down to object files all the PLI +applications that you wish to include in the module. Then, create a +small "C" source file that defines only the startup table like so: + + extern void hello_register(); + void (*vlog_startup_routines[])() = { + hello_register, + 0 + }; + +Compile this table source down to its object file, as well. Finally, +link the application with the command: + + cc -o foo.vpi -shared + +No VPI libraries need to be included because the product that loads +the module will supply all the standard vpi functions. If you use any +non-vpi library functions, you may need to include libraries to +support them. + +The resulting foo.vpi file is the vpi module. Place it in a location +where the product to use it can locate it. + + +CAVEAT EMPTOR + +Only the calltf function is supported. The compiletf and sizetf +functions are invoked at compile time, and the ivl compiler does not +yet support VPI. diff --git a/vpi/.cvsignore b/vpi/.cvsignore new file mode 100644 index 000000000..5f7276687 --- /dev/null +++ b/vpi/.cvsignore @@ -0,0 +1,3 @@ +Makefile +system.vpi +dep diff --git a/vpi/Makefile.in b/vpi/Makefile.in new file mode 100644 index 000000000..d9af27e26 --- /dev/null +++ b/vpi/Makefile.in @@ -0,0 +1,86 @@ +# +# This source code is free software; you can redistribute it +# and/or modify it in source code form under the terms of the GNU +# Library General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) +# any later version. In order to redistribute the software in +# binary form, you will need a Picture Elements Binary Software +# License. +# +# 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 Library General Public License for more details. +# +# You should have received a copy of the GNU Library 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 +# +#ident "$Id: Makefile.in,v 1.1 1999/08/15 01:23:56 steve Exp $" +# +# +SHELL = /bin/sh + +VERSION = 0.0 + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +srcdir = @srcdir@ + +VPATH = $(srcdir) + +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib +includedir = $(prefix)/include + +CC = @CC@ +CXX = @CXX@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CPPFLAGS = @CPPFLAGS@ @DEFS@ +CXXFLAGS = @CXXFLAGS@ +LDFLAGS = @LDFLAGS@ + +all: system.vpi + +%.o dep/%.d: %.c + @[ -d dep ] || mkdir dep + $(CC) -Wall $(CPPFLAGS) -MD -c $< -o $*.o + mv $*.d dep + +O = sys_table.o sys_display.o sys_finish.o + +system.vpi: $O + $(CC) -shared -o $@ $O + +clean: + rm -f *.o dep/*.d + +install: all installdirs $(libdir)/ivl/system.vpi \ + $(includedir)/vpi_user.h \ + $(includedir)/veriuser.h + +$(libdir)/ivl/system.vpi: ./system.vpi + $(INSTALL_PROGRAM) ./system.vpi $(libdir)/ivl/system.vpi + +$(includedir)/vpi_user.h: $(srcdir)/vpi_user.h + $(INSTALL_DATA) $(srcdir)/vpi_user.h $(includedir)/vpi_user.h + +$(includedir)/veriuser.h: $(srcdir)/veriuser.h + $(INSTALL_DATA) $(srcdir)/veriuser.h $(includedir)/veriuser.h + + +installdirs: mkinstalldirs + $(srcdir)/mkinstalldirs $(includedir) $(bindir) $(libdir)/ivl + +uninstall: + rm -f $(libdir)/ivl/system.vpi + rm -f $(includedir)/vpi_user.h + rm -f $(includedir)/veriuser.h + + +-include $(patsubst %.o, dep/%.d, $O) diff --git a/vpi/sys_display.c b/vpi/sys_display.c new file mode 100644 index 000000000..499a83fb6 --- /dev/null +++ b/vpi/sys_display.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 1999 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: sys_display.c,v 1.1 1999/08/15 01:23:56 steve Exp $" +#endif + +# include "vpi_user.h" +# include +# include +# include +# include + +static void format_binary(vpiHandle argv, int fsize) +{ + s_vpi_value value; + vpiHandle item = vpi_scan(argv); + if (item == 0) return; + + value.format = vpiBinStrVal; + vpi_get_value(item, &value); + vpi_printf("%s", value.value.str); +} + +static void format_decimal(vpiHandle argv, int fsize) +{ + s_vpi_value value; + vpiHandle item = vpi_scan(argv); + if (item == 0) return; + + value.format = vpiDecStrVal; + vpi_get_value(item, &value); + vpi_printf("%s", value.value.str); +} + +static void format_hex(vpiHandle argv, int fsize) +{ + s_vpi_value value; + vpiHandle item = vpi_scan(argv); + if (item == 0) return; + + value.format = vpiHexStrVal; + vpi_get_value(item, &value); + vpi_printf("%s", value.value.str); +} + +static void format_m(vpiHandle argv, int fsize) +{ + vpiHandle item = vpi_scan(argv); + if (item == 0) return; + + vpi_printf("%s", vpi_get_str(vpiFullName, item)); +} + +/* + * If $display discovers a string as a parameter, this function is + * called to process it as a format string. I need the argv handle as + * well so that I can look for arguments as I move forward through the + * string. + */ +static void format(s_vpi_value*fmt, vpiHandle argv) +{ + char buf[256]; + char*cp = fmt->value.str; + assert(fmt->value.str); + + while (*cp) { + size_t cnt = strcspn(cp, "%\\"); + if (cnt > 0) { + if (cnt >= sizeof buf) + cnt = sizeof buf - 1; + strncpy(buf, cp, cnt); + buf[cnt] = 0; + vpi_printf("%s", buf); + cp += cnt; + + } else if (*cp == '%') { + int fsize = -1; + + cp += 1; + if (isdigit(*cp)) + fsize = strtoul(cp, &cp, 10); + + switch (*cp) { + case 0: + break; + case 'b': + case 'B': + format_binary(argv, fsize); + cp += 1; + break; + case 'd': + case 'D': + format_decimal(argv, fsize); + cp += 1; + break; + case 'h': + case 'H': + case 'x': + case 'X': + format_hex(argv, fsize); + cp += 1; + break; + case 'm': + format_m(argv, fsize); + cp += 1; + break; + case '%': + vpi_printf("%%"); + cp += 1; + break; + default: + vpi_printf("%c", *cp); + cp += 1; + break; + } + + } else { + + cp += 1; + switch (*cp) { + case 0: + break; + case 'n': + vpi_printf("\n"); + cp += 1; + break; + default: + vpi_printf("%c", *cp); + cp += 1; + } + } + } +} + +static int sys_display_calltf(char *xx) +{ + s_vpi_value value; + vpiHandle sys = vpi_handle(vpiSysTfCall, 0); + + vpiHandle argv = vpi_iterate(vpiArgument, sys); + vpiHandle item; + + for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) { + + switch (vpi_get(vpiType, item)) { + + case 0: + vpi_printf(" "); + break; + + case vpiConstant: + value.format = vpiObjTypeVal; + vpi_get_value(item, &value); + switch (value.format) { + case vpiStringVal: + format(&value, argv); + break; + case vpiSuppressVal: + break; + default: + vpi_printf("?"); + break; + } + break; + + case vpiNet: + case vpiReg: + value.format = vpiBinStrVal; + vpi_get_value(item, &value); + vpi_printf("%s", value.value.str); + break; + + case vpiTimeVar: + value.format = vpiTimeVal; + vpi_get_value(item, &value); + vpi_printf("%u", value.value.time->low); + break; + + default: + vpi_printf("?"); + break; + } + } + + vpi_printf("\n"); + + vpi_free_object(argv); + return 0; +} + +void sys_display_register() +{ + s_vpi_systf_data tf_data; + + tf_data.type = vpiSysTask; + tf_data.tfname = "$display"; + tf_data.calltf = sys_display_calltf; + tf_data.compiletf = 0; + tf_data.sizetf = 0; + vpi_register_systf(&tf_data); +} + + +/* + * $Log: sys_display.c,v $ + * Revision 1.1 1999/08/15 01:23:56 steve + * Convert vvm to implement system tasks with vpi. + * + */ + diff --git a/vpi/sys_finish.c b/vpi/sys_finish.c new file mode 100644 index 000000000..339cf4a13 --- /dev/null +++ b/vpi/sys_finish.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1999 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: sys_finish.c,v 1.1 1999/08/15 01:23:56 steve Exp $" +#endif + +# include "vpi_user.h" +# include "veriuser.h" + +static int sys_finish_calltf(char *xx) +{ + tf_dofinish(); + return 0; +} + +void sys_finish_register() +{ + s_vpi_systf_data tf_data; + + tf_data.type = vpiSysTask; + tf_data.tfname = "$finish"; + tf_data.calltf = sys_finish_calltf; + tf_data.compiletf = 0; + tf_data.sizetf = 0; + vpi_register_systf(&tf_data); +} + +/* + * $Log: sys_finish.c,v $ + * Revision 1.1 1999/08/15 01:23:56 steve + * Convert vvm to implement system tasks with vpi. + * + */ + diff --git a/vpi/sys_table.c b/vpi/sys_table.c new file mode 100644 index 000000000..eaf426a8b --- /dev/null +++ b/vpi/sys_table.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1999 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: sys_table.c,v 1.1 1999/08/15 01:23:56 steve Exp $" +#endif + +extern void sys_finish_register(); +extern void sys_display_register(); + +void (*vlog_startup_routines[])() = { + sys_finish_register, + sys_display_register, + 0 +}; + + +/* + * $Log: sys_table.c,v $ + * Revision 1.1 1999/08/15 01:23:56 steve + * Convert vvm to implement system tasks with vpi. + * + */ + diff --git a/vpi/veriuser.h b/vpi/veriuser.h new file mode 100644 index 000000000..4bcbe30b9 --- /dev/null +++ b/vpi/veriuser.h @@ -0,0 +1,47 @@ +#ifndef __veriuser_H +#define __veriuser_H +/* + * Copyright (c) 1999 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: veriuser.h,v 1.1 1999/08/15 01:23:56 steve Exp $" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This header file only exists as a stub, and to carry the function + * declaration for the tf_dofinish() function. I plan on removing both + * as soon as a VPI way of doing this appears. + */ + +extern void tf_dofinish(); + +#ifdef __cplusplus +} +#endif + +/* + * $Log: veriuser.h,v $ + * Revision 1.1 1999/08/15 01:23:56 steve + * Convert vvm to implement system tasks with vpi. + * + */ +#endif diff --git a/vpi/vpi_user.h b/vpi/vpi_user.h new file mode 100644 index 000000000..b92dfe8d4 --- /dev/null +++ b/vpi/vpi_user.h @@ -0,0 +1,147 @@ +#ifndef __vpi_user_H +#define __vpi_user_H +/* + * Copyright (c) 1999 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_user.h,v 1.1 1999/08/15 01:23:56 steve Exp $" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct __vpiHandle *vpiHandle; + +/* + * This structure is created by the VPI application to provide hooks + * into the application that the compiler/simulator can access. + */ +typedef struct t_vpi_systf_data { + int type; + int subtype; + char *tfname; + int (*calltf)(char*); + int (*compiletf)(char*); + int (*sizetf)(); + char *user_data; +} s_vpi_systf_data, *p_vpi_systf_data; + +/* The type in the above structure can have one of the following + values: */ +#define vpiSysTask 1 +#define vpiSysFunc 2 + + +typedef struct t_vpi_time { + int type; + unsigned int high; + unsigned int low; + double real; +} s_vpi_time, *p_vpi_time; + +#define vpiScaledRealTime 1 +#define vpiSimTime 2 +#define vpiSuppressTime 3 + +/* + * This structure holds values that are passed back and forth between + * the simulator and the application. + */ +typedef struct t_vpi_value { + int format; + union { + char*str; + int scalar; + int integer; + double real; + struct t_vpi_time *time; + struct t_vpi_vecval *vector; + struct t_vpi_strengthval *strength; + char*misc; + } value; +} s_vpi_value, *p_vpi_value; + +/* These are valid codes for the format of the t_vpi_value structure. */ +#define vpiBinStrVal 1 +#define vpiOctStrVal 2 +#define vpiDecStrVal 3 +#define vpiHexStrVal 4 +#define vpiScalerVal 5 +#define vpiIntVal 6 +#define vpiReadVal 7 +#define vpiStringVal 8 +#define vpiVectorVal 9 +#define vpiStrengthVal 10 +#define vpiTimeVal 11 +#define vpiObjTypeVal 12 +#define vpiSuppressVal 13 + + +/* OBJECT CODES */ +#define vpiConstant 7 +#define vpiNet 36 +#define vpiReg 48 +#define vpiSysTaskCall 57 +#define vpiTimeVar 63 +#define vpiSysTfCall 85 +#define vpiArgument 89 + + +/* PROPERTIES */ +#define vpiType 1 +#define vpiName 2 +#define vpiFullName 3 +#define vpiConstType 43 +# define vpiDecConst 1 +# define vpiRealConst 2 +# define vpiBinaryConst 3 +# define vpiOctConst 4 +# define vpiHexConst 5 +# define vpiStringConst 6 + + +/* VPI FUNCTIONS */ +extern void vpi_register_systf(const struct t_vpi_systf_data*ss); +extern void vpi_printf(const char*fmt, ...); + +extern vpiHandle vpi_handle(int type, vpiHandle ref); +extern vpiHandle vpi_iterate(int type, vpiHandle ref); +extern vpiHandle vpi_scan(vpiHandle iter); + +extern int vpi_get(int property, vpiHandle ref); +extern char* vpi_get_str(int property, vpiHandle ref); +extern void vpi_get_value(vpiHandle expr, p_vpi_value value); + +extern int vpi_free_object(vpiHandle ref); + + +/* This is the table of startup routines included in each module. */ +extern void (*vlog_startup_routines[])(); + +#ifdef __cplusplus +} +#endif + +/* + * $Log: vpi_user.h,v $ + * Revision 1.1 1999/08/15 01:23:56 steve + * Convert vvm to implement system tasks with vpi. + * + */ +#endif diff --git a/vvm.txt b/vvm.txt index 8cc47ef42..f8cda7d30 100644 --- a/vvm.txt +++ b/vvm.txt @@ -16,6 +16,17 @@ So a sample command line to compile a Verilog file to C++ would be: ivl -F nobufz -F sigfold -F propinit -t vvm -o foo.cc foo.vl +Once the program is compiled down to C++ code, it needs to be further +compiled and linked into an executable image. The command for doing +this is highly dependent on the system where you use Icarus +Verilog. For Linux, the compile command is typically: + + c++ -o foo foo.cc -lvvm -ldl + +On any system, the compiled program requires that the VPI_MODULE_PATH +be set to a ':' separated list of directories to search for vpi files, +the system.vpi file in particular. This is a run time requirement. + ATTRIBUTES (none) @@ -99,8 +110,11 @@ bits are at: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ - $Id: vvm.txt,v 1.1 1999/04/29 16:29:04 steve Exp $ + $Id: vvm.txt,v 1.2 1999/08/15 01:23:56 steve Exp $ $Log: vvm.txt,v $ + Revision 1.2 1999/08/15 01:23:56 steve + Convert vvm to implement system tasks with vpi. + Revision 1.1 1999/04/29 16:29:04 steve Add vvm target documentation diff --git a/vvm/Makefile.in b/vvm/Makefile.in index 70722beb7..4d3741eec 100644 --- a/vvm/Makefile.in +++ b/vvm/Makefile.in @@ -18,7 +18,7 @@ # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # -#ident "$Id: Makefile.in,v 1.3 1999/05/09 01:24:59 steve Exp $" +#ident "$Id: Makefile.in,v 1.4 1999/08/15 01:23:56 steve Exp $" # # SHELL = /bin/sh @@ -36,7 +36,7 @@ libdir = $(exec_prefix)/lib includedir = $(prefix)/include CC = @CC@ -CXX = @CXX@ +CXX = @CXX@ -I../vpi INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ @@ -52,9 +52,8 @@ all: libvvm.a $(CXX) -Wall -fno-exceptions $(CXXFLAGS) -MD -c $< -o $*.o mv $*.d dep -TF = display.o O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_monitor.o vvm_pevent.o \ -vvm_simulation.o vvm_thread.o $(TF) +vvm_simulation.o vvm_thread.o libvvm.a: $O rm -f $@ diff --git a/vvm/display.cc b/vvm/display.cc deleted file mode 100644 index 5cc479ebb..000000000 --- a/vvm/display.cc +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) 1998 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: display.cc,v 1.5 1999/05/31 15:46:36 steve Exp $" -#endif - -# include "vvm.h" -# include "vvm_calltf.h" -# include - -static void format_hex(vvm_simulation*sim, ostream&os, - class vvm_calltf_parm*parm) -{ - switch (parm->type()) { - case vvm_calltf_parm::TIME: - os << sim->get_sim_time(); - break; - case vvm_calltf_parm::NONE: - os << "z"; - break; - case vvm_calltf_parm::ULONG: - os << ((parm->as_ulong()&1) ? "0" : "1"); - break; - case vvm_calltf_parm::STRING: - os << parm->as_string(); - break; - case vvm_calltf_parm::BITS: - unsigned c = 0; - for (unsigned idx = parm->as_bits()->get_width() - ; idx > 0 ; idx -= 1) - c = (c << 1) | parm->as_bits()->get_bit(idx-1); - cout.form("%x",c); - break; - } -} -static void format_bit(vvm_simulation*sim, ostream&os, - class vvm_calltf_parm*parm) -{ - switch (parm->type()) { - case vvm_calltf_parm::TIME: - os << (sim->get_sim_time()&1); - break; - case vvm_calltf_parm::NONE: - os << "z"; - break; - case vvm_calltf_parm::ULONG: - os << ((parm->as_ulong()&1) ? "0" : "1"); - break; - case vvm_calltf_parm::STRING: - os << parm->as_string(); - break; - case vvm_calltf_parm::BITS: - for (unsigned idx = parm->as_bits()->get_width() - ; idx > 0 ; idx -= 1) - os << parm->as_bits()->get_bit(idx-1); - break; - } -} - -static void format_dec(vvm_simulation*sim, ostream&os, - class vvm_calltf_parm*parm) -{ - switch (parm->type()) { - case vvm_calltf_parm::TIME: - os << sim->get_sim_time(); - break; - case vvm_calltf_parm::NONE: - os << "0"; - break; - case vvm_calltf_parm::ULONG: - os << parm->as_ulong(); - break; - case vvm_calltf_parm::STRING: - os << parm->as_string(); - break; - case vvm_calltf_parm::BITS: { - unsigned long val = 0; - unsigned long mask = 1; - const vvm_bits_t*bstr = parm->as_bits(); - for (unsigned idx = 0 ; idx < bstr->get_width() ; idx += 1) { - if (bstr->get_bit(idx) == V1) val |= mask; - mask <<= 1; - } - os << val; - break; - } - } -} - -static void format_name(ostream&os, class vvm_calltf_parm*parm) -{ - switch (parm->type()) { - case vvm_calltf_parm::TIME: - os << "$time"; - break; - case vvm_calltf_parm::NONE: - break; - case vvm_calltf_parm::ULONG: - os << parm->as_ulong(); - break; - case vvm_calltf_parm::STRING: - os << "\"" << parm->as_string() << "\""; - break; - case vvm_calltf_parm::BITS: - os << parm->sig_name(); - break; - } -} - -static unsigned format(vvm_simulation*sim, const string&str, - unsigned nparms, - class vvm_calltf_parm*parms) -{ - char prev = 0; - unsigned next_parm = 0; - unsigned idx = 0; - while (idx < str.length()) { - if (prev == '%') { - switch (str[idx]) { - case 'b': - case 'B': - format_bit(sim, cout, parms+next_parm); - next_parm += 1; - break; - case 'x': - case 'X': - case 'h': - case 'H': - format_hex(sim, cout, parms+next_parm); - next_parm += 1; - break; - case 'd': - case 'D': - format_dec(sim, cout, parms+next_parm); - next_parm += 1; - break; - case 'm': - case 'M': - format_name(cout, parms+next_parm); - next_parm += 1; - break; - case '%': - cout << str[idx]; - break; - } - - prev = 0; - - } else { - if (str[idx] != '%') - cout << str[idx]; - else - prev = '%'; - } - - idx += 1; - } - - return next_parm; -} - -void Sdisplay(vvm_simulation*sim, const string&name, - unsigned nparms, class vvm_calltf_parm*parms) -{ - for (unsigned idx = 0 ; idx < nparms ; idx += 1) - switch (parms[idx].type()) { - case vvm_calltf_parm::NONE: - cout << " "; - break; - case vvm_calltf_parm::TIME: - cout << sim->get_sim_time(); - break; - case vvm_calltf_parm::ULONG: - cout << parms[idx].as_ulong(); - break; - case vvm_calltf_parm::STRING: - idx += format(sim, parms[idx].as_string(), - nparms-idx-1, parms+idx+1); - break; - case vvm_calltf_parm::BITS: - cout << *parms[idx].as_bits(); - break; - } - - cout << endl; -} - -class monitor_event : public vvm_event { - public: - monitor_event(vvm_simulation*sim, - unsigned nparms, class vvm_calltf_parm*parms) - { sim_ = sim; - nparms_ = nparms; - parms_ = new vvm_calltf_parm[nparms]; - for (unsigned idx = 0 ; idx < nparms_ ; idx += 1) - parms_[idx] = parms[idx]; - } - - ~monitor_event() { delete[]parms_; } - - private: - vvm_simulation*sim_; - unsigned nparms_; - vvm_calltf_parm*parms_; - void event_function(); -}; - -void monitor_event::event_function() -{ - Sdisplay(sim_, "$display", nparms_, parms_); -} - -static monitor_event*mon = 0; - -void Smonitor(vvm_simulation*sim, const string&name, - unsigned nparms, class vvm_calltf_parm*parms) -{ - if (mon) delete mon; - mon = new monitor_event(sim, nparms, parms); - - for (unsigned idx = 0 ; idx < nparms ; idx += 1) { - if (parms[idx].type() != vvm_calltf_parm::BITS) - continue; - - parms[idx].as_mon()->enable(mon); - } -} - -/* - * $Log: display.cc,v $ - * Revision 1.5 1999/05/31 15:46:36 steve - * Handle time in more places. - * - * Revision 1.4 1999/05/12 04:02:17 steve - * Add %x support contributed by Steve Wilson. - * - * Revision 1.3 1999/01/01 01:44:40 steve - * Proberly print vectors in binary. - * - * Revision 1.2 1998/11/10 00:48:31 steve - * Add support it vvm target for level-sensitive - * triggers (i.e. the Verilog wait). - * Fix display of $time is format strings. - * - * Revision 1.1 1998/11/09 23:44:10 steve - * Add vvm library. - * - */ diff --git a/vvm/vpi_priv.h b/vvm/vpi_priv.h new file mode 100644 index 000000000..9b4ce55b9 --- /dev/null +++ b/vvm/vpi_priv.h @@ -0,0 +1,97 @@ +#ifndef __vpi_priv_H +#define __vpi_priv_H +/* + * Copyright (c) 1999 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 1999/08/15 01:23:56 steve Exp $" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This is the most basic type in the vpi implementation. A handle can + * exist to refer to most any of the supported vpi objects. The + * interpretation of the parts depends in general on the type of the + * object. + */ +struct __vpiHandle { + int type; + int subtype; + + /* These are property values. */ + char*full_name; + + /* This pointer is used for to-one references. */ + struct __vpiHandle*referent; + + /* This pointer table is used for to-many refrences to + arguments, and is used by the vpiArgument iterator. */ + struct __vpiHandle**arguments; + unsigned narguments; + + /* These methods support the various vpi_get() functions. */ + int (*get_)(int property, vpiHandle ref); + char* (*get_str_)(int property, vpiHandle ref); + + /* This method is used to get a value. */ + void (*get_value_)(struct __vpiHandle*expr, s_vpi_value*vp); + + /* This is a value union, that reflect state or the value of a + handle. */ + union { + unsigned unum; + struct vvm_bits_t*bits; + struct t_vpi_time time; + } val; +}; + + +/* TYPE MEANINGS: + * + * vpiArgument + * This type of handle contains a single referent, the item that has + * many arguments. It is an iterator. + * + * vpiConstant + * Constant values, such as strings and numbers, are this type. + * + * vpiSysTaskCall + * This handle type represents a call to a system task. It has a + * to-many reference to argument expressions, and a to-one reference + * to a vpiUserSystf object. + * + * vpiTimeVar + * This type is a special kind of variable, that holds a time. The + * time value is a more complex structure then a single number. The + * type really seems to exist to implement the $time system variable. + */ + +#ifdef __cplusplus +} +#endif + +/* + * $Log: vpi_priv.h,v $ + * Revision 1.1 1999/08/15 01:23:56 steve + * Convert vvm to implement system tasks with vpi. + * + */ +#endif diff --git a/vvm/vvm.h b/vvm/vvm.h index b083081eb..0a15061de 100644 --- a/vvm/vvm.h +++ b/vvm/vvm.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vvm.h,v 1.9 1999/06/21 01:02:34 steve Exp $" +#ident "$Id: vvm.h,v 1.10 1999/08/15 01:23:56 steve Exp $" #endif # include @@ -235,17 +235,17 @@ class vvm_simulation { */ class vvm_monitor_t { public: - vvm_monitor_t(const string&); + vvm_monitor_t(const char*); void trigger(vvm_simulation*sim) { if (event_) sim->monitor_event(event_); } - const string& name() const { return name_; } + const char* name() const { return name_; } void enable(vvm_event*e) { event_ = e; } private: - string name_; + const char* name_; vvm_event*event_; private: // not implemented @@ -257,7 +257,7 @@ class vvm_monitor_t { template class vvm_signal_t : public vvm_monitor_t { public: - vvm_signal_t(const string&n, vvm_bitset_t*b) + vvm_signal_t(const char*n, vvm_bitset_t*b) : vvm_monitor_t(n), bits_(b) { } @@ -280,6 +280,9 @@ template class vvm_signal_t : public vvm_monitor_t { /* * $Log: vvm.h,v $ + * Revision 1.10 1999/08/15 01:23:56 steve + * Convert vvm to implement system tasks with vpi. + * * Revision 1.9 1999/06/21 01:02:34 steve * Add init to vvm_signal_t. * diff --git a/vvm/vvm_calltf.cc b/vvm/vvm_calltf.cc index 450d7fdc1..243f71f36 100644 --- a/vvm/vvm_calltf.cc +++ b/vvm/vvm_calltf.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-1999 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,153 +17,461 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vvm_calltf.cc,v 1.2 1999/05/31 15:46:36 steve Exp $" +#ident "$Id: vvm_calltf.cc,v 1.3 1999/08/15 01:23:56 steve Exp $" #endif # include "vvm_calltf.h" +# include +# include "vpi_priv.h" # include # include # include +# include +# include +# include +# include +# include -vvm_calltf_parm::vvm_calltf_parm() -: type_(NONE) -{ -} +# define MAX_PATHLEN 1024 -vvm_calltf_parm::vvm_calltf_parm(TYPE t) -: type_(t) -{ - assert((t == NONE) || (t == TIME)); -} +/* This simulation pointer is used by vpi functions to get back to the + simulation. */ +static vvm_simulation*vpi_sim; -void vvm_calltf_parm::release_() -{ - switch (type_) { - case NONE: - case TIME: - case ULONG: - break; - case STRING: - ((string*)string_)->string::~string(); - break; - case BITS: - break; - } - type_ = NONE; -} +static vpiHandle vvm_vpi_cur_task; -vvm_calltf_parm& vvm_calltf_parm::operator= (unsigned long val) -{ - release_(); - type_ = ULONG; - ulong_ = val; - return *this; -} - -vvm_calltf_parm& vvm_calltf_parm::operator= (const string&val) -{ - release_(); - type_ = STRING; - new (string_) string (val); - return *this; -} - -vvm_calltf_parm& vvm_calltf_parm::operator= (const vvm_calltf_parm::SIG&val) -{ - release_(); - type_ = BITS; - bits_ = val; - return *this; -} - -vvm_calltf_parm& vvm_calltf_parm::operator= (const vvm_calltf_parm&that) -{ - if (this == &that) - return *this; - - release_(); - switch (that.type_) { - case NONE: - case TIME: - type_ = that.type_; - break; - case ULONG: - type_ = ULONG; - ulong_ = that.ulong_; - break; - case STRING: - type_ = STRING; - new (string_) string (that.as_string()); - break; - case BITS: - type_ = BITS; - bits_ = that.bits_; - break; - } - return *this; -} - -vvm_calltf_parm::~vvm_calltf_parm() -{ - release_(); -} - -extern void Sdisplay(vvm_simulation*sim, const string&name, - unsigned nparms, class vvm_calltf_parm*parms); -extern void Smonitor(vvm_simulation*sim, const string&name, - unsigned nparms, class vvm_calltf_parm*parms); - -static void Sfinish(vvm_simulation*sim, const string&, - unsigned, class vvm_calltf_parm*) -{ - sim->s_finish(); -} - -static struct { - const string name; - void (*func)(vvm_simulation*, const string&, - unsigned, class vvm_calltf_parm*); -} sys_table[] = { - { "$display", &Sdisplay }, - { "$finish", &Sfinish }, - { "$monitor", &Smonitor }, - { "", 0 } +/* + * Keep a list of vpi_systf_data structures. This list is searched + * forward whenever a function is invoked by name, and items are + * pushed in front of the list whenever they are registered. This + * allows entries to override older entries. + */ +struct systf_entry { + struct systf_entry* next; + s_vpi_systf_data systf_data; }; -void vvm_calltask(vvm_simulation*sim, const string&fname, - unsigned nparms, class vvm_calltf_parm*parms) +static struct systf_entry*systf_list = 0; + +extern "C" void vpi_register_systf(const struct t_vpi_systf_data*systf) { + struct systf_entry*cur = new struct systf_entry; + cur->systf_data = *systf; + cur->systf_data.tfname = strdup(systf->tfname); + cur->next = systf_list; + systf_list = cur; +} - for (unsigned idx = 0 ; sys_table[idx].func ; idx += 1) - if (fname == sys_table[idx].name) { - sys_table[idx].func(sim, fname, nparms, parms); - return; - } +extern "C" void vpi_printf(const char*fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} - cout << "Call " << fname << "("; - for (unsigned idx = 0 ; idx < nparms ; idx += 1) { - if (idx > 0) cout << ", "; - switch (parms[idx].type()) { - case vvm_calltf_parm::NONE: - break; - case vvm_calltf_parm::ULONG: - cout << parms[idx].as_ulong(); - break; - case vvm_calltf_parm::STRING: - cout << "\"" << parms[idx].as_string() << "\""; - break; - case vvm_calltf_parm::BITS: - cout << *parms[idx].as_bits(); - break; - case vvm_calltf_parm::TIME: - break; - } +extern "C" void tf_dofinish() +{ + vpi_sim->s_finish(); +} + +extern "C" vpiHandle vpi_handle(int type, vpiHandle ref) +{ + switch (type) { + case vpiSysTfCall: + return vvm_vpi_cur_task; + + default: + return 0; } - cout << ")" << endl; +} + +extern "C" vpiHandle vpi_iterate(int type, vpiHandle ref) +{ + vpiHandle res = (vpiHandle)calloc(1, sizeof (struct __vpiHandle)); + res->type = type; + res->referent = ref; + res->val.unum = 0; + + return res; +} + +extern "C" vpiHandle vpi_scan(vpiHandle ref) +{ + assert(ref->type == vpiArgument); + if (ref->val.unum >= ref->referent->narguments) + return 0; + + return ref->referent->arguments[ref->val.unum++]; +} + +extern "C" int vpi_get(int property, vpiHandle ref) +{ + if (property == vpiType) + return ref->type; + + if (ref->get_ == 0) + return -1; + + return (ref->get_)(property, ref); +} + +extern "C" char* vpi_get_str(int property, vpiHandle ref) +{ + if (property == vpiFullName) + return ref->full_name; + + if (ref->get_str_ == 0) + return 0; + + return (ref->get_str_)(property, ref); + + switch (property) { + case vpiName: + return ref->full_name; + } + return 0; +} + +extern "C" void vpi_get_value(vpiHandle expr, s_vpi_value*vp) +{ + if (expr->get_value_) { + expr->get_value_(expr, vp); + return; + } + + vp->format = vpiSuppressVal; +} + +extern "C" int vpi_free_object(vpiHandle ref) +{ + free(ref); + return 0; } +/* + * This function is a get_value_ method of a vpiHandle, that supports + * reading bits as a string. + */ +static void get_value_bits(vpiHandle ref, s_vpi_value*vp) +{ + static char buff[1024]; + char*cp; + unsigned width, bytes; + unsigned val; + assert(ref->val.bits); + width = ref->val.bits->get_width(); + cp = buff; + + switch (vp->format) { + case vpiObjTypeVal: + case vpiBinStrVal: + for (unsigned idx = 0 ; idx < width ; idx += 1) + switch (ref->val.bits->get_bit(width-idx-1)) { + case V0: + *cp++ = '0'; + break; + case V1: + *cp++ = '1'; + break; + case Vx: + *cp++ = 'x'; + break; + case Vz: + *cp++ = 'z'; + break; + } + vp->format = vpiBinStrVal; + break; + + case vpiDecStrVal: + val = 0; + for (unsigned idx = 0 ; idx < width ; idx += 1) { + val *= 2; + switch (ref->val.bits->get_bit(width-idx-1)) { + case V0: + case Vx: + case Vz: + break; + case V1: + val += 1; + break; + } + } + sprintf(cp, "%u", val); + cp += strlen(cp); + break; + + case vpiOctStrVal: + bytes = width%3; + if (bytes) { + *cp++ = '?'; + } + for (unsigned idx = bytes ; idx < width ; idx += 3) { + unsigned x = 0; + unsigned z = 0; + unsigned v = 0; + for (unsigned i = idx ; i < idx+3 ; i += 1) { + v *= 2; + switch (ref->val.bits->get_bit(width-idx-i-1)) { + case V0: + break; + case V1: + v += 1; + break; + case Vx: + x += 1; + break; + case Vz: + z += 1; + break; + } + } + if (x == 3) + *cp++ = 'x'; + else if (x > 0) + *cp++ = 'X'; + else if (z == 3) + *cp++ = 'z'; + else if (z > 0) + *cp++ = 'Z'; + else + *cp++ = "01234567"[v]; + } + break; + + case vpiHexStrVal: + bytes = width%4; + if (bytes) { + *cp++ = '?'; + } + for (unsigned idx = bytes ; idx < width ; idx += 4) { + unsigned x = 0; + unsigned z = 0; + unsigned v = 0; + for (unsigned i = idx ; i < idx+4 ; i += 1) { + v *= 2; + switch (ref->val.bits->get_bit(width-idx-i-1)) { + case V0: + break; + case V1: + v += 1; + break; + case Vx: + x += 1; + break; + case Vz: + z += 1; + break; + } + } + if (x == 4) + *cp++ = 'x'; + else if (x > 0) + *cp++ = 'X'; + else if (z == 4) + *cp++ = 'z'; + else if (z > 0) + *cp++ = 'Z'; + else + *cp++ = "01234567abcdef"[v]; + } + break; + + default: + *cp++ = '('; + *cp++ = '?'; + *cp++ = ')'; + break; + } + + *cp++ = 0; + vp->value.str = buff; +} + +static void get_value_strconst(vpiHandle ref, s_vpi_value*vp) +{ + switch (vp->format) { + case vpiObjTypeVal: + case vpiStringVal: + vp->value.str = ref->full_name; + vp->format = vpiStringVal; + break; + + default: + vp->format = vpiSuppressVal; + break; + } +} + +static void get_value_timevar(vpiHandle ref, s_vpi_value*vp) +{ + static char buf[128]; + switch (vp->format) { + case vpiObjTypeVal: + case vpiTimeVal: + vp->value.time = &ref->val.time; + vp->format = vpiTimeVal; + break; + + case vpiDecStrVal: + sprintf(buf, "%u", ref->val.time.low); + vp->value.str = buf; + break; + + default: + vp->format = vpiSuppressVal; + vp->value.str = 0; + break; + } +} + +/* + * The load_vpi_module function attempts to locate and load the named + * vpi module and call the included startup routines. This is invoked + * by the generated C++ code to load all the modules that the + * simulation requires. + * + * If there is a '/' character in the name, or there is no + * VPI_MODULE_PATH, the the name is usd as is. No path is searched for + * the module. + * + * If there is a VPI_MODULE_PATH and there is no '/' in the name, the + * VPI_MODULE_PATH is taken as a ':' separated list of directory + * names. Each directory is searched for a module with the right name + * that will link in. The current working directory is not implicitly + * tried. If you wish '.' be in th search path, include it. + */ +typedef void (*vlog_startup_routines_t)(void); + +void vvm_load_vpi_module(const char*name) +{ + void*mod = 0; + const char*path = getenv("VPI_MODULE_PATH"); + + if ((path == 0) || (strchr(name, '/'))) { + mod = dlopen(name, RTLD_NOW); + if (mod == 0) { + cerr << name << ": " << dlerror() << endl; + return; + } + + } else { + const char*cur = path; + const char*ep; + for (cur = path ; cur ; cur = ep? ep+1 : 0) { + char dest[MAX_PATHLEN+1]; + + ep = strchr(cur, ':'); + size_t n = ep? ep-cur : strlen(cur); + if ((n + strlen(name) + 2) > sizeof dest) + continue; + + strncpy(dest, cur, n); + dest[n] = '/'; + dest[n+1] = 0; + strcat(dest, name); + + mod = dlopen(dest, RTLD_NOW); + if (mod) break; + } + } + + if (mod == 0) { + cerr << dlerror() << endl; + return; + } + + void*table = dlsym(mod, "vlog_startup_routines"); + vlog_startup_routines_t*routines = (vlog_startup_routines_t*)table; + if (routines == 0) { + cerr << name << ": Unable to locate the vlog_startup_routines" + " table." << endl; + dlclose(mod); + return; + } + + for (unsigned idx = 0 ; routines[idx] ; idx += 1) + (routines[idx])(); +} + +void vvm_make_vpi_parm(vpiHandle ref, const char*val) +{ + memset(ref, 0, sizeof*ref); + ref->type = vpiConstant; + ref->subtype = vpiStringConst; + ref->full_name = const_cast(val); + ref->get_value_ = &get_value_strconst; +} + +void vvm_make_vpi_parm(vpiHandle ref, vvm_bits_t*val) +{ + memset(ref, 0, sizeof*ref); + ref->type = vpiConstant; + ref->subtype = vpiBinaryConst; + ref->full_name = ""; + ref->val.bits = val; + ref->get_value_ = &get_value_bits; +} + +void vvm_init_vpi_handle(vpiHandle ref, vvm_bits_t*bits, vvm_monitor_t*mon) +{ + memset(ref, 0, sizeof*ref); + ref->type = vpiReg; + ref->full_name = const_cast(mon->name()); + ref->val.bits = bits; + ref->get_value_ = &get_value_bits; +} + +void vvm_init_vpi_timevar(vpiHandle ref, const char*name) +{ + memset(ref, 0, sizeof*ref); + ref->type = vpiTimeVar; + ref->full_name = const_cast(name); + ref->get_value_ = &get_value_timevar; +} + +void vvm_make_vpi_parm(vpiHandle ref) +{ + memset(ref, 0, sizeof*ref); + ref->type = 0; +} + +void vvm_calltask(vvm_simulation*sim, const string&fname, + unsigned nparms, vpiHandle*parms) +{ + vpi_sim = sim; + + struct __vpiHandle cur_task; + cur_task.type = vpiSysTaskCall; + cur_task.full_name = 0; + cur_task.referent = 0; + cur_task.arguments = parms; + cur_task.narguments = nparms; + + vvm_vpi_cur_task = &cur_task; + + /* Look for a systf function to invoke. */ + for (systf_entry*idx = systf_list ; idx ; idx = idx->next) + if (fname == idx->systf_data.tfname) { + cur_task.full_name = idx->systf_data.tfname; + idx->systf_data.calltf(idx->systf_data.user_data); + return; + } + + + /* Finally, if nothing is found then something is not + right. Print out the function name all the parameters + passed, so that someone can deal with it. */ + cout << "Call " << fname << endl; +} + + /* * $Log: vvm_calltf.cc,v $ + * Revision 1.3 1999/08/15 01:23:56 steve + * Convert vvm to implement system tasks with vpi. + * * Revision 1.2 1999/05/31 15:46:36 steve * Handle time in more places. * diff --git a/vvm/vvm_calltf.h b/vvm/vvm_calltf.h index a09375e0e..e7979144c 100644 --- a/vvm/vvm_calltf.h +++ b/vvm/vvm_calltf.h @@ -19,69 +19,51 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vvm_calltf.h,v 1.1 1998/11/09 23:44:11 steve Exp $" +#ident "$Id: vvm_calltf.h,v 1.2 1999/08/15 01:23:56 steve Exp $" #endif # include "vvm.h" # include +typedef struct __vpiHandle*vpiHandle; + +/* + * This function loads a vpi module by name. + */ +extern void vvm_load_vpi_module(const char*path); + + +/* + * The vvm_init_vpi_handle functions initialize statis VPI handles + * that may be used many places within the program. + */ +extern void vvm_init_vpi_handle(vpiHandle, vvm_bits_t*, vvm_monitor_t*); +extern void vvm_init_vpi_timevar(vpiHandle, const char*name); + +/* + * The vvm_make_vpi_parm functions initialize the vpiHandles to + * represent objects suitable for use as vvm_calltask parameters. + */ +extern void vvm_make_vpi_parm(vpiHandle ref, const char*val); +extern void vvm_make_vpi_parm(vpiHandle ref, vvm_bits_t*val); +extern void vvm_make_vpi_parm(vpiHandle ref); + /* * The vvm environment supports external calls to C++ by * vvm_calltask. The code generator generates calls to vvm_calltask * that corresponds to the system call in the Verilog source. The - * vvm_calltask in turn locates the function (by name) and calls the - * C++ code that implements the task. - * - * The parameters of the task are implemented as an array of - * vvm_calltf_parm objects. Each object represents a paramter from the - * source. + * vvm_calltask in turn locates the vpi implementation (by name) and + * calls the VPI that implements the task. */ -class vvm_calltf_parm { - - public: - enum TYPE { NONE, ULONG, STRING, BITS, TIME }; - - vvm_calltf_parm(); - explicit vvm_calltf_parm(TYPE); - vvm_calltf_parm(const vvm_calltf_parm&); - ~vvm_calltf_parm(); - - TYPE type() const { return type_; } - - struct SIG { - vvm_bits_t*bits; - vvm_monitor_t*mon; - }; - - unsigned long as_ulong() const { return ulong_; } - string as_string() const { return *(string*)string_; } - vvm_bits_t* as_bits() const { return bits_.bits; } - vvm_monitor_t* as_mon() const { return bits_.mon; } - - const string& sig_name() const { return bits_.mon->name(); } - - vvm_calltf_parm& operator= (unsigned long); - vvm_calltf_parm& operator= (const string&); - vvm_calltf_parm& operator= (const SIG&); - vvm_calltf_parm& operator= (const vvm_calltf_parm&); - - private: - TYPE type_; - - union { - unsigned long ulong_; - char string_[sizeof(string)]; - SIG bits_; - }; - - void release_(); -}; extern void vvm_calltask(vvm_simulation*sim, const string&name, - unsigned nparms, class vvm_calltf_parm*parms); + unsigned nparms, vpiHandle*parms); /* * $Log: vvm_calltf.h,v $ + * Revision 1.2 1999/08/15 01:23:56 steve + * Convert vvm to implement system tasks with vpi. + * * Revision 1.1 1998/11/09 23:44:11 steve * Add vvm library. * diff --git a/vvm/vvm_monitor.cc b/vvm/vvm_monitor.cc index 179d34440..9d9234e42 100644 --- a/vvm/vvm_monitor.cc +++ b/vvm/vvm_monitor.cc @@ -17,13 +17,13 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vvm_monitor.cc,v 1.1 1998/11/09 23:44:11 steve Exp $" +#ident "$Id: vvm_monitor.cc,v 1.2 1999/08/15 01:23:56 steve Exp $" #endif # include "vvm.h" -vvm_monitor_t::vvm_monitor_t(const string&n) +vvm_monitor_t::vvm_monitor_t(const char*n) : name_(n) { } @@ -31,6 +31,9 @@ vvm_monitor_t::vvm_monitor_t(const string&n) /* * $Log: vvm_monitor.cc,v $ + * Revision 1.2 1999/08/15 01:23:56 steve + * Convert vvm to implement system tasks with vpi. + * * Revision 1.1 1998/11/09 23:44:11 steve * Add vvm library. *