diff --git a/cprop.cc b/cprop.cc index 61cf8b554..f05d467f5 100644 --- a/cprop.cc +++ b/cprop.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2010,2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -163,11 +163,6 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj) if (! sel_nex->drivers_constant()) return; - // If the select input is assigned or forced, then again there - // is nothing we can do here. - if (sel_nex->assign_lval()) - return; - // If the constant select is 'bz or 'bx, then give up. verinum::V sel_val = sel_nex->driven_value(); if (sel_val == verinum::Vz || sel_val == verinum::Vx) diff --git a/link_const.cc b/link_const.cc index 867e71b92..9b01c75b3 100644 --- a/link_const.cc +++ b/link_const.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -25,8 +25,7 @@ /* * Scan the link for drivers. If there are only constant drivers, then - * the nexus has a known constant value. If there is a supply net, - * then the nexus again has a known constant value. + * the nexus has a known constant value. */ bool Nexus::drivers_constant() const { @@ -35,15 +34,23 @@ bool Nexus::drivers_constant() const if (driven_ != NO_GUESS) return true; + unsigned constant_drivers = 0; for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) { - Link::DIR cur_dir; - cur_dir = cur->get_dir(); + /* A target of a procedural assign or force statement + can't be treated as constant. */ + const NetNet*sig = dynamic_cast(cur->get_obj()); + if (sig && (sig->peek_lref() > 0)) { + driven_ = VAR; + return false; + } + + Link::DIR cur_dir = cur->get_dir(); if (cur_dir == Link::INPUT) continue; /* If this is an input or inout port of a root module, - then the is probably not a constant value. I + then this is probably not a constant value. I certainly don't know what the value is, anyhow. This can happen in cases like this: @@ -56,16 +63,9 @@ bool Nexus::drivers_constant() const outside world. */ if (cur_dir == Link::PASSIVE) { - const NetNet*sig; - - const NetPins*obj = cur->get_obj(); - const NetObj*as_obj = dynamic_cast(obj); - if (as_obj == 0 || as_obj->scope()->parent() != 0) + if (sig == 0 || sig->scope()->parent() != 0) continue; - sig = dynamic_cast(cur->get_obj()); - assert(sig); - if (sig->port_type() == NetNet::NOT_A_PORT) continue; @@ -74,19 +74,22 @@ bool Nexus::drivers_constant() const driven_ = VAR; return false; - } - /* If there is a supply net, then this nexus will have a - constant value independent of any drivers. */ - if (const NetNet*s = dynamic_cast(cur->get_obj())) - switch (s->type()) { + /* If there is an implicit pullup/pulldown on a net, + count it as a constant driver. */ + if (sig) + switch (sig->type()) { case NetNet::SUPPLY0: + case NetNet::TRI0: + constant_drivers += 1; driven_ = V0; - return true; + continue; case NetNet::SUPPLY1: + case NetNet::TRI1: + constant_drivers += 1; driven_ = V1; - return true; + continue; default: break; } @@ -95,6 +98,18 @@ bool Nexus::drivers_constant() const driven_ = VAR; return false; } + + constant_drivers += 1; + } + + /* If there is more than one constant driver for this nexus, we + would need to resolve the constant value, taking into account + the drive strengths. This is a lot of work for something that + will rarely occur, so for now leave the resolution to be done + at run time. */ + if (constant_drivers > 1) { + driven_ = VAR; + return false; } return true; @@ -127,28 +142,25 @@ verinum::V Nexus::driven_value() const const NetConst*obj; const NetNet*sig; if ((obj = dynamic_cast(cur->get_obj()))) { + // Multiple drivers are not currently supported. + ivl_assert(*obj, val == verinum::Vz); val = obj->value(cur->get_pin()); } else if ((sig = dynamic_cast(cur->get_obj()))) { - // If we find an attached SUPPLY0/1, the we know - // from that what the driven value is. Stop now. - if (sig->type() == NetNet::SUPPLY0) { - driven_ = V0; - return verinum::V0; - } - if (sig->type() == NetNet::SUPPLY1) { - driven_ = V1; - return verinum::V1; - } - - // If we find an attached TRI0/1, then this is a - // good guess for the driven value, but keep - // looking for something better. - if (sig->type() == NetNet::TRI0) { + // If we find an implicit pullup or pulldown on a + // net, this is a good guess for the driven value, + // but keep looking for other drivers. + if ((sig->type() == NetNet::SUPPLY0) || + (sig->type() == NetNet::TRI0)) { + // Multiple drivers are not currently supported. + ivl_assert(*obj, val == verinum::Vz); val = verinum::V0; } - if (sig->type() == NetNet::TRI1) { + if ((sig->type() == NetNet::SUPPLY1) || + (sig->type() == NetNet::TRI1)) { + // Multiple drivers are not currently supported. + ivl_assert(*obj, val == verinum::Vz); val = verinum::V1; } } @@ -179,40 +191,44 @@ verinum Nexus::driven_vector() const const Link*cur = list_; verinum val; + unsigned width = 0; for (cur = first_nlink() ; cur ; cur = cur->next_nlink()) { const NetConst*obj; const NetNet*sig; if ((obj = dynamic_cast(cur->get_obj()))) { + // Multiple drivers are not currently supported. + ivl_assert(*obj, val.len() == 0); ivl_assert(*obj, cur->get_pin() == 0); val = obj->value(); + width = val.len(); } else if ((sig = dynamic_cast(cur->get_obj()))) { - // If we find an attached SUPPLY0/1, the we know - // from that what the driven value is. Stop now. - if (sig->type() == NetNet::SUPPLY0) { - driven_ = V0; - return verinum(verinum::V0, sig->vector_width()); - } - if (sig->type() == NetNet::SUPPLY1) { - driven_ = V1; - return verinum(verinum::V1, sig->vector_width()); - } + width = sig->vector_width(); - // If we find an attached TRI0/1, then this is a - // good guess for the driven value, but keep - // looking for something better. - if (sig->type() == NetNet::TRI0) { - val = verinum(verinum::V0, sig->vector_width()); + // If we find an implicit pullup or pulldown on a + // net, this is a good guess for the driven value, + // but keep looking for other drivers. + if ((sig->type() == NetNet::SUPPLY0) || + (sig->type() == NetNet::TRI0)) { + // Multiple drivers are not currently supported. + ivl_assert(*obj, val.len() == 0); + val = verinum(verinum::V0, width); } - if (sig->type() == NetNet::TRI1) { - val = verinum(verinum::V1, sig->vector_width()); + if ((sig->type() == NetNet::SUPPLY1) || + (sig->type() == NetNet::TRI1)) { + // Multiple drivers are not currently supported. + ivl_assert(*obj, val.len() == 0); + val = verinum(verinum::V1, width); } } } + // If we have a width but not a value, this must be an undriven net. + if (val.len() != width) + val = verinum(verinum::Vz, width); + return val; } - diff --git a/net_link.cc b/net_link.cc index 1883e261e..20e18809f 100644 --- a/net_link.cc +++ b/net_link.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -311,16 +311,13 @@ bool Nexus::drivers_present() const continue; // Must be PASSIVE, so if it is some kind of net, see if - // it is the sort that might drive the nexus. + // it is the sort that might drive the nexus. Note that + // supply0/1 and tri0/1 nets are classified as OUTPUT. const NetPins*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: diff --git a/netlist.cc b/netlist.cc index 6bbd88241..bc59461e7 100644 --- a/netlist.cc +++ b/netlist.cc @@ -479,8 +479,23 @@ PortType::Enum PortType::merged( Enum lhs, Enum rhs ) return PINOUT; } -void NetNet::initialize_dir_(Link::DIR dir) +void NetNet::initialize_dir_() { + Link::DIR dir = Link::PASSIVE; + + switch (type_) { + case REG: + case IMPLICIT_REG: + case SUPPLY0: + case SUPPLY1: + case TRI0: + case TRI1: + dir = Link::OUTPUT; + break; + default: + break; + } + if (pins_are_virtual()) { if (0) cerr << "NetNet setting Link default dir" << endl; set_default_dir(dir); @@ -564,24 +579,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, ivl_assert(*this, 0); } - Link::DIR dir = Link::PASSIVE; - - switch (t) { - case REG: - case IMPLICIT_REG: - dir = Link::OUTPUT; - break; - case SUPPLY0: - dir = Link::OUTPUT; - break; - case SUPPLY1: - dir = Link::OUTPUT; - break; - default: - break; - } - - initialize_dir_(dir); + initialize_dir_(); s->add_signal(this); } @@ -600,24 +598,8 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty) { //XXXX packed_dims_.push_back(netrange_t(calculate_count(ty)-1, 0)); calculate_slice_widths_from_packed_dims_(); - Link::DIR dir = Link::PASSIVE; - switch (t) { - case REG: - case IMPLICIT_REG: - dir = Link::OUTPUT; - break; - case SUPPLY0: - dir = Link::OUTPUT; - break; - case SUPPLY1: - dir = Link::OUTPUT; - break; - default: - break; - } - - initialize_dir_(dir); + initialize_dir_(); s->add_signal(this); } @@ -629,24 +611,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, netdarray_t*ty) discipline_(0), eref_count_(0), lref_count_(0) { - Link::DIR dir = Link::PASSIVE; - - switch (t) { - case REG: - case IMPLICIT_REG: - dir = Link::OUTPUT; - break; - case SUPPLY0: - dir = Link::OUTPUT; - break; - case SUPPLY1: - dir = Link::OUTPUT; - break; - default: - break; - } - - initialize_dir_(dir); + initialize_dir_(); s->add_signal(this); } @@ -659,24 +624,8 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, netvector_t*ty) eref_count_(0), lref_count_(0) { calculate_slice_widths_from_packed_dims_(); - Link::DIR dir = Link::PASSIVE; - switch (t) { - case REG: - case IMPLICIT_REG: - dir = Link::OUTPUT; - break; - case SUPPLY0: - dir = Link::OUTPUT; - break; - case SUPPLY1: - dir = Link::OUTPUT; - break; - default: - break; - } - - initialize_dir_(dir); + initialize_dir_(); s->add_signal(this); } @@ -712,27 +661,9 @@ void NetNet::type(NetNet::Type t) if (type_ == t) return; - Link::DIR dir = Link::PASSIVE; - switch (t) { - case REG: - case IMPLICIT_REG: - dir = Link::OUTPUT; - break; - case SUPPLY0: - dir = Link::OUTPUT; - break; - case SUPPLY1: - dir = Link::OUTPUT; - break; - default: - break; - } - type_ = t; - for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { - pin(idx).set_dir(dir); - } + initialize_dir_(); } diff --git a/netlist.h b/netlist.h index b1d99b849..b176b12b9 100644 --- a/netlist.h +++ b/netlist.h @@ -581,9 +581,10 @@ class NetDelaySrc : public NetObj { * * NetNet objects are located by searching NetScope objects. * - * The pins of a NetNet object are PASSIVE: they do not drive + * The pins of a NetNet object are usually PASSIVE: they do not drive * anything and they are not a data sink, per se. The pins follow the - * values on the nexus. + * values on the nexus. The exceptions are reg, trireg, tri0, tri1, + * supply0, and supply1 objects, whose pins are classed as OUTPUT. */ class PortType @@ -746,7 +747,7 @@ class NetNet : public NetObj, public PortType { virtual void dump_net(ostream&, unsigned) const; private: - void initialize_dir_(Link::DIR dir); + void initialize_dir_(); private: Type type_ : 5;