Fix overly agressive constant propagation through MUX causing lost Z bits.

This commit is contained in:
steve 2005-09-11 02:50:51 +00:00
parent 393102d43a
commit d97560caa7
1 changed files with 117 additions and 175 deletions

292
cprop.cc
View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#ifdef HAVE_CVS_IDENT #ifdef HAVE_CVS_IDENT
#ident "$Id: cprop.cc,v 1.47.2.3 2005/08/28 22:00:39 steve Exp $" #ident "$Id: cprop.cc,v 1.47.2.4 2005/09/11 02:50:51 steve Exp $"
#endif #endif
# include "config.h" # include "config.h"
@ -861,11 +861,34 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj)
bool flag = true; bool flag = true;
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) { for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
if (obj->pin_Data(idx, 0).nexus()->drivers_constant()) bool cflag_a = obj->pin_Data(idx, 0).nexus()->drivers_constant();
continue; bool cflag_b = obj->pin_Data(idx, 1).nexus()->drivers_constant();
if (obj->pin_Data(idx, 1).nexus()->drivers_constant())
/* If both data inputs are constant, we'll be able to do
a substitution. */
if (cflag_a && cflag_b)
continue; continue;
verinum::V va = cflag_a
? obj->pin_Data(idx, 0).nexus()->driven_value()
: verinum::Vx;
verinum::V vb = cflag_b
? obj->pin_Data(idx, 1).nexus()->driven_value()
: verinum::Vx;
/* If only one Data input is constant, but a constant
HiZ, then we will be able to to a bufif
substitution. */
if (cflag_a && va==verinum::Vz)
continue;
if (cflag_b && vb==verinum::Vz)
continue;
/* Otherwise, we cannot accurately do a substitution. If
one input is non-constant, then that input may have a
HiZ value, and there is no Verilog logic other then a
MUX that can pass a HiZ value. */
flag = false; flag = false;
} }
@ -907,192 +930,107 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj)
continue; continue;
} }
/* If both inputs are constant, then derive the output /* At this point, the only cases that are left are where
from the sel input. */ the data inputs are both constant, and neither are
if (obj->pin_Data(idx, 0).nexus()->drivers_constant() HiZ. From this we know how to generate the output
&& obj->pin_Data(idx, 1).nexus()->drivers_constant()) { from only the S input. */
assert(obj->pin_Data(idx, 0).nexus()->drivers_constant()
&& obj->pin_Data(idx, 1).nexus()->drivers_constant());
verinum::V a = obj->pin_Data(idx, 0).nexus()->driven_value();
verinum::V b = obj->pin_Data(idx, 1).nexus()->driven_value();
if (a == b) { verinum::V a = obj->pin_Data(idx, 0).nexus()->driven_value();
connect(obj->pin_Result(idx), obj->pin_Data(idx,0)); verinum::V b = obj->pin_Data(idx, 1).nexus()->driven_value();
continue;
}
if (a == verinum::V0 && b == verinum::V1) { if (a == b) {
connect(obj->pin_Result(idx), obj->pin_Sel(0)); connect(obj->pin_Result(idx), obj->pin_Data(idx,0));
continue;
}
if (a == verinum::V1 && b == verinum::V0) {
NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
2, NetLogic::NOT);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Sel(0), tmp->pin(1));
des->add_node(tmp);
continue;
}
/* A==0: Q = B & S */
if (a == verinum::V0) {
NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
3, NetLogic::AND);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,1), tmp->pin(1));
connect(obj->pin_Sel(0), tmp->pin(2));
des->add_node(tmp);
continue;
}
/* B==1: Q = A | S */
if (b == verinum::V1) {
NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
3, NetLogic::OR);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,0), tmp->pin(1));
connect(obj->pin_Sel(0), tmp->pin(2));
des->add_node(tmp);
continue;
}
/* A==1: Q = B | ~S */
if (a == verinum::V1) {
NetLogic*inv = new NetLogic(scope,
scope->local_symbol(),
2, NetLogic::NOT);
NetNet*invs = new NetNet(scope,
scope->local_symbol(),
NetNet::TRI, 1);
invs->local_flag(true);
connect(inv->pin(0), invs->pin(0));
connect(inv->pin(1), obj->pin_Sel(0));
des->add_node(inv);
NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
3, NetLogic::OR);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,1), tmp->pin(1));
connect(inv->pin(0), tmp->pin(2));
des->add_node(tmp);
continue;
}
/* B==0: Q = A & ~S */
if (b == verinum::V0) {
NetLogic*inv = new NetLogic(scope,
scope->local_symbol(),
2, NetLogic::NOT);
NetNet*invs = new NetNet(scope,
scope->local_symbol(),
NetNet::TRI, 1);
invs->local_flag(true);
connect(inv->pin(0), invs->pin(0));
connect(inv->pin(1), obj->pin_Sel(0));
des->add_node(inv);
NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
3, NetLogic::AND);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,0), tmp->pin(1));
connect(inv->pin(0), tmp->pin(2));
des->add_node(tmp);
continue;
}
assert(0);
continue; continue;
} }
/* Only the Sel==0 input is constant. The output is a if (a == verinum::V0 && b == verinum::V1) {
logical combination of the S and B inputs. */ connect(obj->pin_Result(idx), obj->pin_Sel(0));
continue;
if (obj->pin_Data(idx, 0).nexus()->drivers_constant()) {
verinum::V a = obj->pin_Data(idx, 0).nexus()->driven_value();
/* A==0: Q = B & S */
if (a == verinum::V0) {
NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
3, NetLogic::AND);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,1), tmp->pin(1));
connect(obj->pin_Sel(0), tmp->pin(2));
des->add_node(tmp);
continue;
}
/* A==1: Q = B | ~S */
if (a == verinum::V1) {
NetLogic*inv = new NetLogic(scope,
scope->local_symbol(),
2, NetLogic::NOT);
NetNet*invs = new NetNet(scope,
scope->local_symbol(),
NetNet::TRI, 1);
invs->local_flag(true);
connect(inv->pin(0), invs->pin(0));
connect(inv->pin(1), obj->pin_Sel(0));
des->add_node(inv);
NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
3, NetLogic::OR);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,1), tmp->pin(1));
connect(inv->pin(0), tmp->pin(2));
des->add_node(tmp);
continue;
}
assert(0);
} }
/* Only the Sel==1 input is constant. */ if (a == verinum::V1 && b == verinum::V0) {
if (obj->pin_Data(idx, 1).nexus()->drivers_constant()) { NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
2, NetLogic::NOT);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Sel(0), tmp->pin(1));
des->add_node(tmp);
continue;
}
verinum::V b = obj->pin_Data(idx, 1).nexus()->driven_value(); /* A==0: Q = B & S */
if (a == verinum::V0) {
NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
3, NetLogic::AND);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,1), tmp->pin(1));
connect(obj->pin_Sel(0), tmp->pin(2));
des->add_node(tmp);
continue;
}
/* B==0: Q = A & ~S */ /* B==1: Q = A | S */
if (b == verinum::V0) { if (b == verinum::V1) {
NetLogic*inv = new NetLogic(scope, NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(), scope->local_symbol(),
2, NetLogic::NOT); 3, NetLogic::OR);
NetNet*invs = new NetNet(scope, connect(obj->pin_Result(idx), tmp->pin(0));
scope->local_symbol(), connect(obj->pin_Data(idx,0), tmp->pin(1));
NetNet::TRI, 1); connect(obj->pin_Sel(0), tmp->pin(2));
invs->local_flag(true); des->add_node(tmp);
connect(inv->pin(0), invs->pin(0)); continue;
connect(inv->pin(1), obj->pin_Sel(0)); }
des->add_node(inv); /* A==1: Q = B | ~S */
if (a == verinum::V1) {
NetLogic*inv = new NetLogic(scope,
scope->local_symbol(),
2, NetLogic::NOT);
NetNet*invs = new NetNet(scope,
scope->local_symbol(),
NetNet::TRI, 1);
invs->local_flag(true);
connect(inv->pin(0), invs->pin(0));
connect(inv->pin(1), obj->pin_Sel(0));
des->add_node(inv);
NetLogic*tmp = new NetLogic(scope, NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(), scope->local_symbol(),
3, NetLogic::AND); 3, NetLogic::OR);
connect(obj->pin_Result(idx), tmp->pin(0)); connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,0), tmp->pin(1)); connect(obj->pin_Data(idx,1), tmp->pin(1));
connect(inv->pin(0), tmp->pin(2)); connect(inv->pin(0), tmp->pin(2));
des->add_node(tmp); des->add_node(tmp);
continue; continue;
} }
/* B==1: Q = A | S */ /* B==0: Q = A & ~S */
if (b == verinum::V1) { if (b == verinum::V0) {
NetLogic*tmp = new NetLogic(scope, NetLogic*inv = new NetLogic(scope,
scope->local_symbol(), scope->local_symbol(),
3, NetLogic::OR); 2, NetLogic::NOT);
connect(obj->pin_Result(idx), tmp->pin(0)); NetNet*invs = new NetNet(scope,
connect(obj->pin_Data(idx,0), tmp->pin(1)); scope->local_symbol(),
connect(obj->pin_Sel(0), tmp->pin(2)); NetNet::TRI, 1);
des->add_node(tmp); invs->local_flag(true);
continue; connect(inv->pin(0), invs->pin(0));
} connect(inv->pin(1), obj->pin_Sel(0));
des->add_node(inv);
assert(0); NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
3, NetLogic::AND);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,0), tmp->pin(1));
connect(inv->pin(0), tmp->pin(2));
des->add_node(tmp);
continue;
} }
assert(0); assert(0);
} }
delete obj; delete obj;
@ -1175,6 +1113,7 @@ void cprop_functor::lpm_mux_large(Design*des, NetMux*obj)
slices. Connect all the slices that we are keeping. */ slices. Connect all the slices that we are keeping. */
NetMux*tmp = new NetMux(scope, obj->name(), NetMux*tmp = new NetMux(scope, obj->name(),
width-reduce_width, size, obj->sel_width()); width-reduce_width, size, obj->sel_width());
tmp->set_line(*obj);
for (unsigned idx = 0 ; idx < obj->sel_width() ; idx += 1) for (unsigned idx = 0 ; idx < obj->sel_width() ; idx += 1)
connect(obj->pin_Sel(idx), tmp->pin_Sel(idx)); connect(obj->pin_Sel(idx), tmp->pin_Sel(idx));
@ -1321,6 +1260,9 @@ void cprop(Design*des)
/* /*
* $Log: cprop.cc,v $ * $Log: cprop.cc,v $
* Revision 1.47.2.4 2005/09/11 02:50:51 steve
* Fix overly agressive constant propagation through MUX causing lost Z bits.
*
* Revision 1.47.2.3 2005/08/28 22:00:39 steve * Revision 1.47.2.3 2005/08/28 22:00:39 steve
* Reduce mux slices that are constant throughout range. * Reduce mux slices that are constant throughout range.
* *