diff --git a/Makefile.in b/Makefile.in index e64bdfdc9..43ccd0d2f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -16,7 +16,7 @@ # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # -#ident "$Id: Makefile.in,v 1.131 2002/08/04 19:13:16 steve Exp $" +#ident "$Id: Makefile.in,v 1.132 2002/08/10 22:27:13 steve Exp $" # # SHELL = /bin/sh @@ -67,12 +67,8 @@ ifeq ('@HAVE_IPAL@','yes') TARGETS += tgt-pal endif -ifeq (@ENABLE_VVM@,yes) -SUB_VVM = vvm -endif - all: ivl@EXEEXT@ libvpi.a - for dir in $(SUBDIRS) $(SUB_VVM); do (cd $$dir ; $(MAKE) all); done + for dir in $(SUBDIRS) ; do (cd $$dir ; $(MAKE) all); done cd vpi ; $(MAKE) all cd ivlpp ; $(MAKE) all cd driver ; $(MAKE) VERSION=$(VERSION) all @@ -105,13 +101,12 @@ clean: cd ivlpp ; $(MAKE) clean cd tgt-verilog ; $(MAKE) clean cd tgt-stub ; $(MAKE) clean - for dir in $(SUBDIRS) $(SUB_VVM); do (cd $$dir ; $(MAKE) clean); done + for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) clean); done for tgt in $(TARGETS); do (cd $$tgt ; $(MAKE) clean); done distclean: clean - for dir in $(SUBDIRS) $(SUB_VVM); do (cd $$dir ; $(MAKE) distclean); done + for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) distclean); done for tgt in $(TARGETS); do (cd $$tgt ; $(MAKE) distclean); done - rm -f vvm/Makefile rm -f vpi/Makefile rm -f ivlpp/Makefile rm -f driver/Makefile @@ -119,11 +114,7 @@ distclean: clean rm -f Makefile rm -f tgt-pal/Makefile tgt-stub/Makefile tgt-verilog/Makefile -ifeq (@ENABLE_VVM@,yes) -TT_VVM = mangle.o t-vvm.o -endif - -TT = t-dll.o t-dll-api.o t-dll-expr.o t-dll-proc.o $(TT_VVM) t-xnf.o +TT = t-dll.o t-dll-api.o t-dll-expr.o t-dll-proc.o t-xnf.o FF = cprop.o nodangle.o synth.o synth2.o syn-rules.o xnfio.o O = main.o async.o design_dump.o dup_expr.o elaborate.o elab_expr.o \ @@ -234,7 +225,7 @@ install: all installdirs $(libdir)/ivl/ivl@EXEEXT@ $(libdir)/ivl/iverilog.conf $ cd vpi ; $(MAKE) install cd ivlpp ; $(MAKE) install cd driver ; $(MAKE) install - for tgt in $(SUBDIRS) $(SUB_VVM); do (cd $$tgt ; $(MAKE) install); done + for tgt in $(SUBDIRS); do (cd $$tgt ; $(MAKE) install); done for tgt in $(TARGETS); do (cd $$tgt ; $(MAKE) install); done $(bindir)/iverilog-vpi: ./iverilog-vpi @@ -304,7 +295,7 @@ uninstall: cd driver ; $(MAKE) uninstall cd vpi ; $(MAKE) uninstall cd ivlpp ; $(MAKE) uninstall - for tgt in $(SUBDIRS) $(SUB_VVM); do (cd $$tgt ; $(MAKE) uninstall); done + for tgt in $(SUBDIRS); do (cd $$tgt ; $(MAKE) uninstall); done for tgt in $(TARGETS); do (cd $$tgt ; $(MAKE) uninstall); done diff --git a/configure.in b/configure.in index 99073bfaf..52af6c369 100644 --- a/configure.in +++ b/configure.in @@ -2,16 +2,6 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(netlist.h) AC_CONFIG_HEADER(config.h) -AC_ARG_ENABLE(vvm, vvm target -- the obsolete vvm code generator, - AC_DEFINE(ENABLE_VVM)) -if test "${enable_vvm+set}" = set -then - ENABLE_VVM=yes -else - ENABLE_VVM=no -fi -AC_SUBST(ENABLE_VVM) - dnl Checks for programs. AC_PROG_CC AC_PROG_CXX @@ -86,7 +76,7 @@ AC_CANONICAL_HOST ####################### -## test for underscores. The vpi module loader in vvm needs to know this +## test for underscores. The vpi module loader needs to know this ## in order to know the name of the start symbol for the .vpi module. ####################### @@ -247,4 +237,4 @@ AC_MSG_RESULT($shared) AC_CONFIG_SUBDIRS(vpip vvp tgt-vvp tgt-fpga libveriuser) -AC_OUTPUT(Makefile vpi/Makefile ivlpp/Makefile vvm/Makefile driver/Makefile tgt-null/Makefile tgt-stub/Makefile tgt-verilog/Makefile tgt-pal/Makefile) +AC_OUTPUT(Makefile vpi/Makefile ivlpp/Makefile driver/Makefile tgt-null/Makefile tgt-stub/Makefile tgt-verilog/Makefile tgt-pal/Makefile) diff --git a/driver/main.c b/driver/main.c index 52e753156..7f13544b0 100644 --- a/driver/main.c +++ b/driver/main.c @@ -16,7 +16,7 @@ * 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: main.c,v 1.44 2002/07/15 00:33:50 steve Exp $" +#ident "$Id: main.c,v 1.45 2002/08/10 22:27:13 steve Exp $" # include "config.h" @@ -217,97 +217,6 @@ static int t_default(char*cmd, unsigned ncmd) return 0; } -/* - * This function handles the vvm target. After preprocessing, run the - * ivl translator to get C++, then run g++ to make an executable - * program out of that. - */ -static int t_vvm(char*cmd, unsigned ncmd) -{ - int rc; - - const char*pattern = lookup_pattern(""); - if (pattern == 0) { - fprintf(stderr, "No such target: %s\n", targ); - return -1; - } - - tmp[0] = ' '; - tmp[1] = '|'; - tmp[2] = ' '; - rc = build_string(tmp+3, sizeof tmp - 3, pattern); - cmd = realloc(cmd, ncmd+3+rc+1); - -#ifdef __MINGW32__ - { - char *t; - for (t = tmp; *t; t++) - { - if (*t == '/') *t = '\\'; - } - } -#endif - - - strcpy(cmd+ncmd, tmp); - - - if (verbose_flag) - printf("translate: %s\n", cmd); - - rc = system(cmd); - remove(source_path); - if (rc != 0) { - if (WIFEXITED(rc)) { - fprintf(stderr, "errors translating Verilog program.\n"); - return WEXITSTATUS(rc); - } else { - fprintf(stderr, "Command signaled: %s\n", cmd); - return -1; - } - } - -#if defined(__MINGW32__) - /* In the Windows world, the path to headers and libraries - for vvm is relative the ivl_root, which is in something like: - - d:\iverilog\lib\ivl <-- ivl_root - d:\iverilog\include <-- vvm headers - d:\iverilog\lib <-- vvm libraries - - So we make up all the ugly references that are the g++ - command line to compile a .cc file generated by vvm. */ - sprintf(tmp, "%s " RDYNAMIC " -s -fno-exceptions -o %s " - "-I%s\\..\\..\\include -L%s\\.. %s.cc -lvvm -lvpip %s", - CXX, opath, ivl_root, ivl_root, opath, DLLIB); -#else - /* In the UNIX universe, life is easy. The configure script - has figured everything out and wrote it into the Makefile, - which passes it on as the IVL_INC and IVL_LIB defines. */ - sprintf(tmp, "%s " RDYNAMIC " -s -fno-exceptions -o %s -I%s " - "-L%s %s.cc -lvvm -lvpip %s", CXX, opath, IVL_INC, - IVL_LIB, opath, DLLIB); -#endif - if (verbose_flag) - printf("compile: %s\n", tmp); - - rc = system(tmp); - if (rc != 0) { - if (WIFEXITED(rc)) { - fprintf(stderr, "errors compiling translated program.\n"); - return WEXITSTATUS(rc); - } else { - fprintf(stderr, "Command signaled: %s\n", tmp); - return -1; - } - } - - sprintf(tmp, "%s.cc", opath); - unlink(tmp); - - return 0; -} - static void process_warning_switch(const char*name) { @@ -745,17 +654,16 @@ int main(int argc, char **argv) /* Done writing to the iconfig file. Close it now. */ fclose(iconfig_file); - if (strcmp(targ,"vvm") == 0) - return t_vvm(cmd, ncmd); - else { - return t_default(cmd, ncmd); - } + return t_default(cmd, ncmd); return 0; } /* * $Log: main.c,v $ + * Revision 1.45 2002/08/10 22:27:13 steve + * Kill links to vvm. + * * Revision 1.44 2002/07/15 00:33:50 steve * Improve temporary file name guess. * diff --git a/iverilog.conf b/iverilog.conf index dd64dd21a..fa340bceb 100644 --- a/iverilog.conf +++ b/iverilog.conf @@ -77,16 +77,6 @@ [-tvvp] %B/ivl %[v-v] -C%C %g %W %s %[M-M%M] %[N-N%N] %[T-T%T] -tdll -fDLL=%B/vvp.tgt -fVVP_EXECUTABLE=%B/../../bin/vvp -Fcprop -Fnodangle %f %m -o%o -- - -# -- -# The vvm target uses the string to take the preprocessed code from -# standard input, compile it with the vvm code generator and write the -# result to %o.cc. The driver assumes this when invoking the C++ compiler -# on the result. - -[-tvvm] -%B/ivl %[v-v] -C%C %g %W %s %[N-N%N] %[T-T%T] -tvvm -Fcprop -Fnodangle -fVPI_MODULE_PATH=%B %f %m -o%o.cc -- - - - # This is the XNF code generator. [-txnf] diff --git a/mangle.cc b/mangle.cc deleted file mode 100644 index a49ad3ac9..000000000 --- a/mangle.cc +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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 - * 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: mangle.cc,v 1.7 2001/07/25 03:10:49 steve Exp $" -#endif - -# include "config.h" - -# include "target.h" -# include - -string mangle(const string&str) -{ - if (str[0] == '$') - return str; - - ostrstream res; - string tmp = str; - - while (tmp.length() > 0) { - size_t pos = tmp.find_first_of(".<\\[]/"); - if (pos > tmp.length()) - pos = tmp.length(); - - res << "S" << pos << tmp.substr(0, pos); - if (pos >= tmp.length()) - break; - - tmp = tmp.substr(pos); - switch (tmp[0]) { - case '.': - tmp = tmp.substr(1); - break; - case '<': - tmp = tmp.substr(1); - res << "_"; - while (tmp[0] != '>') { - res << tmp[0]; - tmp = tmp.substr(1); - } - tmp = tmp.substr(1); - res << "_"; - break; - case '\\': - res << "$$"; - tmp = tmp.substr(1); - break; - case '/': - res << "$sl$"; - tmp = tmp.substr(1); - break; - case '[': - res << "$lb$"; - tmp = tmp.substr(1); - break; - case ']': - res << "$rb$"; - tmp = tmp.substr(1); - break; - } - } - res << ends; - return res.str(); -} - -string stresc(const string&str) -{ - ostrstream res; - string tmp = str; - - while (tmp.length() > 0) { - size_t pos = tmp.find_first_of("\\"); - if (pos > tmp.length()) - pos = tmp.length(); - - res << tmp.substr(0, pos); - if (pos >= tmp.length()) - break; - - tmp = tmp.substr(pos); - switch (tmp[0]) { - case '\\': - res << "\\\\"; - tmp = tmp.substr(1); - break; - } - } - res << ends; - return res.str(); -} - -/* - * $Log: mangle.cc,v $ - * Revision 1.7 2001/07/25 03:10:49 steve - * Create a config.h.in file to hold all the config - * junk, and support gcc 3.0. (Stephan Boettcher) - * - * Revision 1.6 2001/04/22 23:09:46 steve - * More UDP consolidation from Stephan Boettcher. - * - * Revision 1.5 2000/12/11 01:06:24 steve - * Mangle [] characters. (PR#67) - * - * Revision 1.4 2000/10/25 23:21:37 steve - * mangle the backslash to a dollar. - * - * Revision 1.3 2000/02/23 02:56:54 steve - * Macintosh compilers do not support ident. - * - * Revision 1.2 1999/02/15 05:52:50 steve - * Mangle that handles device instance numbers. - * - * Revision 1.1 1998/11/03 23:29:00 steve - * Introduce verilog to CVS. - * - */ - diff --git a/t-vvm.cc b/t-vvm.cc deleted file mode 100644 index 7901210c5..000000000 --- a/t-vvm.cc +++ /dev/null @@ -1,3866 +0,0 @@ -/* - * Copyright (c) 1998-2000 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: t-vvm.cc,v 1.214 2002/01/19 19:02:08 steve Exp $" -#endif - -# include "config.h" - -# include -# include -# include -# include -# include -# include -# include -# include -# include "netlist.h" -# include "netmisc.h" -# include "target.h" - - // Comparison for use in sorting algorithms. - -struct less_verinum { - bool operator() (const verinum&left, const verinum&right) const - { return left.is_before(right); } -}; - -/* - * The generated code puts constants in behavioral expressions into a - * bit number table. Every place in the code where a vvm_bits_t is - * created, it references an offset and size into this table. the - * table is collected as numbers are encountered, overlapping values - * as much as possible so that the number of output bits is reduced. - */ -class NumberTable { - - public: - NumberTable(); - ~NumberTable(); - - unsigned position(const verinum&val); - unsigned count() const { return nbits_; } - verinum::V bit(unsigned idx) const { return bits_[idx]; } - - private: - verinum::V*bits_; - unsigned nbits_; -}; - -NumberTable::NumberTable() -{ - bits_ = 0; - nbits_ = 0; -} - -NumberTable::~NumberTable() -{ - if (bits_) delete[]bits_; -} - -unsigned NumberTable::position(const verinum&val) -{ - if (bits_ == 0) { - nbits_ = val.len(); - bits_ = new verinum::V[val.len()]; - for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) - bits_[idx] = val.get(idx); - - return 0; - } - - /* Look for a complete match. If I find one, then return the - index of the start and all done. */ - for (unsigned idx = 0 ; (idx+val.len()) < nbits_ ; idx += 1) { - - bool match_flag = true; - for (unsigned bit = 0 ; bit < val.len() ; bit += 1) - if (bits_[idx+bit] != val.get(bit)) { - match_flag = false; - break; - } - - if (match_flag) - return idx; - } - - unsigned tail_match = 0; - for (unsigned idx = 1; (idx < val.len()) && (idx < nbits_) ; idx += 1) { - - bool match_flag = true; - for (unsigned bit = 0 ; bit < idx ; bit += 1) - if (bits_[nbits_-idx+bit] != val.get(bit)) { - match_flag = false; - break; - } - - if (match_flag) - tail_match = idx; - } - - unsigned ntmp = nbits_+val.len()-tail_match; - verinum::V*tmp = new verinum::V[ntmp]; - for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) - tmp[idx] = bits_[idx]; - - for (unsigned idx = nbits_ ; idx < ntmp ; idx += 1) - tmp[idx] = val.get(idx-nbits_+tail_match); - - unsigned rc = nbits_ - tail_match; - - delete[]bits_; - bits_ = tmp; - nbits_ = ntmp; - - return rc; -} - - -static string make_temp() -{ - static unsigned counter = 0; - ostrstream str; - str << "TMP" << counter << ends; - counter += 1; - return str.str(); -} - -class target_vvm : public target_t { - - public: - target_vvm(); - ~target_vvm(); - - virtual bool start_design(const Design*); - virtual void scope(const NetScope*); - virtual void event(const NetEvent*); - virtual void signal(const NetNet*); - virtual void memory(const NetMemory*); - virtual void task_def(const NetScope*); - virtual void func_def(const NetScope*); - - virtual void lpm_add_sub(const NetAddSub*); - virtual void lpm_clshift(const NetCLShift*); - virtual void lpm_compare(const NetCompare*); - virtual void lpm_divide(const NetDivide*); - virtual void lpm_modulo(const NetModulo*); - virtual void lpm_ff(const NetFF*); - virtual void lpm_mult(const NetMult*); - virtual void lpm_mux(const NetMux*); - virtual void lpm_ram_dq(const NetRamDq*); - - virtual void logic(const NetLogic*); - virtual bool bufz(const NetBUFZ*); - virtual void udp(const NetUDP*); - virtual void net_case_cmp(const NetCaseCmp*); - virtual bool net_cassign(const NetCAssign*); - virtual bool net_const(const NetConst*); - virtual bool net_force(const NetForce*); - virtual void net_probe(const NetEvProbe*); - virtual bool process(const NetProcTop*); - virtual void proc_assign(const NetAssign*); - void proc_assign_rval(const NetAssign_*, const NetEConst*, - unsigned off); - void proc_assign_rval(const NetAssign_*, const string&, - unsigned wid, unsigned off); - virtual void proc_assign_mem(const NetAssignMem*); - virtual void proc_assign_nb(const NetAssignNB*); - void proc_assign_nb_rval(const NetAssign_*, const NetEConst*, - unsigned off); - void proc_assign_nb_rval(const NetAssign_*, const string&, - unsigned wid, unsigned off); - virtual void proc_assign_mem_nb(const NetAssignMemNB*); - virtual bool proc_block(const NetBlock*); - virtual void proc_case(const NetCase*net); - void proc_case_fun(ostream&os, const NetCase*net); - virtual bool proc_cassign(const NetCAssign*); - virtual bool proc_condit(const NetCondit*); - void proc_condit_fun(ostream&os, const NetCondit*); - virtual bool proc_deassign(const NetDeassign*); - virtual bool proc_delay(const NetPDelay*); - virtual bool proc_force(const NetForce*); - virtual void proc_forever(const NetForever*); - virtual bool proc_release(const NetRelease*); - virtual void proc_repeat(const NetRepeat*); - virtual void proc_stask(const NetSTask*); - virtual bool proc_trigger(const NetEvTrig*); - virtual void proc_utask( const NetUTask*); - virtual bool proc_wait( const NetEvWait*); - virtual void proc_while(const NetWhile*); - virtual int end_design(const Design*); - - void start_process(ostream&os, const NetProcTop*); - void end_process(ostream&os, const NetProcTop*); - - - NumberTable bits_table; - - ofstream out; - - // Method definitions go into this file. - char*defn_name; - ofstream defn; - - char*init_code_name; - ofstream init_code; - - char *start_code_name; - ofstream start_code; - - unsigned process_counter; - unsigned thread_step_; - - // String constants that are made into vpiHandles have their - // handle name mapped by this. - mapstring_constants; - unsigned string_counter; - - // Number constants accessed by vpiHandles are mapped by this. - mapnumber_constants; - unsigned number_counter; - - private: - void emit_init_value_(const Link&lnk, verinum::V val); - void emit_gate_outputfun_(const NetNode*, unsigned); - string defn_gate_outputfun_(ostream&os, const NetNode*, unsigned); - - // This is the name of the thread (process or task) that is - // being generated. - string thread_class_; - - // This flag is true if we are writing out a function - // definition. Thread steps are not available within - // functions, and certain constructs are handled - // differently. A flag is enough because function definitions - // cannot nest. - bool function_def_flag_; - - // These methods are use to help prefent duplicate printouts - // of things that may be scanned multiple times. - mapesignal_printed_flag; - mappevent_printed_flag; - - unsigned signal_bit_counter; - unsigned signal_counter; - - public: - mapnexus_wire_map; - unsigned nexus_wire_counter; - - unsigned selector_counter; -}; - -static const char*vvm_val_name(verinum::V val, - Link::strength_t drv0, - Link::strength_t drv1) -{ - switch (val) { - case verinum::V0: - switch (drv0) { - case Link::HIGHZ: - return "HiZ"; - case Link::WEAK: - return "We0"; - case Link::PULL: - return "Pu0"; - case Link::STRONG: - return "St0"; - case Link::SUPPLY: - return "Su0"; - } - break; - - case verinum::V1: - switch (drv1) { - case Link::HIGHZ: - return "HiZ"; - case Link::WEAK: - return "We1"; - case Link::PULL: - return "Pu1"; - case Link::STRONG: - return "St1"; - case Link::SUPPLY: - return "Su1"; - } - break; - - case verinum::Vx: - return "StX"; - - case verinum::Vz: - return "HiZ"; - } - - /* This should not happen! */ - return "?strength?"; -} - - -target_vvm::target_vvm() -: function_def_flag_(false), init_code_name(0) -{ -} - -target_vvm::~target_vvm() -{ - assert(function_def_flag_ == false); -} - -/* - * This class emits code for the rvalue of a procedural - * assignment. The expression is evaluated to fit the width - * specified. The result is a vvm_bitset_t or equivilent that can be - * used for reading values out. - */ -class vvm_proc_rval : public expr_scan_t { - - public: - explicit vvm_proc_rval(target_vvm*t) - : result(""), tgt_(t) { } - - string result; - - private: - target_vvm*tgt_; - - private: - virtual void expr_const(const NetEConst*); - virtual void expr_concat(const NetEConcat*); - virtual void expr_memory(const NetEMemory*mem); - virtual void expr_sfunc(const NetESFunc*); - virtual void expr_signal(const NetESignal*); - virtual void expr_subsignal(const NetEBitSel*sig); - virtual void expr_ternary(const NetETernary*); - virtual void expr_unary(const NetEUnary*); - virtual void expr_binary(const NetEBinary*); - virtual void expr_ufunc(const NetEUFunc*); -}; - -/* - * 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: - explicit vvm_parm_rval(target_vvm*t) - : result(""), tgt_(t) { } - - string result; - - private: - virtual void expr_binary(const NetEBinary*); - virtual void expr_concat(const NetEConcat*); - virtual void expr_const(const NetEConst*); - virtual void expr_memory(const NetEMemory*); - virtual void expr_scope(const NetEScope*); - virtual void expr_sfunc(const NetESFunc*); - virtual void expr_signal(const NetESignal*); - virtual void expr_ufunc(const NetEUFunc*); - virtual void expr_unary(const NetEUnary*); - - private: - target_vvm*tgt_; - - void expr_default_(const NetExpr*); -}; - -/* - * Handle the concatenation operator in a procedural r-value - * expression. Evaluate the concatenation into a temporary variable - * with the right width, and return the name of that temporary as the - * symbol that the context can use. - */ -void vvm_proc_rval::expr_concat(const NetEConcat*expr) -{ - assert(expr->repeat() > 0); - string tname = make_temp(); - - tgt_->defn << " vpip_bit_t " << tname << "_bits[" - << expr->expr_width() << "];" << endl; - tgt_->defn << " vvm_bitset_t " << tname << "(" << tname << "_bits, " - << expr->expr_width() << ");" << endl; - - unsigned pos = 0; - for (unsigned rept = 0 ; rept < expr->repeat() ; rept += 1) - for (unsigned idx = 0 ; idx < expr->nparms() ; idx += 1) { - - NetExpr*pp = expr->parm(expr->nparms() - idx - 1); - pp->expr_scan(this); - - for (unsigned bit = 0 ; bit < pp->expr_width() ; bit += 1) { - tgt_->defn << " " << tname << "[" << pos - <<"] = " << result << "[" << bit << "];" - << endl; - pos+= 1; - } - assert(pos <= expr->expr_width()); - } - - /* Check that the positions came out to the right number of - bits. */ - if (pos != expr->expr_width()) { - tgt_->defn << "#error \"" << expr->get_line() << ": vvm error: " - << "width is " << expr->expr_width() << ", but I count " - << pos << " bits.\"" << endl; - } - - result = tname; -} - -void vvm_proc_rval::expr_const(const NetEConst*expr) -{ - string tname = make_temp(); - - unsigned number_off = tgt_->bits_table.position(expr->value()); - tgt_->defn << " vvm_bitset_t " << tname << "(const_bits_table+" - << number_off << ", " << expr->expr_width() << ");" << endl; - - result = tname; -} - -/* - * a bitset rval that is a memory reference. - */ -void vvm_proc_rval::expr_memory(const NetEMemory*mem) -{ - /* Make a temporary to hold the word from the memory. */ - const string tname = make_temp(); - tgt_->defn << " vpip_bit_t " << tname << "_bits[" - << mem->expr_width() << "];" << endl; - tgt_->defn << " vvm_bitset_t " << tname << "(" << tname << "_bits, " - << mem->expr_width() << ");" << endl; - - const string mname = mangle(mem->name()); - - /* Evaluate the memory index */ - assert(mem->index()); - mem->index()->expr_scan(this); - - - /* Write code to use the calculated index to get the word from - the memory into the temporary we created earlier. */ - - tgt_->defn << " " << mname << ".get_word(" - << result << ".as_unsigned(), " << tname << ");" << endl; - - result = tname; -} - -void vvm_proc_rval::expr_sfunc(const NetESFunc*fun) -{ - tgt_->defn << " // " << fun->get_line() << endl; - - const string retval = make_temp(); - const unsigned retwid = fun->expr_width(); - - /* Make any parameters that might be needed to be passed to - the function. */ - - const string parmtab = make_temp(); - if (fun->nparms() > 0) { - tgt_->defn << " vpiHandle " << parmtab - << "["<nparms()<<"];" << endl; - - for (unsigned idx = 0 ; idx < fun->nparms() ; idx += 1) { - vvm_parm_rval scan(tgt_); - fun->parm(idx)->expr_scan(&scan); - - tgt_->defn << " " << parmtab <<"["<defn << " vpip_bit_t " << retval << "_bits["<defn << " vpip_callfunc(\"" << stresc(fun->name()) << "\", " - << retwid << ", " << retval<<"_bits"; - - if (fun->nparms() == 0) - tgt_->defn << ", 0, 0"; - else - tgt_->defn << ", " << fun->nparms() << ", " << parmtab; - - tgt_->defn << ");" << endl; - - tgt_->defn << " vvm_bitset_t " << retval << "(" << retval<<"_bits, " - << retwid << ");" << endl; - - result = retval; -} - -/* - * A bitset reference to a signal can be done simply by referring to - * the same bits as the signal. We onlt need to copy the bits pointer - * from the vvm_signal_t object to get our reference. - */ -void vvm_proc_rval::expr_signal(const NetESignal*expr) -{ - const string tname = make_temp(); - - tgt_->defn << " vvm_bitset_t " << tname << "(" - << mangle(expr->name()) << ".bits+" << expr->lsi() - << ", " << expr->expr_width() << ");" << endl; - - result = tname; -} - -void vvm_proc_rval::expr_subsignal(const NetEBitSel*sig) -{ - string idx = make_temp(); - string val = make_temp(); - if (const NetEConst*cp = dynamic_cast(sig->index())) { - tgt_->defn << " const unsigned " << idx - << " = " << cp->value().as_ulong() << ";" << endl; - - } else { - sig->index()->expr_scan(this); - tgt_->defn << " const unsigned " << idx - << " = " << result << ".as_unsigned();" << endl; - } - - /* Get the bit select of a signal by making a vvm_bitset_t - object that refers to the single bit within the signal that - is of interest. */ - - tgt_->defn << " vvm_bitset_t " << val << "(" - << mangle(sig->name()) << ".bits+" << idx << ", 1);" << endl; - - result = val; -} - -void vvm_proc_rval::expr_ternary(const NetETernary*expr) -{ - expr->cond_expr()->expr_scan(this); - string cond_val = result; - expr->true_expr()->expr_scan(this); - string true_val = result; - expr->false_expr()->expr_scan(this); - string false_val = result; - - result = make_temp(); - - tgt_->defn << " vpip_bit_t " << result << "_bits[" - << expr->expr_width() << "];" << endl; - tgt_->defn << " vvm_bitset_t " << result << "(" << result<<"_bits, " - << expr->expr_width() << ");" << endl; - - tgt_->defn << " vvm_ternary(" << result << ", " << cond_val<<"[0], " - << true_val << ", " << false_val << ");" << endl; -} - -/* - * A function call is handled by assigning the parameters from the - * input expressions, then calling the function. After the function - * returns, copy the result into a temporary variable. - * - * Function calls are different from tasks in this regard--tasks had - * all this assigning arranged during elaboration. For functions, we - * must do it ourselves. - */ -void vvm_proc_rval::expr_ufunc(const NetEUFunc*expr) -{ - const NetFuncDef*def = expr->func()->func_def(); - const unsigned pcnt = expr->parm_count(); - assert(pcnt == (def->port_count()-1)); - - /* Scan the parameter expressions, and assign the values to - the parameter port register. */ - for (unsigned idx = 0 ; idx < pcnt ; idx += 1) { - assert(expr->parm(idx)); - - const NetNet*pnet = def->port(idx+1); - assert(pnet); - - expr->parm(idx)->expr_scan(this); - tgt_->defn << " // " << pnet->name() << " == " - << result << endl; - - unsigned wid = expr->parm(idx)->expr_width(); - if (pnet->pin_count() < wid) - wid = pnet->pin_count(); - - string bname = mangle(def->port(idx+1)->name()); - for (unsigned bit = 0 ; bit < wid ; bit += 1) { - - string nexus = pnet->pin(bit).nexus()->name(); - unsigned ncode = tgt_->nexus_wire_map[nexus]; - - tgt_->defn << " nexus_wire_table["<defn << " { bool flag;" << endl; - tgt_->defn << " flag = " << mangle(expr->name())<<"(thr);"<< endl; - tgt_->defn << " if (flag == false) return false;" << endl; - tgt_->defn << " }" << endl; - - /* rbits is the bits of the signal that hold the result. */ - string rbits = mangle(expr->result()->name()) + ".bits"; - - /* Make a temporary to hold the result... */ - result = make_temp(); - tgt_->defn << " vpip_bit_t " << result << "_bits[" - << expr->expr_width() << "];" << endl; - tgt_->defn << " vvm_bitset_t " << result << "(" - << result<<"_bits, " << expr->expr_width() << ");" << endl; - - /* Copy the result into the new temporary. */ - for (unsigned idx = 0 ; idx < expr->expr_width() ; idx += 1) - tgt_->defn << " " << result << "_bits[" << idx << "] = " - << rbits << "[" << idx << "];" << endl; - -} - -void vvm_proc_rval::expr_unary(const NetEUnary*expr) -{ - expr->expr()->expr_scan(this); - string tname = make_temp(); - - tgt_->defn << " vpip_bit_t " << tname << "_bits[" - << expr->expr_width() << "];" << endl; - tgt_->defn << " vvm_bitset_t " << tname << "(" << tname<<"_bits, " - << expr->expr_width() << ");" << endl; - - switch (expr->op()) { - case '~': - tgt_->defn << " vvm_unop_not(" << tname << "," << result << - ");" << endl; - break; - case '&': - tgt_->defn << " " << tname << "[0] " - "= vvm_unop_and("<defn << " " << tname << "[0] " - "= vvm_unop_or("<defn << " " << tname << "[0] " - "= vvm_unop_xor("<defn << " " << tname << "[0] " - "= vvm_unop_lnot("<defn << "vvm_unop_uminus(" <defn << " " << tname << "[0] " - "= vvm_unop_nand("<defn << " " << tname << "[0] " - "= vvm_unop_nor("<defn << " " << tname << "[0] " - "= vvm_unop_xnor("<op() << "'" - << endl; - tgt_->defn << "#error \"" << expr->get_line() << ": vvm error: " - "Unhandled unary op: " << *expr << "\"" << endl; - tgt_->defn << result << ";" << endl; - break; - } - - result = tname; -} - -void vvm_proc_rval::expr_binary(const NetEBinary*expr) -{ - expr->left()->expr_scan(this); - string lres = result; - - expr->right()->expr_scan(this); - string rres = result; - - assert(expr->expr_width() != 0); - - result = make_temp(); - tgt_->defn << " // " << expr->get_line() << ": expression node." << endl; - tgt_->defn << " vpip_bit_t " << result<<"_bits[" << expr->expr_width() - << "];" << endl; - tgt_->defn << " vvm_bitset_t " << result << "(" << result << "_bits, " - << expr->expr_width() << ");" << endl; - - switch (expr->op()) { - case 'a': // logical and (&&) - tgt_->defn << " " << result << "[0] = vvm_binop_land(" - << lres << "," << rres << ");" << endl; - break; - case 'E': // === - tgt_->defn << " " << result << "[0] = vvm_binop_eeq(" - << lres << "," << rres << ");" << endl; - break; - case 'e': // == - tgt_->defn << " " << result << "[0] = vvm_binop_eq(" - << lres << "," << rres << ");" << endl; - break; - case 'G': // >= - if (expr->left()->has_sign() && expr->right()->has_sign()) { - tgt_->defn << " " << result << "[0] = vvm_binop_ge_s(" - << lres << "," << rres << ");" << endl; - } else { - tgt_->defn << " " << result << "[0] = vvm_binop_ge(" - << lres << "," << rres << ");" << endl; - } - break; - case 'l': // left shift(<<) - tgt_->defn << " " << "vvm_binop_shiftl(" << result - << ", " << lres << "," << rres << ");" << endl; - break; - case 'L': // <= - if (expr->left()->has_sign() && expr->right()->has_sign()) { - tgt_->defn << " " << result << "[0] = vvm_binop_le_s(" - << lres << "," << rres << ");" << endl; - } else { - tgt_->defn << " " << result << "[0] = vvm_binop_le(" - << lres << "," << rres << ");" << endl; - } - break; - case 'N': // !== - tgt_->defn << " " << result << "[0] = vvm_binop_nee(" - << lres << "," << rres << ");" << endl; - break; - case 'n': - tgt_->defn << " " << result << "[0] = vvm_binop_ne(" - << lres << "," << rres << ");" << endl; - break; - case '<': - if (expr->left()->has_sign() && expr->right()->has_sign()) { - tgt_->defn << " " << result << "[0] = vvm_binop_lt_s(" - << lres << "," << rres << ");" << endl; - } else { - tgt_->defn << " " << result << "[0] = vvm_binop_lt(" - << lres << "," << rres << ");" << endl; - } - break; - case '>': - if (expr->left()->has_sign() && expr->right()->has_sign()) { - tgt_->defn << " " << result << "[0] = vvm_binop_gt_s(" - << lres << "," << rres << ");" << endl; - } else { - tgt_->defn << " " << result << "[0] = vvm_binop_gt(" - << lres << "," << rres << ");" << endl; - } - break; - case 'o': // logical or (||) - tgt_->defn << " " << result << "[0] = vvm_binop_lor(" - << lres << "," << rres << ");" << endl; - break; - case 'r': // right shift(>>) - tgt_->defn << " " << "vvm_binop_shiftr(" << result - << ", " << lres << "," << rres << ");" << endl; - break; - case 'X': - tgt_->defn << " " << "vvm_binop_xnor(" << result - << ", " << lres << "," << rres << ");" << endl; - break; - case '+': - tgt_->defn << " " << "vvm_binop_plus(" << result - << ", " << lres << "," << rres << ");" << endl; - break; - case '-': - tgt_->defn << " " << "vvm_binop_minus(" << result - << ", " << lres << "," << rres << ");" << endl; - break; - case '&': - tgt_->defn << " " << "vvm_binop_and(" << result - << ", " << lres << ", " << rres << ");" << endl; - break; - case '|': - tgt_->defn << " " << "vvm_binop_or(" << result - << ", " << lres << ", " << rres << ");" << endl; - break; - case '^': - tgt_->defn << " " << "vvm_binop_xor(" << result - << ", " << lres << ", " << rres << ");" << endl; - break; - case '*': - tgt_->defn << " " << "vvm_binop_mult(" << result - << "," << lres << "," << rres << ");" << endl; - break; - case '/': - tgt_->defn << " " << "vvm_binop_idiv(" << result - << "," << lres << "," << rres << ");" << endl; - break; - case '%': - tgt_->defn << " " << "vvm_binop_imod(" << result - << "," << lres << "," << rres << ");" << endl; - break; - default: - cerr << "vvm: Unhandled binary op `" << expr->op() << "': " - << *expr << endl; - tgt_->defn << "#error \"" << expr->get_line() << ": vvm error: " - "Unhandled binary op: " << *expr << "\"" << endl; - result = lres; - break; - } -} - -static string emit_proc_rval(target_vvm*tgt, const NetExpr*expr) -{ - vvm_proc_rval scan (tgt); - expr->expr_scan(&scan); - return scan.result; -} - -/* - * This is the default implementation for the expressions that are to - * be passed as parameters to system tasks. This uses the proc_rval - * class to make a vvm_bitset_t, then makes a vpiNumberConst out of that. - */ -void vvm_parm_rval::expr_default_(const NetExpr*expr) -{ - string rval = emit_proc_rval(tgt_, expr); - - string tmp = make_temp(); - tgt_->defn << " struct __vpiNumberConst " << tmp << ";" << endl; - tgt_->defn << " vpip_make_number_const(&" << tmp << ", " - << rval << ".bits, " << expr->expr_width() << ");" << endl; - result = "&" + tmp + ".base"; -} - -void vvm_parm_rval::expr_binary(const NetEBinary*expr) -{ - expr_default_(expr); -} - -void vvm_parm_rval::expr_concat(const NetEConcat*expr) -{ - expr_default_(expr); -} - -void vvm_parm_rval::expr_ufunc(const NetEUFunc*expr) -{ - expr_default_(expr); -} - -void vvm_parm_rval::expr_unary(const NetEUnary*expr) -{ - expr_default_(expr); -} - -void vvm_parm_rval::expr_const(const NetEConst*expr) -{ - if (expr->value().is_string()) { - - unsigned& res = tgt_->string_constants[expr->value().as_string()]; - - if (res == 0) { - res = tgt_->string_counter ++; - tgt_->init_code << " vpip_make_string_const(" - "&string_table[" << res << "], \"" << - expr->value().as_string() << "\");" << endl; - } - - ostrstream tmp; - tmp << "&string_table[" << res << "].base" << ends; - result = tmp.str(); - return; - } - - unsigned&res = tgt_->number_constants[expr->value()]; - if (res == 0) { - res = tgt_->number_counter ++; - unsigned width = expr->expr_width(); - unsigned bit_idx = tgt_->bits_table.position(expr->value()); - tgt_->init_code << " vpip_make_number_const(" - << "&number_table[" << res << "], " - << "const_bits_table+" << bit_idx << ", " - << width << ");" << endl; - } - - ostrstream tmp; - tmp << "&number_table[" << res << "].base" << ends; - result = tmp.str(); - return; -} - -void vvm_parm_rval::expr_sfunc(const NetESFunc*expr) -{ - if (!strcmp(expr->name(),"$time")) { - result = string("vpip_sim_time()"); - } else { - cerr << "Unhandled identifier: " << expr->name() << endl; - } -} - -void vvm_parm_rval::expr_memory(const NetEMemory*mem) -{ - if (mem->index() == 0) { - /* If the expression is a memory without an index, then - return the handle for the memory object. System tasks - can take such things as parameters. */ - result = string("&") + mangle(mem->name()) + ".base"; - - } else if (const NetEConst*idx = dynamic_cast(mem->index())){ - - /* If the expression is a memory with a constant index, - then generate a call to vpi_handle_by_index() to get - the memory word handle. */ - unsigned long val = idx->value().as_ulong(); - ostrstream res; - res << "vpi_handle_by_index(&" << mangle(mem->name()) << - ".base, " << val << ")" << ends; - result = res.str(); - - } else { - - /* Otherwise, evaluate the index at run time and use - that to select the memory word. */ - string rval = emit_proc_rval(tgt_, mem->index()); - result = "vpi_handle_by_index(&" + mangle(mem->name()) + - ".base, " + rval + ".as_unsigned())"; - } -} - -void vvm_parm_rval::expr_scope(const NetEScope*escope) -{ - result = string("&") + mangle(escope->scope()->name()) + "_scope.base"; -} - -void vvm_parm_rval::expr_signal(const NetESignal*expr) -{ - assert(expr->lsi() == 0); - string res = string("&") + mangle(expr->name()) + ".base"; - result = res; -} - -static string emit_parm_rval(target_vvm*tgt, const NetExpr*expr) -{ - vvm_parm_rval scan (tgt); - expr->expr_scan(&scan); - return scan.result; -} - -bool target_vvm::start_design(const Design*mod) -{ - out.open(mod->get_flag("-o").c_str(), ios::out | ios::trunc); - - defn_name = tempnam(0, "ivldf"); - defn.open(defn_name, ios::in | ios::out | ios::trunc); - - init_code_name = tempnam(0, "ivlic"); - init_code.open(init_code_name, ios::in | ios::out | ios::trunc); - - start_code_name = tempnam(0, "ivlsc"); - start_code.open(start_code_name, ios::in | ios::out | ios::trunc); - - out << "# include \"vvm.h\"" << endl; - out << "# include \"vvm_nexus.h\"" << endl; - out << "# include \"vvm_gates.h\"" << endl; - out << "# include \"vvm_signal.h\"" << endl; - out << "# include \"vvm_func.h\"" << endl; - out << "# include \"vvm_calltf.h\"" << endl; - out << "# include \"vvm_thread.h\"" << endl; - out << "# include \"vpi_user.h\"" << endl; - out << "# include \"vpi_priv.h\"" << endl; - - signal_bit_counter = 0; - signal_counter = 0; - process_counter = 0; - string_counter = 1; - number_counter = 1; - nexus_wire_counter = 1; - selector_counter = 0; - - init_code << "static void design_init()" << endl; - init_code << "{" << endl; - init_code << " vpip_init_simulation();" - << endl; - init_code << " vpip_time_scale(" - << mod->get_precision() << ");" << endl; - start_code << "static void design_start()" << endl; - start_code << "{" << endl; - - return true; -} - -void target_vvm::scope(const NetScope*scope) -{ - string hname = mangle(scope->name()) + "_scope"; - out << "// SCOPE: " << scope->name() << endl; - out << "static struct __vpiScope " << hname << ";" << endl; - - string type_code; - switch (scope->type()) { - case NetScope::MODULE: - type_code = "vpiModule"; - break; - case NetScope::TASK: - type_code = "vpiTask"; - break; - case NetScope::FUNC: - type_code = "vpiFunction"; - break; - case NetScope::BEGIN_END: - type_code = "vpiNamedBegin"; - break; - case NetScope::FORK_JOIN: - type_code = "vpiNamedFork"; - break; - } - - init_code << " vpip_make_scope(&" << hname << ", " << - type_code << ", \"" << stresc(scope->name()) << "\");" << endl; - - if (const NetScope*par = scope->parent()) { - string pname = mangle(par->name()) + "_scope"; - init_code << " vpip_attach_to_scope(&" << pname << ", " - << "&" << hname << ".base);" << endl; - } -} - -void target_vvm::event(const NetEvent*event) -{ - string mname = mangle(event->full_name()); - out << "static vvm_sync " << mname << "; // " - << event->get_line() << ": event " << event->full_name() << endl; -} - -int target_vvm::end_design(const Design*mod) -{ - if (string_counter > 0) - out << "static struct __vpiStringConst string_table[" << - string_counter+1 << "];" << endl; - if (number_counter > 0) - out << "static struct __vpiNumberConst number_table[" << - number_counter+1 << "];" << endl; - if (nexus_wire_counter > 0) - out << "static vvm_nexus nexus_wire_table[" << - nexus_wire_counter << "];" << endl; - if (signal_counter > 0) - out << "static vvm_signal_t signal_table[" << - signal_counter << "];" << endl; - if (signal_bit_counter > 0) - out << "static vpip_bit_t signal_bit_table[" << - signal_bit_counter << "];" << endl; - - if (bits_table.count() > 0) { - out << "static vpip_bit_t const_bits_table[" << bits_table.count() - << "] = {"; - - for (unsigned idx = 0 ; idx < bits_table.count() ; idx += 1) { - if (idx%16 == 0) out << endl; - switch (bits_table.bit(idx)) { - case verinum::V0: - out << " St0,"; - break; - case verinum::V1: - out << " St1,"; - break; - case verinum::Vx: - out << " StX,"; - break; - case verinum::Vz: - out << " HiZ,"; - break; - default: - out << " ,"; - break; - } - } - - out << endl << "};" << endl; - } - - defn.close(); - - out << "// **** Definition code" << endl; - { ifstream rdefn (defn_name); - out << rdefn.rdbuf(); - } - unlink(defn_name); - free(defn_name); - defn_name = 0; - out << "// **** end definition code" << endl; - - - out << "// **** init_code" << endl; - init_code << "}" << endl; - init_code.close(); - { ifstream rinit_code (init_code_name); - out << rinit_code.rdbuf(); - } - unlink(init_code_name); - free(init_code_name); - init_code_name = 0; - out << "// **** end init_code" << endl; - - - out << "// **** start_code" << endl; - start_code << "}" << endl; - start_code.close(); - { ifstream rstart_code (start_code_name); - out << rstart_code.rdbuf(); - } - unlink(start_code_name); - free(start_code_name); - start_code_name = 0; - out << "// **** end start_code" << endl; - - - - out << "main(int argc, char*argv[])" << endl << "{" << endl; - - out << " void vvm_vpi_init(void);" << endl; - out << " vpip_set_vlog_info(argc, argv);" << endl; - - string vpi_module_path = mod->get_flag("VPI_MODULE_PATH"); - if (vpi_module_path.length() > 0) - out << " vvm_set_module_path(\"" << stresc(vpi_module_path) << - "\");" << endl; - - out << " vvm_vpi_init();" << endl; - - string vpi_module_list = mod->get_flag("VPI_MODULE_LIST"); - while (vpi_module_list.length()) { - string name; - unsigned pos = vpi_module_list.find(','); - if (pos < vpi_module_list.length()) { - name = vpi_module_list.substr(0, pos); - vpi_module_list = vpi_module_list.substr(pos+1); - } else { - name = vpi_module_list; - vpi_module_list = ""; - } - out << " vvm_load_vpi_module(\"" << stresc(name) << ".vpi\");" << endl; - } - out << " design_init();" << endl; - out << " design_start();" << endl; - out << " vpip_simulation_run();" << endl; - out << "}" << endl; - out.close(); - - return 0; -} - -bool target_vvm::process(const NetProcTop*top) -{ - start_process(out, top); - bool rc = top->statement()->emit_proc(this); - end_process(out, top); - return rc; -} - -void target_vvm::signal(const NetNet*sig) -{ - string net_name = mangle(sig->name()); - - unsigned*ncode_table = new unsigned [sig->pin_count()]; - const char*resolution_function = 0; - - /* By default, the nexus object uses a resolution - function that is suitable for simulating wire and tri - signals. If the signal is some other sort, the write - a resolution function into the nexus that properly - handles the different semantics. */ - - switch (sig->type()) { - case NetNet::SUPPLY0: - resolution_function = "vvm_resolution_sup0"; - break; - case NetNet::SUPPLY1: - resolution_function = "vvm_resolution_sup1"; - break; - case NetNet::TRI0: - resolution_function = "vvm_resolution_tri0"; - break; - case NetNet::TRI1: - resolution_function = "vvm_resolution_tri1"; - break; - } - - /* Scan the signals of the vector, getting an array of all the - nexus numbers. Do any nexus init if necessary. */ - - for (unsigned idx = 0 ; idx < sig->pin_count() ; idx += 1) { - bool new_nexus_flag = false; - string nexus = sig->pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - if (ncode == 0) { - nexus_wire_map[nexus] = (ncode = nexus_wire_counter); - nexus_wire_counter += 1; - new_nexus_flag = true; - } - - ncode_table[idx] = ncode; - - - // Propogate the initial value to inputs throughout. - if (new_nexus_flag) { - verinum::V init = sig->pin(idx).nexus()->get_init(); - emit_init_value_(sig->pin(idx), init); - } - } - - /* Check to see if all the nexus numbers are increasing by one - for each bit of the signal. This is a common case and we - can generate optimal code for the situation. */ - bool increasing_flag = true; - for (unsigned idx = 1 ; idx < sig->pin_count() ; idx += 1) - if (ncode_table[idx] != (ncode_table[idx-1] + 1)) - increasing_flag = false; - - if (increasing_flag) { - - unsigned base = ncode_table[0]; - init_code << " for (unsigned idx = 0 ; idx < " - << sig->pin_count() << " ; idx += 1) {" << endl; - - init_code << " nexus_wire_table[idx+"<pin_count() ; idx += 1) { - unsigned ncode = ncode_table[idx]; - - init_code << " nexus_wire_table[" << ncode - <<"].connect(&" << net_name << ", " << idx << ");" - << endl; - - if (resolution_function) - init_code << " nexus_wire_table[" << ncode - << "].resolution_function = " - << resolution_function << ";" << endl; - - } - } - - delete [] ncode_table; - - out << "#define " << net_name << " (signal_table[" << - signal_counter << "])" << endl; - - signal_counter += 1; - - init_code << " vpip_make_reg(&" << net_name - << ", \"" << stresc(sig->name()) << "\", signal_bit_table+" - << signal_bit_counter << ", " << sig->pin_count() - << ", " << (sig->get_signed()? "1" : "0") << ");" << endl; - - - signal_bit_counter += sig->pin_count(); - - if (! sig->local_flag()) { - const NetScope*scope = sig->scope(); - assert(scope); - string sname = mangle(scope->name()) + "_scope"; - init_code << " vpip_attach_to_scope(&" << sname - << ", &" << net_name << ".base);" << endl; - } - - - /* Look at the initial values of the vector and see if they - can be assigned in a for loop. For this to work, all the - values must be the same. */ - verinum::V init = sig->pin(0).nexus()->get_init(); - bool uniform_flag = true; - for (unsigned idx = 1 ; idx < sig->pin_count() ; idx += 1) - if (init != sig->pin(idx).nexus()->get_init()) - uniform_flag = false; - - if (sig->pin_count() < 2) - uniform_flag = false; - - - if (uniform_flag) { - /* Generate the short form. Assign all the initial - values of the vector using a for loop. */ - init_code << " for (unsigned idx = 0 ; idx < " - << sig->pin_count() << " ; idx += 1)" << endl; - init_code << " " << mangle(sig->name())<<".init_P(idx, "; - switch (init) { - case verinum::V0: - init_code << "St0"; - break; - case verinum::V1: - init_code << "St1"; - break; - case verinum::Vx: - init_code << "StX"; - break; - case verinum::Vz: - init_code << "HiZ"; - break; - } - init_code << ");" << endl; - - } else { - /* Scan the signals of the vector, passing the initial - value to the inputs of all the connected devices. */ - for (unsigned idx = 0 ; idx < sig->pin_count() ; idx += 1) { - - init = sig->pin(idx).nexus()->get_init(); - init_code << " " << mangle(sig->name()) - << ".init_P(" << idx << ", "; - switch (init) { - case verinum::V0: - init_code << "St0"; - break; - case verinum::V1: - init_code << "St1"; - break; - case verinum::Vx: - init_code << "StX"; - break; - case verinum::Vz: - init_code << "HiZ"; - break; - } - init_code << ");" << endl; - } - } -} - -void target_vvm::memory(const NetMemory*mem) -{ - const string mname = mangle(mem->name()); - out << "static vvm_memory_t " << mname << ";" - " /* " << mem->name() << " */" << endl; - init_code << " vpip_make_memory(&" << mname << ", \"" << - stresc(mem->name()) << "\", " << mem->width() << ", " << - mem->count() << ");" << endl; -} - -void target_vvm::task_def(const NetScope*scope) -{ - const NetTaskDef*def = scope->task_def(); - - thread_step_ = 0; - const string name = mangle(def->name()); - const string save_thread_class = thread_class_; - thread_class_ = name; - - out << "static bool " << name << "_step_0_(vvm_thread*thr);" << endl; - - defn << "static bool " << name << "_step_0_(vvm_thread*thr) {" << endl; - - def->proc()->emit_proc(this); - - defn << " thr->back_ -> thread_yield();" << endl; - defn << " return false;" << endl; - defn << "}" << endl; - - thread_class_ = save_thread_class; -} - -/* - * A function definition is emitted as a C++ function that takes no - * parameters and returns no result. The actual parameter passing - * happens in the function call, where the signals that are the inputs - * are assigned by the caller, the caller calls the function (which - * writes the result) then the caller copies the result out of the - * magic result register. - */ -void target_vvm::func_def(const NetScope*scope) -{ - const NetFuncDef*def = scope->func_def(); - thread_step_ = 0; - const string name = mangle(def->name()); - - // Flag that we are now in a function definition. Note that - // function definitions cannot nest. - assert(! function_def_flag_); - function_def_flag_ = true; - - out << "// Function " << def->name() << endl; - out << "static bool " << name << "(vvm_thread*thr);" << endl; - - defn << "// Function " << def->name() << endl; - defn << "static bool " << name << "(vvm_thread*thr)" << endl; - defn << "{" << endl; - def->proc()->emit_proc(this); - defn << " return true;" << endl; - defn << "}" << endl; - - assert(function_def_flag_); - function_def_flag_ = false; -} - -string target_vvm::defn_gate_outputfun_(ostream&os, - const NetNode*gate, - unsigned gpin) -{ - cerr << "internal error: outputfun_ called for gate " << - gate->name() << " (" << typeid(*gate).name() << ")" << - endl; - assert(0); - return ""; -} - -void target_vvm::emit_init_value_(const Link&lnk, verinum::V val) -{ - mapwritten; - const char*val_name = vvm_val_name(val, lnk.drive0(), lnk.drive1()); - - const Nexus*nex = lnk.nexus(); - for (const Link*cur = nex->first_nlink() - ; cur ; cur = cur->next_nlink()) { - - if (cur == &lnk) - continue; - - if (cur->get_dir() == Link::OUTPUT) - continue; - - if (! dynamic_cast(cur->get_obj())) - continue; - - /* If the caller lnk is a signal, then we are declaring - signals so we skip signal initializations as they - take care of themselves. */ - - if (dynamic_cast(cur->get_obj()) - && dynamic_cast(lnk.get_obj())) - continue; - - // Build an init statement for the link, that writes the - // value. - ostrstream line; - line << " " << mangle(cur->get_obj()->name()) - << ".init_" << cur->get_name() << "(" << cur->get_inst() - << ", " << val_name << ");" << endl << ends; - - - // Check to see if the line has already been - // written to. This can happen if the object is a - // NetESignal, because there can be many of them - // with the same name. - if (written[line.str()]) - continue; - - written[line.str()] = true; - - init_code << line.str(); - } -} - -/* - * This method handles writing output functions for gates that have a - * single output (at pin 0). This writes the output_fun method into - * the delayed stream to be emitted to the output file later. - */ -void target_vvm::emit_gate_outputfun_(const NetNode*gate, unsigned gpin) -{ - assert(0); -} - -void target_vvm::lpm_add_sub(const NetAddSub*gate) -{ - out << "static vvm_add_sub " << - mangle(gate->name()) << "(" << gate->width() << ");" << endl; - - /* Connect the DataA inputs. */ - - for (unsigned idx = 0 ; idx < gate->width() ; idx += 1) { - if (! gate->pin_DataA(idx).is_linked()) - continue; - - string nexus = gate->pin_DataA(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - init_code << " nexus_wire_table["<name()) << ", " << - mangle(gate->name()) << ".key_DataA(" << idx << - "));" << endl; - } - - /* Connect the DataB inputs. */ - - for (unsigned idx = 0 ; idx < gate->width() ; idx += 1) { - if (! gate->pin_DataB(idx).is_linked()) - continue; - - string nexus = gate->pin_DataB(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()) << ", " << - mangle(gate->name()) << ".key_DataB(" << idx << - "));" << endl; - } - - /* Connect the outputs of the adder. */ - - for (unsigned idx = 0 ; idx < gate->width() ; idx += 1) { - if (! gate->pin_Result(idx).is_linked()) - continue; - - string nexus = gate->pin_Result(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()) << ".config_rout(" << idx << - "));" << endl; - } - - // Connect the carry output if necessary. - if (gate->pin_Cout().is_linked()) { - string nexus = gate->pin_Cout().nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()) << ".config_cout());" << endl; - } - - if (gate->attribute("LPM_Direction") == "ADD") { - init_code << " " << mangle(gate->name()) << - ".init_Add_Sub(0, St1);" << endl; - - } else if (gate->attribute("LPM_Direction") == "SUB") { - init_code << " " << mangle(gate->name()) << - ".init_Add_Sub(0, St0);" << endl; - - } - - start_code << " " << mangle(gate->name()) << ".start();" << endl; -} - -void target_vvm::lpm_clshift(const NetCLShift*gate) -{ - string mname = mangle(gate->name()); - - out << "static vvm_clshift " << mname << "(" << - gate->width() << "," << gate->width_dist() << ");" << - endl; - - /* Connect the Data input pins... */ - for (unsigned idx = 0 ; idx < gate->width() ; idx += 1) { - string nexus = gate->pin_Data(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<width_dist() ; idx += 1) { - string nexus = gate->pin_Distance(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<pin_Direction().is_linked()) { - string nexus = gate->pin_Direction().nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<width() ; idx += 1) { - string nexus = gate->pin_Result(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()); - - out << "static vvm_compare " << mname << "(" << gate->width() << - ");" << endl; - - /* Connect DataA inputs... */ - for (unsigned idx = 0 ; idx < gate->width() ; idx += 1) { - string nexus = gate->pin_DataA(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<width() ; idx += 1) { - string nexus = gate->pin_DataB(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<pin_ALB().is_linked()) { - string nexus = gate->pin_ALB().nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<pin_AGB().is_linked()) { - string nexus = gate->pin_AGB().nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<pin_ALEB().is_linked()) { - string nexus = gate->pin_ALEB().nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<pin_AGEB().is_linked()) { - string nexus = gate->pin_AGEB().nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()); - - out << "static vvm_idiv " << mname << "(" << mul->width_r() << - "," << mul->width_a() << "," << mul->width_b() << ");" << endl; - - - /* Connect the DataA inputs... */ - for (unsigned idx = 0 ; idx < mul->width_a() ; idx += 1) { - string nexus = mul->pin_DataA(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<width_b() ; idx += 1) { - string nexus = mul->pin_DataB(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<width_r() ; idx += 1) { - string nexus = mul->pin_Result(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()); - - out << "static vvm_imod " << mname << "(" << mul->width_r() << - "," << mul->width_a() << "," << mul->width_b() << ");" << endl; - - - /* Connect the DataA inputs... */ - for (unsigned idx = 0 ; idx < mul->width_a() ; idx += 1) { - string nexus = mul->pin_DataA(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<width_b() ; idx += 1) { - string nexus = mul->pin_DataB(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<width_r() ; idx += 1) { - string nexus = mul->pin_Result(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()); - - out << "static vvm_ff " << mname << "(" << gate->width() << ");" << endl; - - /* Connect the clock input... */ - - nexus = gate->pin_Clock().nexus()->name(); - ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<width() ; idx += 1) { - nexus = gate->pin_Q(idx).nexus()->name(); - ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<width() ; idx += 1) { - nexus = gate->pin_Data(idx).nexus()->name(); - ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()); - - out << "static vvm_mult " << mname << "(" << mul->width_r() << - "," << mul->width_a() << "," << mul->width_b() << "," << - mul->width_s() << ");" << endl; - - - /* Connect the DataA inputs... */ - for (unsigned idx = 0 ; idx < mul->width_a() ; idx += 1) { - string nexus = mul->pin_DataA(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<width_b() ; idx += 1) { - string nexus = mul->pin_DataB(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<width_r() ; idx += 1) { - string nexus = mul->pin_Result(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()); - - out << "static vvm_mux " << mname << "(" << mux->width() << "," - << mux->size() << "," << mux->sel_width() << ");" << endl; - - /* Connect the select inputs... */ - for (unsigned idx = 0 ; idx < mux->sel_width() ; idx += 1) { - string nexus = mux->pin_Sel(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<size() ; idx += 1) { - for (unsigned wid = 0 ; wid < mux->width() ; wid += 1) { - string nexus = mux->pin_Data(wid, idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<width() ; idx += 1) { - string nexus = mux->pin_Result(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()); - - out << "static vvm_ram_dq<" << ram->width() << "," << - ram->awidth() << "," << ram->size() << "> " << mname << - "(&" << mangle(ram->mem()->name()) << ");" << endl; - - if (ram->pin_WE().is_linked()) { - string nexus = ram->pin_WE().nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<pin_InClock().is_linked()) { - string nexus = ram->pin_InClock().nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<awidth() ; idx += 1) { - if (! ram->pin_Address(idx).is_linked()) - continue; - - string nexus = ram->pin_Address(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<width() ; idx += 1) { - if (! ram->pin_Data(idx).is_linked()) - continue; - - string nexus = ram->pin_Data(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<width() ; idx += 1) { - if (! ram->pin_Q(idx).is_linked()) - continue; - - string nexus = ram->pin_Q(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()); - - /* Draw the definition of the gate object. The exact type to - use depends on the gate type. Whatever the type, the basic - format is the same for all the boolean gates. */ - - switch (gate->type()) { - case NetLogic::AND: - if ((gate->pin_count()-1) == 2) - out << "static vvm_and2 " << mname << "("; - else - out << "static vvm_and " << mname << "(" - << (gate->pin_count()-1 ) << ", "; - break; - case NetLogic::BUF: - out << "static vvm_buf " << mname << "("; - break; - case NetLogic::BUFIF0: - out << "static vvm_bufif0 " << mname << "("; - break; - case NetLogic::BUFIF1: - out << "static vvm_bufif1 " << mname << "("; - break; - case NetLogic::NAND: - out << "static vvm_nand " << mname << "(" - << (gate->pin_count()-1 ) << ", "; - break; - case NetLogic::NMOS: - out << "static vvm_nmos " << mname << "("; - break; - case NetLogic::NOR: - if ((gate->pin_count()-1) == 2) - out << "static vvm_nor2 " << mname << "("; - else - out << "static vvm_nor " << mname << "(" - << (gate->pin_count()-1 ) << ", "; - break; - case NetLogic::NOT: - out << "static vvm_not " << mname << "("; - break; - case NetLogic::NOTIF0: - out << "static vvm_notif0 " << mname << "("; - break; - case NetLogic::NOTIF1: - out << "static vvm_notif1 " << mname << "("; - break; - case NetLogic::OR: - out << "static vvm_or " << mname << "(" - << (gate->pin_count()-1 ) << ", "; - break; - case NetLogic::RNMOS: - out << "static vvm_rnmos " << mname << "("; - break; - case NetLogic::RPMOS: - out << "static vvm_rpmos " << mname << "("; - break; - case NetLogic::PMOS: - out << "static vvm_pmos " << mname << "("; - break; - case NetLogic::XNOR: - out << "static vvm_xnor " << mname << "(" - << (gate->pin_count()-1 ) << ", "; - break; - case NetLogic::XOR: - out << "static vvm_xor " << mname << "(" - << (gate->pin_count()-1 ) << ", "; - break; - case NetLogic::PULLDOWN: - out << "static vvm_pulldown " << mname << "("; - break; - case NetLogic::PULLUP: - out << "static vvm_pullup " << mname << "("; - break; - default: - out << "#error \"internal ivl error:bad gate type " << gate->type() << " for " << - gate->name() << "\"" << endl; - } - - out << gate->rise_time() << ");" << endl; - - /* Write the code to invoke startup for this object. */ - - start_code << " " << mname << ".start();" << endl; - - - /* Setup drive strengths that are not STRONG. The gates - default to strong outputs, so don't generate the - unnecessary code to set the signal to strong. We know for - all these types of gates that pin(0) is the output, and the - vvm class takes drive0 and drive1 methods. */ - - const char*str0 = vvm_val_name(verinum::V0, - gate->pin(0).drive0(), - gate->pin(0).drive1()); - if (gate->pin(0).drive0() != Link::STRONG) { - init_code << " " << mname << ".drive0(" << str0 << ");" - << endl; - } - - const char*str1 = vvm_val_name(verinum::V1, - gate->pin(0).drive0(), - gate->pin(0).drive1()); - if (gate->pin(0).drive1() != Link::STRONG) { - init_code << " " << mname << ".drive1(" << str1 << ");" - << endl; - } - - /* Connect the output and all the inputs of the gate to the - nexus objects, one bit at a time. */ - - init_code << " // Connect inputs to gate " << gate->name() - << "." << endl; - - { string nexus = gate->pin(0).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - init_code << " nexus_wire_table[" << ncode << - "].connect(&" << mangle(gate->name()) << ");" << endl; - } - - for (unsigned idx = 1 ; idx < gate->pin_count() ; idx += 1) { - string nexus = gate->pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - init_code << " nexus_wire_table[" << ncode - << "].connect(&" << mangle(gate->name()) << ", " - << (idx-1) << ");" << endl; - } -} - -bool target_vvm::bufz(const NetBUFZ*gate) -{ - string mname = mangle(gate->name()); - string nexus; - unsigned ncode; - - out << "static vvm_bufz " << mname - << "(" << gate->rise_time() << ");" << endl; - nexus = gate->pin(0).nexus()->name(); - ncode = nexus_wire_map[nexus]; - - /* Setup drive strengths that are not STRONG. The BUFZ - defaults to strong outputs, so don't generate the - unnecessary code to set the signal to strong. We also know - that the vvm_bufz class takes drive0 and drive1 methods. */ - - if (gate->pin(0).drive0() != Link::STRONG) { - const char*str = vvm_val_name(verinum::V0, - gate->pin(0).drive0(), - gate->pin(0).drive1()); - init_code << " " << mname << ".drive0(" << str << ");" - << endl; - } - - if (gate->pin(0).drive1() != Link::STRONG) { - const char*str = vvm_val_name(verinum::V1, - gate->pin(0).drive0(), - gate->pin(0).drive1()); - init_code << " " << mname << ".drive1(" << str << ");" - << endl; - } - - init_code << " nexus_wire_table["<pin(1).nexus()->name(); - ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()); - string nexus; - unsigned ncode; - - // TODO: maintain a map of tables already - // emited, and only print the table for each UDP once. - - out << "static const char*" << mname << "_ctab =" << endl; - - string inp; - char outc; - for (bool rc = gate->first(inp, outc) - ; rc ; rc = gate->next(inp,outc)) { - - out << " \"" << inp << outc << "\"" << endl; - } - out << " ;" << endl; - - out << (gate->is_sequential() ? "static vvm_udp_sequ1 " - : "static vvm_udp_comb " ) - << mname << "(" - << (gate->pin_count()-1) << ", " << mname<<"_ctab);" << endl; - - /* Connect the output of the device... */ - nexus = gate->pin(0).nexus()->name(); - ncode = nexus_wire_map[nexus]; - init_code << " nexus_wire_table["<pin_count() ; idx += 1) { - if (! gate->pin(idx).is_linked()) - continue; - - nexus = gate->pin(idx).nexus()->name(); - ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()); - string nexus; - unsigned ncode; - - assert(gate->pin_count() == 3); - out << "static vvm_eeq " << mname << "(" << - gate->rise_time() << ");" << endl; - - /* Connect the output pin */ - nexus = gate->pin(0).nexus()->name(); - ncode = nexus_wire_map[nexus]; - init_code << " nexus_wire_table["<pin(1).nexus()->name(); - ncode = nexus_wire_map[nexus]; - init_code << " nexus_wire_table["<pin(2).nexus()->name(); - ncode = nexus_wire_map[nexus]; - init_code << " nexus_wire_table["<name()); - - out << "static vvm_force " << mname << "(" << dev->pin_count() - << ");" << endl; - - for (unsigned idx = 0 ; idx < dev->pin_count() ; idx += 1) { - string nexus = dev->pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()); - - out << "static vvm_nexus::drive_t " << mname - << "[" << gate->pin_count() << "];" << endl; - - for (unsigned idx = 0 ; idx < gate->pin_count() ; idx += 1) { - string nexus = gate->pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - const char*val_str = vvm_val_name(gate->value(idx), - gate->pin(idx).drive0(), - gate->pin(idx).drive1()); - - init_code << " nexus_wire_table["<name()); - - out << "static vvm_force " << mname << "(" << dev->pin_count() - << ");" << endl; - - for (unsigned idx = 0 ; idx < dev->pin_count() ; idx += 1) { - string nexus = dev->pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()); - string mevent = mangle(net->event()->full_name()); - - switch (net->edge()) { - case NetEvProbe::POSEDGE: - assert(net->pin_count() == 1); - out << "static vvm_posedge " << mname - << "(&" << mevent << ");" << endl; - break; - - case NetEvProbe::NEGEDGE: - assert(net->pin_count() == 1); - out << "static vvm_negedge " << mname - << "(&" << mevent << ");" << endl; - break; - - - case NetEvProbe::ANYEDGE: - out << "static vvm_anyedge " << mname - << "(&" << mevent << ", " << net->pin_count() << ");" << endl; - break; - } - - - /* Connect this device as a receiver to the nexus that is my - source. Write the connect calls into the init code. */ - - for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) { - string nexus = net->pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - init_code << " nexus_wire_table["<name()) << ", " << idx << ");" << endl; - } -} - -void target_vvm::start_process(ostream&os, const NetProcTop*proc) -{ - process_counter += 1; - { ostrstream ts; - ts << "thread" << process_counter << "_t" << ends; - thread_class_ = ts.str(); - } - thread_step_ = 0; - - os << "static bool " << thread_class_ << - "_step_0_(vvm_thread*thr);" << endl; - - os << "static vvm_thread " << thread_class_ << ";" << endl; - - init_code << " " << thread_class_ << ".step_ = &" - << thread_class_ << "_step_0_;" << endl; - init_code << " " << thread_class_ << ".scope = &" - << mangle(proc->scope()->name()) << "_scope;" << endl; - init_code << " " << thread_class_ << ".thread_yield();" << endl; - - - defn << "static bool " << thread_class_ << "_step_0_(vvm_thread*thr)" - << endl << "{" << endl; -} - -/* - * This method handles the special case of the assignment of a - * constant r-value to the l-value. In this case, I can set specific - * values to each of the bits instead of calculating bit values or - * even reading values from a vpip_bit_t elsewhere. - */ -void target_vvm::proc_assign_rval(const NetAssign_*lv, - const NetEConst*rv, - unsigned off) -{ - const verinum value = rv->value(); - - /* This condition catches the special case of assigning to a - non-constant bit select. This cal be something like: - - a[idx] = x; - - For this sort of assignment, I only need a single bit of - the r-value. That bit is written into a single bit of the - target using a generated switch statement, where each case - of the switch assignes to a specific nexus. This is not - unreasonable because there aren't typically all that many - bits in the l-value. */ - - if (lv->bmux()) { - - // This is a bit select. Assign the low bit of the - // constant to the selected bit of the lval. - - const char*rval = vvm_val_name(value.get(off), - Link::STRONG, - Link::STRONG); - - string bval = emit_proc_rval(this, lv->bmux()); - - defn << " switch (" << bval - << ".as_unsigned()) {" << endl; - - for (unsigned idx = 0; idx < lv->lwidth(); idx += 1) { - - string nexus = lv->sig()->pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - defn << " case " << idx << ":" << endl; - - defn << " nexus_wire_table["<lwidth()]; - - bool sequential_flag = true; - bool uniform_flag = true; - verinum::V val = off < value.len() - ? value.get(off) - : verinum::V0; - unsigned zeros_start = 0; - - for (unsigned idx = 0 ; idx < lv->lwidth() ; idx += 1) { - string nexus = lv->sig()->pin(idx).nexus()->name(); - nexus_map[idx] = nexus_wire_map[nexus]; - - verinum::V tmp = (idx+off) < value.len() - ? value.get(idx+off) - : verinum::V0; - - if (tmp != verinum::V0) - zeros_start = idx + 1; - - if (idx > 0) { - if (nexus_map[idx] != (nexus_map[idx-1] + 1)) - sequential_flag = false; - - if (tmp != val) - uniform_flag = false; - } - } - - - if (sequential_flag && uniform_flag && (lv->lwidth() > 1)) { - - const char*rval = vvm_val_name(val, Link::STRONG, Link::STRONG); - unsigned base = nexus_map[0]; - - defn << " for (unsigned idx = 0 ; idx < " - << lv->lwidth() << " ; idx += 1)" << endl; - - defn << " nexus_wire_table[idx+" <lwidth())) { - - /* If the nexa are sequential and the high bits are all - zeros, then we can write simple reg_assign statements - to take care of the low bits, then write a for loop - to fill in all the high zero bits. - - This is interesting as it is common to assign small - integers to wide vectors. */ - - const char*rval; - - for (unsigned idx = 0 ; idx < zeros_start ; idx += 1) { - unsigned ncode = nexus_map[idx]; - - val = (idx+off) < value.len() - ? value.get(idx+off) - : verinum::V0; - rval = vvm_val_name(val, Link::STRONG, Link::STRONG); - - defn << " nexus_wire_table[" <lwidth()-zeros_start) << " ; idx += 1)" << endl; - - defn << " nexus_wire_table[idx+" <lwidth() ; idx += 1) { - unsigned ncode = nexus_map[idx]; - - val = (idx+off) < value.len() - ? value.get(idx+off) - : verinum::V0; - const char*rval = vvm_val_name(val, Link::STRONG, Link::STRONG); - - defn << " nexus_wire_table[" <bmux()) { - - // This is a bit select. Assign the low bit of the rval - // to the selected bit of the lval. - string bval = emit_proc_rval(this, lv->bmux()); - - defn << " switch (" << bval << ".as_unsigned()) {" << endl; - - for (unsigned idx = 0 ; idx < lv->lwidth() ; idx += 1) { - - string nexus = lv->sig()->pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - defn << " case " << idx << ":" << endl; - - defn << " nexus_wire_table["<lwidth(); - if ((wid-off) < min_count) - min_count = wid - off; - - /* First, make a map of the nexa that are connected to - the l-value. */ - - bool sequential_flag = true; - unsigned*nexus_map = new unsigned[lv->lwidth()]; - for (unsigned idx = 0 ; idx < lv->lwidth() ; idx += 1) { - string nexus = lv->sig()->pin(idx).nexus()->name(); - nexus_map[idx] = nexus_wire_map[nexus]; - - if ((idx >= 1) && (nexus_map[idx] != (nexus_map[idx-1]+1))) - sequential_flag = false; - } - - if (sequential_flag && (min_count > 1)) { - unsigned base = nexus_map[0]; - - defn << " for (unsigned idx = 0 ; idx < " - << min_count << "; idx += 1)" << endl; - - defn << " nexus_wire_table[idx+"<lwidth(); idx += 1) { - unsigned ncode = nexus_map[idx]; - defn << " nexus_wire_table["<(net->rval())) { - - const NetAssign_*cur = net->l_val(0); - unsigned off = 0; - unsigned idx = 0; - while (cur != 0) { - proc_assign_rval(cur, rc, off); - off += cur->lwidth(); - idx += 1; - cur = net->l_val(idx); - } - - return; - } - - - string rval; - - - /* Handle another special case, that of an r-value that is a - simple identifier. In this case we don't need to generate - the vvm_bitset_t but can pull the result directly out of - the identifier memory. It is OK to turn the r-value string - into a simple vpip_bit_t array (the .bits member of the - signal) because we know that we will only be using the [] - operator on it. */ - - if (const NetESignal*rs = dynamic_cast(net->rval())) { - - if (net->lwidth() > rs->bit_count()) { - rval = emit_proc_rval(this, net->rval()); - - } else { - - rval = mangle(rs->name()) + ".bits"; - } - - } else { - - rval = emit_proc_rval(this, net->rval()); - } - - - defn << " // " << net->get_line() << ": " << endl; - - { const NetAssign_*cur = net->l_val(0); - unsigned wid = net->rval()->expr_width(); - unsigned off = 0; - unsigned idx = 0; - while (cur != 0) { - proc_assign_rval(cur, rval, wid, off); - off += cur->lwidth(); - idx += 1; - cur = net->l_val(idx); - } - } -} - -/* - * Generate an assignment to a memory location. This causes the index - * expression to be evaluated (run-time) and the index used as the - * location to store the value. - */ -void target_vvm::proc_assign_mem(const NetAssignMem*amem) -{ - /* make a temporary to reference the index signal. */ - string index = emit_proc_rval(this, amem->index()); - - /* Evaluate the rval that gets written into the memory word. */ - string rval = emit_proc_rval(this, amem->rval()); - - - const NetMemory*mem = amem->memory(); - assert(mem->width() <= amem->rval()->expr_width()); - - defn << " /* " << amem->get_line() << " */" << endl; - - /* Set the indexed word from the rval. Note that this - assignment will work even if the rval is too wide, because - the set_word method takes only the low bits of the width of - the memory. */ - - defn << " " << mangle(mem->name()) << - ".set_word(" << index << ".as_unsigned(), " << - rval << ");" << endl; - -} - - -/* - * This method handles the special case of the assignment of a - * constant r-value to the l-value. In this case, I can set specific - * values to each of the bits instead of calculating bit values or - * even reading values from a vpip_bit_t elsewhere. - */ -void target_vvm::proc_assign_nb_rval(const NetAssign_*lv, - const NetEConst*rv, - unsigned off) -{ - const verinum value = rv->value(); -#if 0 - const unsigned rise_time = lv->rise_time(); -#else - const unsigned rise_time = 0; -#endif - - /* This condition catches the special case of assigning to a - non-constant bit select. This cal be something like: - - a[idx] = x; - - For this sort of assignment, I only need a single bit of - the r-value. That bit is written into a single bit of the - target using a generated switch statement, where each case - of the switch assignes to a specific nexus. This is not - unreasonable because there aren't typically all that many - bits in the l-value. */ - - if (lv->bmux()) { - - // This is a bit select. Assign the low bit of the - // constant to the selected bit of the lval. - - const char*rval = vvm_val_name(value.get(off), - Link::STRONG, - Link::STRONG); - - string bval = emit_proc_rval(this, lv->bmux()); - - defn << " switch (" << bval - << ".as_unsigned()) {" << endl; - - for (unsigned idx = 0; idx < lv->lwidth(); idx += 1) { - - string nexus = lv->sig()->pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - defn << " case " << idx << ":" << endl; - - defn << " vvm_delayed_assign(nexus_wire_table[" - <lwidth() ; idx += 1) { - string nexus = lv->sig()->pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - verinum::V val = (idx+off) < value.len() - ? value.get(idx+off) - : verinum::V0; - const char*rval = vvm_val_name(val, Link::STRONG, Link::STRONG); - - defn << " vvm_delayed_assign(nexus_wire_table[" - <rise_time(); -#else - const unsigned rise_time = 0; -#endif - - /* Now, if there is a mux on the l-value, generate a code to - assign a single bit to one of the bits of the - l-value. Otherwise, generate code for a complete - assignment. */ - - if (lv->bmux()) { - - // This is a bit select. Assign the low bit of the rval - // to the selected bit of the lval. - string bval = emit_proc_rval(this, lv->bmux()); - - defn << " switch (" << bval << ".as_unsigned()) {" << endl; - - for (unsigned idx = 0 ; idx < lv->lwidth() ; idx += 1) { - - string nexus = lv->sig()->pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - defn << " case " << idx << ":" << endl; - - defn << " vvm_delayed_assign(nexus_wire_table[" - <lwidth(); - if ((wid-off) < min_count) - min_count = wid - off; - - for (unsigned idx = 0 ; idx < min_count ; idx += 1) { - string nexus = lv->sig()->pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - defn << " vvm_delayed_assign(nexus_wire_table[" - <lwidth(); idx += 1) { - string nexus = lv->sig()->pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - defn << " vvm_delayed_assign(nexus_wire_table[" - <(net->rval())) { - - const NetAssign_*cur = net->l_val(0); - unsigned off = 0; - unsigned idx = 0; - while (cur != 0) { - proc_assign_nb_rval(cur, rc, off); - off += cur->lwidth(); - idx += 1; - cur = net->l_val(idx); - } - - return; - } - - - string rval; - if (net->lwidth() > net->rval()->expr_width()) { - cerr << net->get_line() << ": internal error: " - << "lvalue width is " << net->lwidth() << ", " - << "rvalue width is " << net->rval()->expr_width() - << "." << endl; - } - assert(net->lwidth() <= net->rval()->expr_width()); - - - /* Handle another special case, that of an r-value that is a - simple identifier. In this case we don't need to generate - the vvm_bitset_t but can pull the result directly out of - the identifier memory. It is OK to turn the r-value string - into a simple vpip_bit_t array (the .bits member of the - signal) because we know that we will only be using the [] - operator on it. */ - - if (const NetESignal*rs = dynamic_cast(net->rval())) { - - if (net->lwidth() > rs->bit_count()) { - rval = emit_proc_rval(this, net->rval()); - - } else { - - rval = mangle(rs->name()) + ".bits"; - } - - } else { - - rval = emit_proc_rval(this, net->rval()); - } - - - defn << " // " << net->get_line() << ": " << endl; - - { const NetAssign_*cur = net->l_val(0); - unsigned wid = net->rval()->expr_width(); - unsigned off = 0; - unsigned idx = 0; - while (cur != 0) { - proc_assign_nb_rval(cur, rval, wid, off); - off += cur->lwidth(); - idx += 1; - cur = net->l_val(idx); - } - } -} - -void target_vvm::proc_assign_mem_nb(const NetAssignMemNB*amem) -{ - /* make a temporary to reference the index signal. */ - string index = emit_proc_rval(this, amem->index()); - - - /* Evaluate the rval that gets written into the memory word. */ - string rval = emit_proc_rval(this, amem->rval()); - - const NetMemory*mem = amem->memory(); - - defn << " /* " << amem->get_line() << " */" << endl; - - /* Note here that the vvm_memory_t::assign_nb constructor will - pad the rval with St0 if it is not as wide as the memory - word. If this is not what is desired, then it should have - been fixed up by semantic analysis anyhow. */ - - defn << " (new vvm_memory_t::assign_nb(" << mangle(mem->name()) - << ", " << index << ".as_unsigned(), " << rval << - ")) -> schedule();" << endl; -} - -bool target_vvm::proc_block(const NetBlock*net) -{ - if (net->type() == NetBlock::SEQU) { - net->emit_recurse(this); - return true; - } - - unsigned exit_step = thread_step_ + 1; - - thread_step_ += 1; - - const NetProc*cur; - unsigned cnt = 0; - unsigned idx; - - // Declare the exit step... - - out << "static bool " << thread_class_ << "_step_" << exit_step - << "_(vvm_thread*thr);" << endl; - - - // Declare the first steps for all the threads to be created, - // and count those threads while I'm at it. - - for (cur = net->proc_first() ; cur ; cur = net->proc_next(cur)) { - cnt += 1; - out << "static bool " << thread_class_ << "_step_" - << (exit_step+cnt) << "_(vvm_thread*thr);" << endl; - } - - thread_step_ += cnt; - - // Write the code to start all the threads, then pause the - // current thread. - - defn << " thr->callee_ = new vvm_thread["<ncallee_ = " << cnt << ";" << endl; - - for (idx = 0 ; idx < cnt ; idx += 1) { - defn << " thr->callee_["<callee_["<callee_["<scope;" << endl; - defn << " thr->callee_["<step_ = &" << thread_class_ << "_step_" - << exit_step << "_;" << endl; - defn << " return false;" << endl; - defn << "}" << endl; - - // Generate the thread steps. At the end of the thread proc, - // write code to manage the join. - - for (idx = 0, cur = net->proc_first() - ; cur ; idx +=1, cur = net->proc_next(cur)) { - - defn << "static bool " << thread_class_ << "_step_" - << (exit_step+idx+1) << "_(vvm_thread*thr) {" << endl; - - cur->emit_proc(this); - - defn << " thr->back_->ncallee_ -= 1;" << endl; - defn << " if (thr->back_->ncallee_ == 0)" << endl; - defn << " thr->back_->thread_yield();" << endl; - defn << " return false;" << endl; - defn << "}" << endl; - } - - // Finally, start the exit step. - - defn << "static bool " << thread_class_ << "_step_" << exit_step - << "_(vvm_thread*thr) {" << endl; - - defn << " delete[]thr->callee_;" << endl; - defn << " thr->callee_ = 0;" << endl; - - return true; -} - -/* - * The code for a case statement introduces basic blocks so causes - * steps to be created. There is a step for each case, and the - * out. For example: - * - * case (foo) - * 1 : X; - * 2 : Y; - * endcase - * Z; - * - * causes code for Z to be generated, and also code for X and Y that - * each branch to Z when they finish. X, Y and Z all generate at least - * one step. - */ -void target_vvm::proc_case(const NetCase*net) -{ - if (function_def_flag_) { - proc_case_fun(out, net); - return; - } - - string test_func = ""; - switch (net->type()) { - case NetCase::EQ: - test_func = "vvm_binop_eeq"; - break; - case NetCase::EQX: - test_func = "vvm_binop_xeq"; - break; - case NetCase::EQZ: - test_func = "vvm_binop_zeq"; - break; - } - - defn << " /* case (" << *net->expr() << ") */" << endl; - string expr = emit_proc_rval(this, net->expr()); - - unsigned exit_step = thread_step_ + 1; - thread_step_ += 1; - - unsigned default_idx = net->nitems(); - - /* This iteration generates all the comparisons with the case - expression. If a comparison matches, the next step is set - and return true branches to that step. */ - for (unsigned idx = 0 ; idx < net->nitems() ; idx += 1) { - if (net->expr(idx) == 0) { - assert(default_idx == net->nitems()); - default_idx = idx; - continue; - } - assert(net->expr(idx)); - - thread_step_ += 1; - - defn << " /* " << *net->expr(idx) << " */" << endl; - string guard = emit_proc_rval(this, net->expr(idx)); - - defn << " if (B_IS1(" << test_func << "(" << guard << "," - << expr << "))) {" << endl; - defn << " thr->step_ = &" << thread_class_ << - "_step_" << thread_step_ << "_;" << endl; - defn << " return true;" << endl; - defn << " }" << endl; - } - - /* If none of the above tests pass, then branch to the default - step (or the exit step if there is no default.) */ - if (default_idx < net->nitems()) { - thread_step_ += 1; - - defn << " /* default : */" << endl; - defn << " thr->step_ = &" << thread_class_ << "_step_" << - thread_step_ << "_;" << endl; - - } else { - defn << " /* no default ... fall out of case. */" << endl; - defn << " thr->step_ = &" << thread_class_ << "_step_" << - exit_step << "_;" << endl; - } - defn << " return true;" << endl; - defn << "}" << endl; - - /* Run through the cases again, this time generating the case - steps. Note that I already know which item is the default, - so I just assert that this iteration agrees. */ - unsigned step_num = exit_step; - for (unsigned idx = 0 ; idx < net->nitems() ; idx += 1) { - if (net->expr(idx) == 0) { - assert(default_idx == idx); - continue; - } - assert(net->expr(idx)); - - step_num += 1; - - out << "static bool " << thread_class_ << "_step_" - << step_num << "_(vvm_thread*thr);" << endl; - - defn << "static bool " << thread_class_ << "_step_" - << step_num << "_(vvm_thread*thr) {" << endl; - if (net->stat(idx)) - net->stat(idx)->emit_proc(this); - defn << " thr->step_ = &" << thread_class_ << "_step_" << - exit_step << "_;" << endl; - defn << " return true;" << endl; - defn << "}" << endl; - } - - /* If there is a default case, generate the default step. */ - if (default_idx < net->nitems()) { - step_num += 1; - - out << "static bool " << thread_class_ << "_step_" - << step_num << "_(vvm_thread*thr);" << endl; - - defn << "static bool " << thread_class_ << "_step_" - << step_num << "_(vvm_thread*thr) {" << endl; - if (net->stat(default_idx)) - net->stat(default_idx)->emit_proc(this); - defn << " thr->step_ = &" << thread_class_ << "_step_" << - exit_step << "_;" << endl; - defn << " return true;" << endl; - defn << "}" << endl; - } - - /* Finally, start the exit step. */ - - out << "static bool " << thread_class_ << "_step_" - << exit_step << "_(vvm_thread*thr);" << endl; - - defn << "static bool " << thread_class_ << "_step_" - << exit_step << "_(vvm_thread*thr) {" << endl; -} - -/* - * Within a function definition, the case statement is implemented - * differently. Since statements in this context cannot block, we can - * use open coded if statements to do all the comparisons. - */ -void target_vvm::proc_case_fun(ostream&os, const NetCase*net) -{ - string test_func = ""; - switch (net->type()) { - case NetCase::EQ: - test_func = "vvm_binop_eeq"; - break; - case NetCase::EQX: - test_func = "vvm_binop_xeq"; - break; - case NetCase::EQZ: - test_func = "vvm_binop_zeq"; - break; - } - - defn << " /* " << net->get_line() << ": case (" << - *net->expr() << ") */" << endl; - - defn << " do {" << endl; - - string expr = emit_proc_rval(this, net->expr()); - - unsigned default_idx = net->nitems(); - for (unsigned idx = 0 ; idx < net->nitems() ; idx += 1) { - - // don't emit the default case here. Save it for the - // last else clause. - if (net->expr(idx) == 0) { - default_idx = idx; - continue; - } - - string guard = emit_proc_rval(this, net->expr(idx)); - - defn << " if (B_IS1(" << test_func << "(" << - guard << "," << expr << "))) {" << endl; - if (net->stat(idx)) - net->stat(idx)->emit_proc(this); - defn << " break; }" << endl; - } - - if ((default_idx < net->nitems()) && net->stat(default_idx)) { - net->stat(default_idx)->emit_proc(this); - } - - defn << " /* " << net->get_line() << ": end case (" << - *net->expr() << ") */" << endl; - defn << " } while(0);" << endl; -} - -bool target_vvm::proc_cassign(const NetCAssign*dev) -{ - const string mname = mangle(dev->name()); - - for (unsigned idx = 0 ; idx < dev->pin_count() ; idx += 1) { - string nexus = dev->lval_pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - defn << " " << mname << ".assign("<expr()); - - unsigned if_step = ++thread_step_; - unsigned else_step = ++thread_step_; - unsigned out_step = ++thread_step_; - - /* Declare new steps that I am going to create. */ - - out << "static bool " << thread_class_ << "_step_" - << if_step << "_(vvm_thread*thr);" << endl; - - out << "static bool " << thread_class_ << "_step_" - << else_step << "_(vvm_thread*thr);" << endl; - - out << "static bool " << thread_class_ << "_step_" - << out_step << "_(vvm_thread*thr);" << endl; - - if (net->expr()->expr_width() == 1) - defn << " if (B_IS1(" << expr << "[0]))" << endl; - else - defn << " if (B_IS1(vvm_unop_or(" << expr << ")))" << endl; - - defn << " thr->step_ = &" << thread_class_ << "_step_" << - if_step << "_;" << endl; - defn << " else" << endl; - defn << " thr->step_ = &" << thread_class_ << "_step_" << - else_step << "_;" << endl; - defn << " return true;" << endl; - defn << "}" << endl; - - defn << "static bool " << thread_class_ << "_step_" << if_step << - "_(vvm_thread*thr) {" << endl; - net->emit_recurse_if(this); - defn << " thr->step_ = &" << thread_class_ << "_step_" << - out_step << "_;" << endl; - defn << " return true;" << endl; - defn << "}" << endl; - - defn << "static bool " << thread_class_ << "_step_" << else_step << - "_(vvm_thread*thr) {" << endl; - net->emit_recurse_else(this); - defn << " thr->step_ = &" << thread_class_ << "_step_" << - out_step << "_;" << endl; - defn << " return true;" << endl; - defn << "}" << endl; - - defn << "static bool " << thread_class_ << "_step_" << out_step << - "_(vvm_thread*thr) {" << endl; - return true; -} - -void target_vvm::proc_condit_fun(ostream&os, const NetCondit*net) -{ - string expr = emit_proc_rval(this, net->expr()); - - defn << " // " << net->get_line() << ": conditional (if-else)" - << endl; - defn << " if (B_IS1(" << expr << "[0])) {" << endl; - net->emit_recurse_if(this); - defn << " } else {" << endl; - net->emit_recurse_else(this); - defn << " }" << endl; -} - -bool target_vvm::proc_deassign(const NetDeassign*dev) -{ - const NetNet*lval = dev->lval(); - for (unsigned idx = 0 ; idx < lval->pin_count() ; idx += 1) { - string nexus = lval->pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - defn << " nexus_wire_table["<name()); - - for (unsigned idx = 0 ; idx < dev->pin_count() ; idx += 1) { - string nexus = dev->lval_pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - defn << " " << mname << ".force("<step_ = &" << thread_class_ << "_step_" << - top_step << "_;" << endl; - defn << " return true;" << endl; - defn << "}" << endl; - - out << "static bool " << thread_class_ << "_step_" - << top_step << "_(vvm_thread*thr);" << endl; - - defn << "static bool " << thread_class_ << "_step_" - << top_step << "_(vvm_thread*thr) {" << endl; - - net->emit_recurse(this); - defn << " thr->step_ = &" << thread_class_ << "_step_" << - top_step << "_;" << endl; - defn << " return true;" << endl; - defn << "}" << endl; - - /* Generate a loop out step to catch unreachable stuff afer - the loop. */ - - out << "static bool " << thread_class_ << "_step_" - << out_step << "_(vvm_thread*thr);" << endl; - - defn << "static bool " << thread_class_ << "_step_" - << out_step << "_(vvm_thread*thr) {" << endl; -} - -bool target_vvm::proc_release(const NetRelease*dev) -{ - const NetNet*lval = dev->lval(); - for (unsigned idx = 0 ; idx < lval->pin_count() ; idx += 1) { - string nexus = lval->pin(idx).nexus()->name(); - unsigned ncode = nexus_wire_map[nexus]; - - defn << " nexus_wire_table["<(net->expr())) { - char tmp[64]; - sprintf(tmp, "%lu", val->value().as_ulong()); - expr = tmp; - - } else { - expr = emit_proc_rval(this, net->expr()); - expr = expr + ".as_unsigned()"; - } - - /* Declare a variable to use as a loop index. */ - out << "static unsigned " << thread_class_ << "_step_" - << top_step << "_idx_;" << endl; - - /* Declare the top step. */ - out << "static bool " << thread_class_ << "_step_" - << top_step << "_(vvm_thread*thr);" << endl; - - /* Declare the exit step. */ - out << "static bool " << thread_class_ << "_step_" - << out_step << "_(vvm_thread*thr);" << endl; - - - defn << " " << thread_class_ << "_step_" - << top_step << "_idx_ = " << expr << ";" << endl; - defn << " thr->step_ = &" << thread_class_ << "_step_" - << top_step << "_;" << endl; - defn << " return true;" << endl; - defn << "}" << endl; - - defn << "static bool " << thread_class_ << "_step_" - << top_step << "_(vvm_thread*thr) {" << endl; - - defn << " if (" << thread_class_ << "_step_" - << top_step << "_idx_ == 0) {" << endl; - defn << " thr->step_ = &" << thread_class_ << "_step_" - << out_step << "_;" << endl; - defn << " return true;" << endl; - defn << " }" << endl; - defn << " " << thread_class_ << "_step_" - << top_step << "_idx_ -= 1;" << endl; - - net->emit_recurse(this); - - defn << " thr->step_ = &" << thread_class_ << "_step_" - << top_step << "_;" << endl; - defn << " return true;" << endl; - defn << "}" << endl; - - - defn << "static bool " << thread_class_ << "_step_" - << out_step << "_(vvm_thread*thr) {" << endl; -} - -/* - * Calls to system tasks are done here. We know that this is a system - * task and that I need to generate an external call. Calls to user - * defined tasks are handled elsewhere. - */ -void target_vvm::proc_stask(const NetSTask*net) -{ - /* Handle the special case of a system task without any - parameters. we don't need a parameter array for this. */ - - if (net->nparms() == 0) { - defn << " vpip_calltask(thr->scope, \"" << stresc(net->name()) - << "\", 0, 0);" << endl; - defn << " if (vpip_finished()) return false;" << endl; - return; - } - - string ptmp = make_temp(); - - defn << " vpiHandle " << ptmp << "[" << net->nparms() << - "];" << endl; - for (unsigned idx = 0 ; idx < net->nparms() ; idx += 1) { - string val; - if (net->parm(idx)) { - val = emit_parm_rval(this, net->parm(idx)); - - } else { - val = string("&(vpip_get_null()->base)"); - } - - defn << " " << ptmp << "[" << idx << "] = " << val << ";" - << endl; - } - - defn << " vpip_calltask(thr->scope, \"" << stresc(net->name()) << "\", " - << net->nparms() << ", " << ptmp << ");" << endl; - defn << " if (vpip_finished()) return false;" << endl; -} - -bool target_vvm::proc_trigger(const NetEvTrig*trig) -{ - const NetEvent*ev = trig->event(); - assert(ev); - - string ename = mangle(ev->full_name()); - - defn << " " << ename << ".wakeup(); // " - << trig->get_line() << ": -> " << ev->full_name() << endl; - - return true; -} - -void target_vvm::proc_utask(const NetUTask*net) -{ - unsigned out_step = ++thread_step_; - const string name = mangle(net->name()); - - out << "static bool " << thread_class_ << "_step_" - << out_step << "_(vvm_thread*thr);" << endl; - - defn << " assert(thr->callee_ == 0);" << endl; - defn << " thr->callee_ = new vvm_thread;" << endl; - defn << " thr->callee_->back_ = thr;" << endl; - defn << " thr->callee_->step_ = &" << name << "_step_0_;" << endl; - defn << " thr->callee_->scope = &" << mangle(net->name()) - << "_scope;" << endl; - defn << " thr->callee_->thread_yield();" << endl; - defn << " thr->step_ = &" << thread_class_ << "_step_" - << out_step << "_;" << endl; - defn << " return false;" << endl; - defn << "}" << endl; - - defn << "static bool " << thread_class_ << "_step_" - << out_step << "_(vvm_thread*thr) {" << endl; - defn << " delete thr->callee_;" << endl; - defn << " thr->callee_ = 0;" << endl; -} - -bool target_vvm::proc_wait(const NetEvWait*wait) -{ - unsigned out_step = ++thread_step_; - - defn << " thr->step_ = &" << thread_class_ << "_step_" - << out_step << "_;" << endl; - - if (wait->nevents() == 1) { - const NetEvent*ev = wait->event(0); - assert(ev); - string ename = mangle(ev->full_name()); - defn << " " << ename << ".wait(thr); // " - << wait->get_line() << ": @" << ev->full_name() - << "..." << endl; - - } else { - /* If there are many events to wait for, generate a - selector that is a vvm_sync that I chain to the - source vvm_sync objects. Then, wait on the selector - object instead. */ - unsigned id = selector_counter++; - out << "static vvm_sync selector_" << id << ";" << endl; - - for (unsigned idx = 0 ; idx < wait->nevents() ; idx+= 1) { - const NetEvent*ev = wait->event(idx); - assert(ev); - string ename = mangle(ev->full_name()); - init_code << " selector_" << id - << ".chain_sync(&" << ename << "); // " - << wait->get_line() << ": @" << ev->full_name() - << "..." << endl; - } - - defn << " selector_" << id << ".wait(thr);" - << endl; - } - - defn << " return false;" << endl; - defn << "}" << endl; - - out << "static bool " << thread_class_ << "_step_" << out_step - << "_(vvm_thread*thr);" << endl; - - defn << "bool " << thread_class_ << "_step_" << out_step - << "_(vvm_thread*thr) {" << endl; - - return wait->emit_recurse(this); -} - -/* - * The while loop is implemented by making each iteration one [or - * more] basic block and letting the loop condition skip to the block - * after or continue with the current block. This is similar to how - * the condit is handled. The basic structure of the loop is as follows: - * - * head_step: - * evaluate condition - * if false, go to out_step - * execute body - * - * out_step: - */ -void target_vvm::proc_while(const NetWhile*net) -{ - unsigned head_step = ++thread_step_; - unsigned out_step = ++thread_step_; - - out << "static bool " << thread_class_ << "_step_" - << head_step << "_(vvm_thread*thr);" << endl; - - out << "static bool " << thread_class_ << "_step_" - << out_step << "_(vvm_thread*thr);" << endl; - - defn << " thr->step_ = &" << thread_class_ << "_step_" - << head_step << "_;" << endl; - defn << " return true;" << endl; - defn << "}" << endl; - - defn << "// " << net->expr()->get_line() << - ": top of while condition." << endl; - defn << "static bool " << thread_class_ << "_step_" - << head_step << "_(vvm_thread*thr) {" << endl; - - string expr = emit_proc_rval(this, net->expr()); - - defn << "// " << net->expr()->get_line() << - ": test while condition." << endl; - if (net->expr()->expr_width() == 1) { - defn << " if (!B_IS1(" << expr << "[0])) {" << endl; - } else { - defn << " if (!B_IS1(vvm_unop_or(" << expr << "))) {" << endl; - } - defn << " thr->step_ = &" << thread_class_ << "_step_" - << out_step << "_;" << endl; - defn << " return true;" << endl; - defn << " }" << endl; - - net->emit_proc_recurse(this); - - defn << "// " << net->expr()->get_line() << - ": end of while loop." << endl; - defn << " thr->step_ = &" << thread_class_ << "_step_" - << head_step << "_;" << endl; - defn << " return true;" << endl; - defn << "}" << endl; - - defn << "static bool " << thread_class_ << "_step_" - << out_step << "_(vvm_thread*thr) {" << endl; -} - - -/* - * A delay suspends the thread for a period of time. If the delay - * is an expression expresion, evaluate it at run time and use the - * unsigned interpretation of it as the actual delay. - */ -bool target_vvm::proc_delay(const NetPDelay*proc) -{ - thread_step_ += 1; - - if (proc->expr()) { - string rval = emit_proc_rval(this, proc->expr()); - defn << " thr->step_ = &" << thread_class_ << "_step_" - << thread_step_ << "_;" << endl; - defn << " thr->thread_yield(" << rval << ".as_unsigned());" - << endl; - defn << " return false;" << endl; - defn << "}" << endl; - - } else { - defn << " thr->step_ = &" << thread_class_ << "_step_" - << thread_step_ << "_;" << endl; - defn << " thr->thread_yield(" << proc->delay() << ");" - << endl; - defn << " return false;" << endl; - defn << "}" << endl; - } - - out << "static bool " << thread_class_ << "_step_" - << thread_step_ << "_(vvm_thread*thr);" << endl; - - defn << "static bool " << thread_class_ << "_step_" << thread_step_ - << "_(vvm_thread*thr) {" << endl; - - return proc->emit_proc_recurse(this); -} - -void target_vvm::end_process(ostream&os, const NetProcTop*proc) -{ - if (proc->type() == NetProcTop::KALWAYS) { - defn << " thr->step_ = &" << thread_class_ << "_step_0_;" - << endl; - defn << " return true;" << endl; - } else { - defn << " thr->step_ = 0;" << endl; - defn << " return false;" << endl; - } - - defn << "}" << endl; -} - - -static target_vvm target_vvm_obj; - -extern const struct target tgt_vvm = { - "vvm", - &target_vvm_obj -}; -/* - * $Log: t-vvm.cc,v $ - * Revision 1.214 2002/01/19 19:02:08 steve - * Pass back target errors processing conditionals. - * - * Revision 1.213 2001/10/14 03:50:53 steve - * vvm support for pullup/down gates (PR#288) - * - * Revision 1.212 2001/08/25 23:50:03 steve - * Change the NetAssign_ class to refer to the signal - * instead of link into the netlist. This is faster - * and uses less space. Make the NetAssignNB carry - * the delays instead of the NetAssign_ lval objects. - * - * Change the vvp code generator to support multiple - * l-values, i.e. concatenations of part selects. - * - * Revision 1.211 2001/07/27 04:51:44 steve - * Handle part select expressions as variants of - * NetESignal/IVL_EX_SIGNAL objects, instead of - * creating new and useless temporary signals. - * - * Revision 1.210 2001/07/25 03:10:50 steve - * Create a config.h.in file to hold all the config - * junk, and support gcc 3.0. (Stephan Boettcher) - * - * Revision 1.209 2001/06/18 01:54:49 steve - * Add the ~& reduction operator. - * - * Revision 1.208 2001/06/12 03:53:10 steve - * Change the VPI call process so that loaded .vpi modules - * use a function table instead of implicit binding. - * - * Revision 1.207 2001/05/20 15:09:39 steve - * Mingw32 support (Venkat Iyer) - * - * Revision 1.206 2001/04/22 23:09:46 steve - * More UDP consolidation from Stephan Boettcher. - * - * Revision 1.205 2001/04/06 02:28:02 steve - * Generate vvp code for functions with ports. - * - * Revision 1.204 2001/04/02 02:28:12 steve - * Generate code for task calls. - * - * Revision 1.203 2001/03/27 03:31:06 steve - * Support error code from target_t::end_design method. - * - * Revision 1.202 2001/02/13 04:11:24 steve - * Generate proper code for wide condition expressions. - * - * Revision 1.201 2001/01/16 03:57:46 steve - * Get rid of gate templates. - * - * Revision 1.200 2001/01/12 04:20:18 steve - * Generated function prototype. (PR#107) - * - * Revision 1.199 2001/01/06 22:22:17 steve - * Support signed decimal display of variables. - * - * Revision 1.198 2001/01/01 01:41:09 steve - * reg_assign into function ports. (PR#95) - * - * Revision 1.197 2000/12/17 05:33:11 steve - * Generate smaller code for reg assigns. - * - * Revision 1.196 2000/12/16 23:55:24 steve - * Generate loops to initialize vectors or constants. - * - * Revision 1.195 2000/12/16 16:57:43 steve - * Observe delays in non-blocking assignments (PR#83) - * - * Revision 1.194 2000/12/15 21:54:43 steve - * Allow non-blocking assign to pad memory word with zeros. - * - * Revision 1.193 2000/12/15 21:40:26 steve - * concatenation as parameter to system tasks. PR#64) - * - * Revision 1.192 2000/12/15 20:05:16 steve - * Fix memory access in vvm. (PR#70) - * - * Revision 1.191 2000/12/15 03:06:04 steve - * functions with system tasks (PR#46) - * - * Revision 1.190 2000/12/12 03:30:44 steve - * NetEUFuncs are allowed as system task parameters. - * - * Revision 1.189 2000/12/11 00:31:43 steve - * Add support for signed reg variables, - * simulate in t-vvm signed comparisons. - * - * Revision 1.188 2000/12/10 06:41:59 steve - * Support delays on continuous assignment from idents. (PR#40) - * - * Revision 1.187 2000/12/09 06:17:20 steve - * unary expressions as parameters (PR#42, PR#68) - * - * Revision 1.186 2000/11/30 17:31:42 steve - * Change LineInfo to store const C strings. - * - * Revision 1.185 2000/11/20 00:58:40 steve - * Add support for supply nets (PR#17) - * - * Revision 1.184 2000/11/11 01:52:09 steve - * change set for support of nmos, pmos, rnmos, rpmos, notif0, and notif1 - * change set to correct behavior of bufif0 and bufif1 - * (Tim Leight) - * - * Also includes fix for PR#27 - * - * Revision 1.183 2000/11/04 06:36:24 steve - * Apply sequential UDP rework from Stephan Boettcher (PR#39) - * - * Revision 1.182 2000/10/29 17:10:02 steve - * task threads ned their scope initialized. (PR#32) - * - * Revision 1.181 2000/10/28 00:51:42 steve - * Add scope to threads in vvm, pass that scope - * to vpi sysTaskFunc objects, and add vpi calls - * to access that information. - * - * $display displays scope in %m (PR#1) - * - * Revision 1.180 2000/10/26 00:29:10 steve - * Put signals into a signal_table - * - * Revision 1.179 2000/10/06 23:11:39 steve - * Replace data references with function calls. (Venkat) - * - * Revision 1.178 2000/10/06 02:21:35 steve - * sfuncs are char* and are compared with strcmp - * - * Revision 1.177 2000/09/26 01:35:42 steve - * Remove the obsolete NetEIdent class. - * - * Revision 1.176 2000/09/20 02:53:15 steve - * Correctly measure comples l-values of assignments. - * - * Revision 1.175 2000/09/17 21:26:15 steve - * Add support for modulus (Eric Aardoom) - * - * Revision 1.174 2000/09/16 21:28:14 steve - * full featured l-values for non-blocking assiginment. - * - * Revision 1.173 2000/09/10 02:18:16 steve - * elaborate complex l-values - * - * Revision 1.172 2000/09/08 17:08:10 steve - * initialize vlog info. - * - * Revision 1.171 2000/09/03 17:58:14 steve - * Properly ignore NetAssign_ objects. - * - * Revision 1.170 2000/09/02 20:54:21 steve - * Rearrange NetAssign to make NetAssign_ separate. - * - * Revision 1.169 2000/08/20 17:49:04 steve - * Clean up warnings and portability issues. - * - * Revision 1.168 2000/08/14 04:39:57 steve - * add th t-dll functions for net_const, net_bufz and processes. - * - * Revision 1.167 2000/08/09 03:43:45 steve - * Move all file manipulation out of target class. - * - * Revision 1.166 2000/08/08 01:50:42 steve - * target methods need not take a file stream. - * - * Revision 1.165 2000/08/02 00:57:02 steve - * tri01 support in vvm. - * - * Revision 1.164 2000/07/29 16:21:08 steve - * Report code generation errors through proc_delay. - * - * Revision 1.163 2000/07/26 03:53:11 steve - * Make simulation precision available to VPI. - * - * Revision 1.162 2000/07/14 06:12:57 steve - * Move inital value handling from NetNet to Nexus - * objects. This allows better propogation of inital - * values. - * - * Clean up constant propagation a bit to account - * for regs that are not really values. - * - * Revision 1.161 2000/07/07 04:53:54 steve - * Add support for non-constant delays in delay statements, - * Support evaluating ! in constant expressions, and - * move some code from netlist.cc to net_proc.cc. - * - * Revision 1.160 2000/06/25 19:59:42 steve - * Redesign Links to include the Nexus class that - * carries properties of the connected set of links. - * - * Revision 1.159 2000/06/24 16:40:46 steve - * expression scan uses tgt_ to get output files. - * - * Revision 1.158 2000/06/15 04:23:17 steve - * Binary expressions as operands to system tasks. - * - * Revision 1.157 2000/06/13 03:24:48 steve - * Index in memory assign should be a NetExpr. - * - * Revision 1.156 2000/06/06 02:32:45 steve - * Expand constants in its special case assignment. (Stephan Boettcher) - */ - diff --git a/vvm.txt b/vvm.txt deleted file mode 100644 index 2ca0fa734..000000000 --- a/vvm.txt +++ /dev/null @@ -1,176 +0,0 @@ - -WHAT IS VVM - -The vvm target is C++ output that uses the VVM library for a -runtime. The Verilog module that is elaborated must have no ports, as -the output program is self contained. It is useful to write a "main" -module that tests a part being designed. This output type is most -useful for batch simulation. - -The iverilog target ``vvm'' generates code that uses the vvm library, -and takes care of compiling the code into an executable program. - -The vvm library can also be used directly by C++ programmers if -desired, ir order to skip the Verilog compilation step and write -simulations in C++. - -WRITING SIMULATIONS IN C++/VVM - -It is possible to write simulations using C++ and the vvm library. The -library classes fairly directly represent hardware devices and signal -values, so writing such a simulation should be relatively obvious. The -library also supports calling VPI modules written to work with Icarus -Verilog. There are routines for loading and interfacing with VPI -modules so that they think you are Verilog. - -The details of the various classes are covered by comments in the -various header files. The core header file is vvm.h, but the header -files vvm_gates.h and vvm_signal.h are also important. - -NEXUS, GATES AND DRIVERS - -The vvm library allows the user (the t-vvm code generator from its -point of view) to build up a netlist of gates that operate like -hardware components. The basic unit of connectivity in the vvm_nexus -class. - -A vvm_nexus object represents a nexus of a netlist: that is, a point -where drivers and receivers are connected together. The nexus class -defines the sub-classes (not derived classes) driver_t and recvr_t -that objects and code use to connect to the nexus. The nexus also has -a reg_assign() method for simulating procedural assignment. - -The driver_t class is a means to drive (as opposed to assign) a value -onto the nexus. Gates with outputs have drive_t objects that they can -connect to exactly one nexus. - -The recvr_t class is where the nexus delivers the resolved -value. Receiver objects are actually able to represent many pins of a -device, although a nexus is connected to only one. This is managed by -passing to the nexus a pointer to the object and a key that the -receiver uses to identify the pin. This is done so that the gate class -can derive from the recvr_t class and support multiple input pins. - -The vvm_nexus class connects to any number of drivers and any number -of receivers. This is how fan-in and fan-out are achieved in a design -under test. When a connected driver gets a new value, the vvm_nexus -object scans all the drivers and collects the values that are being -driven. It passes the set to a resolution function that calculates the -actual value that the vvm_nexus will take, then passes that value to -all the receivers. - -If there are no drivers, the vvm_nexus can also receive a value from -procedural assignment, via the reg_assign() method. When assigned in -this manner, the vvm_nexus simply takes the value given to it and -passes it to all the receivers. The vvm_nexus holds the last value -assigned, and does not perform any resolution. - -The vvm/vvm_nexus.h header file describes the vvm_nexus and related -classes. - -ATTRIBUTES - -(none) - -INITIALIZATION OF THE SIMULATION - -The t-vvm generates initialization code that causes gates to get -initial values for their inputs, if any were specified by the -programmer, and outputs if the device is sequential. This -initialization code goes into the generated design_init() function. - -The t-vvm also generates startup code that causes gates to generate -outputs from the initial inputs. This cannot be done in the -design_init() function because of the possibilities of cycles and -other complexities in the netlist. - - -THREADS - -The generated code does not actually use threads. It instead supports -threads of verilog behavior by reducing the sequential process into -basic blocks, and calling those basic blocks as needed. - -SMALL SEQUENTIAL UDP GATES - -For gates with 8 or fewer inputs, vvm has a table based -representation. When a transition happens, the transition is converted -into a table index that addresses the next output value. This is a -compact method for representing even the most degenerate UDP -transition tables, but these degenerate tables can get pretty -large. Hence the practical limit. - -The index into the transtion table is made up of the current output -and current inputs with the following recursive formula: - - I[0] = X - I[N] = X[N] + 3 * I[N-1] - -where X[N], the value of pin N, is 0 for V0, 1 for V1 and 2 for Vx. In -other words: - - unsigned state = current_output; - for (unsigned idx = 1 ; idx < npins ; idx += 1) - state = 3*state + current_input[idx]; - -The state indexes into an array of 32bit words that contain all the -transitions out of that state. Each pin transition is represented by 4 -bits--two bits for each possible transition for the pin. The 4 bits -represent transitions as in this table: - - bits [3:2] bits [1:0] - 0 -> 1 0 -> x - 1 -> 0 1 -> x - x -> 0 x -> 1 - -The values of the bit pairs in the table entry are 2b'00 for V0, 2b'01 -for V1 and 2b'10 for Vx. The transitions are arranged in the 32bit -entry with the last pin in the lowest 4 bits, the next to last pin in -the next 4 bits, and so on. So, if P is the changing pin on a 7 pin -UDP, and E is the 32bit entry for the current state, the transition -bits are at: - - (E >> 4*(6-P)) & 0xf - -/* - * 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 - * 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 - */ - - $Id: vvm.txt,v 1.6 2000/05/11 01:44:52 steve Exp $ - $Log: vvm.txt,v $ - Revision 1.6 2000/05/11 01:44:52 steve - No need for nobufz. - - Revision 1.5 2000/03/16 19:03:04 steve - Revise the VVM backend to use nexus objects so that - drivers and resolution functions can be used, and - the t-vvm module doesn't need to write a zillion - output functions. - - Revision 1.4 1999/12/30 17:37:14 steve - Remove the now useless sigfold functor. - - Revision 1.3 1999/08/18 03:45:36 steve - Update compile command line. - - 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 -