diff --git a/compiler.h b/compiler.h index cbd0e969f..85b908b87 100644 --- a/compiler.h +++ b/compiler.h @@ -100,6 +100,9 @@ extern bool warn_sens_entire_arr; /* Warn about level-appropriate anachronisms. */ extern bool warn_anachronisms; +/* Warn about nets that are references but not driven. */ +extern bool warn_floating_nets; + /* This is true if verbose output is requested. */ extern bool verbose_flag; diff --git a/driver/main.c b/driver/main.c index 048308206..810a2de90 100644 --- a/driver/main.c +++ b/driver/main.c @@ -503,6 +503,9 @@ static void process_warning_switch(const char*name) } else if (strcmp(name,"anachronisms") == 0) { if (! strchr(warning_flags, 'n')) strcat(warning_flags, "n"); + } else if (strcmp(name,"floating-nets") == 0) { + if (! strchr(warning_flags, 'f')) + strcat(warning_flags, "f"); } else if (strcmp(name,"implicit") == 0) { if (! strchr(warning_flags, 'i')) strcat(warning_flags, "i"); @@ -532,6 +535,12 @@ static void process_warning_switch(const char*name) cp[0] = cp[1]; cp += 1; } + } else if (strcmp(name,"no-floating-nets") == 0) { + char*cp = strchr(warning_flags, 'f'); + if (cp) while (*cp) { + cp[0] = cp[1]; + cp += 1; + } } else if (strcmp(name,"no-implicit") == 0) { char*cp = strchr(warning_flags, 'i'); if (cp) while (*cp) { diff --git a/main.cc b/main.cc index 2e9dfdcfb..1b11f4f87 100644 --- a/main.cc +++ b/main.cc @@ -160,6 +160,7 @@ bool warn_ob_select = false; bool warn_sens_entire_vec = false; bool warn_sens_entire_arr = false; bool warn_anachronisms = false; +bool warn_floating_nets = false; /* * Debug message class flags. @@ -675,6 +676,9 @@ static void read_iconfig_file(const char*ipath) } else if (strcmp(buf,"warnings") == 0) { /* Scan the warnings enable string for warning flags. */ for ( ; *cp ; cp += 1) switch (*cp) { + case 'f': + warn_floating_nets = true; + break; case 'i': warn_implicit = true; break; diff --git a/nodangle.cc b/nodangle.cc index 3dcb32391..d02882a43 100644 --- a/nodangle.cc +++ b/nodangle.cc @@ -122,10 +122,61 @@ void nodangle_f::event(Design*, NetEvent*ev) } } +static bool floating_net_tested(NetNet*sig) +{ + static set tested_set; + + pair< set::iterator, bool > cur = tested_set.insert(sig); + return !cur.second; +} + +static void check_is_floating(NetNet*sig) +{ + if (sig->type() == NetNet::SUPPLY0) return; + if (sig->type() == NetNet::SUPPLY1) return; + if (sig->type() == NetNet::TRI0) return; + if (sig->type() == NetNet::TRI1) return; + if (sig->type() == NetNet::IMPLICIT_REG) return; + if (sig->type() == NetNet::REG) return ; + + if (sig->peek_lref() > 0) return; + + for (unsigned idx = 0 ; idx < sig->pin_count() ; idx += 1) { + if (sig->pin(idx).get_dir() == Link::OUTPUT) + continue; + + if (sig->pin(idx).nexus()->drivers_present()) + continue; + + if (sig->port_type() == PortType::NOT_A_PORT && sig->pin_count()==1) { + cerr << sig->get_fileline() << ": warning: " + << "Signal " << scope_path(sig->scope()) + << "." << sig->name() + << " has no drivers." << endl; + } else if (sig->port_type()==PortType::NOT_A_PORT) { + cerr << sig->get_fileline() << ": warning: " + << "Signal " << scope_path(sig->scope()) + << "." << sig->name() + << "[" << idx << "]" + << " has no drivers." << endl; + } else { + cerr << sig->get_fileline() << ": warning: " + << "Port " << sig->name() + << " of " << scope_path(sig->scope()) + << " has no drivers." << endl; + } + } + +} + void nodangle_f::signal(Design*, NetNet*sig) { if (scomplete) return; + if (warn_floating_nets && !floating_net_tested(sig)) { + check_is_floating(sig); + } + /* Cannot delete signals referenced in an expression or an l-value. */ if (sig->get_refs() > 0) diff --git a/scripts/devel-stub.conf b/scripts/devel-stub.conf index 202c7eed5..def994a22 100644 --- a/scripts/devel-stub.conf +++ b/scripts/devel-stub.conf @@ -15,7 +15,7 @@ iwidth:32 sys_func:vpi/system.sft sys_func:vpi/v2005_math.sft sys_func:vpi/va_math.sft -warnings:ailnpstv +warnings:afilnpstv debug:eval_tree debug:elaborate debug:emit