diff --git a/compiler.h b/compiler.h index a9922baf9..747e411cc 100644 --- a/compiler.h +++ b/compiler.h @@ -88,6 +88,11 @@ extern bool warn_ob_select; /* Warn about structures that may have infinite loops. */ extern bool warn_inf_loop; +/* Warn about always @* statements where a part or word select causes + sensitivity to an entire vector or array. */ +extern bool warn_sens_entire_vec; +extern bool warn_sens_entire_arr; + /* This is true if verbose output is requested. */ extern bool verbose_flag; diff --git a/driver/iverilog.man b/driver/iverilog.man index c81d463eb..ca2c00951 100644 --- a/driver/iverilog.man +++ b/driver/iverilog.man @@ -259,8 +259,8 @@ after a \fB-Wall\fP argument to suppress isolated warning types. .TP 8 .B all -This enables the implicit, portbind, select-range and timescale warning -categories. +This enables the implicit, portbind, select-range, timescale, and +sensitivity-entire-array warning categories. .TP 8 .B implicit @@ -303,6 +303,22 @@ verified. It is expected that many of the warnings will be false positives, since the code treats the value of all variables and signals as indeterminate. +.TP 8 +.B sensitivity-entire-vector +This enables warnings for when a part select within an "always @*" +statement results in the entire vector being added to the implicit +sensitivity list. Although this behaviour is prescribed by the IEEE +standard, it is not what might be expected and can have performance +implications if the vector is large. + +.TP 8 +.B sensitivity-entire-array +This enables warnings for when a word select within an "always @*" +statement results in the entire array being added to the implicit +sensitivity list. Although this behaviour is prescribed by the IEEE +standard, it is not what might be expected and can have performance +implications if the array is large. + .SH "SYSTEM FUNCTION TABLE FILES" If the source file name as a \fB.sft\fP suffix, then it is taken to be a system function table file. A System function table file is used to diff --git a/driver/main.c b/driver/main.c index c75eb09c2..a56ca6ef0 100644 --- a/driver/main.c +++ b/driver/main.c @@ -477,6 +477,7 @@ static void process_warning_switch(const char*name) process_warning_switch("portbind"); process_warning_switch("select-range"); process_warning_switch("timescale"); + process_warning_switch("sensitivity-entire-array"); } else if (strcmp(name,"implicit") == 0) { if (! strchr(warning_flags, 'i')) strcat(warning_flags, "i"); @@ -494,6 +495,12 @@ static void process_warning_switch(const char*name) } else if (strcmp(name,"infloop") == 0) { if (! strchr(warning_flags, 'l')) strcat(warning_flags, "l"); + } else if (strcmp(name,"sensitivity-entire-vector") == 0) { + if (! strchr(warning_flags, 'v')) + strcat(warning_flags, "v"); + } else if (strcmp(name,"sensitivity-entire-array") == 0) { + if (! strchr(warning_flags, 'a')) + strcat(warning_flags, "a"); } else if (strcmp(name,"no-implicit") == 0) { char*cp = strchr(warning_flags, 'i'); if (cp) while (*cp) { @@ -518,6 +525,18 @@ static void process_warning_switch(const char*name) cp[0] = cp[1]; cp += 1; } + } else if (strcmp(name,"no-sensitivity-entire-vector") == 0) { + char*cp = strchr(warning_flags, 'v'); + if (cp) while (*cp) { + cp[0] = cp[1]; + cp += 1; + } + } else if (strcmp(name,"no-sensitivity-entire-array") == 0) { + char*cp = strchr(warning_flags, 'a'); + if (cp) while (*cp) { + cp[0] = cp[1]; + cp += 1; + } } } diff --git a/elab_expr.cc b/elab_expr.cc index 261539812..89698a49a 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1488,6 +1488,12 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, def->port(idx)->data_type(), def->port(idx)->vector_width(), tmp); + if (NetEEvent*evt = dynamic_cast (parms[idx])) { + cerr << evt->get_fileline() << ": error: An event '" + << evt->event()->name() << "' can not be a user " + "function argument." << endl; + des->errors += 1; + } if (debug_elaborate) cerr << get_fileline() << ": debug:" << " function " << path_ diff --git a/elaborate.cc b/elaborate.cc index 1ef37368a..ba18d812e 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2644,6 +2644,13 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const ivl_variable_type_t lv_type = lv->expr_type(); NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_[idx]); + if (NetEEvent*evt = dynamic_cast (rv)) { + cerr << evt->get_fileline() << ": error: An event '" + << evt->event()->name() << "' can not be a user " + "task argument." << endl; + des->errors += 1; + continue; + } if (wid > rv->expr_width()) { rv->set_width(wid); rv = pad_to_width(rv, wid, *this); diff --git a/expr_synth.cc b/expr_synth.cc index 6e4a7f842..444c00bb3 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -1369,6 +1369,10 @@ NetNet* NetEUFunc::synthesize(Design*des, NetScope*scope, NetExpr*root) /* Synthesize the arguments. */ bool errors = false; for (unsigned idx = 0; idx < eparms.count(); idx += 1) { + if (dynamic_cast (parms_[idx])) { + errors = true; + continue; + } NetNet*tmp = parms_[idx]->synthesize(des, scope, root); if (tmp == 0) { cerr << get_fileline() << ": error: Unable to synthesize " diff --git a/libveriuser/getp.c b/libveriuser/getp.c index 5e074bdd8..9d832e4a4 100644 --- a/libveriuser/getp.c +++ b/libveriuser/getp.c @@ -53,6 +53,8 @@ PLI_INT32 tf_igetp(PLI_INT32 n, void *obj) { value.format = vpiStringVal; vpi_get_value(arg_h, &value); + /* The following may generate a compilation warning, but this + * functionality is required by some versions of the standard. */ rtn = (int) value.value.str; /* Oh my */ } else { value.format = vpiIntVal; diff --git a/main.cc b/main.cc index 9a389708f..e0acd91e1 100644 --- a/main.cc +++ b/main.cc @@ -116,6 +116,8 @@ bool warn_timescale = false; bool warn_portbinding = false; bool warn_inf_loop = false; bool warn_ob_select = false; +bool warn_sens_entire_vec = false; +bool warn_sens_entire_arr = false; bool error_implicit = false; @@ -501,6 +503,12 @@ static void read_iconfig_file(const char*ipath) case 't': warn_timescale = true; break; + case 'v': + warn_sens_entire_vec = true; + break; + case 'a': + warn_sens_entire_arr = true; + break; default: break; } diff --git a/net_nex_input.cc b/net_nex_input.cc index a1f81829c..2da521912 100644 --- a/net_nex_input.cc +++ b/net_nex_input.cc @@ -23,6 +23,7 @@ # include # include +# include "compiler.h" # include "netlist.h" # include "netmisc.h" @@ -115,7 +116,7 @@ NexusSet* NetESelect::nex_input(bool rem_out) result->add(*tmp); delete tmp; /* See the comment for NetESignal below. */ - if (base_) { + if (base_ && warn_sens_entire_vec) { cerr << get_fileline() << ": warning: @* is sensitive to all " "bits in '" << *expr_ << "'." << endl; } @@ -151,9 +152,11 @@ NexusSet* NetESignal::nex_input(bool rem_out) tmp = word_->nex_input(rem_out); result->add(*tmp); delete tmp; - cerr << get_fileline() << ": warning: @* is sensitive to all " - << net_->array_count() << " words in array '" - << name() << "'." << endl; + if (warn_sens_entire_arr) { + cerr << get_fileline() << ": warning: @* is sensitive to all " + << net_->array_count() << " words in array '" + << name() << "'." << endl; + } } for (unsigned idx = 0 ; idx < net_->pin_count() ; idx += 1) result->add(net_->pin(idx).nexus()); diff --git a/t-dll-expr.cc b/t-dll-expr.cc index e4dcbf289..e67caca11 100644 --- a/t-dll-expr.cc +++ b/t-dll-expr.cc @@ -308,6 +308,7 @@ void dll_target::expr_event(const NetEEvent*net) assert(expr_); expr_->type_ = IVL_EX_EVENT; + FILE_NAME(expr_, net); expr_->value_= IVL_VT_VOID; /* Locate the event by name. Save the ivl_event_t in the diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index 0858e672c..2695f56db 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -217,7 +217,7 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result, (ivl_expr_width(bexpr) < 8*sizeof(int))) { fprintf(stderr, "%s:%u: tgt-vvp warning: V0.9 may give " "incorrect results for a select with a " - "signed index less than %d bits.\n", + "signed index less than %zu bits.\n", ivl_expr_file(expr), ivl_expr_lineno(expr), 8*sizeof(int)); diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index a41ba97f9..ebe9bb03f 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -2983,6 +2983,12 @@ struct vector_info draw_eval_expr_wid(ivl_expr_t exp, unsigned wid, res.base = 0; res.wid = 0; break; + case IVL_EX_EVENT: + fprintf(stderr, "%s:%u: vvp-tgt error: A named event is not " + "handled in this context (expression).\n", + ivl_expr_file(exp), ivl_expr_lineno(exp)); + exit(1); + break; case IVL_EX_STRING: res = draw_string_expr(exp, wid); diff --git a/vpi/sys_fileio.c b/vpi/sys_fileio.c index 2fccdd49e..9961d95b6 100644 --- a/vpi/sys_fileio.c +++ b/vpi/sys_fileio.c @@ -214,7 +214,6 @@ static PLI_INT32 sys_fclose_calltf(PLI_BYTE8*name) vpiHandle fd = vpi_scan(argv); s_vpi_value val; PLI_UINT32 fd_mcd; - char *str = ""; /* This prevents the compiler from complaining. */ errno = 0; vpi_free_object(argv); @@ -225,7 +224,7 @@ static PLI_INT32 sys_fclose_calltf(PLI_BYTE8*name) fd_mcd = val.value.integer; if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) || - ( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, str) == EOF) || + ( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, "%s", "") == EOF) || (! fd_mcd)) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -254,7 +253,6 @@ static PLI_INT32 sys_fflush_calltf(PLI_BYTE8*name) s_vpi_value val; PLI_UINT32 fd_mcd; FILE *fp; - char *str = ""; /* This prevents the compiler from complaining. */ errno = 0; /* If we have no argument then flush all the streams. */ @@ -274,7 +272,7 @@ static PLI_INT32 sys_fflush_calltf(PLI_BYTE8*name) if (fd_mcd == 0) return 0; if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) || - ( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, str) == EOF) || + ( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, "%s", "") == EOF) || (! fd_mcd)) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); diff --git a/vvp/array.cc b/vvp/array.cc index 2a812f57e..993a4744a 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -31,6 +31,7 @@ #endif # include # include +# include # include # include "compile.h" # include @@ -133,6 +134,15 @@ struct __vpiArrayVthrA { { if (address_handle) { s_vpi_value vp; + /* Check to see if the value is defined. */ + vp.format = vpiVectorVal; + vpi_get_value(address_handle, &vp); + int words = (vpi_get(vpiSize, address_handle)-1)/32 + 1; + for(int idx = 0; idx < words; idx += 1) { + /* Return UINT_MAX to indicate an X base. */ + if (vp.value.vector[idx].bval != 0) return UINT_MAX; + } + /* The value is defined so get and return it. */ vp.format = vpiIntVal; vpi_get_value(address_handle, &vp); return vp.value.integer; @@ -146,7 +156,7 @@ struct __vpiArrayVthrA { vvp_bit4_t bit = vthread_get_bit(vpip_current_vthread, address+idx); tmp.set_bit(idx, bit); } - unsigned long val; + unsigned long val = ULONG_MAX; vector4_to_value(tmp, val); return val; } diff --git a/vvp/part.cc b/vvp/part.cc index 9070779c7..f9e98eced 100644 --- a/vvp/part.cc +++ b/vvp/part.cc @@ -238,7 +238,7 @@ vvp_fun_part_var::~vvp_fun_part_var() } bool vvp_fun_part_var::recv_vec4_(vvp_net_ptr_t port, const vvp_vector4_t&bit, - long&base, vvp_vector4_t&source, + int&base, vvp_vector4_t&source, vvp_vector4_t&ref) { long tmp; @@ -247,12 +247,13 @@ bool vvp_fun_part_var::recv_vec4_(vvp_net_ptr_t port, const vvp_vector4_t&bit, source = bit; break; case 1: - // LONG_MIN is before the vector and is used to + // INT_MIN is before the vector and is used to // represent a 'bx value on the select input. - tmp = LONG_MIN; - // We need a new &PV<> that knows if the index is signed. + tmp = INT_MIN; + // We need a new .part/v that knows if the index is signed. + // For now this will work for a normal integer value. vector4_to_value(bit, tmp, false); - if (tmp == base) return false; + if ((int)tmp == base) return false; base = tmp; break; default: @@ -264,7 +265,7 @@ bool vvp_fun_part_var::recv_vec4_(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_vector4_t res (wid_); for (unsigned idx = 0 ; idx < wid_ ; idx += 1) { - long adr = base+idx; + int adr = base+idx; if (adr < 0) continue; if ((unsigned)adr >= source.size()) break; @@ -313,7 +314,7 @@ void vvp_fun_part_var_sa::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&b struct vvp_fun_part_var_state_s { vvp_fun_part_var_state_s() : base(0) { } - long base; + int base; vvp_vector4_t source; vvp_vector4_t ref; }; diff --git a/vvp/part.h b/vvp/part.h index f42dc6cd3..09f32093c 100644 --- a/vvp/part.h +++ b/vvp/part.h @@ -130,7 +130,7 @@ class vvp_fun_part_var : public vvp_net_fun_t { protected: bool recv_vec4_(vvp_net_ptr_t port, const vvp_vector4_t&bit, - long&base, vvp_vector4_t&source, + int&base, vvp_vector4_t&source, vvp_vector4_t&ref); unsigned wid_; @@ -154,7 +154,7 @@ class vvp_fun_part_var_sa : public vvp_fun_part_var { vvp_context_t); private: - long base_; + int base_; vvp_vector4_t source_; // Save the last output, for detecting change. vvp_vector4_t ref_; diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 6ee5bfb2c..5e15ba436 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -139,8 +139,8 @@ static void format_vpiBinStrVal(vvp_signal_value*sig, int base, unsigned wid, s_vpi_value*vp) { char *rbuf = need_result_buf(wid+1, RBUF_VAL); - long offset = wid - 1 + base; long end = base + (signed)wid; + long offset = end - 1; long ssize = (signed)sig->value_size(); for (long idx = base ; idx < end ; idx += 1) { @@ -993,6 +993,15 @@ static int PV_get_base(struct __vpiPV*rfp) /* We return from the symbol base if it is defined. */ if (rfp->sbase != 0) { s_vpi_value val; + /* Check to see if the value is defined. */ + val.format = vpiVectorVal; + vpi_get_value(rfp->sbase, &val); + int words = (vpi_get(vpiSize, rfp->sbase)-1)/32 + 1; + for(int idx = 0; idx < words; idx += 1) { + /* Return INT_MIN to indicate an X base. */ + if (val.value.vector[idx].bval != 0) return INT_MIN; + } + /* The value is defined so get and return it. */ val.format = vpiIntVal; vpi_get_value(rfp->sbase, &val); return val.value.integer; diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index f779ecddd..159b5f390 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -1300,8 +1300,8 @@ vvp_vector4_t& vvp_vector4_t::operator |= (const vvp_vector4_t&that) if (size_ <= BITS_PER_WORD) { unsigned long tmp = abits_val_ | bbits_val_ | that.abits_val_ | that.bbits_val_; - bbits_val_ = (~abits_val_ | bbits_val_) & that.bbits_val_ | - (~that.abits_val_ | that.bbits_val_) & bbits_val_; + bbits_val_ = ((~abits_val_ | bbits_val_) & that.bbits_val_) | + ((~that.abits_val_ | that.bbits_val_) & bbits_val_); abits_val_ = tmp; } else { @@ -1309,10 +1309,10 @@ vvp_vector4_t& vvp_vector4_t::operator |= (const vvp_vector4_t&that) for (unsigned idx = 0; idx < words ; idx += 1) { unsigned long tmp = abits_ptr_[idx] | bbits_ptr_[idx] | that.abits_ptr_[idx] | that.bbits_ptr_[idx]; - bbits_ptr_[idx] = (~abits_ptr_[idx] | bbits_ptr_[idx]) & - that.bbits_ptr_[idx] | - (~that.abits_ptr_[idx] | - that.bbits_ptr_[idx]) & bbits_ptr_[idx]; + bbits_ptr_[idx] = ((~abits_ptr_[idx] | bbits_ptr_[idx]) & + that.bbits_ptr_[idx]) | + ((~that.abits_ptr_[idx] | + that.bbits_ptr_[idx]) & bbits_ptr_[idx]); abits_ptr_[idx] = tmp; } }