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.
This commit is contained in:
Stephen Williams 2008-08-06 21:04:52 -07:00
parent d84771428a
commit 893aae2ca4
3 changed files with 66 additions and 1 deletions

View File

@ -944,6 +944,17 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
return tmp; return tmp;
} }
static bool need_bufz_for_input_port(const svector<NetNet*>&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 * Instantiate a module by recursively elaborating it. Set the path of
* the recursive elaboration so that signal names get properly * 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 width. We use that, then, to decide how to hook
it up. 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 port is actually empty on the inside. We assume
in that case that the port is input. */ in that case that the port is input. */
@ -1176,6 +1187,21 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
continue; 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) { } else if (prts[0]->port_type() == NetNet::PINOUT) {
/* Inout to/from module. This is a more /* Inout to/from module. This is a more

View File

@ -247,6 +247,41 @@ verinum::V Nexus::get_init() const
return verinum::Vz; 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<const NetNet*>(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) void Nexus::drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay)
{ {
for (Link*cur = list_ ; cur ; cur = cur->next_) { for (Link*cur = list_ ; cur ; cur = cur->next_) {

View File

@ -290,6 +290,10 @@ class Nexus {
NetNet* pick_any_net(); 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 method returns true if all the possible drivers of
this nexus are constant. It will also return true if there this nexus are constant. It will also return true if there
are no drivers at all. */ are no drivers at all. */