From 893aae2ca44b30a11cf178ceef6036bb442b3e44 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 6 Aug 2008 21:04:52 -0700 Subject: [PATCH] Add BUFZ to input ports when necessary. When driving an input port to a module, watch out for the case where the net is also driven within the instance. If this is the case, take pains to make sure what goes on in the instance doesn't leak out through the input port. Add a BUFZ (continuous assignment) to isolate the context from internal driving. --- elaborate.cc | 28 +++++++++++++++++++++++++++- net_link.cc | 35 +++++++++++++++++++++++++++++++++++ netlist.h | 4 ++++ 3 files changed, 66 insertions(+), 1 deletion(-) 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. */