diff --git a/aclocal.m4 b/aclocal.m4 index a6982fbeb..0b0d9c29c 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -64,7 +64,7 @@ fi # AX_WIN32 # -------- # Combined check for several flavors of Microsoft Windows so -# their "issues" can be dealt with + # their "issues" can be dealt with AC_DEFUN([AX_WIN32], [AC_MSG_CHECKING([for Microsoft Windows]) AC_REQUIRE([AC_CANONICAL_HOST]) []dnl @@ -230,6 +230,17 @@ case "${host}" in esac ])# AX_CPP_PRECOMP +# AX_C99_STRTOD +# ------------- +AC_DEFUN([AX_C99_STRTOD], +[# On MinGW we need to jump through hoops to get a C99 compliant strtod(). +case "${host}" in + *-*-mingw*) + LDFLAGS+=" -Wl,--undefined=___strtod,--wrap,strtod,--defsym,___wrap_strtod=___strtod" + ;; +esac +])# AX_C99_STRTOD + # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp file name are based on the header name. diff --git a/configure.in b/configure.in index d3ca2fdc9..cae2abf7c 100644 --- a/configure.in +++ b/configure.in @@ -192,6 +192,9 @@ AX_C_PICFLAG # may modify CPPFLAGS and CFLAGS AX_CPP_PRECOMP +# may modify LDFLAGS +AX_C99_STRTOD + # Processor specific compile flags case "${host}" in alpha*-*-linux*) diff --git a/driver/cfparse.y b/driver/cfparse.y index db2759e61..40f20c5a8 100644 --- a/driver/cfparse.y +++ b/driver/cfparse.y @@ -1,6 +1,6 @@ %{ /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2011 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 @@ -24,6 +24,7 @@ # include # include # include +# include "ivl_alloc.h" /* diff --git a/elab_expr.cc b/elab_expr.cc index d4795ee03..ad24ecff3 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1268,6 +1268,156 @@ NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope, return tmp; } +/* + * Routine to look for and build enumeration method calls. + */ +static NetExpr* check_for_enum_methods(const LineInfo*li, + Design*des, NetScope*scope, + netenum_t*netenum, + pform_name_t use_path, + perm_string method_name, + NetExpr*expr, + unsigned rtn_wid, + PExpr*parg, unsigned args) +{ + // The "num()" method returns the number of elements. + if (method_name == "num") { + if (args != 0) { + cerr << li->get_fileline() << ": error: enumeration " + "method " << use_path << ".num() does not " + "take an argument." << endl; + des->errors += 1; + } + NetEConst*tmp = make_const_val(netenum->size()); + tmp->set_line(*li); + delete expr; // The elaborated enum variable is not needed. + return tmp; + } + + // The "first()" method returns the first enumeration value. + if (method_name == "first") { + if (args != 0) { + cerr << li->get_fileline() << ": error: enumeration " + "method " << use_path << ".first() does not " + "take an argument." << endl; + des->errors += 1; + } + netenum_t::iterator item = netenum->first_name(); + NetEConstEnum*tmp = new NetEConstEnum(scope, item->first, + netenum, item->second); + tmp->set_line(*li); + delete expr; // The elaborated enum variable is not needed. + return tmp; + } + + // The "last()" method returns the first enumeration value. + if (method_name == "last") { + if (args != 0) { + cerr << li->get_fileline() << ": error: enumeration " + "method " << use_path << ".last() does not " + "take an argument." << endl; + des->errors += 1; + } + netenum_t::iterator item = netenum->last_name(); + NetEConstEnum*tmp = new NetEConstEnum(scope, item->first, + netenum, item->second); + tmp->set_line(*li); + delete expr; // The elaborated enum variable is not needed. + return tmp; + } + + NetESFunc*sys_expr; + + // Process the method argument if it is available. + NetExpr* count = 0; + if (args != 0 && parg) { + count = elaborate_rval_expr(des, scope, IVL_VT_BOOL, 32, parg); + if (count == 0) { + cerr << li->get_fileline() << ": error: unable to elaborate " + "enumeration method argument " << use_path << "." + << method_name << "(" << parg << ")." << endl; + args = 0; + des->errors += 1; + } else if (NetEEvent*evt = dynamic_cast (count)) { + cerr << evt->get_fileline() << ": error: An event '" + << evt->event()->name() << "' cannot be an enumeration " + "method argument." << endl; + args = 0; + des->errors += 1; + } + } + + // The "name()" method returns the name of the current + // enumeration value. + if (method_name == "name") { + if (args != 0) { + cerr << li->get_fileline() << ": error: enumeration " + "method " << use_path << ".name() does not " + "take an argument." << endl; + des->errors += 1; + } + sys_expr = new NetESFunc("$ivl_enum_method$name", IVL_VT_STRING, + rtn_wid, 2); + sys_expr->parm(0, new NetENetenum(netenum)); + sys_expr->parm(1, expr); + + /* The compiler/code generators need to be fixed to support a + * string return value. In some contexts we could use the + * expression width, but that doesn't always work. */ + if (rtn_wid == 0) { + cerr << li->get_fileline() << ": sorry: Enumeration method " + "name() is not currently supported in this context " + "(self-determined)." << endl; + des->errors += 1; + } + + // The "next()" method returns the next enumeration value. + } else if (method_name == "next") { + if (args > 1) { + cerr << li->get_fileline() << ": error: enumeration " + "method " << use_path << ".next() take at " + "most one argument." << endl; + des->errors += 1; + } + sys_expr = new NetESFunc("$ivl_enum_method$next", netenum, + 2 + (args != 0)); + sys_expr->parm(0, new NetENetenum(netenum)); + sys_expr->parm(1, expr); + if (args != 0) sys_expr->parm(2, count); + + // The "prev()" method returns the previous enumeration value. + } else if (method_name == "prev") { + if (args > 1) { + cerr << li->get_fileline() << ": error: enumeration " + "method " << use_path << ".prev() take at " + "most one argument." << endl; + des->errors += 1; + } + sys_expr = new NetESFunc("$ivl_enum_method$prev", netenum, + 2 + (args != 0)); + sys_expr->parm(0, new NetENetenum(netenum)); + sys_expr->parm(1, expr); + if (args != 0) sys_expr->parm(2, count); + + // This is an unknown enumeration method. + } else { + cerr << li->get_fileline() << ": error: Unknown enumeration " + "method " << use_path << "." << method_name << "()." + << endl; + des->errors += 1; + return expr; + } + + sys_expr->set_line(*li); + + if (debug_elaborate) { + cerr << li->get_fileline() << ": debug: Generate " + << sys_expr->name() << "(" << use_path << ")" << endl; + } + + return sys_expr; +} + NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags) const { @@ -1286,6 +1436,46 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, return elaborate_access_func_(des, scope, access_nature, expr_wid); + // Maybe this is a method attached to an enumeration name? If + // this is system verilog, then test to see if the name is + // really a method attached to an object. + if (gn_system_verilog() && path_.size() >= 2) { + pform_name_t use_path = path_; + perm_string method_name = peek_tail_name(use_path); + use_path.pop_back(); + + NetNet *net; + const NetExpr *par; + NetEvent *eve; + const NetExpr *ex1, *ex2; + + symbol_search(this, des, scope, use_path, + net, par, eve, ex1, ex2); + + // Check to see if we have a net and if so is it an + // enumeration? If so then check to see if this is an + // enumeration method call. + if (net != 0) { + netenum_t*netenum = net->enumeration(); + if (netenum) { + // We may need the net expression for the + // enumeration variable so get it. + NetESignal*expr = new NetESignal(net); + expr->set_line(*this); + // This expression cannot be a select! + assert(use_path.back().index.empty()); + + PExpr*tmp = parms_.size() ? parms_[0] : 0; + return check_for_enum_methods(this, des, scope, + netenum, use_path, + method_name, expr, + expr_wid, tmp, + parms_.size()); + } + } + } + + // Nothing was found so report this as an error. cerr << get_fileline() << ": error: No function named `" << path_ << "' found in this context (" << scope_path(scope) << ")." << endl; @@ -2087,73 +2277,32 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, // Maybe this is a method attached to an enumeration name? If // this is system verilog, then test to see if the name is // really a method attached to an object. - if (gn_system_verilog() && found_in==0 && path_.size() >= 2) { pform_name_t use_path = path_; perm_string method_name = peek_tail_name(use_path); use_path.pop_back(); found_in = symbol_search(this, des, scope, use_path, - net, par, eve, ex1, ex2); + net, par, eve, ex1, ex2); + // Check to see if we have a net and if so is it an + // enumeration? If so then check to see if this is an + // enumeration method call. if (net != 0) { - // Special case: The net is an enum, and the - // method name is "num". netenum_t*netenum = net->enumeration(); - if (netenum && method_name == "num") { - NetEConst*tmp = make_const_val(netenum->size()); - tmp->set_line(*this); - return tmp; + if (netenum) { + // We may need the net expression for the + // enumeration variable so get it. + NetESignal*expr = new NetESignal(net); + expr->set_line(*this); + // This expression cannot be a select! + assert(use_path.back().index.empty()); + + return check_for_enum_methods(this, des, scope, + netenum, + use_path, method_name, + expr, expr_wid, NULL, 0); } - - // Special case: The net is an enum, and the - // method name is "first" or "last". These - // evaluate to constant values. - if (netenum && method_name == "first") { - netenum_t::iterator item = netenum->first_name(); - NetEConstEnum*tmp = new NetEConstEnum(scope, item->first, - netenum, item->second); - tmp->set_line(*this); - return tmp; - } - if (netenum && method_name == "last") { - netenum_t::iterator item = netenum->last_name(); - NetEConstEnum*tmp = new NetEConstEnum(scope, item->first, - netenum, item->second); - tmp->set_line(*this); - return tmp; - } - - NetExpr*expr = elaborate_expr_net(des, scope, net, found_in, - expr_wid, NO_FLAGS); - NetESFunc*sys_expr = 0; - - if (method_name == "name") { - sys_expr = new NetESFunc("$ivl_method$name", IVL_VT_STRING,0, 1); - sys_expr->parm(0, expr); - } else if (method_name == "next") { - sys_expr = new NetESFunc("$ivl_method$next", netenum, 2); - sys_expr->parm(0, new NetENetenum(netenum)); - sys_expr->parm(1, expr); - } else if (method_name == "prev") { - sys_expr = new NetESFunc("$ivl_method$prev", netenum, 2); - sys_expr->parm(0, new NetENetenum(netenum)); - sys_expr->parm(1, expr); - } else { - cerr << get_fileline() << ": error: " - << "Unknown method name `" << method_name << "'" - << " attached to " << use_path << "." << endl; - des->errors += 1; - return elaborate_expr_net(des, scope, net, found_in, - expr_wid, NO_FLAGS); - } - - sys_expr->set_line(*this); - - if (debug_elaborate) - cerr << get_fileline() << ": debug: Generate " - << sys_expr->name() << "(" << use_path << ")" << endl; - return sys_expr; } } diff --git a/elaborate.cc b/elaborate.cc index 28384e005..42acbea88 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3500,7 +3500,7 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope, /* Elaborate wait expression. Don't eval yet, we will do that shortly, after we apply a reduction or. */ - PExpr::width_mode_t mode; + PExpr::width_mode_t mode = PExpr::SIZED; pe->test_width(des, scope, mode); NetExpr*expr = pe->elaborate_expr(des, scope, pe->expr_width(), PExpr::NO_FLAGS); diff --git a/eval_tree.cc b/eval_tree.cc index 6bc35b4c0..bbce3cbc2 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -364,7 +364,6 @@ NetEConst* NetEBComp::eval_leeq_() left_->expr_type() == IVL_VT_REAL) return eval_leeq_real_(left_, right_, true); // assert(expr_type() == IVL_VT_LOGIC); -// HERE NetEConst*r = dynamic_cast(right_); if (r == 0) return 0; @@ -1090,7 +1089,6 @@ NetEConst* NetEBShift::eval_tree() NetEConst* NetEConcat::eval_tree() { -// HERE unsigned repeat_val = repeat(); unsigned local_errors = 0; @@ -1182,7 +1180,6 @@ NetEConst* NetEConcat::eval_tree() NetEConst* NetESelect::eval_tree() { -// HERE if (debug_eval_tree) { cerr << get_fileline() << ": debug: Evaluating expression:" << *this << endl; @@ -1846,7 +1843,6 @@ static NetExpr* evaluate_min_max(NetExpr*&arg0_, NetExpr*&arg1_, NetExpr* NetESFunc::eval_tree() { -// HERE /* If we are not targeting at least Verilog-2005, Verilog-AMS * or using the Icarus misc flag then we do not support these * functions as constant. */ diff --git a/iverilog-vpi.man.in b/iverilog-vpi.man.in index ad870cb1b..b1708bddf 100644 --- a/iverilog-vpi.man.in +++ b/iverilog-vpi.man.in @@ -48,7 +48,7 @@ modules, then exit. It is a convenience for makefiles or automated plug-in installers. .TP 8 -.B --cflags, --ldflags and -ldlibs +.B --cflags, --ldflags and --ldlibs These flags provide compile time information. .SH "PC-ONLY OPTIONS" diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index 2e054ee90..348f78ba3 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -1795,14 +1795,14 @@ static void open_input_file(struct include_stack_t*isp) for (idx = 0 ; idx < vhdlpp_libdir_cnt ; idx += 1) { size_t next_len = 6 + strlen(vhdlpp_libdir[idx]); libs = realloc(libs, liblen+next_len); - snprintf(libs+liblen-1, next_len, " -L'%s'", vhdlpp_libdir[idx]); + snprintf(libs+liblen-1, next_len, " -L\"%s\"", vhdlpp_libdir[idx]); liblen = strlen(libs) + 1; } cmdlen += liblen; char*cmd = malloc(cmdlen); - snprintf(cmd, cmdlen, "%s -w'%s'%s %s", vhdlpp_path, vhdlpp_work, libs, isp->path); + snprintf(cmd, cmdlen, "%s -w\"%s\"%s %s", vhdlpp_path, vhdlpp_work, libs, isp->path); if (verbose_flag) fprintf(stderr, "Invoke vhdlpp: %s\n", cmd); diff --git a/ivlpp/main.c b/ivlpp/main.c index f0e6cb871..d7fedab32 100644 --- a/ivlpp/main.c +++ b/ivlpp/main.c @@ -1,5 +1,5 @@ const char COPYRIGHT[] = - "Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com)"; + "Copyright (c) 1999-2011 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 @@ -457,6 +457,14 @@ int main(int argc, char*argv[]) } free(include_dir); + /* Free the VHDL library directories, the path and work directory. */ + for (lp = 0; lp < vhdlpp_libdir_cnt; lp += 1) { + free(vhdlpp_libdir[lp]); + } + free(vhdlpp_libdir); + free(vhdlpp_path); + free(vhdlpp_work); + free_macros(); return error_count; diff --git a/libveriuser/getsimtime.c b/libveriuser/getsimtime.c index 5791ac13a..e016af08e 100644 --- a/libveriuser/getsimtime.c +++ b/libveriuser/getsimtime.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2010 Michael Ruff (mruff at chiaro.com) + * Copyright (c) 2002-2011 Michael Ruff (mruff at chiaro.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 @@ -83,9 +83,24 @@ PLI_INT32 tf_getlongtime(PLI_INT32 *high) return tf_igetlongtime(high, 0); } -/* Alias for commercial simulators */ -PLI_INT32 tf_getlongsimtime(PLI_INT32 *high) \ - __attribute__ ((weak, alias ("tf_getlongtime"))); +/* + * This function is not defined in the IEE standard, but is provided for + * compatibility with other simulators. On platforms that support this, + * make it a weak symbol just in case the user has defined their own + * function for this. + */ +#if !defined(__CYGWIN__) && !defined(__MINGW32__) +PLI_INT32 tf_getlongsimtime(PLI_INT32 *high) __attribute__ ((weak)); +#endif +PLI_INT32 tf_getlongsimtime(PLI_INT32 *high) +{ + s_vpi_time timerec; + timerec.type = vpiSimTime; + vpi_get_time (0, &timerec); + + *high = timerec.high; + return timerec.low; +} void tf_scale_longdelay(void*obj, PLI_INT32 low, PLI_INT32 high, PLI_INT32 *alow, PLI_INT32 *ahigh) diff --git a/main.cc b/main.cc index 2c65eb46d..bac6e326c 100644 --- a/main.cc +++ b/main.cc @@ -737,7 +737,7 @@ static double cycles_diff(struct tms *a, struct tms *b) // Provide dummies struct tms { int x; }; inline static void times(struct tms *) { } -inline static double cycles_diff(struct tms *a, struct tms *b) { return 0; } +inline static double cycles_diff(struct tms *, struct tms *) { return 0; } #endif // ! defined(HAVE_TIMES) static void EOC_cleanup(void) diff --git a/netenum.cc b/netenum.cc index 2f5f14aed..99dd26f9b 100644 --- a/netenum.cc +++ b/netenum.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2010-2011 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 @@ -62,7 +62,7 @@ perm_string netenum_t::find_value(const verinum&val) const { perm_string res; for(netenum_t::iterator cur = names_map_.begin(); - cur != names_map_.end(); cur++) { + cur != names_map_.end(); ++ cur) { if (cur->second == val) { res = cur->first; break; diff --git a/netmisc.cc b/netmisc.cc index ec50f45e3..b9abaad93 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -589,8 +589,7 @@ void eval_expr(NetExpr*&expr, int context_width) // The expression is a constant, so resize it if needed. if (ce->expr_width() < (unsigned)context_width) { expr = pad_to_width(expr, context_width, *expr); - } - if (ce->expr_width() > (unsigned)context_width) { + } else if (ce->expr_width() > (unsigned)context_width) { verinum value(ce->value(), context_width); ce = new NetEConst(value); ce->set_line(*expr); diff --git a/sv_vpi_user.h b/sv_vpi_user.h index e6e20b527..606f7f73f 100644 --- a/sv_vpi_user.h +++ b/sv_vpi_user.h @@ -1,7 +1,7 @@ #ifndef __sv_vpi_user_H #define __sv_vpi_user_H /* - * Copyright (c) 2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2010-2011 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 @@ -54,6 +54,9 @@ EXTERN_C_START #define vpiEnumTypespec 633 #define vpiEnumConst 634 +/********* One-to-One ***********/ +#define vpiBaseTypespec 703 + /********* Many-to-One ***********/ #define vpiMember 742 diff --git a/t-dll.cc b/t-dll.cc index 2038b425c..7ac03ae15 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -1045,6 +1045,7 @@ bool dll_target::ureduce(const NetUReduce*net) switch (net->type()) { case NetUReduce::NONE: assert(0); + delete obj; return false; case NetUReduce::AND: obj->type = IVL_LPM_RE_AND; diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 76002195d..24fd5bdb4 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -229,7 +229,7 @@ static void show_lpm_arithmetic_pins(ivl_lpm_t net) { ivl_nexus_t nex; nex = ivl_lpm_q(net); - fprintf(out, " Q: %p\n", ivl_lpm_q(net)); + fprintf(out, " Q: %p\n", nex); nex = ivl_lpm_data(net, 0); fprintf(out, " DataA: %p\n", nex); @@ -247,7 +247,7 @@ static void show_lpm_abs(ivl_lpm_t net) ivl_lpm_basename(net), width); nex = ivl_lpm_q(net); - fprintf(out, " Q: %p\n", ivl_lpm_q(net)); + fprintf(out, " Q: %p\n", nex); nex = ivl_lpm_data(net, 0); fprintf(out, " D: %p\n", nex); @@ -690,6 +690,7 @@ static void show_lpm_re(ivl_lpm_t net) break; case IVL_LPM_RE_NOR: type = "NOR"; + break; case IVL_LPM_RE_XOR: type = "XOR"; break; diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 7581113df..4e2f6c1af 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -1,7 +1,7 @@ /* * VHDL code generation for statements. * - * Copyright (C) 2008-2010 Nick Gasson (nick@nickg.me.uk) + * Copyright (C) 2008-2011 Nick Gasson (nick@nickg.me.uk) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1312,6 +1312,15 @@ static bool process_signal(vhdl_binop_expr *all, vhdl_var_ref *test, } unsigned ewid = ivl_expr_width(expr); + if (sizeof(unsigned) >= sizeof(long)) { + // Since we will be casting i (constrained by swid) to a long make sure + // it will fit into a long. This is actually off by one, but this is the + // best we can do since on 32 bit machines an unsigned and long are the + // same size. + assert(swid <= static_cast(numeric_limits::max())); + // We are also going to cast ewid to long so check it as well. + assert(ewid <= static_cast(numeric_limits::max())); + } for (unsigned i = 0; i < swid; i++) { // Generate a comparison for this bit position vhdl_binop_expr *cmp; @@ -1321,7 +1330,8 @@ static bool process_signal(vhdl_binop_expr *all, vhdl_var_ref *test, // Check if this is an out of bounds access. If this is a casez // then check against a constant 'x' for the out of bound bits // otherwise skip the check (casex). - if (i + sbase >= ewid || i + sbase < 0) { + if (static_cast(i) + sbase >= static_cast(ewid) || + static_cast(i) + sbase < 0) { if (is_casez) { // Get the current test bit. type = vhdl_type::nunsigned(width); diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index 388a56275..2ce8ba45a 100644 --- a/tgt-vlog95/logic_lpm.c +++ b/tgt-vlog95/logic_lpm.c @@ -1015,7 +1015,6 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm) emit_nexus_as_ca(scope, nex); if (have_data | have_sset) fprintf(vlog_out, " & "); if (have_data & have_sset) fprintf(vlog_out, "("); - emitted = 1; } nex = ivl_lpm_sync_set(lpm); if (nex) { diff --git a/tgt-vlog95/udp.c b/tgt-vlog95/udp.c index e95d44135..34feb356d 100644 --- a/tgt-vlog95/udp.c +++ b/tgt-vlog95/udp.c @@ -20,6 +20,7 @@ # include # include "config.h" # include "vlog95_priv.h" +# include "ivl_alloc.h" static void emit_entry(ivl_udp_t udp, char entry, unsigned *rerun) { diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 298ad5125..a975ca729 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -1276,10 +1276,31 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval) } if (ivl_signal_width(lsig) > ivl_signal_width(rsig) || (part_off_ex && get_number_immediate(part_off_ex) != 0)) { - fprintf(stderr, "%s:%u: tgt-vvp sorry: cannot %s signal to " - "a bit/part select.\n", ivl_expr_file(rval), - ivl_expr_lineno(rval), command_name); - exit(1); + /* Normalize the bit/part select. */ + long real_msb = ivl_signal_msb(lsig); + long real_lsb = ivl_signal_lsb(lsig); + long use_wid = ivl_signal_width(rsig); + long use_lsb, use_msb; + if (real_msb >= real_lsb) { + use_lsb = get_number_immediate(part_off_ex); + use_lsb += real_lsb; + use_msb = use_lsb + use_wid - 1; + } else { + use_lsb = real_lsb; + use_lsb -= get_number_immediate(part_off_ex); + use_msb = use_lsb; + use_msb -= use_wid - 1; + } + fprintf(stderr, "%s:%u: tgt-vvp sorry: cannot %s signal to a ", + ivl_stmt_file(net), ivl_stmt_lineno(net), command_name); + if (use_wid > 1) { + fprintf(stderr, "part select (%s[%lu:%lu]).\n", + ivl_signal_basename(lsig), use_msb, use_lsb); + } else { + fprintf(stderr, "bit select (%s[%lu]).\n", + ivl_signal_basename(lsig), use_lsb); + } + vvp_errors += 1; } /* At least for now, only handle force to fixed words of an array. */ @@ -1287,17 +1308,42 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval) assert(number_is_immediate(lword_idx, IMM_WID, 0)); assert(! number_is_unknown(lword_idx)); use_lword = get_number_immediate(lword_idx); + /* We do not currently support using a word from a variable + * array as the L-value (Icarus extension). */ + if (ivl_signal_type(lsig) == IVL_SIT_REG) { + /* Normalize the array access. */ + long real_word = use_lword; + real_word += ivl_signal_array_base(lsig); + fprintf(stderr, "%s:%u: tgt-vvp sorry: cannot %s to the " + "word of a variable array (%s[%ld]).\n", + ivl_stmt_file(net), ivl_stmt_lineno(net), + command_name, ivl_signal_basename(lsig), real_word); + vvp_errors += 1; + } } if ((rword_idx = ivl_expr_oper1(rval)) != 0) { + assert(ivl_signal_dimensions(rsig) != 0); assert(number_is_immediate(rword_idx, IMM_WID, 0)); assert(! number_is_unknown(rword_idx)); use_rword = get_number_immediate(rword_idx); + /* We do not currently support using a word from a variable + * array as the R-value. */ + if (ivl_signal_type(rsig) == IVL_SIT_REG) { + /* Normalize the array access. */ + long real_word = use_rword; + real_word += ivl_signal_array_base(rsig); + fprintf(stderr, "%s:%u: tgt-vvp sorry: cannot %s from the " + "word of a variable array (%s[%ld]).\n", + ivl_expr_file(rval), ivl_expr_lineno(rval), + command_name, ivl_signal_basename(rsig), real_word); + vvp_errors += 1; + } + } else { + assert(ivl_signal_dimensions(rsig) == 0); + use_rword = 0; } - assert(ivl_signal_dimensions(rsig) == 0); - use_rword = 0; - fprintf(vvp_out, " %s/link", command_name); fprintf(vvp_out, " v%p_%lu", lsig, use_lword); fprintf(vvp_out, ", v%p_%lu;\n", rsig, use_rword); diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index d5bee38e1..ed767565c 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -162,8 +162,8 @@ Expression*ExpAggregate::choice_t::simple_expression(bool detach_flag) ExpAggregate::element_t::element_t(list*fields, Expression*val) : fields_(fields? fields->size() : 0), val_(val) { - size_t idx = 0; if (fields) { + size_t idx = 0; while (! fields->empty()) { assert(idx < fields_.size()); fields_[idx++] = fields->front(); diff --git a/vhdlpp/lexor.lex b/vhdlpp/lexor.lex index bf300c6f3..9ab591168 100644 --- a/vhdlpp/lexor.lex +++ b/vhdlpp/lexor.lex @@ -278,7 +278,7 @@ static bool is_based_correct(char* text) if(base == 0) return 0; } - bool point = 0; + bool point = false; set allowed_chars; unsigned c; @@ -299,12 +299,12 @@ static bool is_based_correct(char* text) if(*ptr == '.') { //we found a dot and another one was already found - if(point == 1) + if(point) return 0; else { //notice the fact of finding a point and continue, without increasing the length - point = 1; + point = true; continue; } } diff --git a/vhdlpp/main.cc b/vhdlpp/main.cc index 0cadb31ce..7901b699e 100644 --- a/vhdlpp/main.cc +++ b/vhdlpp/main.cc @@ -81,6 +81,10 @@ const char NOTICE[] = # include #endif # include +#if defined(__MINGW32__) +# include +# define mkdir(path, mode) _mkdir(path) +#endif bool verbose_flag = false; diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index d2127674f..121b46627 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -118,7 +118,7 @@ class Scope : public ScopeBase { class ActiveScope : public ScopeBase { public: - ActiveScope() { } + ActiveScope() : context_entity_(0) { } ActiveScope(ActiveScope*par) : ScopeBase(*par), context_entity_(0) { } ~ActiveScope() { } diff --git a/vpi/Makefile.in b/vpi/Makefile.in index f692a37c7..dec1fd066 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -151,7 +151,7 @@ va_math.vpi: $V ../vvp/libvpi.a $(CC) @shared@ -o $@ $V -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS) vhdl_sys.vpi: $(VHDL_SYS) ../vvp/libvpi.a - $(CXX) @shared@ -o $@ $(VHDL_SYS) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) + $(CC) @shared@ -o $@ $(VHDL_SYS) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) stamp-vpi_config-h: $(srcdir)/vpi_config.h.in ../config.status @rm -f $@ diff --git a/vpi/cppcheck.sup b/vpi/cppcheck.sup index f72ed579c..1ba0e2488 100644 --- a/vpi/cppcheck.sup +++ b/vpi/cppcheck.sup @@ -3,22 +3,23 @@ // problems will not be fixed. // fstapi.c from GTKWave -variableScope:fstapi.c:1689 -variableScope:fstapi.c:1817 -variableScope:fstapi.c:1911 -variableScope:fstapi.c:1912 -variableScope:fstapi.c:2617 -variableScope:fstapi.c:2937 -variableScope:fstapi.c:2941 -variableScope:fstapi.c:2942 +variableScope:fstapi.c:1713 +variableScope:fstapi.c:1841 +variableScope:fstapi.c:1935 +variableScope:fstapi.c:1936 +variableScope:fstapi.c:2642 +variableScope:fstapi.c:2962 +variableScope:fstapi.c:2966 +variableScope:fstapi.c:2967 +variableScope:fstapi.c:4641 // lxt2_write.c from GTKWave variableScope:lxt2_write.c:63 variableScope:lxt2_write.c:523 variableScope:lxt2_write.c:581 variableScope:lxt2_write.c:587 -variableScope:lxt2_write.c:1602 -variableScope:lxt2_write.c:2049 +variableScope:lxt2_write.c:1600 +variableScope:lxt2_write.c:2047 // lxt_write.c from GTKWave variableScope:lxt_write.c:31 diff --git a/vpi/fstapi.c b/vpi/fstapi.c index 8ed5af6f3..f59a12fc8 100644 --- a/vpi/fstapi.c +++ b/vpi/fstapi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2010 Tony Bybell. + * Copyright (c) 2009-2011 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -505,6 +505,7 @@ unsigned repack_on_close : 1; unsigned skip_writing_section_hdr : 1; unsigned size_limit_locked : 1; unsigned section_header_only : 1; +unsigned flush_context_pending : 1; /* should really be semaphores, but are bytes to cut down on read-modify-write window size */ unsigned char already_in_flush; /* in case control-c handlers interrupt */ @@ -758,272 +759,6 @@ return(xc); } -void fstWriterClose(void *ctx) -{ -struct fstWriterContext *xc = (struct fstWriterContext *)ctx; -if(xc && !xc->already_in_close && !xc->already_in_flush) - { - unsigned char *tmem; - off_t fixup_offs, tlen, hlen; - - xc->already_in_close = 1; /* never need to zero this out as it is freed at bottom */ - - if(xc->section_header_only && xc->section_header_truncpos && (xc->vchg_siz <= 1) && (!xc->is_initial_time)) - { - fstFtruncate(fileno(xc->handle), xc->section_header_truncpos); - fseeko(xc->handle, xc->section_header_truncpos, SEEK_SET); - xc->section_header_only = 0; - } - else - { - xc->skip_writing_section_hdr = 1; - if(!xc->size_limit_locked) - { - if(xc->is_initial_time) /* simulation time never advanced so mock up the changes as time zero ones */ - { - fstHandle dupe_idx; - - fstWriterEmitTimeChange(xc, 0); /* emit some time change just to have one */ - for(dupe_idx = 0; dupe_idx < xc->maxhandle; dupe_idx++) /* now clone the values */ - { - fstWriterEmitValueChange(xc, dupe_idx+1, xc->curval_mem + xc->valpos_mem[4*dupe_idx]); - } - } - fstWriterFlushContext(xc); - } - } - fstDestroyMmaps(xc, 1); - - /* write out geom section */ - fflush(xc->geom_handle); - tlen = ftello(xc->geom_handle); - tmem = fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->geom_handle), 0); - if(tmem) - { - unsigned long destlen = tlen; - unsigned char *dmem = malloc(destlen); - int rc = compress2(dmem, &destlen, tmem, tlen, 9); - - if((rc != Z_OK) || (destlen > tlen)) - { - destlen = tlen; - } - - fixup_offs = ftello(xc->handle); - fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ - fstWriterUint64(xc->handle, destlen + 24); /* section length */ - fstWriterUint64(xc->handle, tlen); /* uncompressed */ - /* compressed len is section length - 24 */ - fstWriterUint64(xc->handle, xc->maxhandle); /* maxhandle */ - fstFwrite((destlen != tlen) ? dmem : tmem, destlen, 1, xc->handle); - fflush(xc->handle); - - fseeko(xc->handle, fixup_offs, SEEK_SET); - fputc(FST_BL_GEOM, xc->handle); /* actual tag */ - - fseeko(xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ - fflush(xc->handle); - - free(dmem); - fstMunmap(tmem, tlen); - } - - if(xc->num_blackouts) - { - uint64_t cur_bl = 0; - off_t bpos, eos; - uint32_t i; - - fixup_offs = ftello(xc->handle); - fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ - bpos = fixup_offs + 1; - fstWriterUint64(xc->handle, 0); /* section length */ - fstWriterVarint(xc->handle, xc->num_blackouts); - - for(i=0;inum_blackouts;i++) - { - fputc(xc->blackout_head->active, xc->handle); - fstWriterVarint(xc->handle, xc->blackout_head->tim - cur_bl); - cur_bl = xc->blackout_head->tim; - xc->blackout_curr = xc->blackout_head->next; - free(xc->blackout_head); - xc->blackout_head = xc->blackout_curr; - } - - eos = ftello(xc->handle); - fseeko(xc->handle, bpos, SEEK_SET); - fstWriterUint64(xc->handle, eos - bpos); - fflush(xc->handle); - - fseeko(xc->handle, fixup_offs, SEEK_SET); - fputc(FST_BL_BLACKOUT, xc->handle); /* actual tag */ - - fseeko(xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ - fflush(xc->handle); - } - - if(xc->compress_hier) - { - unsigned char *mem = malloc(FST_GZIO_LEN); - off_t hl, eos; - gzFile zhandle; - int zfd; -#ifndef __MINGW32__ - char *fnam = malloc(strlen(xc->filename) + 5 + 1); -#endif - - fixup_offs = ftello(xc->handle); - fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ - hlen = ftello(xc->handle); - fstWriterUint64(xc->handle, 0); /* section length */ - fstWriterUint64(xc->handle, xc->hier_file_len); /* uncompressed length */ - - fflush(xc->handle); - zfd = dup(fileno(xc->handle)); - zhandle = gzdopen(zfd, "wb4"); - if(zhandle) - { - fseeko(xc->hier_handle, 0, SEEK_SET); - for(hl = 0; hl < xc->hier_file_len; hl += FST_GZIO_LEN) - { - unsigned len = ((xc->hier_file_len - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (xc->hier_file_len - hl); - fstFread(mem, len, 1, xc->hier_handle); - gzwrite(zhandle, mem, len); - } - gzclose(zhandle); - } - else - { - close(zfd); - } - free(mem); - - fseeko(xc->handle, 0, SEEK_END); - eos = ftello(xc->handle); - fseeko(xc->handle, hlen, SEEK_SET); - fstWriterUint64(xc->handle, eos - hlen); - fflush(xc->handle); - - fseeko(xc->handle, fixup_offs, SEEK_SET); - fputc(FST_BL_HIER, xc->handle); /* actual tag */ - - fseeko(xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ - fflush(xc->handle); - -#ifndef __MINGW32__ - sprintf(fnam, "%s.hier", xc->filename); - unlink(fnam); - free(fnam); -#endif - } - - /* finalize out header */ - fseeko(xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET); - fstWriterUint64(xc->handle, xc->firsttime); - fstWriterUint64(xc->handle, xc->curtime); - fseeko(xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET); - fstWriterUint64(xc->handle, xc->numscopes); - fstWriterUint64(xc->handle, xc->numsigs); - fstWriterUint64(xc->handle, xc->maxhandle); - fstWriterUint64(xc->handle, xc->secnum); - fflush(xc->handle); - - if(xc->tchn_handle) { fclose(xc->tchn_handle); xc->tchn_handle = NULL; } - free(xc->vchg_mem); xc->vchg_mem = NULL; - if(xc->curval_handle) { fclose(xc->curval_handle); xc->curval_handle = NULL; } - if(xc->valpos_handle) { fclose(xc->valpos_handle); xc->valpos_handle = NULL; } - if(xc->geom_handle) { fclose(xc->geom_handle); xc->geom_handle = NULL; } - if(xc->hier_handle) { fclose(xc->hier_handle); xc->hier_handle = NULL; } - if(xc->handle) - { - if(xc->repack_on_close) - { - FILE *fp; - off_t offpnt, uclen; - int flen = strlen(xc->filename); - char *hf = calloc(1, flen + 5); - - strcpy(hf, xc->filename); - strcpy(hf+flen, ".pak"); - fp = fopen(hf, "wb"); - - if(fp) - { - void *dsth; - int zfd; - char gz_membuf[FST_GZIO_LEN]; - - fseeko(xc->handle, 0, SEEK_END); - uclen = ftello(xc->handle); - - fputc(FST_BL_ZWRAPPER, fp); - fstWriterUint64(fp, 0); - fstWriterUint64(fp, uclen); - fflush(fp); - - fseeko(xc->handle, 0, SEEK_SET); - zfd = dup(fileno(fp)); - dsth = gzdopen(zfd, "wb4"); - if(dsth) - { - for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN) - { - size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt); - fstFread(gz_membuf, this_len, 1, xc->handle); - gzwrite(dsth, gz_membuf, this_len); - } - gzclose(dsth); - } - else - { - close(zfd); - } - fseeko(fp, 0, SEEK_END); - offpnt = ftello(fp); - fseeko(fp, 1, SEEK_SET); - fstWriterUint64(fp, offpnt - 1); - fclose(fp); - fclose(xc->handle); xc->handle = NULL; - - unlink(xc->filename); - rename(hf, xc->filename); - } - else - { - xc->repack_on_close = 0; - fclose(xc->handle); xc->handle = NULL; - } - - free(hf); - } - else - { - fclose(xc->handle); xc->handle = NULL; - } - } - -#ifdef __MINGW32__ - { - int flen = strlen(xc->filename); - char *hf = calloc(1, flen + 6); - strcpy(hf, xc->filename); - - if(xc->compress_hier) - { - strcpy(hf + flen, ".hier"); - unlink(hf); /* no longer needed as a section now exists for this */ - } - - free(hf); - } -#endif - - free(xc->filename); xc->filename = NULL; - free(xc); - } -} - - /* * generation and writing out of value change data sections */ @@ -1074,7 +809,11 @@ if(xc) } -void fstWriterFlushContext(void *ctx) +/* + * only to be called directly by fst code...otherwise must + * be synced up with time changes + */ +static void fstWriterFlushContextPrivate(void *ctx) { #ifdef FST_DEBUG int cnt = 0; @@ -1409,7 +1148,7 @@ for(i=0;imaxhandle;i++) JudyHSFreeArray(&PJHSArray, NULL); #endif -free(packmem); packmem = NULL; packmemlen = 0; +free(packmem); packmem = NULL; /* packmemlen = 0; */ /* scan-build */ prevpos = 0; zerocnt = 0; free(scratchpad); scratchpad = NULL; @@ -1449,7 +1188,7 @@ for(i=0;imaxhandle;i++) } if(zerocnt) { - fpos += fstWriterVarint(f, (zerocnt << 1)); + /* fpos += */ fstWriterVarint(f, (zerocnt << 1)); /* scan-build */ } #ifdef FST_DEBUG printf("value chains: %d\n", cnt); @@ -1538,6 +1277,291 @@ xc->already_in_flush = 0; } +/* + * queues up a flush context operation + */ +void fstWriterFlushContext(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) + { + if(xc->tchn_idx > 1) + { + xc->flush_context_pending = 1; + } + } +} + + +/* + * close out FST file + */ +void fstWriterClose(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc && !xc->already_in_close && !xc->already_in_flush) + { + unsigned char *tmem; + off_t fixup_offs, tlen, hlen; + + xc->already_in_close = 1; /* never need to zero this out as it is freed at bottom */ + + if(xc->section_header_only && xc->section_header_truncpos && (xc->vchg_siz <= 1) && (!xc->is_initial_time)) + { + fstFtruncate(fileno(xc->handle), xc->section_header_truncpos); + fseeko(xc->handle, xc->section_header_truncpos, SEEK_SET); + xc->section_header_only = 0; + } + else + { + xc->skip_writing_section_hdr = 1; + if(!xc->size_limit_locked) + { + if(xc->is_initial_time) /* simulation time never advanced so mock up the changes as time zero ones */ + { + fstHandle dupe_idx; + + fstWriterEmitTimeChange(xc, 0); /* emit some time change just to have one */ + for(dupe_idx = 0; dupe_idx < xc->maxhandle; dupe_idx++) /* now clone the values */ + { + fstWriterEmitValueChange(xc, dupe_idx+1, xc->curval_mem + xc->valpos_mem[4*dupe_idx]); + } + } + fstWriterFlushContextPrivate(xc); + } + } + fstDestroyMmaps(xc, 1); + + /* write out geom section */ + fflush(xc->geom_handle); + tlen = ftello(xc->geom_handle); + tmem = fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->geom_handle), 0); + if(tmem) + { + unsigned long destlen = tlen; + unsigned char *dmem = malloc(destlen); + int rc = compress2(dmem, &destlen, tmem, tlen, 9); + + if((rc != Z_OK) || (destlen > tlen)) + { + destlen = tlen; + } + + fixup_offs = ftello(xc->handle); + fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ + fstWriterUint64(xc->handle, destlen + 24); /* section length */ + fstWriterUint64(xc->handle, tlen); /* uncompressed */ + /* compressed len is section length - 24 */ + fstWriterUint64(xc->handle, xc->maxhandle); /* maxhandle */ + fstFwrite((destlen != tlen) ? dmem : tmem, destlen, 1, xc->handle); + fflush(xc->handle); + + fseeko(xc->handle, fixup_offs, SEEK_SET); + fputc(FST_BL_GEOM, xc->handle); /* actual tag */ + + fseeko(xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ + fflush(xc->handle); + + free(dmem); + fstMunmap(tmem, tlen); + } + + if(xc->num_blackouts) + { + uint64_t cur_bl = 0; + off_t bpos, eos; + uint32_t i; + + fixup_offs = ftello(xc->handle); + fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ + bpos = fixup_offs + 1; + fstWriterUint64(xc->handle, 0); /* section length */ + fstWriterVarint(xc->handle, xc->num_blackouts); + + for(i=0;inum_blackouts;i++) + { + fputc(xc->blackout_head->active, xc->handle); + fstWriterVarint(xc->handle, xc->blackout_head->tim - cur_bl); + cur_bl = xc->blackout_head->tim; + xc->blackout_curr = xc->blackout_head->next; + free(xc->blackout_head); + xc->blackout_head = xc->blackout_curr; + } + + eos = ftello(xc->handle); + fseeko(xc->handle, bpos, SEEK_SET); + fstWriterUint64(xc->handle, eos - bpos); + fflush(xc->handle); + + fseeko(xc->handle, fixup_offs, SEEK_SET); + fputc(FST_BL_BLACKOUT, xc->handle); /* actual tag */ + + fseeko(xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ + fflush(xc->handle); + } + + if(xc->compress_hier) + { + unsigned char *mem = malloc(FST_GZIO_LEN); + off_t hl, eos; + gzFile zhandle; + int zfd; +#ifndef __MINGW32__ + char *fnam = malloc(strlen(xc->filename) + 5 + 1); +#endif + + fixup_offs = ftello(xc->handle); + fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ + hlen = ftello(xc->handle); + fstWriterUint64(xc->handle, 0); /* section length */ + fstWriterUint64(xc->handle, xc->hier_file_len); /* uncompressed length */ + + fflush(xc->handle); + zfd = dup(fileno(xc->handle)); + zhandle = gzdopen(zfd, "wb4"); + if(zhandle) + { + fseeko(xc->hier_handle, 0, SEEK_SET); + for(hl = 0; hl < xc->hier_file_len; hl += FST_GZIO_LEN) + { + unsigned len = ((xc->hier_file_len - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (xc->hier_file_len - hl); + fstFread(mem, len, 1, xc->hier_handle); + gzwrite(zhandle, mem, len); + } + gzclose(zhandle); + } + else + { + close(zfd); + } + free(mem); + + fseeko(xc->handle, 0, SEEK_END); + eos = ftello(xc->handle); + fseeko(xc->handle, hlen, SEEK_SET); + fstWriterUint64(xc->handle, eos - hlen); + fflush(xc->handle); + + fseeko(xc->handle, fixup_offs, SEEK_SET); + fputc(FST_BL_HIER, xc->handle); /* actual tag */ + + fseeko(xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ + fflush(xc->handle); + +#ifndef __MINGW32__ + sprintf(fnam, "%s.hier", xc->filename); + unlink(fnam); + free(fnam); +#endif + } + + /* finalize out header */ + fseeko(xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET); + fstWriterUint64(xc->handle, xc->firsttime); + fstWriterUint64(xc->handle, xc->curtime); + fseeko(xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET); + fstWriterUint64(xc->handle, xc->numscopes); + fstWriterUint64(xc->handle, xc->numsigs); + fstWriterUint64(xc->handle, xc->maxhandle); + fstWriterUint64(xc->handle, xc->secnum); + fflush(xc->handle); + + if(xc->tchn_handle) { fclose(xc->tchn_handle); xc->tchn_handle = NULL; } + free(xc->vchg_mem); xc->vchg_mem = NULL; + if(xc->curval_handle) { fclose(xc->curval_handle); xc->curval_handle = NULL; } + if(xc->valpos_handle) { fclose(xc->valpos_handle); xc->valpos_handle = NULL; } + if(xc->geom_handle) { fclose(xc->geom_handle); xc->geom_handle = NULL; } + if(xc->hier_handle) { fclose(xc->hier_handle); xc->hier_handle = NULL; } + if(xc->handle) + { + if(xc->repack_on_close) + { + FILE *fp; + off_t offpnt, uclen; + int flen = strlen(xc->filename); + char *hf = calloc(1, flen + 5); + + strcpy(hf, xc->filename); + strcpy(hf+flen, ".pak"); + fp = fopen(hf, "wb"); + + if(fp) + { + void *dsth; + int zfd; + char gz_membuf[FST_GZIO_LEN]; + + fseeko(xc->handle, 0, SEEK_END); + uclen = ftello(xc->handle); + + fputc(FST_BL_ZWRAPPER, fp); + fstWriterUint64(fp, 0); + fstWriterUint64(fp, uclen); + fflush(fp); + + fseeko(xc->handle, 0, SEEK_SET); + zfd = dup(fileno(fp)); + dsth = gzdopen(zfd, "wb4"); + if(dsth) + { + for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN) + { + size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt); + fstFread(gz_membuf, this_len, 1, xc->handle); + gzwrite(dsth, gz_membuf, this_len); + } + gzclose(dsth); + } + else + { + close(zfd); + } + fseeko(fp, 0, SEEK_END); + offpnt = ftello(fp); + fseeko(fp, 1, SEEK_SET); + fstWriterUint64(fp, offpnt - 1); + fclose(fp); + fclose(xc->handle); xc->handle = NULL; + + unlink(xc->filename); + rename(hf, xc->filename); + } + else + { + xc->repack_on_close = 0; + fclose(xc->handle); xc->handle = NULL; + } + + free(hf); + } + else + { + fclose(xc->handle); xc->handle = NULL; + } + } + +#ifdef __MINGW32__ + { + int flen = strlen(xc->filename); + char *hf = calloc(1, flen + 6); + strcpy(hf, xc->filename); + + if(xc->compress_hier) + { + strcpy(hf + flen, ".hier"); + unlink(hf); /* no longer needed as a section now exists for this */ + } + + free(hf); + } +#endif + + free(xc->filename); xc->filename = NULL; + free(xc); + } +} + + /* * functions to set miscellaneous header/block information */ @@ -1940,9 +1964,10 @@ if(xc) } else { - if(xc->vchg_siz >= FST_BREAK_SIZE) + if((xc->vchg_siz >= FST_BREAK_SIZE) || (xc->flush_context_pending)) { - fstWriterFlushContext(xc); + xc->flush_context_pending = 0; + fstWriterFlushContextPrivate(xc); xc->tchn_cnt++; fstWriterVarint(xc->tchn_handle, xc->curtime); } @@ -3359,7 +3384,10 @@ uint64_t tsec_nitems; int secnum = 0; int blocks_skipped = 0; off_t blkpos = 0; -uint64_t seclen, beg_tim, end_tim; +uint64_t seclen, beg_tim; +#ifdef FST_DEBUG +uint64_t end_tim; +#endif uint64_t frame_uclen, frame_clen, frame_maxhandle, vc_maxhandle; off_t vc_start; off_t indx_pntr, indx_pos; @@ -3414,7 +3442,10 @@ for(;;) if(!seclen) break; beg_tim = fstReaderUint64(xc->f); - end_tim = fstReaderUint64(xc->f); +#ifdef FST_DEBUG + end_tim = +#endif + fstReaderUint64(xc->f); if(xc->limit_range_valid) { @@ -3443,8 +3474,8 @@ for(;;) { unsigned char *ucdata; unsigned char *cdata; - unsigned long destlen = tsec_uclen; - unsigned long sourcelen = tsec_clen; + unsigned long destlen /* = tsec_uclen */; /* scan-build */ + unsigned long sourcelen /*= tsec_clen */; /* scan-build */ int rc; unsigned char *tpnt; uint64_t tpval; @@ -3896,12 +3927,12 @@ for(;;) unsigned char val; if(!(vli & 1)) { - tdelta = vli >> 2; + /* tdelta = vli >> 2; */ /* scan-build */ val = ((vli >> 1) & 1) | '0'; } else { - tdelta = vli >> 4; + /* tdelta = vli >> 4; */ /* scan-build */ val = FST_RCV_STR[((vli >> 1) & 7)]; } @@ -3946,7 +3977,7 @@ for(;;) vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen); len = fstGetVarint32(mem_for_traversal + headptr[idx] + skiplen, &skiplen2); - tdelta = vli >> 1; + /* tdelta = vli >> 1; */ /* scan-build */ skiplen += skiplen2; vdata = mem_for_traversal + headptr[idx] + skiplen; @@ -4002,7 +4033,7 @@ for(;;) unsigned char *vdata; vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen); - tdelta = vli >> 1; + /* tdelta = vli >> 1; */ /* scan-build */ vdata = mem_for_traversal + headptr[idx] + skiplen; if(xc->signal_typs[idx] != FST_VT_VCD_REAL) @@ -4058,7 +4089,7 @@ for(;;) else { double d; - unsigned char *clone_d = (unsigned char *)&d; + unsigned char *clone_d /*= (unsigned char *)&d */; /* scan-build */ unsigned char buf[8]; unsigned char *srcdata; @@ -4261,7 +4292,9 @@ uint64_t seclen; uint64_t tsec_uclen = 0, tsec_clen = 0; uint64_t tsec_nitems; uint64_t frame_uclen, frame_clen; +#ifdef FST_DEBUG uint64_t mem_required_for_traversal; +#endif off_t indx_pntr, indx_pos; long chain_clen; unsigned char *chain_cmem; @@ -4352,7 +4385,11 @@ for(;;) xc->rvat_beg_tim = beg_tim; xc->rvat_end_tim = end_tim; -mem_required_for_traversal = fstReaderUint64(xc->f); +#ifdef FST_DEBUG +mem_required_for_traversal = +#endif + fstReaderUint64(xc->f); + #ifdef FST_DEBUG printf("rvat sec: %d seclen: %d begtim: %d endtim: %d\n", secnum, (int)seclen, (int)beg_tim, (int)end_tim); @@ -4363,8 +4400,8 @@ printf("\tmem_required_for_traversal: %d\n", (int)mem_required_for_traversal); { unsigned char *ucdata; unsigned char *cdata; -unsigned long destlen = tsec_uclen; -unsigned long sourcelen = tsec_clen; +unsigned long destlen /* = tsec_uclen */; /* scan-build */ +unsigned long sourcelen /* = tsec_clen */; /* scan-build */ int rc; unsigned char *tpnt; uint64_t tpval; @@ -4628,7 +4665,7 @@ if(xc->signal_lens[facidx] == 1) iprev = i; pvli = vli; ptidx = tidx; - pskip = skiplen; + /* pskip = skiplen; */ /* scan-build */ tidx += tdelta; i+=skiplen; diff --git a/vpi/lxt2_write.c b/vpi/lxt2_write.c index d432b3bd8..74832e505 100644 --- a/vpi/lxt2_write.c +++ b/vpi/lxt2_write.c @@ -1144,7 +1144,7 @@ unsigned int total_chgs; unsigned int partial_length; total_chgs = 0; -partial_length = 0; +/* partial_length = 0; */ /* scan-build : never read */ iter_hi = iter + partial_iter; if(iter_hi > lt->numfacs) iter_hi = lt->numfacs; @@ -1491,8 +1491,6 @@ if(lt) if( (!lt->timepos) && (!lt->timegranule) && ((!lt->numblock)||(!lt->no_checkpoint)) ) { - struct lxt2_wr_symbol *s = lt->symchain; - /* fprintf(stderr, "initial value burst timepos==0, timegranule==0\n"); */ if(lt->blackout) { @@ -1501,7 +1499,7 @@ if(lt) } else { - s = lt->symchain; + struct lxt2_wr_symbol *s = lt->symchain; while(s) { if((!(s->flags&LXT2_WR_SYM_F_ALIAS))&&(s->rows<2)) diff --git a/vpi/sys_display.c b/vpi/sys_display.c index cf315c97c..8e380572c 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -248,9 +248,11 @@ static void get_time(char *rtn, const char *value, int prec, static void get_time_real(char *rtn, double value, int prec, PLI_INT32 time_units) { - /* Scale the value if its time units differ from the format units. */ - if (time_units != timeformat_info.units) { + /* Scale the value from its time units to the format time units. */ + if (time_units >= timeformat_info.units) { value *= pow(10.0, time_units - timeformat_info.units); + } else { + value /= pow(10.0, timeformat_info.units - time_units); } sprintf(rtn, "%0.*f%s", prec, value, timeformat_info.suff); } @@ -444,7 +446,9 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, strcpy(cpb+pad, cp); /* If a width was not given, use the default, unless we have a - * leading zero (width of zero). */ + * leading zero (width of zero). Because the width of a real in + * Icarus is 1 the string length will set the width of a real + * displayed using %d. */ if (width == -1) { width = (ld_zero == 1) ? 0 : vpi_get_dec_size(info->items[*idx]); } @@ -856,7 +860,7 @@ static unsigned int get_format(char **rtn, char *fmt, static unsigned int get_numeric(char **rtn, const struct strobe_cb_info *info, vpiHandle item) { - int size; + int size, min; s_vpi_value val; val.format = info->default_format; @@ -865,6 +869,11 @@ static unsigned int get_numeric(char **rtn, const struct strobe_cb_info *info, switch(info->default_format){ case vpiDecStrVal: size = vpi_get_dec_size(item); + /* -1 can be represented as a one bit signed value. This returns + * a size of 1 which is too small for the -1 string value so make + * the string width the minimum display width. */ + min = strlen(val.value.str); + if (size < min) size = min; *rtn = malloc((size+1)*sizeof(char)); sprintf(*rtn, "%*s", size, val.value.str); break; diff --git a/vpi/sys_icarus.c b/vpi/sys_icarus.c index 58e290dc6..d80a67074 100644 --- a/vpi/sys_icarus.c +++ b/vpi/sys_icarus.c @@ -45,7 +45,7 @@ static PLI_INT32 task_not_implemented_compiletf(ICARUS_VPI_CONST PLI_BYTE8* name { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - vpi_printf("%s:%d: SORRY: task %s() is not currently implemented.\n", + vpi_printf("SORRY: %s:%d: task %s() is not currently implemented.\n", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh), name); vpi_control(vpiFinish, 1); @@ -60,7 +60,7 @@ static PLI_INT32 missing_optional_compiletf(ICARUS_VPI_CONST PLI_BYTE8* name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - vpi_printf("%s:%d: SORRY: %s() is not available in Icarus verilog.\n", + vpi_printf("SORRY: %s:%d: %s() is not available in Icarus verilog.\n", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh), name); vpi_control(vpiFinish, 1); diff --git a/vpi/sys_lxt.c b/vpi/sys_lxt.c index 7879cba81..151c058ec 100644 --- a/vpi/sys_lxt.c +++ b/vpi/sys_lxt.c @@ -524,7 +524,6 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) struct t_cb_data cb; struct vcd_info* info; - const char* type; const char* name; const char* ident; int nexus_id; @@ -547,7 +546,6 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) switch (vpi_get(vpiType, item)) { - case vpiNet: type = "wire"; if(0){ case vpiMemoryWord: if (vpi_get(vpiConstantSelect, item) == 0) { /* Turn a non-constant array word select into a @@ -563,7 +561,8 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) case vpiIntVar: case vpiLongIntVar: case vpiTimeVar: - case vpiReg: type = "reg"; } + case vpiReg: + case vpiNet: /* An array word is implicitly escaped so look for an * escaped identifier that this could conflict with. */ @@ -656,11 +655,11 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) break; - case vpiModule: type = "module"; if(0){ - case vpiNamedBegin: type = "begin"; }if(0){ - case vpiTask: type = "task"; }if(0){ - case vpiFunction: type = "function"; }if(0){ - case vpiNamedFork: type = "fork"; } + case vpiModule: + case vpiNamedBegin: + case vpiTask: + case vpiFunction: + case vpiNamedFork: if (depth > 0) { int nskip; @@ -683,7 +682,7 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) name = vpi_get_str(vpiName, item); - push_scope(name); /* keep in type info determination for possible future usage */ + push_scope(name); for (i=0; types[i]>0; i++) { vpiHandle hand; diff --git a/vpi/sys_lxt2.c b/vpi/sys_lxt2.c index 0a558138c..bfd30fd5f 100644 --- a/vpi/sys_lxt2.c +++ b/vpi/sys_lxt2.c @@ -587,7 +587,6 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) struct t_cb_data cb; struct vcd_info* info; - const char* type; const char* name; const char* ident; int nexus_id; @@ -610,7 +609,6 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) switch (vpi_get(vpiType, item)) { - case vpiNet: type = "wire"; if(0){ case vpiMemoryWord: if (vpi_get(vpiConstantSelect, item) == 0) { /* Turn a non-constant array word select into a @@ -626,7 +624,8 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) case vpiIntVar: case vpiLongIntVar: case vpiTimeVar: - case vpiReg: type = "reg"; } + case vpiReg: + case vpiNet: /* An array word is implicitly escaped so look for an * escaped identifier that this could conflict with. */ @@ -711,11 +710,11 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) break; - case vpiModule: type = "module"; if(0){ - case vpiNamedBegin: type = "begin"; }if(0){ - case vpiTask: type = "task"; }if(0){ - case vpiFunction: type = "function"; }if(0){ - case vpiNamedFork: type = "fork"; } + case vpiModule: + case vpiNamedBegin: + case vpiTask: + case vpiFunction: + case vpiNamedFork: if (depth > 0) { int nskip; @@ -738,7 +737,7 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) name = vpi_get_str(vpiName, item); - push_scope(name); /* keep in type info determination for possible future usage */ + push_scope(name); for (i=0; types[i]>0; i++) { vpiHandle hand; diff --git a/vpi/sys_random.c b/vpi/sys_random.c index 2193b3140..3300f5fbb 100644 --- a/vpi/sys_random.c +++ b/vpi/sys_random.c @@ -567,6 +567,7 @@ static PLI_INT32 sys_urandom_range_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) /* Check that there are at least two arguments. */ arg = vpi_scan(argv); /* This should never be zero. */ + assert(arg); arg = vpi_scan(argv); if (arg == 0) { vpi_printf("ERROR: %s requires two arguments.\n", name); diff --git a/vpi/sys_scanf.c b/vpi/sys_scanf.c index 440661eba..0bca2c5f8 100644 --- a/vpi/sys_scanf.c +++ b/vpi/sys_scanf.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ - /* round() is ISO C99 from math.h. This define should enable it. */ +/* round() is ISO C99 from math.h. This define should enable it. */ # define _ISOC99_SOURCE 1 # define _SVID_SOURCE 1 @@ -28,32 +28,45 @@ # include # include # include +# include # include # include "ivl_alloc.h" +/* + * The wrapper routines below get a value from either a string or a file. + * This structure is used to determine which one is used. The unused one + * must be assigned a zero value. + */ struct byte_source { - const char*str; - FILE*fd; + const char *str; + FILE *fd; }; -static int byte_getc(struct byte_source*byte) +/* + * Wrapper routine to get a byte from either a string or a file descriptor. + */ +static int byte_getc(struct byte_source *src) { - int ch; - if (byte->str) { - if (byte->str[0] == 0) return EOF; + if (src->str) { + assert(! src->fd); + if (src->str[0] == 0) return EOF; - return *(byte->str)++; + return *(src->str)++; } - ch = fgetc(byte->fd); - return ch; + assert(src->fd); + return fgetc(src->fd); } -static void byte_ungetc(struct byte_source*src, int ch) +/* + * Wrapper routine to unget a byte to either a string or a file descriptor. + */ +static void byte_ungetc(struct byte_source *src, int ch) { if (ch == EOF) return; if (src->str) { + assert(! src->fd); src->str -= 1; return; } @@ -67,154 +80,642 @@ static void byte_ungetc(struct byte_source*src, int ch) * This function matches the input characters of a floating point * number and generates a floating point (double) from that string. * - * Need support for +-Inf and NaN. Look at the $plusargs code. + * Do we need support for +-Inf and NaN? It's not in the standard. + * + * The match variable is set to 1 for a match or 0 for no match. */ -static double float_string(struct byte_source*src) +static double get_float(struct byte_source *src, unsigned width, int *match) { + char *endptr; + char *strval = malloc(1); + unsigned len = 0; + double result; int ch; - char*str = 0; - size_t len; - double sign_flag = 1.0; + /* Skip any leading space. */ ch = byte_getc(src); - /* Skip leading space. */ while (isspace(ch)) ch = byte_getc(src); - if (ch == '+') { - sign_flag = 1.0; - ch = byte_getc(src); - } else if (ch == '-') { - sign_flag = -1.0; + /* If we are being asked for no digits then return a match fail. */ + if (width == 0) { + byte_ungetc(src, ch); + free(strval); + *match = 0; + return 0.0; + } + + /* Look for the optional sign. */ + if ((ch == '+') || (ch == '-')) { + /* If we have a sign then the width must not be + * one since we need a sign and a digit. */ + if (width == 1) { + byte_ungetc(src, ch); + free(strval); + *match = 0; + return 0.0; + } + strval = realloc(strval, len+2); + strval[len++] = ch; ch = byte_getc(src); } - str = malloc(1); - len = 0; - *str = 0; - - while (isdigit(ch)) { - str = realloc(str, len+2); - str[len++] = ch; + /* Get any digits before the optional decimal point, but no more + * than width. */ + while (isdigit(ch) && (len < width)) { + strval = realloc(strval, len+2); + strval[len++] = ch; ch = byte_getc(src); } - if (ch == '.') { - str = realloc(str, len+2); - str[len++] = ch; + /* Get the optional decimal point and any following digits, but + * no more than width total characters are copied. */ + if ((ch == '.') && (len < width)) { + strval = realloc(strval, len+2); + strval[len++] = ch; ch = byte_getc(src); - while (isdigit(ch)) { - str = realloc(str, len+2); - str[len++] = ch; + /* Get any trailing digits. */ + while (isdigit(ch) && (len < width)) { + strval = realloc(strval, len+2); + strval[len++] = ch; ch = byte_getc(src); } } - if (ch == 'e' || ch == 'E') { - str = realloc(str, len+2); - str[len++] = ch; + /* No leading digits were matched. */ + if ((len == 0) || + ((len == 1) && ((strval[0] == '+') || (strval[0] == '-')))) { + byte_ungetc(src, ch); + free(strval); + *match = 0; + return 0.0; + } + + /* Match an exponent. */ + if (((ch == 'e') || (ch == 'E')) && (len < width)) { + strval = realloc(strval, len+2); + strval[len++] = ch; ch = byte_getc(src); - if (ch == '-' || ch == '+') { - str = realloc(str, len+2); - str[len++] = ch; - ch = byte_getc(src); + /* We must have enough space for at least one digit after + * the exponent. */ + if (len == width) { + byte_ungetc(src, ch); + free(strval); + *match = 0; + return 0.0; } - while (isdigit(ch)) { - str = realloc(str, len+2); - str[len++] = ch; + /* Check to see if the exponent has a sign. */ + if ((ch == '-') || (ch == '+')) { + strval = realloc(strval, len+2); + strval[len++] = ch; + ch = byte_getc(src); + /* We must have enough space for at least one digit + * after the exponent sign. */ + if (len == width) { + byte_ungetc(src, ch); + free(strval); + *match = 0; + return 0.0; + } + } + + /* We must have at least one digit after the exponent/sign. */ + if (! isdigit(ch)) { + byte_ungetc(src, ch); + free(strval); + *match = 0; + return 0.0; + } + + /* Get the exponent digits, but no more than width total + * characters are copied. */ + while (isdigit(ch) && (len < width)) { + strval = realloc(strval, len+2); + strval[len++] = ch; ch = byte_getc(src); } } + strval[len] = 0; - str[len] = 0; + /* Put the last character back. */ + byte_ungetc(src, ch); - sign_flag *= strtod(str, 0); - free(str); - - if (ch != EOF) byte_ungetc(src, ch); - - return sign_flag; + /* Calculate and return the result. */ + result = strtod(strval, &endptr); + /* If this asserts then there is a bug in the code above.*/ + assert(*endptr == 0); + free(strval); + *match = 1; + return result; } -static int scan_format_float(struct byte_source*src, - vpiHandle arg) +/* + * Routine to return a floating point value (implements %e, %f and %g). + * + * Return: 1 for a match, 0 for no match/variable and -1 for a + * suppressed match. No variable is fatal. + */ +static int scan_format_float(vpiHandle callh, vpiHandle argv, + struct byte_source *src, unsigned width, + unsigned suppress_flag, PLI_BYTE8 *name, + char code) { + vpiHandle arg; + int match; s_vpi_value val; + double result; + /* Get the real value. */ + result = get_float(src, width, &match); + + /* Nothing was matched. */ + if (match == 0) return 0; + + /* If this match is being suppressed then return after consuming + * the digits and report that no arguments were used. */ + if (suppress_flag) return -1; + + /* We must have a variable to put the double value into. */ + arg = vpi_scan(argv); + if (! arg) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s() ran out of variables for %%%c format code", + name, code); + vpi_control(vpiFinish, 1); + return 0; + } + + /* Put the value into the variable. */ val.format = vpiRealVal; - val.value.real = float_string(src); - vpi_put_value(arg, &val, 0, vpiNoDelay); - - return 1; -} - -static int scan_format_float_time(vpiHandle callh, - struct byte_source*src, - vpiHandle arg) -{ - vpiHandle scope = vpi_handle(vpiScope, callh); - int time_units = vpi_get(vpiTimeUnit, scope); - double scale; - - s_vpi_value val; - - val.format = vpiRealVal; - val.value.real = float_string(src); - - /* Round the value to the specified precision. Handle this bit - by shifting the decimal point to the precision where we - want to round, do the rounding, then shift the point back */ - scale = pow(10.0, timeformat_info.prec); - val.value.real = round(val.value.real*scale) / scale; - - /* Change the units from the timeformat to the timescale. */ - scale = pow(10.0, timeformat_info.units - time_units); - val.value.real *= scale; + val.value.real = result; vpi_put_value(arg, &val, 0, vpiNoDelay); + /* We always consume one variable if it is available. */ return 1; } /* - * Match the %s format by loading a string of non-space characters. + * Routine to return a floating point value scaled and rounded to the + * current time scale and precision (implements %t). + * + * Return: 1 for a match, 0 for no match/variable and -1 for a + * suppressed match. No variable is fatal. */ -static int scan_format_string(struct byte_source*src, vpiHandle arg) +static int scan_format_float_time(vpiHandle callh, vpiHandle argv, + struct byte_source*src, unsigned width, + unsigned suppress_flag, PLI_BYTE8 *name) { - char*tmp = malloc(1); - size_t len = 0; + vpiHandle scope = vpi_handle(vpiScope, callh); + int time_units = vpi_get(vpiTimeUnit, scope); + vpiHandle arg; + int match; s_vpi_value val; - int ch; + double result; + double scale; - *tmp = 0; + /* Get the raw real value. */ + result = get_float(src, width, &match); - ch = byte_getc(src); - /* Skip leading space. */ - while (isspace(ch)) ch = byte_getc(src); + /* Nothing was matched. */ + if (match == 0) return 0; - while (!isspace(ch)) { - if (ch == EOF) break; + /* If this match is being suppressed then return after consuming + * the digits and report that no arguments were used. */ + if (suppress_flag) return -1; - tmp = realloc(tmp, len+2); - tmp[len++] = ch; + /* Round the raw value to the specified precision. Handle this + by shifting the decimal point to the precision where we want + to round, do the rounding, then shift the decimal point back */ + scale = pow(10.0, timeformat_info.prec); + result = round(result*scale) / scale; - ch = byte_getc(src); + /* Scale the value from the timeformat units to the current + * timescale units. To minimize the error keep the scale an + * integer value. */ + if (timeformat_info.units >= time_units) { + scale = pow(10.0, timeformat_info.units - time_units); + result *= scale; + } else { + scale = pow(10.0, time_units - timeformat_info.units); + result /= scale; } - if (ch == EOF && len == 0) return 0; + /* We must have a variable to put the double value into. */ + arg = vpi_scan(argv); + if (! arg) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s() ran out of variables for %%t format code", name); + vpi_control(vpiFinish, 1); + return 0; + } - if (ch != EOF) byte_ungetc(src, ch); - - tmp[len] = 0; - val.format = vpiStringVal; - val.value.str = tmp; + /* Put the value into the variable. */ + val.format = vpiRealVal; + val.value.real = result; vpi_put_value(arg, &val, 0, vpiNoDelay); - free(tmp); - + /* We always consume one variable if it is available. */ return 1; } +/* + * Base routine for getting binary, octal and hex values. + * + * Return: 1 for a match, 0 for no match/variable and -1 for a + * suppressed match. No variable is fatal. + */ +static int scan_format_base(vpiHandle callh, vpiHandle argv, + struct byte_source *src, unsigned width, + unsigned suppress_flag, PLI_BYTE8 *name, + const char *match, char code, + PLI_INT32 type) +{ + vpiHandle arg; + char *strval = malloc(1); + unsigned len = 0; + s_vpi_value val; + int ch; + + /* Skip any leading space. */ + ch = byte_getc(src); + while (isspace(ch)) ch = byte_getc(src); + + /* If we are being asked for no digits or the first character is + * an underscore then return a match fail. */ + if ((width == 0) || (ch == '_')) { + byte_ungetc(src, ch); + free(strval); + return 0; + } + + /* Get all the digits, but no more than width. */ + while (strchr(match , ch) && (len < width)) { + if (ch == '?') ch = 'x'; + + strval = realloc(strval, len+2); + strval[len++] = ch; + + ch = byte_getc(src); + } + strval[len] = 0; + + /* Put the last character back. */ + byte_ungetc(src, ch); + + /* Nothing was matched. */ + if (len == 0) { + free(strval); + return 0; + } + + /* If this match is being suppressed then return after consuming + * the digits and report that no arguments were used. */ + if (suppress_flag) { + free(strval); + return -1; + } + + /* We must have a variable to put the binary value into. */ + arg = vpi_scan(argv); + if (! arg) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s() ran out of variables for %%%c format code", + name, code); + vpi_control(vpiFinish, 1); + free(strval); + return 0; + } + + /* Put the value into the variable. */ + val.format = type; + val.value.str = strval; + vpi_put_value(arg, &val, 0, vpiNoDelay); + free(strval); + + /* We always consume one variable if it is available. */ + return 1; +} + +/* + * Routine to return a binary value (implements %b). + */ +static int scan_format_binary(vpiHandle callh, vpiHandle argv, + struct byte_source *src, int width, + unsigned suppress_flag, PLI_BYTE8 *name) +{ + return scan_format_base(callh, argv, src, width, suppress_flag, name, + "01xzXZ?_", 'b', vpiBinStrVal); +} + +/* + * Routine to return a character value (implements %c). + * + * Return: 1 for a match, 0 for no match/variable and -1 for a + * suppressed match. No variable is fatal. + */ +static int scan_format_char(vpiHandle callh, vpiHandle argv, + struct byte_source *src, unsigned width, + unsigned suppress_flag, PLI_BYTE8 *name) +{ + vpiHandle arg; + s_vpi_value val; + int ch; + + /* If we are being asked for no digits then return a match fail. */ + if (width == 0) return 0; + + /* Get the character to return. */ + ch = byte_getc(src); + + /* Nothing was matched. */ + if (ch == EOF) return 0; + + /* If this match is being suppressed then return after consuming + * the character and report that no arguments were used. */ + if (suppress_flag) return -1; + + /* We must have a variable to put the character value into. */ + arg = vpi_scan(argv); + if (! arg) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s() ran out of variables for %%c format code", name); + vpi_control(vpiFinish, 1); + return 0; + } + + /* Put the character into the variable. */ + val.format = vpiIntVal; + val.value.integer = ch; + vpi_put_value(arg, &val, 0, vpiNoDelay); + + /* We always consume one variable if it is available. */ + return 1; +} + +/* + * Routine to return a decimal value (implements %d). + * + * Return: 1 for a match, 0 for no match/variable and -1 for a + * suppressed match. No variable is fatal. + */ +static int scan_format_decimal(vpiHandle callh, vpiHandle argv, + struct byte_source *src, unsigned width, + unsigned suppress_flag, PLI_BYTE8 *name) +{ + vpiHandle arg; + char *strval = malloc(1); + unsigned len = 0; + s_vpi_value val; + int ch; + + /* Skip any leading space. */ + ch = byte_getc(src); + while (isspace(ch)) ch = byte_getc(src); + + /* If we are being asked for no digits or the first character is + * an underscore then return a match fail. */ + if ((width == 0) || (ch == '_')) { + byte_ungetc(src, ch); + free(strval); + return 0; + } + + /* A decimal can match a single x/X, ? or z/Z character. */ + if (strchr("xX?", ch)) { + strval = realloc(strval, 2); + strval[0] = 'x'; + strval[1] = 0; + } else if (strchr("zZ", ch)) { + strval = realloc(strval, 2); + strval[0] = 'z'; + strval[1] = 0; + } else { + + /* To match a + or - we must have a digit after it. */ + if (ch == '+') { + /* If we have a '+' sign then the width must not be + * one since we need a sign and a digit. */ + if (width == 1) { + free(strval); + return 0; + } + + ch = byte_getc(src); + if (! isdigit(ch)) { + byte_ungetc(src, ch); + free(strval); + return 0; + } + /* The '+' used up a character. */ + width -= 1; + } else if (ch == '-') { + /* If we have a '-' sign then the width must not be + * one since we need a sign and a digit. */ + if (width == 1) { + free(strval); + return 0; + } + + ch = byte_getc(src); + if (isdigit(ch)) { + strval = realloc(strval, len+2); + strval[len++] = '-'; + } else { + byte_ungetc(src, ch); + free(strval); + return 0; + } + } + + /* Get all the characters, but no more than width. */ + while ((isdigit(ch) || ch == '_') && (len < width)) { + strval = realloc(strval, len+2); + strval[len++] = ch; + + ch = byte_getc(src); + } + strval[len] = 0; + + /* Put the last character back. */ + byte_ungetc(src, ch); + + /* Nothing was matched. */ + if (len == 0) { + free(strval); + return 0; + } + } + + /* If this match is being suppressed then return after consuming + * the digits and report that no arguments were used. */ + if (suppress_flag) { + free(strval); + return -1; + } + + /* We must have a variable to put the decimal value into. */ + arg = vpi_scan(argv); + if (! arg) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s() ran out of variables for %%d format code", name); + vpi_control(vpiFinish, 1); + free(strval); + return 0; + } + + /* Put the decimal value into the variable. */ + val.format = vpiDecStrVal; + val.value.str = strval; + vpi_put_value(arg, &val, 0, vpiNoDelay); + free(strval); + + /* We always consume one variable if it is available. */ + return 1; +} + +/* + * Routine to return a hex value (implements %h). + */ +static int scan_format_hex(vpiHandle callh, vpiHandle argv, + struct byte_source *src, unsigned width, + unsigned suppress_flag, PLI_BYTE8 *name) +{ + return scan_format_base(callh, argv, src, width, suppress_flag, name, + "0123456789abcdefxzABCDEFXZ?_", 'h', + vpiHexStrVal); +} + +/* + * Routine to return an octal value (implements %o). + */ +static int scan_format_octal(vpiHandle callh, vpiHandle argv, + struct byte_source *src, unsigned width, + unsigned suppress_flag, PLI_BYTE8 *name) +{ + return scan_format_base(callh, argv, src, width, suppress_flag, name, + "01234567xzXZ?_", 'o', vpiOctStrVal); +} + + +/* + * Routine to return the current hierarchical path (implements %m). + */ +static int scan_format_module_path(vpiHandle callh, vpiHandle argv, + unsigned suppress_flag, PLI_BYTE8 *name) +{ + vpiHandle scope, arg; + char *module_path; + s_vpi_value val; + + /* If this format code is being suppressed then just return that no + * arguments were used. */ + if (suppress_flag) return -1; + + /* We must have a variable to put the hierarchical path into. */ + arg = vpi_scan(argv); + if (! arg) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s() ran out of variables for %%m format code", name); + vpi_control(vpiFinish, 1); + return 0; + } + + /* Get the current hierarchical path. */ + scope = vpi_handle(vpiScope, callh); + assert(scope); + module_path = vpi_get_str(vpiFullName, scope); + + /* Put the hierarchical path into the variable. */ + val.format = vpiStringVal; + val.value.str = module_path; + vpi_put_value(arg, &val, 0, vpiNoDelay); + + /* We always consume one variable if it is available. */ + return 1; +} + +/* + * Routine to return a string value (implements %s). + * + * Return: 1 for a match, 0 for no match/variable and -1 for a + * suppressed match. No variable is fatal. + */ +static int scan_format_string(vpiHandle callh, vpiHandle argv, + struct byte_source *src, unsigned width, + unsigned suppress_flag, PLI_BYTE8 *name) +{ + vpiHandle arg; + char *strval = malloc(1); + unsigned len = 0; + s_vpi_value val; + int ch; + + /* Skip any leading space. */ + ch = byte_getc(src); + while (isspace(ch)) ch = byte_getc(src); + + /* If we are being asked for no digits then return a match fail. */ + if (width == 0) { + byte_ungetc(src, ch); + free(strval); + return 0; + } + + /* Get all the non-space characters, but no more than width. */ + while (! isspace(ch) && (len < width)) { + if (ch == EOF) break; + + strval = realloc(strval, len+2); + strval[len++] = ch; + + ch = byte_getc(src); + } + strval[len] = 0; + + /* Nothing was matched (this can only happen at EOF). */ + if (len == 0) { + assert(ch == EOF); + free(strval); + return 0; + } + + /* Put the last character back. */ + byte_ungetc(src, ch); + + /* If this match is being suppressed then return after consuming + * the string and report that no arguments were used. */ + if (suppress_flag) { + free(strval); + return -1; + } + + /* We must have a variable to put the string into. */ + arg = vpi_scan(argv); + if (! arg) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s() ran out of variables for %%s format code", name); + vpi_control(vpiFinish, 1); + free(strval); + return 0; + } + + /* Put the string into the variable. */ + val.format = vpiStringVal; + val.value.str = strval; + vpi_put_value(arg, &val, 0, vpiNoDelay); + free(strval); + + /* We always consume one variable if it is available. */ + return 1; +} /* * The $fscanf and $sscanf functions are the same except for the first @@ -222,21 +723,45 @@ static int scan_format_string(struct byte_source*src, vpiHandle arg) * the first argument and make a byte_source object that then gets * passed to this function, which processes the rest of the function. */ -static int scan_format(vpiHandle callh, struct byte_source*src, vpiHandle argv) +static int scan_format(vpiHandle callh, struct byte_source*src, vpiHandle argv, + PLI_BYTE8 *name) { s_vpi_value val; vpiHandle item; + PLI_INT32 len, words, idx, mask; - char*fmt, *fmtp; + char *fmt, *fmtp; int rc = 0; int ch; - int match_fail = 0; + int match = 1; /* Get the format string. */ item = vpi_scan(argv); assert(item); + /* Look for an undefined bit (X/Z) in the format string. If one is + * found just return EOF. */ + len = vpi_get(vpiSize, item); + words = ((len + 31) / 32) - 1; + /* The mask is defined to be 32 bits. */ + mask = 0xffffffff >> (32 - ((len - 1) % 32 + 1)); + val.format = vpiVectorVal; + vpi_get_value(item, &val); + /* Check the full words for an undefined bit. */ + for (idx = 0; idx < words; idx += 1) { + if (val.value.vector[idx].bval) { + match = 0; + rc = EOF; + break; + } + } + /* Check the top word for an undefined bit. */ + if (match && (val.value.vector[words].bval & mask)) { + match = 0; + rc = EOF; + } + /* Now get the format as a string. */ val.format = vpiStringVal; vpi_get_value(item, &val); fmtp = fmt = strdup(val.value.str); @@ -245,23 +770,22 @@ static int scan_format(vpiHandle callh, struct byte_source*src, vpiHandle argv) ch = byte_getc(src); if (ch == EOF) { rc = EOF; - match_fail = 1; + match = 0; } byte_ungetc(src, ch); - while ( fmtp && *fmtp != 0 && !match_fail) { + while ( fmtp && *fmtp != 0 && match) { if (isspace((int)*fmtp)) { - /* White space matches a string of white space in - the input. The number of spaces is not - relevant, and the match may be 0 or more - spaces. */ + /* White space matches a string of white space in the + * input. The number of spaces is not relevant, and + * the match may be 0 or more spaces. */ while (*fmtp && isspace((int)*fmtp)) fmtp += 1; ch = byte_getc(src); while (isspace(ch)) ch = byte_getc(src); - if (ch != EOF) byte_ungetc(src, ch); + byte_ungetc(src, ch); } else if (*fmtp != '%') { /* Characters other than % match themselves. */ @@ -276,260 +800,143 @@ static int scan_format(vpiHandle callh, struct byte_source*src, vpiHandle argv) } else { /* We are at a pattern character. The pattern has - the format %x no matter what the x code, so - parse it generically first. */ + * the format %x no matter what the x code, so + * parse it generically first. */ - int suppress_flag = 0; - int length_field = -1; + unsigned suppress_flag = 0; + unsigned max_width = UINT_MAX; int code = 0; - PLI_INT32 value; - - char*tmp; + /* Look for the suppression character '*'. */ fmtp += 1; if (*fmtp == '*') { suppress_flag = 1; fmtp += 1; } + /* Look for the maximum match width. */ if (isdigit((int)*fmtp)) { - length_field = 0; + max_width = 0; while (isdigit((int)*fmtp)) { - length_field *= 10; - length_field += *fmtp - '0'; + max_width *= 10; + max_width += *fmtp - '0'; fmtp += 1; } } + /* Get the format character. */ code = *fmtp; fmtp += 1; /* The format string is parsed: - - length_field is the length, - - code is the format code character, - - suppress_flag is true if the length is an arg. - Now we interpret the code. */ + * - max_width is the width, + * - code is the format code character, + * - suppress_flag is true if the match is to be ignored. + * Now interpret the code. */ switch (code) { /* Read a '%' character from the input. */ case '%': + assert(max_width == -1); + assert(suppress_flag == 0); ch = byte_getc(src); if (ch != '%') { byte_ungetc(src, ch); - fmtp = 0; + match = 0; } break; - /* Read a binary integer. If there is a match, - store that integer in the next argument and - increment the completion count. */ case 'b': - /* binary integer */ - tmp = malloc(2); - value = 0; - tmp[0] = 0; - match_fail = 1; - - ch = byte_getc(src); - /* Skip leading space. */ - while (isspace(ch)) ch = byte_getc(src); - - while (strchr("01xXzZ?_", ch)) { - match_fail = 0; - if (ch == '?') ch = 'x'; - if (ch != '_') { - ch = tolower(ch); - tmp[value++] = ch; - tmp = realloc(tmp, value+1); - tmp[value] = 0; - } - ch = byte_getc(src); - } - byte_ungetc(src, ch); - - if (match_fail) { - free(tmp); - break; - } - - /* Matched a binary value, put it to an argument. */ - item = vpi_scan(argv); - assert(item); - - val.format = vpiBinStrVal; - val.value.str = tmp; - vpi_put_value(item, &val, 0, vpiNoDelay); - - free(tmp); - rc += 1; + match = scan_format_binary(callh, argv, src, max_width, + suppress_flag, name); + if (match == 1) rc += 1; break; case 'c': - ch = byte_getc(src); - item = vpi_scan(argv); - assert(item); - - val.format = vpiIntVal; - val.value.integer = ch; - vpi_put_value(item, &val, 0, vpiNoDelay); - rc += 1; + match = scan_format_char(callh, argv, src, max_width, + suppress_flag, name); + if (match == 1) rc += 1; break; case 'd': - /* decimal integer */ - tmp = malloc(2); - value = 0; - tmp[0] = 0; - match_fail = 1; - - ch = byte_getc(src); - /* Skip leading space. */ - while (isspace(ch)) ch = byte_getc(src); - - while (isdigit(ch) || ch == '_' || (value == 0 && ch == '-')) { - match_fail = 0; - if (ch != '_') { - tmp[value++] = ch; - tmp = realloc(tmp, value+1); - tmp[value] = 0; - ch = byte_getc(src); - } - } - byte_ungetc(src, ch); - - if (match_fail) { - free(tmp); - break; - } - - /* Matched a decimal value, put it to an argument. */ - item = vpi_scan(argv); - assert(item); - - val.format = vpiDecStrVal; - val.value.str = tmp; - vpi_put_value(item, &val, 0, vpiNoDelay); - - free(tmp); - rc += 1; + match = scan_format_decimal(callh, argv, src, max_width, + suppress_flag, name); + if (match == 1) rc += 1; break; case 'e': case 'f': case 'g': - item = vpi_scan(argv); - assert(item); - rc += scan_format_float(src, item); + match = scan_format_float(callh, argv, src, max_width, + suppress_flag, name, code); + if (match == 1) rc += 1; break; case 'h': case 'x': - match_fail = 1; + match = scan_format_hex(callh, argv, src, max_width, + suppress_flag, name); + if (match == 1) rc += 1; + break; - /* Hex integer */ - tmp = malloc(2); - value = 0; - tmp[0] = 0; - - ch = byte_getc(src); - /* Skip leading space. */ - while (isspace(ch)) ch = byte_getc(src); - - while (strchr("0123456789abcdefABCDEFxXzZ?_", ch)) { - match_fail = 0; - if (ch == '?') ch = 'x'; - if (ch != '_') { - ch = tolower(ch); - tmp[value++] = ch; - tmp = realloc(tmp, value+1); - tmp[value] = 0; - } - ch = byte_getc(src); - } - byte_ungetc(src, ch); - - if (match_fail) { - free(tmp); - break; - } - - item = vpi_scan(argv); - assert(item); - - val.format = vpiHexStrVal; - val.value.str = tmp; - vpi_put_value(item, &val, 0, vpiNoDelay); - free(tmp); - rc += 1; + case 'm': + /* Since this code does not consume any characters + * the width makes no difference. */ + match = scan_format_module_path(callh, argv, + suppress_flag, name); + if (match == 1) rc += 1; break; case 'o': - match_fail = 1; - /* binary integer */ - tmp = malloc(2); - value = 0; - tmp[0] = 0; - - ch = byte_getc(src); - /* Skip leading space. */ - while (isspace(ch)) ch = byte_getc(src); - - while (strchr("01234567xXzZ?_", ch)) { - match_fail = 0; - if (ch == '?') ch = 'x'; - if (ch != '_') { - ch = tolower(ch); - tmp[value++] = ch; - tmp = realloc(tmp, value+1); - tmp[value] = 0; - } - ch = byte_getc(src); - } - byte_ungetc(src, ch); - - if (match_fail) { - free(tmp); - break; - } - - item = vpi_scan(argv); - assert(item); - - val.format = vpiOctStrVal; - val.value.str = tmp; - vpi_put_value(item, &val, 0, vpiNoDelay); - free(tmp); - rc += 1; + match = scan_format_octal(callh, argv, src, max_width, + suppress_flag, name); + if (match == 1) rc += 1; break; case 's': - item = vpi_scan(argv); - assert(item); - rc += scan_format_string(src, item); + match = scan_format_string(callh, argv, src, max_width, + suppress_flag, name); + if (match == 1) rc += 1; break; case 't': - item = vpi_scan(argv); - assert(item); - rc += scan_format_float_time(callh, src, item); + match = scan_format_float_time(callh, argv, src, + max_width, + suppress_flag, name); + if (match == 1) rc += 1; + break; + + case 'u': + case 'v': + case 'z': + vpi_printf("SORRY: %s:%d: ", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s() format code '%%%c' is not " + "currently supported.\n", name, code); + vpi_control(vpiFinish, 1); break; default: vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("$scanf: Unknown format code: %c\n", code); + vpi_printf("%s() was given an invalid format code: " + "%%%c\n", name, code); + vpi_control(vpiFinish, 1); break; } } } + /* Clean up the allocated memory. */ free(fmt); - vpi_free_object(argv); + /* Return the number of successful matches. */ val.format = vpiIntVal; val.value.integer = rc; vpi_put_value(callh, &val, 0, vpiNoDelay); + return 0; } @@ -611,7 +1018,7 @@ static int sys_check_args(vpiHandle callh, vpiHandle argv, const PLI_BYTE8 *name return rtn; } -static PLI_INT32 sys_fscanf_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) +static PLI_INT32 sys_fscanf_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); @@ -639,7 +1046,7 @@ static PLI_INT32 sys_fscanf_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -static PLI_INT32 sys_fscanf_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +static PLI_INT32 sys_fscanf_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); @@ -666,12 +1073,12 @@ static PLI_INT32 sys_fscanf_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) src.str = 0; src.fd = fd; - scan_format(callh, &src, argv); + scan_format(callh, &src, argv, name); return 0; } -static PLI_INT32 sys_sscanf_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) +static PLI_INT32 sys_sscanf_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); @@ -709,7 +1116,7 @@ static PLI_INT32 sys_sscanf_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } -static PLI_INT32 sys_sscanf_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) +static PLI_INT32 sys_sscanf_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); @@ -723,7 +1130,7 @@ static PLI_INT32 sys_sscanf_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) str = strdup(val.value.str); src.str = str; src.fd = 0; - scan_format(callh, &src, argv); + scan_format(callh, &src, argv, name); free(str); return 0; diff --git a/vpi/sys_time.c b/vpi/sys_time.c index 65f361600..07e5560f8 100644 --- a/vpi/sys_time.c +++ b/vpi/sys_time.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2011 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 @@ -95,7 +95,9 @@ static PLI_INT32 sys_realtime_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) /* For $abstime() we return the time in second. */ if (strcmp(name, "$abstime") == 0) { - now.real *= pow(10.0, vpi_get(vpiTimeUnit, mod)); + PLI_INT32 scale = vpi_get(vpiTimeUnit, mod); + if (scale >= 0) now.real *= pow(10.0, scale); + else now.real /= pow(10.0, -scale); } val.format = vpiRealVal; diff --git a/vpi/v2005_math.c b/vpi/v2005_math.c index 09edc03e2..4306faccf 100644 --- a/vpi/v2005_math.c +++ b/vpi/v2005_math.c @@ -2,7 +2,7 @@ * Verilog-2005 math library for Icarus Verilog * http://www.icarus.com/eda/verilog/ * - * Copyright (C) 2007-2010 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2007-2011 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -191,6 +191,7 @@ static PLI_INT32 va_single_argument_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *ud) arg = vpi_scan(argv); if (arg != 0) { va_error_message(callh, "%s takes only one argument.\n", name); + vpi_free_object(argv); } /* Get the function that is to be used by the calltf routine. */ @@ -274,6 +275,7 @@ static PLI_INT32 va_double_argument_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *ud) arg = vpi_scan(argv); if (arg != 0) { va_error_message(callh, "%s takes only two arguments.\n", name); + vpi_free_object(argv); } /* Get the function that is to be used by the calltf routine. */ diff --git a/vpi/v2009_enum.c b/vpi/v2009_enum.c index bdf61e1a9..bd43cc09c 100644 --- a/vpi/v2009_enum.c +++ b/vpi/v2009_enum.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2010-2011 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 @@ -20,243 +20,514 @@ # include "vpi_config.h" # include "sv_vpi_user.h" # include +# include # include -static void missing_arguments(vpiHandle sys) -{ - vpi_printf("%s:%d: error: Invalid/missing arguments next/prev method\n", - vpi_get_str(vpiFile, sys), vpi_get(vpiLineNo,sys)); - vpi_control(vpiFinish, 1); -} - -static PLI_INT32 ivl_method_next_prev_compiletf(ICARUS_VPI_CONST PLI_BYTE8*data) +/* + * The compiletf routine for the enumeration next() and prev() methods. + */ +static PLI_INT32 ivl_enum_method_next_prev_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, sys); - vpiHandle arg_enum, arg_item, arg_extra; + vpiHandle arg_enum, arg_var, arg_count; + /* These routines must have arguments. */ if (argv == 0) { - missing_arguments(sys); + vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys), + (int) vpi_get(vpiLineNo,sys)); + vpi_printf("No arguments given for enum method %s().\n", name); + vpi_control(vpiFinish, 1); return 0; } + /* Check for the enumeration type argument. */ arg_enum = vpi_scan(argv); if (arg_enum == 0) { - missing_arguments(sys); + vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys), + (int) vpi_get(vpiLineNo,sys)); + vpi_printf("No enumeration type argument given for enum " + "method %s().\n", name); + vpi_control(vpiFinish, 1); return 0; } - - arg_item = vpi_scan(argv); - if (arg_item == 0) { - missing_arguments(sys); - return 0; - } - - /* Make sure there are no excess arguments */ - arg_extra = vpi_scan(argv); - if (arg_extra != 0) { - missing_arguments(sys); - vpi_free_object(argv); - return 0; - } - - /* The first argument must be an enum typespec */ if (vpi_get(vpiType, arg_enum) != vpiEnumTypespec) { - missing_arguments(sys); - return 0; + vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys), + (int) vpi_get(vpiLineNo,sys)); + vpi_printf("The first argument to enum method %s() must be an " + "enumeration type, found a %s.\n", name, + vpi_get_str(vpiType, arg_enum)); + vpi_control(vpiFinish, 1); } - /* The return value and input value must be the same size */ - if (vpi_get(vpiSize,sys) != vpi_get(vpiSize,arg_item)) { - missing_arguments(sys); + /* Check for the enumeration variable. */ + arg_var = vpi_scan(argv); + if (arg_var == 0) { + vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys), + (int) vpi_get(vpiLineNo,sys)); + vpi_printf("No enumeration variable argument given for enum " + "method %s().\n", name); + vpi_control(vpiFinish, 1); return 0; } + switch(vpi_get(vpiType, arg_var)) { + case vpiBitVar: + case vpiByteVar: + case vpiIntegerVar: + case vpiIntVar: + case vpiLongIntVar: + case vpiReg: + case vpiShortIntVar: + break; + default: + vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys), + (int) vpi_get(vpiLineNo,sys)); + vpi_printf("The second argument to enum method %s() must be an " + "enumeration variable, found a %s.\n", name, + vpi_get_str(vpiType, arg_var)); + vpi_control(vpiFinish, 1); + } + + /* We can have an optional numeric count value. */ + arg_count = vpi_scan(argv); + if (arg_count) { + switch(vpi_get(vpiType, arg_count)) { + case vpiBitVar: + case vpiByteVar: + case vpiIntegerVar: + case vpiIntVar: + case vpiLongIntVar: + case vpiMemoryWord: + case vpiNet: + case vpiPartSelect: + case vpiRealVar: + case vpiReg: + case vpiShortIntVar: + case vpiTimeVar: + break; + case vpiConstant: + case vpiParameter: + if (vpi_get(vpiConstType, arg_count) != vpiStringConst) break; + default: + vpi_printf("%s:%d: compiler error: ", + vpi_get_str(vpiFile, sys), + (int) vpi_get(vpiLineNo,sys)); + vpi_printf("The second argument to enum method %s() must be " + "numeric, found a %s.\n", name, + vpi_get_str(vpiType, arg_count)); + vpi_control(vpiFinish, 1); + } + } + + /* If we have a count argument then check to see if any extra + * arguments were given. */ + if (arg_count && (vpi_scan(argv) != 0)) { + vpi_free_object(argv); + vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys), + (int) vpi_get(vpiLineNo,sys)); + vpi_printf("Extra argument(s) given to enum method %s().\n", name); + vpi_control(vpiFinish, 1); + } + + /* The method return value and the enum variable must be the + * same size */ + if (vpi_get(vpiSize, sys) != vpi_get(vpiSize, arg_var)) { + vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys), + (int) vpi_get(vpiLineNo,sys)); + vpi_printf("The enum method %s() return width (%d) must match " + "the enum variable width (%d).\n", name, + (int) vpi_get(vpiSize, sys), + (int) vpi_get(vpiSize, arg_var)); + vpi_control(vpiFinish, 1); + } + return 0; } -static int compare_value_eequal(s_vpi_value*ref1, s_vpi_value*ref2, long wid) +/* + * Compare it two values are equal to each other. + */ +static int compare_value_eequal(s_vpi_value*ref1, s_vpi_value*ref2, + PLI_INT32 wid) { + /* Two integer values are easy. */ if (ref1->format == vpiIntVal && ref2->format == vpiIntVal) return ref1->value.integer == ref2->value.integer; + /* For two vectors compare them word by word. */ if (ref1->format == vpiVectorVal && ref2->format == vpiVectorVal) { - int words = (wid-1)/32 + 1; - int idx; + PLI_INT32 words = (wid-1)/32 + 1; + PLI_INT32 idx; for (idx = 0 ; idx < words ; idx += 1) { - if (ref1->value.vector[idx].aval != ref2->value.vector[idx].aval) - return 0; - if (ref1->value.vector[idx].bval != ref2->value.vector[idx].bval) - return 0; + if (ref1->value.vector[idx].aval != + ref2->value.vector[idx].aval) return 0; + if (ref1->value.vector[idx].bval != + ref2->value.vector[idx].bval) return 0; } return 1; } + /* Swap the order so the code below can be used. */ if (ref1->format == vpiVectorVal && ref2->format == vpiIntVal) { s_vpi_value*tmp = ref1; ref1 = ref2; ref2 = tmp; } + /* Compare an integer to a vector. */ if (ref1->format == vpiIntVal && ref2->format == vpiVectorVal) { - int use_aval = ref1->value.integer; - int words = (wid-1)/32 + 1; - int idx; + PLI_INT32 aval = ref1->value.integer; + PLI_INT32 words = (wid-1)/32 + 1; + PLI_INT32 idx; for (idx = 0 ; idx < words ; idx += 1) { - if (use_aval != ref2->value.vector[idx].aval) - return 0; - if (0 != ref2->value.vector[idx].bval) - return 0; + if (aval != ref2->value.vector[idx].aval) return 0; + if (ref2->value.vector[idx].bval) return 0; - use_aval = 0; + aval = 0; } return 1; } + /* Unsupported types. */ vpi_printf("XXXX formats are: %d vs %d\n", ref1->format, ref2->format); assert(0); return 0; } -static PLI_INT32 ivl_method_next_calltf(PLI_BYTE8*data) +/* + * If the current value is not found in the enumeration. Then we need to + * return X/0 for the next()/prev() value. + */ +static void fill_handle_with_init(vpiHandle arg, int is_two_state) +{ + s_vpi_value val; + PLI_INT32 words = ((vpi_get(vpiSize, arg) - 1) / 32) + 1; + PLI_INT32 idx; + p_vpi_vecval val_ptr = (p_vpi_vecval) malloc(words*sizeof(s_vpi_vecval)); + PLI_INT32 fill = (is_two_state) ? 0x0 : 0xffffffff; + + assert(val_ptr); + + /* Fill the vector with X. */ + for (idx=0; idx < words; idx += 1) { + val_ptr[idx].aval = fill; + val_ptr[idx].bval = fill; + } + + /* Put the vector to the argument. */ + val.format = vpiVectorVal; + val.value.vector = val_ptr; + vpi_put_value(arg, &val, 0, vpiNoDelay); + free(val_ptr); +} + +/* + * Implement the next()/prev() enumeration methods. + */ +static PLI_INT32 ivl_enum_method_next_prev_calltf(PLI_BYTE8*name) { vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, sys); vpiHandle arg_enum = vpi_scan(argv); - vpiHandle arg_item = vpi_scan(argv); - vpiHandle arg_extra = vpi_scan(argv); + vpiHandle arg_var = vpi_scan(argv); + vpiHandle arg_count = vpi_scan(argv); - vpiHandle enum_list = 0; - vpiHandle memb = 0, first_memb = 0; - long use_width = 0; - long item_width = vpi_get(vpiSize, arg_item); + vpiHandle enum_list; + vpiHandle cur; + PLI_INT32 var_width = vpi_get(vpiSize, arg_var); + PLI_UINT32 enum_size = vpi_get(vpiSize, arg_enum); + PLI_UINT32 count = 1; + PLI_UINT32 loc = 0; - s_vpi_value memb_value, item_value; + s_vpi_value cur_val, var_val; - assert(arg_extra == 0); + /* Get the count value if one was given. */ + if (arg_count) { + s_vpi_value count_val; - item_value.format = vpiObjTypeVal; - vpi_get_value(arg_item, &item_value); - - /* If this value is a vector value, then make a safe copy of - the vector so that other vpi functions don't trash it. */ - if (item_value.format == vpiVectorVal) { - unsigned idx; - unsigned hwid = (item_width - 1)/32 + 1; - s_vpi_vecval*op = calloc(hwid, sizeof(s_vpi_vecval)); - for (idx = 0 ; idx < hwid ; idx += 1) { - op[idx].aval = item_value.value.vector[idx].aval; - op[idx].bval = item_value.value.vector[idx].bval; - } - item_value.value.vector = op; + /* Get the count value. */ + count_val.format = vpiIntVal; + vpi_get_value(arg_count, &count_val); + count = count_val.value.integer; + /* Remove any multiple loops around the enumeration. */ + count %= enum_size; + /* Free the argument iterator. */ + vpi_free_object(argv); } - enum_list = vpi_iterate(vpiMember, arg_enum); - assert(enum_list); + /* Get the current value. */ + var_val.format = vpiObjTypeVal; + vpi_get_value(arg_var, &var_val); - /* Search for the current value in the member list. */ - do { - memb = vpi_scan(enum_list); - if (first_memb == 0) { - first_memb = memb; - use_width = vpi_get(vpiSize, first_memb); - assert(use_width == vpi_get(vpiSize, arg_item)); + /* If the count is zero then just return the current value. */ + if (count == 0) { + vpi_put_value(sys, &var_val, 0, vpiNoDelay); + return 0; + } + + /* If the current value is a vector, then make a safe copy of + it so that other vpi_get_value() calls don't trash the value. */ + if (var_val.format == vpiVectorVal) { + PLI_INT32 idx; + PLI_INT32 words = (var_width - 1)/32 + 1; + p_vpi_vecval nvec = malloc(words*sizeof(s_vpi_vecval)); + for (idx = 0 ; idx < words ; idx += 1) { + nvec[idx].aval = var_val.value.vector[idx].aval; + nvec[idx].bval = var_val.value.vector[idx].bval; } - if (memb == 0) break; + var_val.value.vector = nvec; + } - memb_value.format = vpiObjTypeVal; - vpi_get_value(memb, &memb_value); + /* Search for the current value in the enumeration list. */ + enum_list = vpi_iterate(vpiEnumConst, arg_enum); + assert(enum_list); + do { + cur = vpi_scan(enum_list); + if (cur == 0) break; - } while (! compare_value_eequal(&item_value, &memb_value, use_width)); + cur_val.format = vpiObjTypeVal; + vpi_get_value(cur, &cur_val); + assert(var_width == vpi_get(vpiSize, cur)); + loc += 1; + } while (! compare_value_eequal(&cur_val, &var_val, var_width)); - if (memb != 0) - memb = vpi_scan(enum_list); + /* If the variable is a vector then free the copy we created above. */ + if (var_val.format == vpiVectorVal) free(var_val.value.vector); - if (memb != 0) + /* The current value was not found in the list so return X/0. */ + if (cur == 0) { + /* This only works correctly since we don't really define the + * the correct base typespec. */ + int is_two_state = vpi_get(vpiBaseTypespec, arg_enum) != vpiReg; + fill_handle_with_init(sys, is_two_state); + } else { + if (strcmp(name, "$ivl_enum_method$next") == 0) { + /* Check to see if we need to wrap to the beginning. */ + if (loc + count > enum_size) { + /* Free the current iterator before creating a new + * one that is at the beginning of the list. */ + vpi_free_object(enum_list); + enum_list = vpi_iterate(vpiEnumConst, arg_enum); + assert(enum_list); + count -= (enum_size - loc); + } + } else if (strcmp(name, "$ivl_enum_method$prev") == 0) { + /* Because of wrapping the count could be either before + * or after the current element. */ + if (loc <= count ) { + /* The element we want is after the current + * element. */ + count = enum_size - count; + } else { + /* The element we want is before the current + * element (at the beginning of the list). Free + * the current iterator before creating a new + * one that is at the beginning of the list. */ + vpi_free_object(enum_list); + enum_list = vpi_iterate(vpiEnumConst, arg_enum); + assert(enum_list); + count = loc - count; + } + } else assert(0); + + /* Find the correct element. */ + while (count) { + cur = vpi_scan(enum_list); + count -= 1; + } + assert(cur != 0); + + /* Free the iterator. */ vpi_free_object(enum_list); - if (memb == 0) { - memb = first_memb; - memb_value.format = vpiIntVal; + /* Get the value and return it. */ + cur_val.format = vpiObjTypeVal; + vpi_get_value(cur, &cur_val); + vpi_put_value(sys, &cur_val, 0, vpiNoDelay); } - /* Free any stached copy of the vector. */ - if (item_value.format == vpiVectorVal) - free(item_value.value.vector); - - vpi_get_value(memb, &memb_value); - vpi_put_value(sys, &memb_value, 0, vpiNoDelay); - return 0; } -static PLI_INT32 ivl_method_prev_calltf(PLI_BYTE8*data) +/* + * The compiletf routine for the enumeration name() method. + */ +static PLI_INT32 ivl_enum_method_name_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) +{ + vpiHandle sys = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, sys); + vpiHandle arg_enum, arg_var; + + /* This routine must have arguments. */ + if (argv == 0) { + vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys), + (int) vpi_get(vpiLineNo,sys)); + vpi_printf("No arguments given for enum method %s().\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + /* Check for the enumeration type argument. */ + arg_enum = vpi_scan(argv); + if (arg_enum == 0) { + vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys), + (int) vpi_get(vpiLineNo,sys)); + vpi_printf("No enumeration type argument given for enum " + "method %s().\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + if (vpi_get(vpiType, arg_enum) != vpiEnumTypespec) { + vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys), + (int) vpi_get(vpiLineNo,sys)); + vpi_printf("The first argument to enum method %s() must be an " + "enumeration type, found a %s.\n", name, + vpi_get_str(vpiType, arg_enum)); + vpi_control(vpiFinish, 1); + } + + /* Check for the enumeration variable. */ + arg_var = vpi_scan(argv); + if (arg_var == 0) { + vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys), + (int) vpi_get(vpiLineNo,sys)); + vpi_printf("No enumeration variable argument given for enum " + "method %s().\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + switch(vpi_get(vpiType, arg_var)) { + case vpiBitVar: + case vpiByteVar: + case vpiIntegerVar: + case vpiIntVar: + case vpiLongIntVar: + case vpiReg: + case vpiShortIntVar: + break; + default: + vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys), + (int) vpi_get(vpiLineNo,sys)); + vpi_printf("The second argument to enum method %s() must be an " + "enumeration variable, found a %s.\n", name, + vpi_get_str(vpiType, arg_var)); + vpi_control(vpiFinish, 1); + } + + /* Only two arguments are supported. */ + if (vpi_scan(argv) != 0) { + vpi_free_object(argv); + vpi_printf("%s:%d: compiler error: ", vpi_get_str(vpiFile, sys), + (int) vpi_get(vpiLineNo,sys)); + vpi_printf("Extra argument(s) given to enum method %s().\n", name); + vpi_control(vpiFinish, 1); + } + + return 0; +} + +/* + * Implement the name() enumeration method. + */ +static PLI_INT32 ivl_enum_method_name_calltf(PLI_BYTE8*name) { vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, sys); vpiHandle arg_enum = vpi_scan(argv); - vpiHandle arg_item = vpi_scan(argv); - vpiHandle arg_extra = vpi_scan(argv); + vpiHandle arg_var = vpi_scan(argv); - vpiHandle enum_list = 0; - vpiHandle memb = 0, prev = 0, last_memb = 0; - int use_wid = 0; + vpiHandle enum_list; + vpiHandle cur; + PLI_INT32 var_width = vpi_get(vpiSize, arg_var); - s_vpi_value memb_value, item_value; + s_vpi_value cur_val, var_val; - assert(arg_extra == 0); + /* Free the argument iterator. */ + vpi_free_object(argv); - item_value.format = vpiIntVal; - vpi_get_value(arg_item, &item_value); + /* Get the current value. */ + var_val.format = vpiObjTypeVal; + vpi_get_value(arg_var, &var_val); - enum_list = vpi_iterate(vpiMember, arg_enum); - assert(enum_list); - - /* Search for the current value in the member list. */ - do { - prev = memb; - memb = vpi_scan(enum_list); - if (memb == 0) break; - if (use_wid == 0) - use_wid = vpi_get(vpiSize, memb); - - last_memb = memb; - memb_value.format = vpiIntVal; - vpi_get_value(memb, &memb_value); - } while (! compare_value_eequal(&memb_value, &item_value, use_wid)); - - while (memb) { - last_memb = memb; - memb = vpi_scan(enum_list); + /* If the current value is a vector, then make a safe copy of + it so that other vpi_get_value() calls don't trash the value. */ + if (var_val.format == vpiVectorVal) { + PLI_INT32 idx; + PLI_INT32 words = (var_width - 1)/32 + 1; + p_vpi_vecval nvec = malloc(words*sizeof(s_vpi_vecval)); + for (idx = 0 ; idx < words ; idx += 1) { + nvec[idx].aval = var_val.value.vector[idx].aval; + nvec[idx].bval = var_val.value.vector[idx].bval; + } + var_val.value.vector = nvec; } - if (prev == 0) - prev = last_memb; + /* Search for the current value in the enumeration list. */ + enum_list = vpi_iterate(vpiEnumConst, arg_enum); + assert(enum_list); + do { + cur = vpi_scan(enum_list); + if (cur == 0) break; - vpi_get_value(prev, &memb_value); - vpi_put_value(sys, &memb_value, 0, vpiNoDelay); + cur_val.format = vpiObjTypeVal; + vpi_get_value(cur, &cur_val); + assert(var_width == vpi_get(vpiSize, cur)); + } while (! compare_value_eequal(&cur_val, &var_val, var_width)); + /* If the variable is a vector then free the copy we created above. */ + if (var_val.format == vpiVectorVal) free(var_val.value.vector); + + /* The current value was not found in the list so return an empty + * string. */ + cur_val.format = vpiStringVal; + if (cur == 0) { + cur_val.value.str = ""; + } else { + cur_val.value.str = vpi_get_str(vpiName, cur); + + /* Free the iterator. */ + vpi_free_object(enum_list); + } + + /* Return the appropriate string value. */ + vpi_put_value(sys, &cur_val, 0, vpiNoDelay); return 0; } void v2009_enum_register(void) { s_vpi_systf_data tf_data; + vpiHandle res; tf_data.type = vpiSysFunc; - tf_data.calltf = ivl_method_next_calltf; - tf_data.compiletf = ivl_method_next_prev_compiletf; + tf_data.calltf = ivl_enum_method_name_calltf; + tf_data.compiletf = ivl_enum_method_name_compiletf; tf_data.sizetf = 0; - tf_data.tfname = "$ivl_method$next"; - tf_data.user_data = "$ivl_method$next"; - vpi_register_systf(&tf_data); + tf_data.tfname = "$ivl_enum_method$name"; + tf_data.user_data = "$ivl_enum_method$name"; + res = vpi_register_systf(&tf_data); + /* This is not a user defined system function so hide it. */ + vpip_make_systf_system_defined(res); tf_data.type = vpiSysFunc; - tf_data.calltf = ivl_method_prev_calltf; - tf_data.compiletf = 0; + tf_data.calltf = ivl_enum_method_next_prev_calltf; + tf_data.compiletf = ivl_enum_method_next_prev_compiletf; tf_data.sizetf = 0; - tf_data.tfname = "$ivl_method$prev"; - tf_data.user_data = "$ivl_method$prev"; - vpi_register_systf(&tf_data); + tf_data.tfname = "$ivl_enum_method$next"; + tf_data.user_data = "$ivl_enum_method$next"; + res = vpi_register_systf(&tf_data); + /* This is not a user defined system function so hide it. */ + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysFunc; + tf_data.calltf = ivl_enum_method_next_prev_calltf; + tf_data.compiletf = ivl_enum_method_next_prev_compiletf; + tf_data.sizetf = 0; + tf_data.tfname = "$ivl_enum_method$prev"; + tf_data.user_data = "$ivl_enum_method$prev"; + res = vpi_register_systf(&tf_data); + /* This is not a user defined system function so hide it. */ + vpip_make_systf_system_defined(res); } diff --git a/vpi/va_math.c b/vpi/va_math.c index 1b6bb0ea1..8ca38e190 100644 --- a/vpi/va_math.c +++ b/vpi/va_math.c @@ -2,7 +2,7 @@ * Verilog-A math library for Icarus Verilog * http://www.icarus.com/eda/verilog/ * - * Copyright (C) 2007-2010 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2007-2011 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -218,6 +218,7 @@ static PLI_INT32 va_single_argument_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *ud) arg = vpi_scan(argv); if (arg != 0) { va_error_message(callh, "%s takes only one argument.\n", name); + vpi_free_object(argv); } /* Get the function that is to be used by the calltf routine. */ @@ -301,6 +302,7 @@ static PLI_INT32 va_double_argument_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *ud) arg = vpi_scan(argv); if (arg != 0) { va_error_message(callh, "%s takes only two arguments.\n", name); + vpi_free_object(argv); } /* Get the function that is to be used by the calltf routine. */ diff --git a/vpi/vams_simparam.c b/vpi/vams_simparam.c index 2246ac5c9..74fa6772d 100644 --- a/vpi/vams_simparam.c +++ b/vpi/vams_simparam.c @@ -214,8 +214,7 @@ static PLI_INT32 simparam_str_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name_ext) char path [MAX_STRING_RESULT]; char *ptr = getcwd(path, MAX_STRING_RESULT); if (ptr == NULL) { - ptr = strcpy(path, ""); + strcpy(path, ""); } retval = strdup(path); } else if (strcmp(param, "module") == 0) { diff --git a/vpi/vhdl_table.cc b/vpi/vhdl_table.c similarity index 62% rename from vpi/vhdl_table.cc rename to vpi/vhdl_table.c index 5cfb7171a..e2bb3e8a1 100644 --- a/vpi/vhdl_table.cc +++ b/vpi/vhdl_table.c @@ -19,7 +19,8 @@ # include "vpi_config.h" # include "vpi_user.h" -# include +# include +# include "ivl_alloc.h" /* * The $ivlh_attribute_event implements the VHDL 'event @@ -32,14 +33,28 @@ struct monitor_data { struct t_vpi_time last_event; }; -/* - * All the following are called from C so define them for C linkage. - */ -extern "C" { +static struct monitor_data **mdata = 0; +static unsigned mdata_count = 0; + +/* To keep valgrind happy free the allocated memory. */ +static PLI_INT32 cleanup_mdata(p_cb_data cause) +{ + unsigned idx; + (void) cause; /* Unused argument. */ + + for (idx= 0; idx < mdata_count; idx += 1) { + free(mdata[idx]); + } + free(mdata); + mdata = 0; + mdata_count = 0; + + return 0; +} static PLI_INT32 monitor_events(struct t_cb_data*cb) { - struct monitor_data*mon = reinterpret_cast (cb->user_data); + struct monitor_data*mon = (struct monitor_data*)(cb->user_data); assert(cb->time); assert(cb->time->type == vpiSimTime); @@ -48,56 +63,71 @@ static PLI_INT32 monitor_events(struct t_cb_data*cb) return 0; } -static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*) +static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, sys); vpiHandle arg; + struct monitor_data*mon; + struct t_cb_data cb; + struct t_vpi_time tb; - // Check that there is at least 1 argument... + /* Check that there are arguments. */ if (argv == 0) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), vpi_get(vpiLineNo, sys)); - vpi_printf("Call to %s missing its argument\n", vpi_get_str(vpiName,sys)); + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), + (int)vpi_get(vpiLineNo, sys)); + vpi_printf("(compiler error) %s requires a single argument.\n", + name); vpi_control(vpiFinish, 1); return 0; } + /* Icarus either returns 0 above or has one argument. */ arg = vpi_scan(argv); assert(arg); - struct monitor_data*monitor_handle = new struct monitor_data; + mon = malloc(sizeof(struct monitor_data)); + /* Add this to the list of data. */ + mdata_count += 1; + mdata = (struct monitor_data **) realloc(mdata, + sizeof(struct monitor_data **) * + mdata_count); + mdata[mdata_count-1] = mon; - struct t_cb_data cb; - struct t_vpi_time tb; tb.type = vpiSimTime; cb.reason = cbValueChange; cb.cb_rtn = monitor_events; cb.obj = arg; cb.time = &tb; cb.value = 0; - cb.user_data = reinterpret_cast(monitor_handle); + cb.user_data = (char*) (mon); vpi_register_cb(&cb); - vpi_put_userdata(sys, monitor_handle); + vpi_put_userdata(sys, mon); - // check that there is no more then 1 argument + /* Check that there are no more then one argument. */ arg = vpi_scan(argv); if (arg != 0) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), vpi_get(vpiLineNo, sys)); - vpi_printf("Too many arguments for call to %s.\n", vpi_get_str(vpiName,sys)); + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), + (int)vpi_get(vpiLineNo, sys)); + vpi_printf("(compiler error) %s only takes a single argument.\n", + name); + vpi_free_object(argv); vpi_control(vpiFinish, 1); } return 0; } -static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*) +static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle sys = vpi_handle(vpiSysTfCall, 0); - struct t_vpi_value rval; + struct monitor_data*mon; + (void) name; + rval.format = vpiScalarVal; - struct monitor_data*mon = reinterpret_cast(vpi_get_userdata(sys)); + mon = (struct monitor_data*) (vpi_get_userdata(sys)); if (mon->last_event.type == 0) { rval.value.scalar = vpi0; @@ -105,7 +135,7 @@ static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*) } else { struct t_vpi_time tnow; tnow.type = vpiSimTime; - vpi_get_time(0,&tnow); + vpi_get_time(0, &tnow); rval.value.scalar = vpi1; if (mon->last_event.high != tnow.high) @@ -119,14 +149,16 @@ static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*) return 0; } -static PLI_INT32 ivlh_attribute_event_sizetf(ICARUS_VPI_CONST PLI_BYTE8*) +static PLI_INT32 ivlh_attribute_event_sizetf(ICARUS_VPI_CONST PLI_BYTE8*name) { + (void) name; return 1; } static void vhdl_register(void) { s_vpi_systf_data tf_data; + s_cb_data cb; vpiHandle res; tf_data.type = vpiSysFunc; @@ -138,11 +170,19 @@ static void vhdl_register(void) tf_data.user_data = (PLI_BYTE8 *) "$ivlh_attribute_event"; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); + + /* Create a callback to clear the monitor data memory when the + * simulator finishes. */ + cb.time = NULL; + cb.reason = cbEndOfSimulation; + cb.cb_rtn = cleanup_mdata; + cb.user_data = NULL; + cb.obj = NULL; + + vpi_register_cb(&cb); } void (*vlog_startup_routines[])() = { vhdl_register, 0 }; - -} /* extern "C" */ diff --git a/vpi/wavealloca.h b/vpi/wavealloca.h index 5f4b2186e..ac2416d62 100644 --- a/vpi/wavealloca.h +++ b/vpi/wavealloca.h @@ -27,24 +27,3 @@ #define wave_alloca alloca #endif -/* - * $Id: wavealloca.h,v 1.3 2009/12/06 00:10:17 gtkwave Exp $ - * $Log: wavealloca.h,v $ - * Revision 1.3 2009/12/06 00:10:17 gtkwave - * mingw compatibility fix from icarus - * - * Revision 1.2 2007/08/26 21:35:50 gtkwave - * integrated global context management from SystemOfCode2007 branch - * - * Revision 1.1.1.1.2.1 2007/08/06 03:50:50 gtkwave - * globals support for ae2, gtk1, cygwin, mingw. also cleaned up some machine - * generated structs, etc. - * - * Revision 1.1.1.1 2007/05/30 04:27:29 gtkwave - * Imported sources - * - * Revision 1.2 2007/04/20 02:08:18 gtkwave - * initial release - * - */ - diff --git a/vpi_user.h b/vpi_user.h index e0d25de96..7dbe6da81 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -288,6 +288,7 @@ typedef struct t_vpi_delay { #define vpiSysTaskCall 57 #define vpiTask 59 #define vpiTimeVar 63 +#define vpiUdpDefn 66 #define vpiUserSystf 67 #define vpiNetArray 114 #define vpiIndex 78 @@ -362,7 +363,7 @@ typedef struct t_vpi_delay { # define vpiSysFuncReal vpiRealFunc # define vpiSysFuncTime vpiTimeFunc # define vpiSysFuncSized vpiSizedFunc -#define vpiUserDefn 49 +#define vpiUserDefn 45 #define vpiAutomatic 50 #define vpiConstantSelect 53 #define vpiSigned 65 diff --git a/vvp/codes.cc b/vvp/codes.cc index d1b4650f8..d99451330 100644 --- a/vvp/codes.cc +++ b/vvp/codes.cc @@ -101,6 +101,12 @@ void codespace_delete(void) { vvp_code_t cur = first_chunk; + /* If there are no opcodes then just delete the code space. */ + if (count_opcodes == 0) { + delete [] cur; + return; + } + do { vvp_code_t next = cur[code_chunk_size-1].cptr; for (unsigned idx = 0 ; idx < code_chunk_size; idx += 1) { diff --git a/vvp/compile.cc b/vvp/compile.cc index 0050678c4..61d3e81fe 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -1512,7 +1512,6 @@ void compile_udp_def(int sequ, char *label, char *name, u->compile_table(table); } free(label); - delete[] name; } char **compile_udp_table(char **table, char *row) diff --git a/vvp/delay.cc b/vvp/delay.cc index 03cd6b506..43d647546 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2010 Stephen Williams + * Copyright (c) 2005-2011 Stephen Williams * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -771,6 +771,11 @@ static vpiHandle modpath_src_get_handle(int code, vpiHandle ref) return vpi_handle(scope); } + // Handles to path term objects should really be obtained via + // the vpi_iterate and vpi_scan functions. Continue to allow + // them to be obtained here for backwards compatibility with + // older versions of Icarus Verilog. + case vpiModPathIn: return vpi_handle(&rfp->path_term_in); @@ -780,6 +785,30 @@ static vpiHandle modpath_src_get_handle(int code, vpiHandle ref) return 0; } +static vpiHandle modpath_src_iterate(int code, vpiHandle ref) +{ + struct __vpiModPathSrc*rfp = vpip_modpath_src_from_handle(ref); + assert(rfp); + + // Module paths with multiple sources or destinations are + // currently represented by a separate modpath object for + // each source/destination combination, so there is only + // ever one input path term and one output path term. + switch (code) { + case vpiModPathIn: { + vpiHandle*args = (vpiHandle*)calloc(1, sizeof(vpiHandle*)); + args[0] = vpi_handle(&rfp->path_term_in); + return vpip_make_iterator(1, args, true); + } + case vpiModPathOut: { + vpiHandle*args = (vpiHandle*)calloc(1, sizeof(vpiHandle*)); + args[0] = vpi_handle(&rfp->dest->path_term_out); + return vpip_make_iterator(1, args, true); + } + } + return 0; +} + static vpiHandle modpath_src_index ( vpiHandle ref, int) { assert(ref->vpi_type->type_code == vpiModPathIn); @@ -946,7 +975,7 @@ static const struct __vpirt vpip_modpath_src_rt = { modpath_src_get_value, modpath_src_put_value, modpath_src_get_handle, - 0, /* modpath_src_iterate,*/ + modpath_src_iterate, modpath_src_index, modpath_src_free_object, modpath_src_get_delays, diff --git a/vvp/enum_type.cc b/vvp/enum_type.cc index 4e11191de..13ad72b4b 100644 --- a/vvp/enum_type.cc +++ b/vvp/enum_type.cc @@ -19,6 +19,9 @@ # include "compile.h" # include "enum_type.h" +#ifdef CHECK_WITH_VALGRIND +# include "vvp_cleanup.h" +#endif # include # include @@ -40,6 +43,7 @@ static struct enumconst_s* enumconst_from_handle(vpiHandle obj) struct __vpiEnumTypespec { struct __vpiHandle base; std::vector names; + int base_type_code; bool is_signed; }; @@ -60,6 +64,13 @@ static int enum_type_get(int code, vpiHandle obj) case vpiSize: return ref->names.size(); + /* This is not currently set correctly. We always use vpiReg for + * four state variables and vpiBitVar for two state variables. + * This minimal functionality is needed to get the next() and + * prev() methods to work correctly with invalid values. */ + case vpiBaseTypespec: + return ref->base_type_code; + case vpiSigned: return ref->is_signed; @@ -76,7 +87,7 @@ static vpiHandle enum_type_iterate(int code, vpiHandle obj) struct __vpiEnumTypespec*ref = vpip_enum_typespec_from_handle(obj); assert(ref); - if (code == vpiMember) { + if (code == vpiEnumConst) { vpiHandle*args = (vpiHandle*) calloc(ref->names.size(), sizeof(vpiHandle*)); for (size_t idx = 0 ; idx < ref->names.size() ; idx += 1) @@ -160,6 +171,7 @@ void compile_enum2_type(char*label, long width, bool signed_flag, spec->base.vpi_type = &enum_type_rt; spec->names = std::vector (names->size()); spec->is_signed = signed_flag; + spec->base_type_code = vpiBitVar; size_t idx = 0; for (list::iterator cur = names->begin() @@ -172,6 +184,7 @@ void compile_enum2_type(char*label, long width, bool signed_flag, assert(idx == spec->names.size()); compile_vpi_symbol(label, vpi_handle(spec)); + vpip_attach_to_current_scope(vpi_handle(spec)); free(label); delete names; @@ -184,6 +197,7 @@ void compile_enum4_type(char*label, long width, bool signed_flag, spec->base.vpi_type = &enum_type_rt; spec->names = std::vector (names->size()); spec->is_signed = signed_flag; + spec->base_type_code = vpiReg; size_t idx = 0; for (list::iterator cur = names->begin() @@ -198,7 +212,22 @@ void compile_enum4_type(char*label, long width, bool signed_flag, assert(idx == spec->names.size()); compile_vpi_symbol(label, vpi_handle(spec)); + vpip_attach_to_current_scope(vpi_handle(spec)); free(label); delete names; } + +#ifdef CHECK_WITH_VALGRIND +void enum_delete(vpiHandle item) +{ + struct __vpiEnumTypespec*obj = (struct __vpiEnumTypespec*) item; + + for (vector::iterator iter = obj->names.begin(); + iter != obj->names.end(); ++ iter ) { + delete [] iter->name; + } + + delete obj; +} +#endif diff --git a/vvp/udp.cc b/vvp/udp.cc index 0c45be816..ef8d2f1fd 100644 --- a/vvp/udp.cc +++ b/vvp/udp.cc @@ -82,8 +82,9 @@ ostream& operator <<(ostream&o, const struct udp_levels_table&table) return o; } -vvp_udp_s::vvp_udp_s(char*label, unsigned ports, vvp_bit4_t init, bool type) -: ports_(ports), init_(init), seq_(type) +vvp_udp_s::vvp_udp_s(char*label, char*name__, unsigned ports, + vvp_bit4_t init, bool type) +: name_(name__), ports_(ports), init_(init), seq_(type) { if (!udp_table) udp_table = new_symbol_table(); @@ -104,6 +105,7 @@ vvp_udp_s::vvp_udp_s(char*label, unsigned ports, vvp_bit4_t init, bool type) vvp_udp_s::~vvp_udp_s() { + delete[] name_; } unsigned vvp_udp_s::port_count() const @@ -116,10 +118,9 @@ vvp_bit4_t vvp_udp_s::get_init() const return init_; } -vvp_udp_comb_s::vvp_udp_comb_s(char*label, char*name, unsigned ports) -: vvp_udp_s(label, ports, BIT4_X, false) +vvp_udp_comb_s::vvp_udp_comb_s(char*label, char*name__, unsigned ports) +: vvp_udp_s(label, name__, ports, BIT4_X, false) { - name_ = name; levels0_ = 0; levels1_ = 0; nlevels0_ = 0; @@ -295,11 +296,10 @@ void vvp_udp_comb_s::compile_table(char**tab) assert(nrows1 == nlevels1_); } -vvp_udp_seq_s::vvp_udp_seq_s(char*label, char*name, +vvp_udp_seq_s::vvp_udp_seq_s(char*label, char*name__, unsigned ports, vvp_bit4_t init) -: vvp_udp_s(label, ports, init, true) +: vvp_udp_s(label, name__, ports, init, true) { - name_ = name; levels0_ = 0; levels1_ = 0; levelsx_ = 0; diff --git a/vvp/udp.h b/vvp/udp.h index 5769b63d0..97b3541a8 100644 --- a/vvp/udp.h +++ b/vvp/udp.h @@ -1,7 +1,7 @@ #ifndef __udp_H #define __udp_H /* - * Copyright (c) 2005-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2005-2011 Stephen Williams (steve@icarus.com) * * (This is a rewrite of code that was ... * Copyright (c) 2001 Stephan Boettcher ) @@ -30,15 +30,16 @@ struct udp_levels_table; struct vvp_udp_s { public: - explicit vvp_udp_s(char*label, unsigned ports, vvp_bit4_t init, - bool type); + explicit vvp_udp_s(char*label, char*name, unsigned ports, + vvp_bit4_t init, bool type); virtual ~vvp_udp_s(); // Return the number of input ports for the defined UDP. This // does *not* include the current output value for a // sequential UDP. unsigned port_count() const; - bool is_sequential() const {return seq_;}; + bool is_sequential() const { return seq_; }; + char *name() { return name_; } // Return the initial output value. vvp_bit4_t get_init() const; @@ -48,6 +49,7 @@ struct vvp_udp_s { vvp_bit4_t cur_out) =0; private: + char *name_; unsigned ports_; vvp_bit4_t init_; bool seq_; @@ -112,7 +114,7 @@ extern ostream& operator<< (ostream&o, const struct udp_levels_table&t); class vvp_udp_comb_s : public vvp_udp_s { public: - vvp_udp_comb_s(char*label, char*name, unsigned ports); + vvp_udp_comb_s(char*label, char*name__, unsigned ports); ~vvp_udp_comb_s(); void compile_table(char**tab); @@ -125,8 +127,6 @@ class vvp_udp_comb_s : public vvp_udp_s { vvp_bit4_t cur_out); private: - char*name_; - // Level sensitive rows of the device. struct udp_levels_table*levels0_; struct udp_levels_table*levels1_; @@ -180,7 +180,7 @@ struct udp_edges_table { class vvp_udp_seq_s : public vvp_udp_s { public: - vvp_udp_seq_s(char*label, char*name, unsigned ports, vvp_bit4_t init); + vvp_udp_seq_s(char*label, char*name__, unsigned ports, vvp_bit4_t init); ~vvp_udp_seq_s(); void compile_table(char**tab); @@ -190,8 +190,6 @@ class vvp_udp_seq_s : public vvp_udp_s { vvp_bit4_t cur_out); private: - char*name_; - vvp_bit4_t test_levels_(const udp_levels_table&cur); // Level sensitive rows of the device. diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index a009be2fa..7a626f192 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -262,6 +262,8 @@ static const char* vpi_type_values(PLI_INT32 code) return "vpiByteVar"; case vpiConstant: return "vpiConstant"; + case vpiEnumTypespec: + return "vpiEnumTypespec"; case vpiFunction: return "vpiFunction"; case vpiIntVar: @@ -473,7 +475,7 @@ int vpip_time_precision_from_handle(vpiHandle obj) void vpi_get_time(vpiHandle obj, s_vpi_time*vp) { - int units; + int scale; vvp_time64_t time; assert(vp); @@ -487,9 +489,10 @@ void vpi_get_time(vpiHandle obj, s_vpi_time*vp) break; case vpiScaledRealTime: - units = vpip_time_units_from_handle(obj); - vp->real = pow(10.0L, vpip_get_time_precision() - units); - vp->real *= time; + scale = vpip_get_time_precision() - + vpip_time_units_from_handle(obj); + if (scale >= 0) vp->real = (double)time * pow(10.0, scale); + else vp->real = (double)time / pow(10.0, -scale); break; default: @@ -951,6 +954,7 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, if (flags!=vpiNoDelay && flags!=vpiForceFlag && flags!=vpiReleaseFlag) { vvp_time64_t dly; + int scale; if (vpi_get(vpiAutomatic, obj)) { fprintf(stderr, "vpi error: cannot put a value with " @@ -964,10 +968,13 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, switch (when->type) { case vpiScaledRealTime: - dly = (vvp_time64_t)(when->real * - (pow(10.0L, - vpip_time_units_from_handle(obj) - - vpip_get_time_precision()))); + scale = vpip_time_units_from_handle(obj) - + vpip_get_time_precision(); + if (scale >= 0) { + dly = (vvp_time64_t)(when->real * pow(10.0, scale)); + } else { + dly = (vvp_time64_t)(when->real / pow(10.0, -scale)); + } break; case vpiSimTime: dly = vpip_timestruct_to_time(when); @@ -1047,6 +1054,13 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle ref) return res; } +static vpiHandle vpip_make_udp_iterator() +{ +// HERE: Add support for iterating over UDP definitions. +// See 26.6.16 (page 400 in 1364-2005). + return 0; +} + /* * This function asks the object to return an iterator for * the specified reference. It is up to the iterate_ method to @@ -1058,6 +1072,9 @@ static vpiHandle vpi_iterate_global(int type) case vpiModule: return vpip_make_root_iterator(); + case vpiUdpDefn: + return vpip_make_udp_iterator(); + case vpiUserSystf: return vpip_make_systf_iterator(); } diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index 084cd064f..5d9d95b9e 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -90,6 +90,9 @@ static void delete_sub_scopes(struct __vpiScope *scope) case vpiRealVar: real_delete((scope->intern)[idx]); break; + case vpiEnumTypespec: + enum_delete((scope->intern)[idx]); + break; default: fprintf(stderr, "Need support for type: %d\n", scope->intern[idx]->vpi_type->type_code); diff --git a/vvp/vpi_time.cc b/vvp/vpi_time.cc index 83bd2b3e4..167fbe6d8 100644 --- a/vvp/vpi_time.cc +++ b/vvp/vpi_time.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2011 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 @@ -55,14 +55,12 @@ vvp_time64_t vpip_timestruct_to_time(const struct t_vpi_time*ts) double vpip_time_to_scaled_real(vvp_time64_t ti, struct __vpiScope*scope) { - int units; - if (scope) - units = scope->time_units; - else - units = vpi_time_precision; + double val; + int scale = 0; + if (scope) scale = vpi_time_precision - scope->time_units; - double val = pow(10.0L, vpi_time_precision - units); - val *= ti; + if (scale >= 0) val = (double)ti * pow(10.0, scale); + else val = (double)ti / pow(10.0, -scale); return val; } diff --git a/vvp/vpip_to_dec.cc b/vvp/vpip_to_dec.cc index 6b2a99bf3..3ac2650d7 100644 --- a/vvp/vpip_to_dec.cc +++ b/vvp/vpip_to_dec.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2010 Stephen Williams + * Copyright (c) 2008-2011 Stephen Williams * Copyright (c) 2002 Larry Doolittle (larry@doolittle.boa.org) * * This source code is free software; you can redistribute it @@ -121,7 +121,7 @@ unsigned vpip_vec4_to_dec_str(const vvp_vector4_t&vec4, char *buf, unsigned int nbuf, int signed_flag) { - unsigned int idx, len, vlen; + unsigned int idx, vlen; unsigned int mbits=vec4.size(); /* number of non-sign bits */ unsigned count_x = 0, count_z = 0; @@ -186,19 +186,15 @@ unsigned vpip_vec4_to_dec_str(const vvp_vector4_t&vec4, } if (count_x == vec4.size()) { - len = 1; buf[0] = 'x'; buf[1] = 0; } else if (count_x > 0) { - len = 1; buf[0] = 'X'; buf[1] = 0; } else if (count_z == vec4.size()) { - len = 1; buf[0] = 'z'; buf[1] = 0; } else if (count_z > 0) { - len = 1; buf[0] = 'Z'; buf[1] = 0; } else { diff --git a/vvp/vvp_cleanup.h b/vvp/vvp_cleanup.h index c6e895dd3..c223f46dc 100644 --- a/vvp/vvp_cleanup.h +++ b/vvp/vvp_cleanup.h @@ -1,7 +1,7 @@ #ifndef __vvp_cleanup_H #define __vvp_cleanup_H /* - * Copyright (c) 2009 Cary R. (cygcary@yahoo.com) + * Copyright (c) 2009-2011 Cary R. (cygcary@yahoo.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 @@ -43,6 +43,7 @@ extern void A_delete(struct __vpiHandle *item); extern void PV_delete(struct __vpiHandle *item); extern void constant_delete(struct __vpiHandle *item); extern void contexts_delete(struct __vpiScope *scope); +extern void enum_delete(struct __vpiHandle *item); extern void memory_delete(struct __vpiHandle *item); extern void named_event_delete(struct __vpiHandle *item); extern void parameter_delete(struct __vpiHandle *item); diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index e11504cc9..d0128940e 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -34,6 +34,7 @@ # include # include # include "sfunc.h" +# include "udp.h" # include "ivl_alloc.h" #endif @@ -85,6 +86,7 @@ void* vvp_net_t::operator new (size_t size) #ifdef CHECK_WITH_VALGRIND static map vvp_net_map; static map sfunc_map; +static map udp_map; static vvp_net_t **local_net_pool = 0; static unsigned local_net_pool_count = 0; @@ -102,6 +104,9 @@ void vvp_net_delete(vvp_net_t *item) if (sfunc_core*tmp = dynamic_cast (item->fun)) { sfunc_map[tmp] = true; } + if (vvp_udp_fun_core*tmp = dynamic_cast (item->fun)) { + udp_map[tmp] = true; + } } void vvp_net_pool_delete() @@ -128,6 +133,12 @@ void vvp_net_pool_delete() } sfunc_map.clear(); + map::iterator uiter; + for (uiter = udp_map.begin(); uiter != udp_map.end(); ++ uiter ) { + delete uiter->first; + } + udp_map.clear(); + if (RUNNING_ON_VALGRIND && (vvp_nets_del != count_vvp_nets)) { fflush(NULL); VALGRIND_PRINTF("Error: vvp missed deleting %ld of %lu net(s).",