Fix overly agressive constant propagation through MUX causing lost Z bits.
This commit is contained in:
parent
393102d43a
commit
d97560caa7
292
cprop.cc
292
cprop.cc
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue