diff --git a/Makefile b/Makefile index 9c0557eb5..4b3f38013 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CXXFLAGS = -O -g -Wall -Wno-uninitialized #TT = t-debug.o t-vvm.o TT = t-verilog.o t-vvm.o -O = main.o design_dump.o elaborate.o emit.o eval.o lexor.o mangle.o \ +O = main.o cprop.o design_dump.o elaborate.o emit.o eval.o lexor.o mangle.o \ netlist.o parse.o parse_misc.o pform.o pform_dump.o stupid.o verinum.o \ target.o targets.o Module.o PExpr.o Statement.o $(TT) diff --git a/cprop.cc b/cprop.cc new file mode 100644 index 000000000..f134d9451 --- /dev/null +++ b/cprop.cc @@ -0,0 +1,190 @@ +/* + * 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.1 1998/11/13 06:23:17 steve Exp $" +#endif + +# include "netlist.h" +# include + +/* + * 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. + */ + +static bool is_a_const_node(const NetNode*obj) +{ + return dynamic_cast(obj); +} + +static bool const_into_xnor(Design*des, NetConst*obj, + NetLogic*log, unsigned pin) +{ + assert(pin > 0); + + /* if this is the last input pin of the XNOR device, then + the device is simply buffering the constant value. */ + if (log->pin_count() == 2) { + cerr << "cprop: delete gate " << log->name() << + " and propogate " << obj->value() << "." << endl; + + assert(pin == 1); + connect(log->pin(0), log->pin(1)); + + delete log; + return true; + } + + /* If this is a constant 0, then replace the gate with one + 1-pin smaller. Skip this pin. */ + if (obj->value() == verinum::V0) { + cerr << "cprop: disconnect pin " << pin << " from gate " + << log->name() << "." << endl; + + NetLogic*tmp = new NetLogic(log->name(), + log->pin_count()-1, + NetLogic::XNOR); + connect(log->pin(0), tmp->pin(0)); + unsigned idx, jdx; + for (idx = 1, jdx = 1 ; idx < log->pin_count() ; idx += 1) { + if (idx == pin) continue; + connect(log->pin(idx), tmp->pin(jdx)); + jdx += 1; + } + + delete log; + des->add_node(tmp); + return true; + } + + /* If this is a constant 1, then replace the gate with an XOR + that is 1-pin smaller. Removing the constant 1 causes the + sense of the output to change. */ + if (obj->value() == verinum::V1) { + cerr << "cprop: disconnect pin " << pin << " from gate " + << log->name() << "." << endl; + + NetLogic*tmp = new NetLogic(log->name(), + log->pin_count()-1, + NetLogic::XOR); + connect(log->pin(0), tmp->pin(0)); + unsigned idx, jdx; + for (idx = 1, jdx = 1 ; idx < log->pin_count() ; idx += 1) { + if (idx == pin) continue; + connect(log->pin(idx), tmp->pin(jdx)); + jdx += 1; + } + + delete log; + des->add_node(tmp); + return true; + } + + /* If this is a constant X or Z, then the gate is certain to + generate an X. Replace the gate with a constant X. This may + cause other signals all over to become dangling. */ + if ((obj->value() == verinum::Vx) || (obj->value() == verinum::Vz)) { + cerr << "cprop: replace gate " << log->name() << " with " + "a constant X." << endl; + + NetConst*tmp = new NetConst(log->name(), verinum::Vx); + connect(log->pin(0), tmp->pin(0)); + delete log; + des->add_node(tmp); + return true; + } + + return false; +} + +static void look_for_core_logic(Design*des, NetConst*obj) +{ + NetObj*cur = obj; + unsigned pin = 0; + for (obj->pin(0).next_link(cur, pin) + ; cur != obj + ; cur->pin(pin).next_link(cur, pin)) { + + NetLogic*log = dynamic_cast(cur); + if (log == 0) + continue; + + bool flag = false; + switch (log->type()) { + case NetLogic::XNOR: + flag = const_into_xnor(des, obj, log, pin); + break; + default: + break; + } + + /* If the optimization test tells me that a link was + deleted, restart the scan. */ + if (flag) obj->pin(0).next_link(cur, pin); + } +} + +/* + * This function 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. + */ +static void dangling_const(Design*des, NetConst*obj) +{ + NetObj*cur; + unsigned pin; + for (obj->pin(0).next_link(cur, pin) + ; cur != obj + ; cur->pin(pin).next_link(cur, pin)) { + if (! dynamic_cast(cur)) + return; + } + + obj->pin(0).next_link(cur, pin); + while (cur != obj) { + cerr << "cprop: delete dangling signal " << cur->name() << + "." << endl; + delete cur; + obj->pin(0).next_link(cur, pin); + } + delete obj; +} + +void cprop(Design*des) +{ + des->clear_node_marks(); + while (NetNode*obj = des->find_node(&is_a_const_node)) { + NetConst*cur = dynamic_cast(obj); + look_for_core_logic(des, cur); + cur->set_mark(); + dangling_const(des, cur); + } + +} + +/* + * $Log: cprop.cc,v $ + * Revision 1.1 1998/11/13 06:23:17 steve + * Introduce netlist optimizations with the + * cprop function to do constant propogation. + * + */ + diff --git a/main.cc b/main.cc index 88b6fe095..191229f65 100644 --- a/main.cc +++ b/main.cc @@ -17,12 +17,13 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: main.cc,v 1.2 1998/11/07 17:05:05 steve Exp $" +#ident "$Id: main.cc,v 1.3 1998/11/13 06:23:17 steve Exp $" #endif # include # include # include +# include # include # include "pform.h" # include "netlist.h" @@ -36,23 +37,52 @@ string start_module = ""; extern Design* elaborate(const list&modules, const string&root); extern void emit(ostream&o, const Design*, const char*); + +extern void cprop(Design*des); extern void stupid(Design*des); +typedef void (*net_func)(Design*); +static struct net_func_map { + const char*name; + void (*func)(Design*); +} func_table[] = { + { "stupid", &stupid }, + { "cprop", &cprop }, + { 0, 0 } +}; + +net_func name_to_net_func(const string&name) +{ + for (unsigned idx = 0 ; func_table[idx].name ; idx += 1) + if (name == func_table[idx].name) + return func_table[idx].func; + + return 0; +} + + int main(int argc, char*argv[]) { bool dump_flag = false; - bool optimize_flag = false; const char* out_path = 0; int opt; unsigned flag_errors = 0; + queue net_func_queue; - while ((opt = getopt(argc, argv, "DOo:s:t:")) != EOF) switch (opt) { + while ((opt = getopt(argc, argv, "DF:o:s:t:")) != EOF) switch (opt) { case 'D': dump_flag = true; break; - case 'O': - optimize_flag = true; - break; + case 'F': { + net_func tmp = name_to_net_func(optarg); + if (tmp == 0) { + cerr << "No such design transform function ``" + << optarg << "''." << endl; + break; + } + net_func_queue.push(tmp); + break; + } case 'o': out_path = optarg; break; @@ -114,8 +144,10 @@ int main(int argc, char*argv[]) return 1; } - if (optimize_flag) { - stupid(des); + while (!net_func_queue.empty()) { + net_func func = net_func_queue.front(); + net_func_queue.pop(); + func(des); } if (dump_flag) { @@ -144,6 +176,10 @@ int main(int argc, char*argv[]) /* * $Log: main.cc,v $ + * Revision 1.3 1998/11/13 06:23:17 steve + * Introduce netlist optimizations with the + * cprop function to do constant propogation. + * * Revision 1.2 1998/11/07 17:05:05 steve * Handle procedural conditional, and some * of the conditional expressions. diff --git a/netlist.cc b/netlist.cc index 9482d619c..02b6353a1 100644 --- a/netlist.cc +++ b/netlist.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: netlist.cc,v 1.4 1998/11/09 18:55:34 steve Exp $" +#ident "$Id: netlist.cc,v 1.5 1998/11/13 06:23:17 steve Exp $" #endif # include @@ -63,7 +63,7 @@ const NetNet* find_link_signal(const NetObj*net, unsigned pin, unsigned&bidx) } NetObj::NetObj(const string&n, unsigned np) -: name_(n), npins_(np), delay1_(0), delay2_(0), delay3_(0) +: name_(n), npins_(np), delay1_(0), delay2_(0), delay3_(0), mark_(false) { pins_ = new Link[npins_]; for (unsigned idx = 0 ; idx < npins_ ; idx += 1) { @@ -265,20 +265,6 @@ NetNet* Design::find_signal(const string&name) return 0; } -void Design::scan_signals(SigFunctor*fun) -{ - if (signals_ == 0) - return; - - NetNet*cur = signals_->sig_next_; - do { - NetNet*next = cur->sig_next_; - fun->sig_function(cur); - cur = next; - } while (cur != signals_->sig_next_); -} - - void Design::add_node(NetNode*net) { assert(net->design_ == 0); @@ -317,9 +303,40 @@ void Design::add_process(NetProcTop*pro) procs_ = pro; } +void Design::clear_node_marks() +{ + if (nodes_ == 0) + return; + + NetNode*cur = nodes_; + do { + cur->set_mark(false); + cur = cur->node_next_; + } while (cur != nodes_); +} + +NetNode* Design::find_node(bool (*func)(const NetNode*)) +{ + if (nodes_ == 0) + return 0; + + NetNode*cur = nodes_->node_next_; + do { + if ((cur->test_mark() == false) && func(cur)) + return cur; + + cur = cur->node_next_; + } while (cur != nodes_->node_next_); + + return 0; +} /* * $Log: netlist.cc,v $ + * Revision 1.5 1998/11/13 06:23:17 steve + * Introduce netlist optimizations with the + * cprop function to do constant propogation. + * * Revision 1.4 1998/11/09 18:55:34 steve * Add procedural while loops, * Parse procedural for loops, diff --git a/netlist.h b/netlist.h index 2b87955c6..6493e768e 100644 --- a/netlist.h +++ b/netlist.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: netlist.h,v 1.4 1998/11/09 18:55:34 steve Exp $" +#ident "$Id: netlist.h,v 1.5 1998/11/13 06:23:17 steve Exp $" #endif /* @@ -117,6 +117,9 @@ class NetObj { void delay2(unsigned d) { delay2_ = d; } void delay3(unsigned d) { delay3_ = d; } + bool test_mark() const { return mark_; } + void set_mark(bool flag=true) { mark_ = flag; } + Link&pin(unsigned idx) { return pins_[idx]; } const Link&pin(unsigned idx) const { return pins_[idx]; } @@ -130,6 +133,8 @@ class NetObj { unsigned delay1_; unsigned delay2_; unsigned delay3_; + + bool mark_; }; /* @@ -667,12 +672,8 @@ class Design { void dump(ostream&) const; void emit(ostream&, struct target_t*) const; - class SigFunctor { - public: - virtual void sig_function(NetNet*) =0; - }; - - void scan_signals(SigFunctor*); + void clear_node_marks(); + NetNode*find_node(bool (*test)(const NetNode*)); private: // List all the signals in the design. @@ -709,6 +710,10 @@ inline ostream& operator << (ostream&o, const NetExpr&exp) /* * $Log: netlist.h,v $ + * Revision 1.5 1998/11/13 06:23:17 steve + * Introduce netlist optimizations with the + * cprop function to do constant propogation. + * * Revision 1.4 1998/11/09 18:55:34 steve * Add procedural while loops, * Parse procedural for loops, diff --git a/stupid.cc b/stupid.cc index 5cf907ce0..f254fb10a 100644 --- a/stupid.cc +++ b/stupid.cc @@ -17,63 +17,22 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: stupid.cc,v 1.1 1998/11/03 23:29:05 steve Exp $" +#ident "$Id: stupid.cc,v 1.2 1998/11/13 06:23:17 steve Exp $" #endif # include "netlist.h" -# include -vector* list_link_nodes(NetObj::Link&link) -{ - NetObj*net; - unsigned npin; - vector*result = new vector; - - link.cur_link(net, npin); - NetObj*cur = net; - unsigned cpin = npin; - do { - if (dynamic_cast(cur)) - result->push_back(&cur->pin(cpin)); - - cur->pin(cpin).next_link(cur, cpin); - } while ((cur != net) || (cpin != npin)); - - return result; -} - -/* - * This function scans a design and removes artifacts from the - * elaboration step, and maybe a few other stupid inefficiencies. - */ - -class Functor : public Design::SigFunctor { - - public: - virtual void sig_function(NetNet*); -}; - - -void Functor::sig_function(NetNet*net) -{ - for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) { - vector*nodes = list_link_nodes(net->pin(idx)); -#if 0 - cerr << "XXXX " << net->name() << "[" << idx << "] " - "nodes->size() == " << nodes->size() << endl; -#endif - delete nodes; - } -} void stupid(Design*des) { - Functor fun; - des->scan_signals(&fun); } /* * $Log: stupid.cc,v $ + * Revision 1.2 1998/11/13 06:23:17 steve + * Introduce netlist optimizations with the + * cprop function to do constant propogation. + * * Revision 1.1 1998/11/03 23:29:05 steve * Introduce verilog to CVS. *