From 2cce0ce23886338bee3ad2b4399dd388ca9cc3c8 Mon Sep 17 00:00:00 2001 From: steve Date: Fri, 5 Nov 1999 04:40:40 +0000 Subject: [PATCH] Patch to synthesize LPM_ADD_SUB from expressions, Thanks to Larry Doolittle. Also handle constants in expressions. Synthesize adders in XNF, based on a patch from Larry. Accept synthesis of constants from Larry as is. --- expr_synth.cc | 65 ++++++++++++++++++- netlist.cc | 27 +++++++- netlist.h | 17 ++++- t-xnf.cc | 171 +++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 274 insertions(+), 6 deletions(-) diff --git a/expr_synth.cc b/expr_synth.cc index 3ef4b83fb..5b06b7aba 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: expr_synth.cc,v 1.2 1999/11/04 03:53:26 steve Exp $" +#ident "$Id: expr_synth.cc,v 1.3 1999/11/05 04:40:40 steve Exp $" #endif # include "netlist.h" @@ -31,6 +31,44 @@ NetNet* NetExpr::synthesize(Design*des) return 0; } +/* + * Make an LPM_ADD_SUB device from addition operators. + */ +NetNet* NetEBAdd::synthesize(Design*des) +{ + assert((op()=='+') || (op()=='-')); + + string path = des->local_symbol("SYNTH"); + NetNet*lsig = left_->synthesize(des); + NetNet*rsig = right_->synthesize(des); + + assert(lsig->pin_count() == rsig->pin_count()); + unsigned width=lsig->pin_count(); + + NetNet*osig = new NetNet(path, NetNet::IMPLICIT, width); + + string oname = des->local_symbol(path); + NetAddSub *adder = new NetAddSub(oname, width); + for (unsigned idx = 0 ; idx < width; idx += 1) { + connect(lsig->pin(idx), adder->pin_DataA(idx)); + connect(rsig->pin(idx), adder->pin_DataB(idx)); + connect(osig->pin(idx), adder->pin_Result(idx)); + } + des->add_node(adder); + des->add_signal(osig); + + switch (op()) { + case '+': + adder->attribute("LPM_Direction", "ADD"); + break; + case '-': + adder->attribute("LPM_Direction", "SUB"); + break; + } + + return osig; +} + /* * The bitwise logic operators are turned into discrete gates pretty * easily. Synthesize the left and right sub-expressions to get @@ -81,6 +119,22 @@ NetNet* NetEBBits::synthesize(Design*des) return osig; } +NetNet* NetEConst::synthesize(Design*des) +{ + string path = des->local_symbol("SYNTH"); + unsigned width=expr_width(); + + NetNet*osig = new NetNet(path, NetNet::IMPLICIT, width); + for (unsigned idx = 0 ; idx < width; idx += 1) { + string oname = des->local_symbol(path); + NetConst *c = new NetConst(oname, value().get(idx)); + connect(osig->pin(idx), c->pin(0)); + des->add_node(c); + } + des->add_signal(osig); + return osig; +} + /* * The bitwise unary logic operator (there is only one) is turned * into discrete gates just as easily as the binary ones above. @@ -150,6 +204,15 @@ NetNet* NetESignal::synthesize(Design*des) /* * $Log: expr_synth.cc,v $ + * Revision 1.3 1999/11/05 04:40:40 steve + * Patch to synthesize LPM_ADD_SUB from expressions, + * Thanks to Larry Doolittle. Also handle constants + * in expressions. + * + * Synthesize adders in XNF, based on a patch from + * Larry. Accept synthesis of constants from Larry + * as is. + * * Revision 1.2 1999/11/04 03:53:26 steve * Patch to synthesize unary ~ and the ternary operator. * Thanks to Larry Doolittle . diff --git a/netlist.cc b/netlist.cc index b809994bd..3f6eedeb2 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.82 1999/11/04 03:53:26 steve Exp $" +#ident "$Id: netlist.cc,v 1.83 1999/11/05 04:40:40 steve Exp $" #endif # include @@ -555,6 +555,13 @@ NetObj::Link& NetAddSub::pin_DataA(unsigned idx) return pin(idx); } +const NetObj::Link& NetAddSub::pin_DataA(unsigned idx) const +{ + idx = 6 + idx*3; + assert(idx < pin_count()); + return pin(idx); +} + NetObj::Link& NetAddSub::pin_DataB(unsigned idx) { idx = 7 + idx*3; @@ -562,6 +569,13 @@ NetObj::Link& NetAddSub::pin_DataB(unsigned idx) return pin(idx); } +const NetObj::Link& NetAddSub::pin_DataB(unsigned idx) const +{ + idx = 7 + idx*3; + assert(idx < pin_count()); + return pin(idx); +} + NetObj::Link& NetAddSub::pin_Result(unsigned idx) { idx = 8 + idx*3; @@ -602,7 +616,7 @@ NetMux::NetMux(const string&n, unsigned wi, unsigned si, unsigned sw) } for (unsigned idx = 0 ; idx < swidth_ ; idx += 1) { - pin_Sel(idx).set_dir(Link::OUTPUT); + pin_Sel(idx).set_dir(Link::INPUT); pin_Sel(idx).set_name("Sel", idx); } } @@ -2090,6 +2104,15 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*)) /* * $Log: netlist.cc,v $ + * Revision 1.83 1999/11/05 04:40:40 steve + * Patch to synthesize LPM_ADD_SUB from expressions, + * Thanks to Larry Doolittle. Also handle constants + * in expressions. + * + * Synthesize adders in XNF, based on a patch from + * Larry. Accept synthesis of constants from Larry + * as is. + * * Revision 1.82 1999/11/04 03:53:26 steve * Patch to synthesize unary ~ and the ternary operator. * Thanks to Larry Doolittle . diff --git a/netlist.h b/netlist.h index cd6a7cb7f..a505d94e2 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.85 1999/11/04 03:53:26 steve Exp $" +#ident "$Id: netlist.h,v 1.86 1999/11/05 04:40:40 steve Exp $" #endif /* @@ -317,6 +317,8 @@ class NetAddSub : public NetNode { NetObj::Link& pin_DataB(unsigned idx); NetObj::Link& pin_Result(unsigned idx); + const NetObj::Link& pin_DataA(unsigned idx) const; + const NetObj::Link& pin_DataB(unsigned idx) const; const NetObj::Link& pin_Result(unsigned idx) const; virtual void dump_node(ostream&, unsigned ind) const; @@ -493,7 +495,7 @@ class NetExpr : public LineInfo { /* * The expression constant is slightly special, and is sometimes - * retured from other classes that can be evaluated at compile + * returned from other classes that can be evaluated at compile * time. This class represents constant values in expressions. */ class NetEConst : public NetExpr { @@ -509,6 +511,7 @@ class NetEConst : public NetExpr { virtual void dump(ostream&) const; virtual NetEConst* dup_expr() const; + virtual NetNet*synthesize(Design*); private: verinum value_; @@ -1339,6 +1342,7 @@ class NetEBAdd : public NetEBinary { virtual bool set_width(unsigned w); virtual NetEBAdd* dup_expr() const; virtual NetEConst* eval_tree(); + virtual NetNet* synthesize(Design*); }; /* @@ -1854,6 +1858,15 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.86 1999/11/05 04:40:40 steve + * Patch to synthesize LPM_ADD_SUB from expressions, + * Thanks to Larry Doolittle. Also handle constants + * in expressions. + * + * Synthesize adders in XNF, based on a patch from + * Larry. Accept synthesis of constants from Larry + * as is. + * * Revision 1.85 1999/11/04 03:53:26 steve * Patch to synthesize unary ~ and the ternary operator. * Thanks to Larry Doolittle . diff --git a/t-xnf.cc b/t-xnf.cc index 33bf22f60..14423ef20 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.11 1999/11/04 03:53:26 steve Exp $" +#ident "$Id: t-xnf.cc,v 1.12 1999/11/05 04:40:40 steve Exp $" #endif /* XNF BACKEND @@ -71,9 +71,11 @@ class target_xnf : public target_t { void end_design(ostream&os, const Design*); void signal(ostream&os, const NetNet*); + void lpm_add_sub(ostream&os, const NetAddSub*); void lpm_ff(ostream&os, const NetFF*); void lpm_mux(ostream&os, const NetMux*); + void net_const(ostream&os, const NetConst*); void logic(ostream&os, const NetLogic*); void bufz(ostream&os, const NetBUFZ*); void udp(ostream&os, const NetUDP*); @@ -259,6 +261,142 @@ void target_xnf::signal(ostream&os, const NetNet*net) << ", " << num << endl; } +/* + * This function makes an adder out of carry logic symbols. It makes + * as many 2 bit adders as are possible, then the top bit is made into + * a 1-bit adder (with carry in) in the F unit. The low carry is + * initialized with the FORCE-0 configuration of a carry unit below + * the 0 bit. This takes up the carry logic of the CLB below, but not + * the G function. + * + * References: + * XNF 6.1 Specification + * Application note XAPP 013 + */ +void target_xnf::lpm_add_sub(ostream&os, const NetAddSub*gate) +{ + // Keep people from thinking this really works. + //assert(0); + unsigned width = gate->width(); + + string name = mangle(gate->name()); + + /* Make the force-0 cary mode object to initialize the bottom + bits of the carry chain. Label this with the width instead + of the bit position so that symbols dont clash. */ + os << "SYM, " << name << name << "<" << width << ">, CY4, " + "LIBVER=2.0.0" << endl; + os << " PIN, COUT, O, " << name << "/COUT<0>" << endl; + for (unsigned cn = 0 ; cn < 8 ; cn += 1) { + os << " PIN, C" << cn << ", I, " << name << "/C" + << cn << "<" << width << ">" << endl; + } + os << "END" << endl; + + os << "SYM, " << name << "/C<" << width << ">, CY4_37, " + "CYMODE=FORCE-0" << endl; + for (unsigned cn = 0 ; cn < 8 ; cn += 1) { + os << " PIN, C" << cn << ", O, " << name << "/C" + << cn << "<" << width << ">" << endl; + } + os << "END" << endl; + + /* Now make the 2 bit adders that chain from the cin + initializer and up. Safe the tail bit (if there is one) for + later. */ + for (unsigned idx = 0 ; idx < (width&~1) ; idx += 2) { + os << "SYM, " << name << "<" << idx << ">, CY4, " + "LIBVER=2.0.0" << endl; + + draw_pin(os, "A0", gate->pin_DataA(idx+0)); + draw_pin(os, "B0", gate->pin_DataB(idx+0)); + draw_pin(os, "A1", gate->pin_DataA(idx+1)); + draw_pin(os, "B1", gate->pin_DataB(idx+1)); + + // Connect the Cout to the next Cin + if ((idx+2) < width) + os << " PIN, COUT, O, " << name << "/COUT<" << + (idx+1) << ">" << endl; + + // Connect the Cin to the previous Cout + if (idx > 0) + os << " PIN, CIN, I, " << name << "/COUT<" << + (idx-1) << ">" << endl; + else + os << " PIN, CIN, I, " << name << "/COUT<" << + (width) << ">" << endl; + + + for (unsigned cn = 0 ; cn < 8 ; cn += 1) { + os << " PIN, C" << cn << ", I, " << name << "/C" + << cn << "<" << idx << ">" << endl; + } + os << "END" << endl; + + os << "SYM, " << name << "/C<" << idx << ">, "; + os << "CY4_02, CYMODE=ADD-FG-CI" << endl; + for (unsigned cn = 0 ; cn < 8 ; cn += 1) { + os << " PIN, C" << cn << ", O, " << name << "/C" + << cn << "<" << idx << ">" << endl; + } + os << "END" << endl; + } + + /* If there is a tail bit, draw it as a single bit adder that + takes its carry in from the previously drawn adder. */ + if (width%2) { + os << "SYM, " << name << "<" << (width-1) << ">, CY4, " + "LIBVER=2.0.0" << endl; + + draw_pin(os, "A0", gate->pin_DataA(width-1)); + draw_pin(os, "B0", gate->pin_DataB(width-1)); + + if (width > 2) + os << " PIN, CIN, I, " << name << "/COUT<" << + (width-2) << ">" << endl; + + + for (unsigned cn = 0 ; cn < 8 ; cn += 1) { + os << " PIN, C" << cn << ", I, " << name << "/C" + << cn << "<" << (width-1) << ">" << endl; + } + os << "END" << endl; + + os << "SYM, " << name << "/C<" << (width-1) << ">, "; + os << "CY4_01, CYMODE=ADD-F-CI" << endl; + for (unsigned cn = 0 ; cn < 8 ; cn += 1) { + os << " PIN, C" << cn << ", O, " << name << "/C" + << cn << "<" << (width-1) << ">" << endl; + } + os << "END" << endl; + } + +#if 0 + for (unsigned idx = 0 ; idx < width ; idx += 1) { + + os << "SYM, " << name << "/C<" << idx << ">, CY4, LIBVER=2.0.0" << endl; + + draw_pin(os, "A0", gate->pin_DataA(idx)); + draw_pin(os, "B0", gate->pin_DataB(idx)); + // if (idx==0) draw_pin(os, "CIN", gate->pin_Cin()); + os << " PIN, CIN, I, " << name << "/CY<" << idx << ">" << endl; + // if (idx+1==width) draw_pin(os, "COUT", gate->pin_Cout()); + os << " PIN, COUT, I, " << name << "/CY<" << idx+1 << ">" << endl; + os << "END" << endl; + + os << "SYM, " << name << "/X<" << idx << ">, XOR, LIBVER=2.0.0" << endl; + + draw_pin(os, "O", gate->pin_Result(idx)); + draw_pin(os, "I0", gate->pin_DataA(idx)); + draw_pin(os, "I1", gate->pin_DataB(idx)); + // if (idx==0) draw_pin(os, "CIN", gate->pin_Cin()); + os << " PIN, I2, I, " << name << "/CY<" << idx << ">" << endl; + os << "END" << endl; + } + os << "PWR, 0, " << name << "/CY<0>" << endl; +#endif +} + void target_xnf::lpm_ff(ostream&os, const NetFF*net) { string type = net->attribute("LPM_FFType"); @@ -315,6 +453,28 @@ void target_xnf::lpm_mux(ostream&os, const NetMux*net) } +void target_xnf::net_const(ostream&os, const NetConst*c) +{ + verinum::V v=c->value(); + assert(v==verinum::V0 || v==verinum::V1); + const NetObj::Link& lnk = c->pin(0); + // Code parallels draw_pin above, some smart c++ guru should + // find a way to make a method out of this. + unsigned cpin; + const NetObj*cur; + for (lnk.next_link(cur, cpin) + ; cur->pin(cpin) != lnk + ; cur->pin(cpin).next_link(cur, cpin)) { + + const NetNet*sig = dynamic_cast(cur); + if (sig) { + os << "PWR, " << v << ", " << mangle(sig->name()); + if (sig->pin_count() > 1) + os << "<" << cpin << ">"; + os << endl; + } + } +} /* * The logic gates I know so far can be translated directly into XNF @@ -411,6 +571,15 @@ extern const struct target tgt_xnf = { "xnf", &target_xnf_obj }; /* * $Log: t-xnf.cc,v $ + * Revision 1.12 1999/11/05 04:40:40 steve + * Patch to synthesize LPM_ADD_SUB from expressions, + * Thanks to Larry Doolittle. Also handle constants + * in expressions. + * + * Synthesize adders in XNF, based on a patch from + * Larry. Accept synthesis of constants from Larry + * as is. + * * Revision 1.11 1999/11/04 03:53:26 steve * Patch to synthesize unary ~ and the ternary operator. * Thanks to Larry Doolittle .