diff --git a/elaborate.cc b/elaborate.cc index f22e38f00..ad7c273ab 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -944,6 +944,17 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope, return tmp; } +static bool need_bufz_for_input_port(const svector&prts) +{ + if (prts[0]->port_type() != NetNet::PINPUT) + return false; + + if (prts[0]->pin(0).nexus()->drivers_present()) + return true; + + return false; +} + /* * Instantiate a module by recursively elaborating it. Set the path of * the recursive elaboration so that signal names get properly @@ -1162,7 +1173,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const width. We use that, then, to decide how to hook it up. - NOTE that this also handles the case that the +v NOTE that this also handles the case that the port is actually empty on the inside. We assume in that case that the port is input. */ @@ -1176,6 +1187,21 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const continue; } + if (need_bufz_for_input_port(prts)) { + NetBUFZ*tmp = new NetBUFZ(scope, scope->local_symbol(), + sig->vector_width()); + des->add_node(tmp); + connect(tmp->pin(1), sig->pin(0)); + + NetNet*tmp2 = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, sig->vector_width()); + tmp2->local_flag(true); + tmp2->set_line(*this); + tmp2->data_type(sig->data_type()); + connect(tmp->pin(0), tmp2->pin(0)); + sig = tmp2; + } + } else if (prts[0]->port_type() == NetNet::PINOUT) { /* Inout to/from module. This is a more diff --git a/net_link.cc b/net_link.cc index 228add8c0..5b2621b90 100644 --- a/net_link.cc +++ b/net_link.cc @@ -247,6 +247,41 @@ verinum::V Nexus::get_init() const return verinum::Vz; } +bool Nexus::drivers_present() const +{ + assert(list_); + for (Link*cur = list_ ; cur ; cur = cur->next_) { + if (cur->get_dir() == Link::OUTPUT) + return true; + + if (cur->get_dir() == Link::INPUT) + continue; + + // Must be PASSIVE, so if it is some kind of net, see if + // it is the sort that might drive the nexus. + const NetObj*obj; + unsigned pin; + cur->cur_link(obj, pin); + if (const NetNet*net = dynamic_cast(obj)) + switch (net->type()) { + case NetNet::SUPPLY0: + case NetNet::SUPPLY1: + case NetNet::TRI0: + case NetNet::TRI1: + case NetNet::WAND: + case NetNet::WOR: + case NetNet::TRIAND: + case NetNet::TRIOR: + case NetNet::REG: + return true; + default: + break; + } + } + + return false; +} + void Nexus::drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay) { for (Link*cur = list_ ; cur ; cur = cur->next_) { diff --git a/netlist.h b/netlist.h index d6e01bab2..7818938e8 100644 --- a/netlist.h +++ b/netlist.h @@ -290,6 +290,10 @@ class Nexus { NetNet* pick_any_net(); + /* This method returns true if there are any drivers + (including variables) attached to this nexus. */ + bool drivers_present() const; + /* This method returns true if all the possible drivers of this nexus are constant. It will also return true if there are no drivers at all. */