Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

366 lines (323 sloc) 11.395 kb
/*
* Copyright (c) 1998 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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: cprop.cc,v 1.6 2000/01/02 17:56:42 steve Exp $"
#endif
# include "netlist.h"
# include "functor.h"
# include <assert.h>
/*
* This local function returns true if all the the possible drivers of
* this link are constant. It will also return true if there are no
* drivers at all.
*/
static bool all_drivers_constant(const NetObj::Link&lnk)
{
for (const NetObj::Link*cur = lnk.next_link()
; *cur != lnk ; cur = cur->next_link()) {
if (cur->get_dir() == NetObj::Link::INPUT)
continue;
if (cur->get_dir() == NetObj::Link::PASSIVE)
continue;
if (! dynamic_cast<const NetConst*>(cur->get_obj()))
return false;
}
return true;
}
/*
* This function returns the value of the constant driving this link,
* or Vz if there is no constant. The results of this function are
* only meaningful if all_drivers_constant(lnk) == true.
*/
static verinum::V driven_value(const NetObj::Link&lnk)
{
for (const NetObj::Link*cur = lnk.next_link()
; *cur != lnk ; cur = cur->next_link()) {
const NetConst*obj;
if (obj = dynamic_cast<const NetConst*>(cur->get_obj()))
return obj->value(cur->get_pin());
}
return verinum::Vz;
}
/*
* The cprop function below invokes constant propogation where
* possible. The elaboration generates NetConst objects. I can remove
* these and replace the gates connected to it with simpler ones. I
* may even be able to replace nets with a new constant.
*/
struct cprop_functor : public functor_t {
unsigned count;
virtual void lpm_add_sub(Design*des, NetAddSub*obj);
virtual void lpm_ff(Design*des, NetFF*obj);
virtual void lpm_logic(Design*des, NetLogic*obj);
};
void cprop_functor::lpm_add_sub(Design*des, NetAddSub*obj)
{
// For now, only additions are handled.
if (obj->attribute("LPM_Direction") != "ADD")
return;
// If the low bit on the A side is 0, then eliminate it from
// the adder, and pass the B side directly to the
// result. Don't reduce the adder smaller then a 1-bit
// adder. These will be eliminated later.
while ((obj->width() > 1)
&& all_drivers_constant(obj->pin_DataA(0))
&& (driven_value(obj->pin_DataA(0)) == verinum::V0)) {
NetAddSub*tmp = 0;
tmp = new NetAddSub(obj->name(), obj->width()-1);
//connect(tmp->pin_Aclr(), obj->pin_Aclr());
//connect(tmp->pin_Add_Sub(), obj->pin_Add_Sub());
//connect(tmp->pin_Clock(), obj->pin_Clock());
//connect(tmp->pin_Cin(), obj->pin_Cin());
connect(tmp->pin_Cout(), obj->pin_Cout());
//connect(tmp->pin_Overflow(), obj->pin_Overflow());
for (unsigned idx = 0 ; idx < tmp->width() ; idx += 1) {
connect(tmp->pin_DataA(idx), obj->pin_DataA(idx+1));
connect(tmp->pin_DataB(idx), obj->pin_DataB(idx+1));
connect(tmp->pin_Result(idx), obj->pin_Result(idx+1));
}
connect(obj->pin_Result(0), obj->pin_DataB(0));
delete obj;
des->add_node(tmp);
obj = tmp;
count += 1;
}
// Now do the same thing on the B side.
while ((obj->width() > 1)
&& all_drivers_constant(obj->pin_DataB(0))
&& (driven_value(obj->pin_DataB(0)) == verinum::V0)) {
NetAddSub*tmp = 0;
tmp = new NetAddSub(obj->name(), obj->width()-1);
//connect(tmp->pin_Aclr(), obj->pin_Aclr());
//connect(tmp->pin_Add_Sub(), obj->pin_Add_Sub());
//connect(tmp->pin_Clock(), obj->pin_Clock());
//connect(tmp->pin_Cin(), obj->pin_Cin());
connect(tmp->pin_Cout(), obj->pin_Cout());
//connect(tmp->pin_Overflow(), obj->pin_Overflow());
for (unsigned idx = 0 ; idx < tmp->width() ; idx += 1) {
connect(tmp->pin_DataA(idx), obj->pin_DataA(idx+1));
connect(tmp->pin_DataB(idx), obj->pin_DataB(idx+1));
connect(tmp->pin_Result(idx), obj->pin_Result(idx+1));
}
connect(obj->pin_Result(0), obj->pin_DataA(0));
delete obj;
des->add_node(tmp);
obj = tmp;
count += 1;
}
// If the adder is only 1 bit wide, then replace it with the
// simple logic gate.
if (obj->width() == 1) {
NetLogic*tmp;
if (obj->pin_Cout().is_linked()) {
tmp = new NetLogic(des->local_symbol(obj->name()), 3,
NetLogic::AND);
connect(tmp->pin(0), obj->pin_Cout());
connect(tmp->pin(1), obj->pin_DataA(0));
connect(tmp->pin(2), obj->pin_DataB(0));
des->add_node(tmp);
}
tmp = new NetLogic(obj->name(), 3, NetLogic::XOR);
connect(tmp->pin(0), obj->pin_Result(0));
connect(tmp->pin(1), obj->pin_DataA(0));
connect(tmp->pin(2), obj->pin_DataB(0));
delete obj;
des->add_node(tmp);
count += 1;
return;
}
}
void cprop_functor::lpm_ff(Design*des, NetFF*obj)
{
// Look for and count unlinked FF outputs. Note that if the
// Data and Q pins are connected together, they can be removed
// from the circuit.
unsigned unlinked_count = 0;
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
if (connected(obj->pin_Data(idx), obj->pin_Q(idx))) {
obj->pin_Data(idx).unlink();
obj->pin_Q(idx).unlink();
}
if (! obj->pin_Q(idx).is_linked())
unlinked_count += 1;
}
// If the entire FF is unlinked, remove the whole thing.
if (unlinked_count == obj->width()) {
delete obj;
count += 1;
return;
}
// If some of the FFs are unconnected, make a new FF array
// that does not include the useless FF devices.
if (unlinked_count > 0) {
NetFF*tmp = new NetFF(obj->name(), obj->width()-unlinked_count);
connect(tmp->pin_Clock(), obj->pin_Clock());
connect(tmp->pin_Enable(), obj->pin_Enable());
connect(tmp->pin_Aload(), obj->pin_Aload());
connect(tmp->pin_Aset(), obj->pin_Aset());
connect(tmp->pin_Aclr(), obj->pin_Aclr());
connect(tmp->pin_Sload(), obj->pin_Sload());
connect(tmp->pin_Sset(), obj->pin_Sset());
connect(tmp->pin_Sclr(), obj->pin_Sclr());
unsigned tidx = 0;
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1)
if (obj->pin_Q(idx).is_linked()) {
connect(tmp->pin_Data(tidx), obj->pin_Data(idx));
connect(tmp->pin_Q(tidx), obj->pin_Q(idx));
tidx += 1;
}
assert(tidx == obj->width() - unlinked_count);
delete obj;
des->add_node(tmp);
count += 1;
return;
}
}
void cprop_functor::lpm_logic(Design*des, NetLogic*obj)
{
switch (obj->type()) {
case NetLogic::AND:
// If there is one zero input to an AND gate, we know
// the resulting output is going to be zero and can
// elininate the gate.
for (unsigned idx = 1 ; idx < obj->pin_count() ; idx += 1) {
if (! all_drivers_constant(obj->pin(idx)))
continue;
if (driven_value(obj->pin(idx)) == verinum::V0) {
connect(obj->pin(0), obj->pin(idx));
delete obj;
count += 1;
return;
}
}
// There are no zero constant drivers. If there are any
// non-constant drivers, give up.
for (unsigned idx = 1 ; idx < obj->pin_count() ; idx += 1) {
if (! all_drivers_constant(obj->pin(idx)))
return;
}
// If there are any non-1 values (Vx or Vz) then the
// result is Vx.
for (unsigned idx = 1 ; idx < obj->pin_count() ; idx += 1) {
if (driven_value(obj->pin(idx)) != verinum::V1) {
connect(obj->pin(0), obj->pin(idx));
delete obj;
count += 1;
return;
}
}
// What's left? The inputs are all 1's, return the first
// input as the output value and remove the gate.
connect(obj->pin(0), obj->pin(1));
delete obj;
count += 1;
return;
default:
break;
}
}
/*
* This functor looks to see if the constant is connected to nothing
* but signals. If that is the case, delete the dangling constant and
* the now useless signals. This functor is applied after the regular
* functor to clean up dangling constants that might be left behind.
*/
struct cprop_dc_functor : public functor_t {
virtual void lpm_const(Design*des, NetConst*obj);
};
void cprop_dc_functor::lpm_const(Design*des, NetConst*obj)
{
// If there are any links that take input, the constant is
// used structurally somewhere.
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1)
if (count_inputs(obj->pin(idx)) > 0)
return;
// Look for signals that have NetESignal nodes attached to
// them. If I find any, this this constant is used by a
// behavioral expression somewhere.
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) {
NetObj*cur;
unsigned pin;
obj->pin(idx).next_link(cur, pin);
while (cur != obj) {
NetNet*tmp = dynamic_cast<NetNet*>(cur);
if (tmp && tmp->get_eref() > 0)
return;
cur->pin(pin).next_link(cur, pin);
}
}
// If there are no other drivers, delete all the signals that
// are also dangling.
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) {
if (count_outputs(obj->pin(idx)) != 1)
continue;
NetObj*cur;
unsigned pin;
obj->pin(idx).next_link(cur, pin);
while (cur != obj) {
NetNet*tmp = dynamic_cast<NetNet*>(cur);
cur->pin(pin).next_link(cur, pin);
assert(tmp->get_eref() == 0);
cerr << "cprop: delete dangling signal " <<
tmp->name() << "." << endl;
delete tmp;
}
}
// Done. Delete me.
delete obj;
}
void cprop(Design*des)
{
// Continually propogate constants until a scan finds nothing
// to do.
cprop_functor prop;
do {
prop.count = 0;
des->functor(&prop);
} while (prop.count > 0);
cprop_dc_functor dc;
des->functor(&dc);
}
/*
* $Log: cprop.cc,v $
* Revision 1.6 2000/01/02 17:56:42 steve
* Do not delete constants that input to exressions.
*
* Revision 1.5 1999/12/30 04:19:12 steve
* Propogate constant 0 in low bits of adders.
*
* Revision 1.4 1999/12/17 06:18:15 steve
* Rewrite the cprop functor to use the functor_t interface.
*
* Revision 1.3 1999/12/17 03:38:46 steve
* NetConst can now hold wide constants.
*
* Revision 1.2 1998/12/02 04:37:13 steve
* Add the nobufz function to eliminate bufz objects,
* Object links are marked with direction,
* constant propagation is more careful will wide links,
* Signal folding is aware of attributes, and
* the XNF target can dump UDP objects based on LCA
* attributes.
*
* Revision 1.1 1998/11/13 06:23:17 steve
* Introduce netlist optimizations with the
* cprop function to do constant propogation.
*
*/
Jump to Line
Something went wrong with that request. Please try again.