diff --git a/Makefile b/Makefile index 6b6764324..2467d2d20 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ CXXFLAGS = -O -g -Wall -Wno-uninitialized #TT = t-debug.o t-vvm.o TT = t-verilog.o t-vvm.o t-xnf.o -FF = nobufz.o sigfold.o stupid.o +FF = nobufz.o sigfold.o stupid.o xnfio.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 verinum.o target.o \ diff --git a/README.txt b/README.txt index ada0aea06..52cdd2f31 100644 --- a/README.txt +++ b/README.txt @@ -78,6 +78,10 @@ not part of a type attribute. Currently, type attributes are only supported for UDP types. +Note that attributes are also occasionally used for communication +between processing steps. Processing steps that are aware of others +may place attributes on netlist objects to communicate information to +later steps. HOW IT WORKS -- STAGES OF PROCESSING diff --git a/design_dump.cc b/design_dump.cc index a78ee0b89..c1732240e 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: design_dump.cc,v 1.6 1998/12/02 04:37:13 steve Exp $" +#ident "$Id: design_dump.cc,v 1.7 1998/12/07 04:53:17 steve Exp $" #endif /* @@ -137,6 +137,9 @@ void NetLogic::dump_node(ostream&o, unsigned ind) const case AND: o << "and"; break; + case BUF: + o << "buf"; + break; case NAND: o << "nand"; break; @@ -404,6 +407,13 @@ void Design::dump(ostream&o) const /* * $Log: design_dump.cc,v $ + * Revision 1.7 1998/12/07 04:53:17 steve + * Generate OBUF or IBUF attributes (and the gates + * to garry them) where a wire is a pad. This involved + * figuring out enough of the netlist to know when such + * was needed, and to generate new gates and signales + * to handle what's missing. + * * Revision 1.6 1998/12/02 04:37:13 steve * Add the nobufz function to eliminate bufz objects, * Object links are marked with direction, diff --git a/elaborate.cc b/elaborate.cc index 752eb0b4a..e0d6553c6 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: elaborate.cc,v 1.8 1998/12/02 04:37:13 steve Exp $" +#ident "$Id: elaborate.cc,v 1.9 1998/12/07 04:53:17 steve Exp $" #endif /* @@ -32,13 +32,12 @@ # include "pform.h" # include "netlist.h" -static string local_symbol(const string&path) +string Design::local_symbol(const string&path) { - static unsigned counter = 0; string result = "_L"; strstream res; - res << "_L" << (counter++) << ends; + res << "_L" << (lcounter_++) << ends; return path + "." + res.str(); } @@ -76,7 +75,7 @@ static void do_assign(Design*des, const string&path, delete lval; } else for (unsigned idx = 0 ; idx < pin_count ; idx += 1) { - NetBUFZ*cur = new NetBUFZ(local_symbol(path)); + NetBUFZ*cur = new NetBUFZ(des->local_symbol(path)); connect(cur->pin(0), lval->pin(idx)); connect(cur->pin(1), rval->pin(idx)); @@ -153,12 +152,15 @@ void PGBuiltin::elaborate(Design*des, const string&path) const NetLogic*cur = 0; string name = get_name(); if (name == "") - name = local_symbol(path); + name = des->local_symbol(path); switch (type()) { case AND: cur = new NetLogic(name, pin_count(), NetLogic::AND); break; + case BUF: + cur = new NetLogic(name, pin_count(), NetLogic::BUF); + break; case NAND: cur = new NetLogic(name, pin_count(), NetLogic::NAND); break; @@ -206,7 +208,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, const string&path) const { string my_name; if (get_name() == "") - my_name = local_symbol(path); + my_name = des->local_symbol(path); else my_name = path + "." + get_name(); @@ -333,10 +335,10 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path) const case '^': // XOR assert(lsig->pin_count() == 1); assert(rsig->pin_count() == 1); - gate = new NetLogic(local_symbol(path), 3, NetLogic::XOR); + gate = new NetLogic(des->local_symbol(path), 3, NetLogic::XOR); connect(gate->pin(1), lsig->pin(0)); connect(gate->pin(2), rsig->pin(0)); - osig = new NetNet(local_symbol(path), NetNet::WIRE); + osig = new NetNet(des->local_symbol(path), NetNet::WIRE); osig->local_flag(true); connect(gate->pin(0), osig->pin(0)); des->add_signal(osig); @@ -346,10 +348,10 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path) const case '&': // AND assert(lsig->pin_count() == 1); assert(rsig->pin_count() == 1); - gate = new NetLogic(local_symbol(path), 3, NetLogic::AND); + gate = new NetLogic(des->local_symbol(path), 3, NetLogic::AND); connect(gate->pin(1), lsig->pin(0)); connect(gate->pin(2), rsig->pin(0)); - osig = new NetNet(local_symbol(path), NetNet::WIRE); + osig = new NetNet(des->local_symbol(path), NetNet::WIRE); osig->local_flag(true); connect(gate->pin(0), osig->pin(0)); des->add_signal(osig); @@ -359,10 +361,10 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path) const case 'e': // == assert(lsig->pin_count() == 1); assert(rsig->pin_count() == 1); - gate = new NetLogic(local_symbol(path), 3, NetLogic::XNOR); + gate = new NetLogic(des->local_symbol(path), 3, NetLogic::XNOR); connect(gate->pin(1), lsig->pin(0)); connect(gate->pin(2), rsig->pin(0)); - osig = new NetNet(local_symbol(path), NetNet::WIRE); + osig = new NetNet(des->local_symbol(path), NetNet::WIRE); osig->local_flag(true); connect(gate->pin(0), osig->pin(0)); des->add_signal(osig); @@ -427,9 +429,9 @@ NetNet* PEIdent::elaborate_net(Design*des, const string&path) const */ NetNet* PENumber::elaborate_net(Design*des, const string&path) const { - NetNet*net = new NetNet(local_symbol(path), NetNet::IMPLICIT); + NetNet*net = new NetNet(des->local_symbol(path), NetNet::IMPLICIT); net->local_flag(true); - NetConst*tmp = new NetConst(local_symbol(path), value_->get(0)); + NetConst*tmp = new NetConst(des->local_symbol(path), value_->get(0)); des->add_node(tmp); des->add_signal(net); connect(net->pin(0), tmp->pin(0)); @@ -446,9 +448,9 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path) const switch (op_) { case '~': // Bitwise NOT assert(sub_sig->pin_count() == 1); - sig = new NetNet(local_symbol(path), NetNet::WIRE); + sig = new NetNet(des->local_symbol(path), NetNet::WIRE); sig->local_flag(true); - gate = new NetLogic(local_symbol(path), 2, NetLogic::NOT); + gate = new NetLogic(des->local_symbol(path), 2, NetLogic::NOT); connect(gate->pin(0), sig->pin(0)); connect(gate->pin(1), sub_sig->pin(0)); des->add_signal(sig); @@ -456,9 +458,9 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path) const break; case '&': // Reduction AND - sig = new NetNet(local_symbol(path), NetNet::WIRE); + sig = new NetNet(des->local_symbol(path), NetNet::WIRE); sig->local_flag(true); - gate = new NetLogic(local_symbol(path), + gate = new NetLogic(des->local_symbol(path), 1+sub_sig->pin_count(), NetLogic::AND); connect(gate->pin(0), sig->pin(0)); @@ -598,7 +600,7 @@ NetProc* PDelayStatement::elaborate(Design*des, const string&path) const NetProc* PEventStatement::elaborate(Design*des, const string&path) const { NetProc*enet = statement_->elaborate(des, path); - NetPEvent*ev = new NetPEvent(local_symbol(path), type_, enet); + NetPEvent*ev = new NetPEvent(des->local_symbol(path), type_, enet); NetNet*expr = expr_->elaborate_net(des, path); if (expr == 0) { @@ -732,6 +734,13 @@ Design* elaborate(const map&modules, /* * $Log: elaborate.cc,v $ + * Revision 1.9 1998/12/07 04:53:17 steve + * Generate OBUF or IBUF attributes (and the gates + * to garry them) where a wire is a pad. This involved + * figuring out enough of the netlist to know when such + * was needed, and to generate new gates and signales + * to handle what's missing. + * * Revision 1.8 1998/12/02 04:37:13 steve * Add the nobufz function to eliminate bufz objects, * Object links are marked with direction, diff --git a/main.cc b/main.cc index 40f11fa96..8ea184545 100644 --- a/main.cc +++ b/main.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: main.cc,v 1.8 1998/12/02 04:37:13 steve Exp $" +#ident "$Id: main.cc,v 1.9 1998/12/07 04:53:17 steve Exp $" #endif # include @@ -64,6 +64,7 @@ extern void cprop(Design*des); extern void sigfold(Design*des); extern void stupid(Design*des); extern void nobufz(Design*des); +extern void xnfio(Design*des); typedef void (*net_func)(Design*); static struct net_func_map { @@ -74,6 +75,7 @@ static struct net_func_map { { "nobufz", &nobufz }, { "sigfold", &sigfold }, { "stupid", &stupid }, + { "xnfio", &xnfio }, { 0, 0 } }; @@ -229,6 +231,13 @@ int main(int argc, char*argv[]) /* * $Log: main.cc,v $ + * Revision 1.9 1998/12/07 04:53:17 steve + * Generate OBUF or IBUF attributes (and the gates + * to garry them) where a wire is a pad. This involved + * figuring out enough of the netlist to know when such + * was needed, and to generate new gates and signales + * to handle what's missing. + * * Revision 1.8 1998/12/02 04:37:13 steve * Add the nobufz function to eliminate bufz objects, * Object links are marked with direction, diff --git a/netlist.cc b/netlist.cc index e579cab3a..2e0ba6567 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.10 1998/12/02 04:37:13 steve Exp $" +#ident "$Id: netlist.cc,v 1.11 1998/12/07 04:53:17 steve Exp $" #endif # include @@ -145,6 +145,25 @@ unsigned count_outputs(const NetObj::Link&pin) return count; } +unsigned count_signals(const NetObj::Link&pin) +{ + unsigned count = 0; + if (dynamic_cast(pin.get_obj())) + count += 1; + + const NetObj*cur; + unsigned cpin; + pin.next_link(cur, cpin); + while (cur->pin(cpin) != pin) { + if (dynamic_cast(cur)) + count += 1; + + cur->pin(cpin).next_link(cur, cpin); + } + + return count; +} + const NetNet* find_link_signal(const NetObj*net, unsigned pin, unsigned&bidx) { const NetObj*cur; @@ -193,6 +212,11 @@ string NetObj::attribute(const string&key) const return (*idx).second; } +void NetObj::attribute(const string&key, const string&value) +{ + attributes_[key] = value; +} + bool NetObj::has_compat_attributes(const NetObj&that) const { map::const_iterator idx; @@ -559,6 +583,13 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*)) /* * $Log: netlist.cc,v $ + * Revision 1.11 1998/12/07 04:53:17 steve + * Generate OBUF or IBUF attributes (and the gates + * to garry them) where a wire is a pad. This involved + * figuring out enough of the netlist to know when such + * was needed, and to generate new gates and signales + * to handle what's missing. + * * Revision 1.10 1998/12/02 04:37:13 steve * Add the nobufz function to eliminate bufz objects, * Object links are marked with direction, diff --git a/netlist.h b/netlist.h index b893c9310..4efdf69e3 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.10 1998/12/02 04:37:13 steve Exp $" +#ident "$Id: netlist.h,v 1.11 1998/12/07 04:53:17 steve Exp $" #endif /* @@ -85,6 +85,9 @@ class NetObj { pin = next_->pin_; } + Link* next_link() { return next_; } + const Link* next_link() const { return next_; } + // Remove this link from the set of connected pins. The // destructor will automatically do this if needed. void unlink() @@ -105,6 +108,12 @@ class NetObj { bool is_equal(const NetObj::Link&that) const { return (node_ == that.node_) && (pin_ == that.pin_); } + // Return information about the object that this link is + // a part of. + const NetObj*get_obj() const { return node_; } + NetObj*get_obj() { return node_; } + unsigned get_pin() const { return pin_; } + private: // The NetNode manages these. They point back to the // NetNode so that following the links can get me here. @@ -139,6 +148,7 @@ class NetObj { void set_attributes(const map&); string attribute(const string&key) const; + void attribute(const string&key, const string&value); // Return true if this has all the attributes in that and they // all have the same values. @@ -311,7 +321,7 @@ class NetConst : public NetNode { class NetLogic : public NetNode { public: - enum TYPE { AND, NAND, NOR, NOT, OR, XNOR, XOR }; + enum TYPE { AND, BUF, NAND, NOR, NOT, OR, XNOR, XOR }; explicit NetLogic(const string&n, unsigned pins, TYPE t); @@ -699,7 +709,7 @@ class NetESignal : public NetExpr { class Design { public: - Design() : signals_(0), nodes_(0), procs_(0) { } + Design() : signals_(0), nodes_(0), procs_(0), lcounter_(0) { } /* The flags are a generic way of accepting command line parameters/flags and passing them to the processing steps @@ -736,6 +746,10 @@ class Design { void clear_signal_marks(); NetNet*find_signal(bool (*test)(const NetNet*)); + + public: + string local_symbol(const string&path); + private: // List all the signals in the design. NetNet*signals_; @@ -748,6 +762,8 @@ class Design { map flags_; + unsigned lcounter_; + private: // not implemented Design(const Design&); Design& operator= (const Design&); @@ -776,8 +792,11 @@ inline bool connected(const NetObj::Link&l, const NetObj::Link&r) checking signal vectors. */ extern bool connected(const NetObj&l, const NetObj&r); +/* return the number of links in the ring that are of the specified + type. */ extern unsigned count_inputs(const NetObj::Link&pin); extern unsigned count_outputs(const NetObj::Link&pin); +extern unsigned count_signals(const NetObj::Link&pin); /* Find the signal connected to the given node pin. There should always be exactly one signal. The bidx parameter get filled with @@ -792,6 +811,13 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.11 1998/12/07 04:53:17 steve + * Generate OBUF or IBUF attributes (and the gates + * to garry them) where a wire is a pad. This involved + * figuring out enough of the netlist to know when such + * was needed, and to generate new gates and signales + * to handle what's missing. + * * Revision 1.10 1998/12/02 04:37:13 steve * Add the nobufz function to eliminate bufz objects, * Object links are marked with direction, diff --git a/t-xnf.cc b/t-xnf.cc index 5120b73f9..208eab348 100644 --- a/t-xnf.cc +++ b/t-xnf.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: t-xnf.cc,v 1.4 1998/12/02 04:37:13 steve Exp $" +#ident "$Id: t-xnf.cc,v 1.5 1998/12/07 04:53:17 steve Exp $" #endif /* XNF BACKEND @@ -45,10 +45,20 @@ * NODE ATTRIBUTES * * XNF-LCA = :,... - * Specify the LCA library part type for the UDP node. The lname + * Specify the LCA library part type for the gate. The lname * is the name of the symbol to use (i.e. DFF) and the comma - * seperated list is the names of the pins, in the order they - * appear in the verilog source. + * separated list is the names of the pins, in the order they + * appear in the verilog source. If the name is prefixed with a + * tilde (~) then the pin is inverted, and the proper "INV" token + * will be added to the PIN record. + * + * This attribute can override even the typical generation of + * gates that one might naturally expect of the code generator, + * but may be used by the optimizers for placing parts. + * + * An example is "XNF-LCA=OBUF:O,~I". This attribute means that + * the object is an OBUF. Pin 0 is called "O", and pin 1 is + * called "I". In addition, pin 1 is inverted. */ # include "netlist.h" @@ -65,8 +75,10 @@ class target_xnf : public target_t { private: static string mangle(const string&); - static void draw_pin(ostream&os, const string&name, char type, + static void draw_pin(ostream&os, const string&name, const NetObj::Link&lnk); + static void draw_sym_with_lcaname(ostream&os, string lca, + const NetNode*net); }; /* @@ -89,9 +101,27 @@ string target_xnf::mangle(const string&name) return result; } -void target_xnf::draw_pin(ostream&os, const string&name, char type, - const NetObj::Link&lnk) +void target_xnf::draw_pin(ostream&os, const string&name, + const NetObj::Link&lnk) { + bool inv = false; + string use_name = name; + if (use_name[0] == '~') { + inv = true; + use_name = use_name.substr(1); + } + + char type; + switch (lnk.get_dir()) { + case NetObj::Link::INPUT: + case NetObj::Link::PASSIVE: + type = 'I'; + break; + case NetObj::Link::OUTPUT: + type = 'O'; + break; + } + unsigned cpin; const NetObj*cur; for (lnk.next_link(cur, cpin) @@ -100,16 +130,47 @@ void target_xnf::draw_pin(ostream&os, const string&name, char type, const NetNet*sig = dynamic_cast(cur); if (sig) { - os << " PIN, " << name << ", " << type << ", " + os << " PIN, " << use_name << ", " << type << ", " << mangle(sig->name()); if (sig->pin_count() > 1) os << "<" << cpin << ">"; + if (inv) + os << ",,INV"; + os << endl; } } } +static string scrape_pin_name(string&list) +{ + unsigned idx = list.find(','); + string name = list.substr(0, idx); + list = list.substr(idx+1); + return name; +} + +/* + * This method draws an LCA item based on the XNF-LCA attribute + * given. The LCA attribute gives enough information to completely + * draw the node in XNF, which is pretty handy at this point. + */ +void target_xnf::draw_sym_with_lcaname(ostream&os, string lca, + const NetNode*net) +{ + unsigned idx = lca.find(':'); + string lcaname = lca.substr(0, idx); + lca = lca.substr(idx+1); + + os << "SYM, " << mangle(net->name()) << ", " << lcaname + << ", LIBVER=2.0.0" << endl; + + for (idx = 0 ; idx < net->pin_count() ; idx += 1) + draw_pin(os, scrape_pin_name(lca), net->pin(idx)); + + os << "END" << endl; +} void target_xnf::start_design(ostream&os, const Design*des) { @@ -198,11 +259,22 @@ void target_xnf::signal(ostream&os, const NetNet*net) */ void target_xnf::logic(ostream&os, const NetLogic*net) { + // The XNF-LCA attribute overrides anything I might guess + // about this object. + string lca = net->attribute("XNF-LCA"); + if (lca != "") { + draw_sym_with_lcaname(os, lca, net); + return; + } + os << "SYM, " << mangle(net->name()) << ", "; switch (net->type()) { case NetLogic::AND: os << "AND"; break; + case NetLogic::BUF: + os << "BUF"; + break; case NetLogic::NAND: os << "NAND"; break; @@ -227,44 +299,29 @@ void target_xnf::logic(ostream&os, const NetLogic*net) } os << ", LIBVER=2.0.0" << endl; - draw_pin(os, "O", 'O', net->pin(0)); + draw_pin(os, "O", net->pin(0)); for (unsigned idx = 1 ; idx < net->pin_count() ; idx += 1) { string name = "I"; assert(net->pin_count() <= 11); name += (char)('0'+idx-1); - draw_pin(os, name, 'I', net->pin(idx)); + draw_pin(os, name, net->pin(idx)); } os << "END" << endl; } -static string scrape_pin_name(string&list) -{ - unsigned idx = list.find(','); - string name = list.substr(0, idx); - list = list.substr(idx+1); - return name; -} - void target_xnf::udp(ostream&os, const NetUDP*net) { string lca = net->attribute("XNF-LCA"); + + // I only know how to draw a UDP if it has the XNF-LCA + // attribute attached to it. if (lca == "") { cerr << "I don't understand this UDP." << endl; return; } - unsigned idx = lca.find(':'); - string lcaname = lca.substr(0, idx); - lca = lca.substr(idx+1); - - os << "SYM, " << mangle(net->name()) << ", " << lcaname - << ", LIBVER=2.0.0" << endl; - draw_pin(os, scrape_pin_name(lca), 'O', net->pin(0)); - for (idx = 1 ; idx < net->pin_count() ; idx += 1) { - draw_pin(os, scrape_pin_name(lca), 'I', net->pin(idx)); - } - os << "END" << endl; + draw_sym_with_lcaname(os, lca, net); } static target_xnf target_xnf_obj; @@ -273,6 +330,13 @@ extern const struct target tgt_xnf = { "xnf", &target_xnf_obj }; /* * $Log: t-xnf.cc,v $ + * Revision 1.5 1998/12/07 04:53:17 steve + * Generate OBUF or IBUF attributes (and the gates + * to garry them) where a wire is a pad. This involved + * figuring out enough of the netlist to know when such + * was needed, and to generate new gates and signales + * to handle what's missing. + * * Revision 1.4 1998/12/02 04:37:13 steve * Add the nobufz function to eliminate bufz objects, * Object links are marked with direction, diff --git a/xnfio.cc b/xnfio.cc new file mode 100644 index 000000000..e76783485 --- /dev/null +++ b/xnfio.cc @@ -0,0 +1,193 @@ +/* + * 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: xnfio.cc,v 1.1 1998/12/07 04:53:17 steve Exp $" +#endif + +# include "netlist.h" + +static bool is_a_pad(const NetNet*net) +{ + if (net->attribute("PAD") == "") + return false; + + return true; +} + +/* + * The xnfio function looks for the PAD signals in the design, and + * generates the needed IOB devices to handle being connected to the + * actual FPGA PAD. This will add items to the netlist if needed. + * + * FIXME: If there is a DFF connected to the pad, try to convert it + * to an IO DFF instead. This would save a CLB, and it is + * really lame to not do the obvious optimization. + */ + +static void make_obuf(Design*des, NetNet*net) +{ + assert(net->pin_count() == 1); + + /* FIXME: If there is nothing internally driving this PAD, I + can connect the PAD to a pullup and disconnect it from the + rest of the circuit. This would save routing resources. */ + assert(count_outputs(net->pin(0)) > 0); + + /* Look for an existing OBUF connected to this signal. If it + is there, then no need to add one. */ + for (NetObj::Link*idx = net->pin(0).next_link() + ; *idx != net->pin(0) ; idx = idx->next_link()) { + NetLogic*tmp; + if ((tmp = dynamic_cast(idx->get_obj())) == 0) + continue; + + // Try to use an existing BUF as an OBUF. This moves the + // BUF into the IOB. + if ((tmp->type() == NetLogic::BUF) && + (count_inputs(tmp->pin(0)) == 0) && + (count_outputs(tmp->pin(0)) == 1)) { + tmp->attribute("XNF-LCA", "OBUF:O,I"); + return; + } + + // Try to use an existing INV as an OBUF. Certain + // technologies support inverting the input of an OBUF, + // which looks just like an inverter. This uses the + // available resources of an IOB to optimize away an + // otherwise expensive inverter. + if ((tmp->type() == NetLogic::NOT) && + (count_inputs(tmp->pin(0)) == 0) && + (count_outputs(tmp->pin(0)) == 1)) { + tmp->attribute("XNF-LCA", "OBUF:O,~I"); + return; + } + } + + // Can't seem to find a way to rearrange the existing netlist, + // so I am stuck creating a new buffer, the OBUF. + NetLogic*buf = new NetLogic(des->local_symbol("$"), 2, NetLogic::BUF); + des->add_node(buf); + + mapattr; + attr["XNF-LCA"] = "OBUF:O,I"; + buf->set_attributes(attr); + + // Put the buffer between this signal and the rest of the + // netlist. + connect(net->pin(0), buf->pin(1)); + net->pin(0).unlink(); + connect(net->pin(0), buf->pin(0)); + + // It is possible, in putting an OBUF between net and the rest + // of the netlist, to create a ring without a signal. Detect + // this case and create a new signal. + if (count_signals(buf->pin(1)) == 0) { + NetNet*tmp = new NetNet(des->local_symbol("$"), NetNet::WIRE); + connect(buf->pin(1), tmp->pin(0)); + des->add_signal(tmp); + } +} + +static void make_ibuf(Design*des, NetNet*net) +{ + assert(net->pin_count() == 1); + // XXXX For now, require at least one input. + assert(count_inputs(net->pin(0)) > 0); + + /* Look for an existing BUF connected to this signal and + suitably connected that I can use it as an IBUF. */ + for (NetObj::Link*idx = net->pin(0).next_link() + ; *idx != net->pin(0) ; idx = idx->next_link()) { + NetLogic*tmp; + if ((tmp = dynamic_cast(idx->get_obj())) == 0) + continue; + + // Found a BUF, it is only useable if the only input is + // the signal and there are no other inputs. + if ((tmp->type() == NetLogic::BUF) && + (count_inputs(tmp->pin(1)) == 1) && + (count_outputs(tmp->pin(1)) == 0)) { + tmp->attribute("XNF-LCA", "IBUF:O,I"); + return; + } + + } + + // I give up, create an IBUF. + NetLogic*buf = new NetLogic(des->local_symbol("$"), 2, NetLogic::BUF); + des->add_node(buf); + + mapattr; + attr["XNF-LCA"] = "IBUF:O,I"; + buf->set_attributes(attr); + + // Put the buffer between this signal and the rest of the + // netlist. + connect(net->pin(0), buf->pin(0)); + net->pin(0).unlink(); + connect(net->pin(0), buf->pin(1)); + + // It is possible, in putting an OBUF between net and the rest + // of the netlist, to create a ring without a signal. Detect + // this case and create a new signal. + if (count_signals(buf->pin(0)) == 0) { + NetNet*tmp = new NetNet(des->local_symbol("$"), NetNet::WIRE); + connect(buf->pin(0), tmp->pin(0)); + des->add_signal(tmp); + } +} + +void xnfio(Design*des) +{ + des->clear_signal_marks(); + while (NetNet*net = des->find_signal(&is_a_pad)) { + + assert(net->pin_count() == 1); + string pattr = net->attribute("PAD"); + + switch (pattr[0]) { + case 'i': + case 'I': + make_ibuf(des, net); + break; + case 'o': + case 'O': + make_obuf(des, net); + break; + // FIXME: Only IPAD and OPAD supported. Need to + // add support for IOPAD. + default: + assert(0); + break; + } + net->set_mark(); + } +} + +/* + * $Log: xnfio.cc,v $ + * Revision 1.1 1998/12/07 04:53:17 steve + * Generate OBUF or IBUF attributes (and the gates + * to garry them) where a wire is a pad. This involved + * figuring out enough of the netlist to know when such + * was needed, and to generate new gates and signales + * to handle what's missing. + * + */ +