From aa8908c52f2ddcb0ee4d209eabaa38a82a922a67 Mon Sep 17 00:00:00 2001 From: steve Date: Thu, 13 Jan 2000 03:35:35 +0000 Subject: [PATCH] Multiplication all the way to simulation. --- PExpr.h | 10 +++- design_dump.cc | 15 ++++- elab_expr.cc | 10 +++- elab_net.cc | 67 ++++++++++++++++++----- emit.cc | 10 +++- eval_tree.cc | 11 +++- functor.cc | 14 ++++- functor.h | 8 ++- netlist.cc | 142 +++++++++++++++++++++++++++++++++++++++++++++++- netlist.h | 72 +++++++++++++++++++++++- set_width.cc | 15 ++++- t-vvm.cc | 35 +++++++++++- target.cc | 11 +++- target.h | 6 +- vvm/Makefile.in | 6 +- vvm/vvm_func.h | 23 +++++++- vvm/vvm_gates.h | 35 +++++++++++- vvm/vvm_mult.cc | 114 ++++++++++++++++++++++++++++++++++++++ 18 files changed, 570 insertions(+), 34 deletions(-) create mode 100644 vvm/vvm_mult.cc diff --git a/PExpr.h b/PExpr.h index fd0d45715..bb96e81c0 100644 --- a/PExpr.h +++ b/PExpr.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: PExpr.h,v 1.26 1999/12/16 03:46:39 steve Exp $" +#ident "$Id: PExpr.h,v 1.27 2000/01/13 03:35:35 steve Exp $" #endif # include @@ -264,6 +264,11 @@ class PEBinary : public PExpr { unsigned long rise, unsigned long fall, unsigned long decay) const; + NetNet* elaborate_net_mul_(Design*des, const string&path, + unsigned lwidth, + unsigned long rise, + unsigned long fall, + unsigned long decay) const; NetNet* elaborate_net_shift_(Design*des, const string&path, unsigned lwidth, unsigned long rise, @@ -318,6 +323,9 @@ class PECallFunction : public PExpr { /* * $Log: PExpr.h,v $ + * Revision 1.27 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.26 1999/12/16 03:46:39 steve * Structural logical or. * diff --git a/design_dump.cc b/design_dump.cc index cb7ba8a69..21c13b345 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.65 2000/01/10 01:35:23 steve Exp $" +#ident "$Id: design_dump.cc,v 1.66 2000/01/13 03:35:35 steve Exp $" #endif /* @@ -142,8 +142,14 @@ void NetCLShift::dump_node(ostream&o, unsigned ind) const void NetCompare::dump_node(ostream&o, unsigned ind) const { - o << setw(ind) << "" << "LPM_COMPARE (NetCompare): " << - name() << endl; + o << setw(ind) << "" << "LPM_COMPARE (NetCompare): " << name() << endl; + dump_node_pins(o, ind+4); + dump_obj_attr(o, ind+4); +} + +void NetMult::dump_node(ostream&o, unsigned ind) const +{ + o << setw(ind) << "" << "LPM_MULT (NetMult): " << name() << endl; dump_node_pins(o, ind+4); dump_obj_attr(o, ind+4); } @@ -865,6 +871,9 @@ void Design::dump(ostream&o) const /* * $Log: design_dump.cc,v $ + * Revision 1.66 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.65 2000/01/10 01:35:23 steve * Elaborate parameters afer binding of overrides. * diff --git a/elab_expr.cc b/elab_expr.cc index d88524cac..338588a91 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: elab_expr.cc,v 1.14 2000/01/01 06:18:00 steve Exp $" +#ident "$Id: elab_expr.cc,v 1.15 2000/01/13 03:35:35 steve Exp $" #endif @@ -68,6 +68,11 @@ NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const tmp->set_line(*this); break; + case '*': + tmp = new NetEBMult(op_, lp, rp); + tmp->set_line(*this); + break; + case 'l': case 'r': tmp = new NetEBShift(op_, lp, rp); @@ -373,6 +378,9 @@ NetExpr*PETernary::elaborate_expr(Design*des, const string&path) const /* * $Log: elab_expr.cc,v $ + * Revision 1.15 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.14 2000/01/01 06:18:00 steve * Handle synthesis of concatenation. * diff --git a/elab_net.cc b/elab_net.cc index c73151f7e..5f0508e28 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: elab_net.cc,v 1.18 2000/01/11 04:20:57 steve Exp $" +#ident "$Id: elab_net.cc,v 1.19 2000/01/13 03:35:35 steve Exp $" #endif # include "PExpr.h" @@ -35,6 +35,10 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path, unsigned long decay) const { switch (op_) { + case '*': + //case '/': + //case '%': + return elaborate_net_mul_(des, path, width, rise, fall, decay); case '+': case '-': return elaborate_net_add_(des, path, width, rise, fall, decay); @@ -272,18 +276,6 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, const string&path, return 0; } -#if 0 - if (lsig->pin_count() != rsig->pin_count()) { - cerr << get_line() << ": internal error: Cannot match " - "structural net widths " << lsig->pin_count() << - " and " << rsig->pin_count() << "." << endl; - delete lsig; - delete rsig; - des->errors += 1; - return 0; - } -#endif - unsigned dwidth = lsig->pin_count(); if (rsig->pin_count() > dwidth) dwidth = rsig->pin_count(); @@ -508,6 +500,52 @@ NetNet* PEBinary::elaborate_net_log_(Design*des, const string&path, return osig; } +NetNet* PEBinary::elaborate_net_mul_(Design*des, const string&path, + unsigned lwidth, + unsigned long rise, + unsigned long fall, + unsigned long decay) const +{ + NetNet*lsig = left_->elaborate_net(des, path, 0, 0, 0, 0); + if (lsig == 0) return 0; + NetNet*rsig = right_->elaborate_net(des, path, 0, 0, 0, 0); + if (rsig == 0) return 0; + + unsigned rwidth = lsig->pin_count() + rsig->pin_count(); + NetMult*mult = new NetMult(des->local_symbol(path), rwidth, + lsig->pin_count(), + rsig->pin_count()); + des->add_node(mult); + + for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) + connect(mult->pin_DataA(idx), lsig->pin(idx)); + for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1) + connect(mult->pin_DataB(idx), rsig->pin(idx)); + + if (lwidth == 0) lwidth = rwidth; + NetNet*osig = new NetNet(0, des->local_symbol(path), + NetNet::IMPLICIT, lwidth); + osig->local_flag(true); + des->add_signal(osig); + + unsigned cnt = osig->pin_count(); + if (cnt > rwidth) cnt = rwidth; + + for (unsigned idx = 0 ; idx < cnt ; idx += 1) + connect(mult->pin_Result(idx), osig->pin(idx)); + + /* If the lvalue is larger then the result, then pad the + output with constant 0. */ + if (cnt < osig->pin_count()) { + NetConst*tmp = new NetConst(des->local_symbol(path), verinum::V0); + des->add_node(tmp); + for (unsigned idx = cnt ; idx < osig->pin_count() ; idx += 1) + connect(osig->pin(idx), tmp->pin(0)); + } + + return osig; +} + NetNet* PEBinary::elaborate_net_shift_(Design*des, const string&path, unsigned lwidth, unsigned long rise, @@ -1224,6 +1262,9 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path, /* * $Log: elab_net.cc,v $ + * Revision 1.19 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.18 2000/01/11 04:20:57 steve * Elaborate net widths of constants to as small * as is possible, obeying context constraints. diff --git a/emit.cc b/emit.cc index 8d093d6ad..a61fe191a 100644 --- a/emit.cc +++ b/emit.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: emit.cc,v 1.31 1999/11/28 23:42:02 steve Exp $" +#ident "$Id: emit.cc,v 1.32 2000/01/13 03:35:35 steve Exp $" #endif /* @@ -85,6 +85,11 @@ void NetFF::emit_node(ostream&o, struct target_t*tgt) const tgt->lpm_ff(o, this); } +void NetMult::emit_node(ostream&o, struct target_t*tgt) const +{ + tgt->lpm_mult(o, this); +} + void NetMux::emit_node(ostream&o, struct target_t*tgt) const { tgt->lpm_mux(o, this); @@ -389,6 +394,9 @@ bool emit(ostream&o, const Design*des, const char*type) /* * $Log: emit.cc,v $ + * Revision 1.32 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.31 1999/11/28 23:42:02 steve * NetESignal object no longer need to be NetNode * objects. Let them keep a pointer to NetNet objects. diff --git a/eval_tree.cc b/eval_tree.cc index 1cb9426b3..e870e0ee5 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: eval_tree.cc,v 1.6 1999/10/22 23:57:53 steve Exp $" +#ident "$Id: eval_tree.cc,v 1.7 2000/01/13 03:35:35 steve Exp $" #endif # include "netlist.h" @@ -138,6 +138,12 @@ NetEConst* NetEBLogic::eval_tree() return 0; } +NetEConst* NetEBMult::eval_tree() +{ + eval_sub_tree_(); + return 0; +} + /* * Evaluate the shift operator if possible. For this to work, both * operands must be constant. @@ -262,6 +268,9 @@ NetExpr* NetEParam::eval_tree() /* * $Log: eval_tree.cc,v $ + * Revision 1.7 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.6 1999/10/22 23:57:53 steve * do the <= in bits, not numbers. * diff --git a/functor.cc b/functor.cc index ee5f56b53..1465091ad 100644 --- a/functor.cc +++ b/functor.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: functor.cc,v 1.9 2000/01/02 17:57:20 steve Exp $" +#ident "$Id: functor.cc,v 1.10 2000/01/13 03:35:35 steve Exp $" #endif # include "functor.h" @@ -51,6 +51,10 @@ void functor_t::lpm_logic(class Design*, class NetLogic*) { } +void functor_t::lpm_mult(class Design*, class NetMult*) +{ +} + void Design::functor(functor_t*fun) { // apply to signals @@ -107,6 +111,11 @@ void NetLogic::functor_node(Design*des, functor_t*fun) fun->lpm_logic(des, this); } +void NetMult::functor_node(Design*des, functor_t*fun) +{ + fun->lpm_mult(des, this); +} + proc_match_t::~proc_match_t() { } @@ -158,6 +167,9 @@ int NetPEvent::match_proc(proc_match_t*that) /* * $Log: functor.cc,v $ + * Revision 1.10 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.9 2000/01/02 17:57:20 steve * Handle nodes running out during node scan. * diff --git a/functor.h b/functor.h index 1029aff05..ed93b2c5b 100644 --- a/functor.h +++ b/functor.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: functor.h,v 1.6 1999/12/30 04:19:12 steve Exp $" +#ident "$Id: functor.h,v 1.7 2000/01/13 03:35:35 steve Exp $" #endif /* @@ -53,6 +53,9 @@ struct functor_t { /* Handle LPM combinational logic devices. */ virtual void lpm_logic(class Design*des, class NetLogic*); + + /* This method is called for each multiplier. */ + virtual void lpm_mult(class Design*des, class NetMult*); }; struct proc_match_t { @@ -67,6 +70,9 @@ struct proc_match_t { /* * $Log: functor.h,v $ + * Revision 1.7 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.6 1999/12/30 04:19:12 steve * Propogate constant 0 in low bits of adders. * diff --git a/netlist.cc b/netlist.cc index 75d5a6169..d04341f50 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.103 2000/01/10 01:35:24 steve Exp $" +#ident "$Id: netlist.cc,v 1.104 2000/01/13 03:35:35 steve Exp $" #endif # include @@ -932,6 +932,126 @@ const NetObj::Link& NetCompare::pin_DataB(unsigned idx) const return pin(8+width_+idx); } +NetMult::NetMult(const string&n, unsigned wr, unsigned wa, unsigned wb, + unsigned ws) +: NetNode(n, 2+wr+wa+wb+ws), width_r_(wr), width_a_(wa), width_b_(wb), + width_s_(ws) +{ + pin(0).set_dir(NetObj::Link::INPUT); pin(0).set_name("Aclr", 0); + pin(1).set_dir(NetObj::Link::INPUT); pin(1).set_name("Clock", 0); + + + unsigned p = 2; + for (unsigned idx = 0 ; idx < width_r_ ; idx += 1, p += 1) { + pin(p).set_dir(NetObj::Link::OUTPUT); + pin(p).set_name("Result", idx); + } + for (unsigned idx = 0 ; idx < width_a_ ; idx += 1, p += 1) { + pin(p).set_dir(NetObj::Link::INPUT); + pin(p).set_name("DataA", idx); + } + for (unsigned idx = 0 ; idx < width_b_ ; idx += 1, p += 1) { + pin(p).set_dir(NetObj::Link::INPUT); + pin(p).set_name("DataB", idx); + } + for (unsigned idx = 0 ; idx < width_s_ ; idx += 1, p += 1) { + pin(p).set_dir(NetObj::Link::INPUT); + pin(p).set_name("Sum", idx); + } +} + +NetMult::~NetMult() +{ +} + +unsigned NetMult::width_r() const +{ + return width_r_; +} + +unsigned NetMult::width_a() const +{ + return width_a_; +} + +unsigned NetMult::width_b() const +{ + return width_b_; +} + +unsigned NetMult::width_s() const +{ + return width_s_; +} + +NetObj::Link& NetMult::pin_Aclr() +{ + return pin(0); +} + +const NetObj::Link& NetMult::pin_Aclr() const +{ + return pin(0); +} + +NetObj::Link& NetMult::pin_Clock() +{ + return pin(1); +} + +const NetObj::Link& NetMult::pin_Clock() const +{ + return pin(1); +} + +NetObj::Link& NetMult::pin_Result(unsigned idx) +{ + assert(idx < width_r_); + return pin(idx+2); +} + +const NetObj::Link& NetMult::pin_Result(unsigned idx) const +{ + assert(idx < width_r_); + return pin(idx+2); +} + +NetObj::Link& NetMult::pin_DataA(unsigned idx) +{ + assert(idx < width_a_); + return pin(idx+2+width_r_); +} + +const NetObj::Link& NetMult::pin_DataA(unsigned idx) const +{ + assert(idx < width_a_); + return pin(idx+2+width_r_); +} + +NetObj::Link& NetMult::pin_DataB(unsigned idx) +{ + assert(idx < width_b_); + return pin(idx+2+width_r_+width_a_); +} + +const NetObj::Link& NetMult::pin_DataB(unsigned idx) const +{ + assert(idx < width_b_); + return pin(idx+2+width_r_+width_a_); +} + +NetObj::Link& NetMult::pin_Sum(unsigned idx) +{ + assert(idx < width_s_); + return pin(idx+2+width_r_+width_a_+width_b_); +} + +const NetObj::Link& NetMult::pin_Sum(unsigned idx) const +{ + assert(idx < width_s_); + return pin(idx+2+width_r_+width_a_+width_b_); +} + /* * The NetMux class represents an LPM_MUX device. The pinout is assigned * like so: @@ -1798,6 +1918,23 @@ NetEBLogic* NetEBLogic::dup_expr() const return result; } +NetEBMult::NetEBMult(char op, NetExpr*l, NetExpr*r) +: NetEBinary(op, l, r) +{ + expr_width(l->expr_width() + r->expr_width()); +} + +NetEBMult::~NetEBMult() +{ +} + +NetEBMult* NetEBMult::dup_expr() const +{ + NetEBMult*result = new NetEBMult(op_, left_->dup_expr(), + right_->dup_expr()); + return result; +} + NetEBShift::NetEBShift(char op, NetExpr*l, NetExpr*r) : NetEBinary(op, l, r) { @@ -2775,6 +2912,9 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*)) /* * $Log: netlist.cc,v $ + * Revision 1.104 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.103 2000/01/10 01:35:24 steve * Elaborate parameters afer binding of overrides. * diff --git a/netlist.h b/netlist.h index 2e9cda176..bea4907f8 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.107 2000/01/10 01:35:24 steve Exp $" +#ident "$Id: netlist.h,v 1.108 2000/01/13 03:35:35 steve Exp $" #endif /* @@ -487,6 +487,56 @@ class NetMemory { NetRamDq* ram_list_; }; +/* + * This class implements the LPM_MULT component as described in the + * EDIF LPM Version 2 1 0 standard. It is used as a structural + * implementation of the * operator. The device has inputs DataA and + * DataB that can have independent widths, as can the result. If the + * result is smaller then the widths of a and b together, then the + * device drops the least significant bits of the product. + */ +class NetMult : public NetNode { + + public: + NetMult(const string&n, unsigned width, unsigned wa, unsigned wb, + unsigned width_s =0); + ~NetMult(); + + // Get the width of the device bussed inputs. There are these + // parameterized widths: + unsigned width_r() const; // Result + unsigned width_a() const; // DataA + unsigned width_b() const; // DataB + unsigned width_s() const; // Sum (my be 0) + + NetObj::Link& pin_Aclr(); + NetObj::Link& pin_Clock(); + + NetObj::Link& pin_DataA(unsigned idx); + NetObj::Link& pin_DataB(unsigned idx); + NetObj::Link& pin_Result(unsigned idx); + NetObj::Link& pin_Sum(unsigned idx); + + const NetObj::Link& pin_Aclr() const; + const NetObj::Link& pin_Clock() const; + + const NetObj::Link& pin_DataA(unsigned idx) const; + const NetObj::Link& pin_DataB(unsigned idx) const; + const NetObj::Link& pin_Result(unsigned idx) const; + const NetObj::Link& pin_Sum(unsigned idx) const; + + virtual void dump_node(ostream&, unsigned ind) const; + virtual void emit_node(ostream&, struct target_t*) const; + virtual void functor_node(Design*des, functor_t*fun); + + private: + unsigned width_r_; + unsigned width_a_; + unsigned width_b_; + unsigned width_s_; +}; + + /* * This class represents an LPM_MUX device. This device has some * number of Result points (the width of the device) and some number @@ -1583,6 +1633,23 @@ class NetEBLogic : public NetEBinary { }; +/* + * Support the binary multiplication (*) operator. + */ +class NetEBMult : public NetEBinary { + + public: + NetEBMult(char op, NetExpr*l, NetExpr*r); + ~NetEBMult(); + + virtual bool set_width(unsigned w); + virtual NetEBMult* dup_expr() const; + virtual NetEConst* eval_tree(); + + private: +}; + + /* * The binary logical operators are those that return boolean * results. The supported operators are: @@ -2084,6 +2151,9 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.108 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.107 2000/01/10 01:35:24 steve * Elaborate parameters afer binding of overrides. * diff --git a/set_width.cc b/set_width.cc index 5e9a78ece..17f0f3e6d 100644 --- a/set_width.cc +++ b/set_width.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: set_width.cc,v 1.7 2000/01/01 19:56:51 steve Exp $" +#ident "$Id: set_width.cc,v 1.8 2000/01/13 03:35:35 steve Exp $" #endif /* @@ -126,7 +126,6 @@ bool NetEBBits::set_width(unsigned w) */ bool NetEBComp::set_width(unsigned w) { - bool flag = true; return (w == 1); } @@ -139,6 +138,15 @@ bool NetEBLogic::set_width(unsigned w) return (w == 1); } +/* + * There is nothing we can do to the operands of a multiply to make it + * confirm to the requested width. Force the context to pad or truncate. + */ +bool NetEBMult::set_width(unsigned w) +{ + return w == expr_width(); +} + /* * The shift operator allows the shift amount to have its own * natural width. The width of the operator result is the width of the @@ -266,6 +274,9 @@ bool NetEUnary::set_width(unsigned w) /* * $Log: set_width.cc,v $ + * Revision 1.8 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.7 2000/01/01 19:56:51 steve * Properly expand/shrink constants in expressions. * diff --git a/t-vvm.cc b/t-vvm.cc index 92e1385da..1295fa50f 100644 --- a/t-vvm.cc +++ b/t-vvm.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: t-vvm.cc,v 1.94 2000/01/08 03:09:14 steve Exp $" +#ident "$Id: t-vvm.cc,v 1.95 2000/01/13 03:35:35 steve Exp $" #endif # include @@ -64,6 +64,7 @@ class target_vvm : public target_t { virtual void lpm_clshift(ostream&os, const NetCLShift*); virtual void lpm_compare(ostream&os, const NetCompare*); virtual void lpm_ff(ostream&os, const NetFF*); + virtual void lpm_mult(ostream&os, const NetMult*); virtual void lpm_mux(ostream&os, const NetMux*); virtual void lpm_ram_dq(ostream&os, const NetRamDq*); @@ -452,6 +453,18 @@ void vvm_proc_rval::expr_binary(const NetEBinary*expr) os_ << setw(indent_) << "" << result << " = vvm_binop_xor(" << lres << "," << rres << ");" << endl; break; + case '*': + os_ << setw(indent_) << "" << "vvm_binop_mult(" << result + << "," << lres << "," << rres << ");" << endl; + break; + case '/': + os_ << setw(indent_) << "" << result << " = vvm_binop_idiv(" + << lres << "," << rres << ");" << endl; + break; + case '%': + os_ << setw(indent_) << "" << result << " = vvm_binop_imod(" + << lres << "," << rres << ");" << endl; + break; default: cerr << "vvm: Unhandled binary op `" << expr->op() << "': " << *expr << endl; @@ -1017,6 +1030,23 @@ void target_vvm::lpm_ff(ostream&os, const NetFF*gate) } } +void target_vvm::lpm_mult(ostream&os, const NetMult*mul) +{ + string mname = mangle(mul->name()); + os << "static vvm_mult " << mname << "(" << mul->width_r() << + "," << mul->width_a() << "," << mul->width_b() << "," << + mul->width_s() << ");" << endl; + + // Write the output functions for the multiplier device. + for (unsigned idx = 0 ; idx < mul->width_r() ; idx += 1) { + unsigned pin = mul->pin_Result(idx).get_pin(); + string outfun = defn_gate_outputfun_(os, mul, pin); + init_code << " " << mangle(mul->name()) << + ".config_rout(" << idx << ", &" << outfun << ");" << endl; + emit_gate_outputfun_(mul, pin); + } +} + void target_vvm::lpm_mux(ostream&os, const NetMux*mux) { string mname = mangle(mux->name()); @@ -1993,6 +2023,9 @@ extern const struct target tgt_vvm = { }; /* * $Log: t-vvm.cc,v $ + * Revision 1.95 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.94 2000/01/08 03:09:14 steve * Non-blocking memory writes. * diff --git a/target.cc b/target.cc index 0fde1c66b..c7ef5f582 100644 --- a/target.cc +++ b/target.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: target.cc,v 1.28 1999/11/28 23:42:03 steve Exp $" +#ident "$Id: target.cc,v 1.29 2000/01/13 03:35:35 steve Exp $" #endif # include "target.h" @@ -97,6 +97,12 @@ void target_t::lpm_ff(ostream&, const NetFF*) "Unhandled NetFF." << endl; } +void target_t::lpm_mult(ostream&, const NetMult*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled NetMult." << endl; +} + void target_t::lpm_mux(ostream&, const NetMux*) { cerr << "target (" << typeid(*this).name() << "): " @@ -308,6 +314,9 @@ void expr_scan_t::expr_binary(const NetEBinary*ex) /* * $Log: target.cc,v $ + * Revision 1.29 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.28 1999/11/28 23:42:03 steve * NetESignal object no longer need to be NetNode * objects. Let them keep a pointer to NetNet objects. diff --git a/target.h b/target.h index 04f361cbe..25b5c2426 100644 --- a/target.h +++ b/target.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: target.h,v 1.27 1999/11/28 23:42:03 steve Exp $" +#ident "$Id: target.h,v 1.28 2000/01/13 03:35:35 steve Exp $" #endif # include "netlist.h" @@ -74,6 +74,7 @@ struct target_t { virtual void lpm_clshift(ostream&os, const NetCLShift*); virtual void lpm_compare(ostream&os, const NetCompare*); virtual void lpm_ff(ostream&os, const NetFF*); + virtual void lpm_mult(ostream&os, const NetMult*); virtual void lpm_mux(ostream&os, const NetMux*); virtual void lpm_ram_dq(ostream&os, const NetRamDq*); @@ -146,6 +147,9 @@ extern const struct target *target_table[]; /* * $Log: target.h,v $ + * Revision 1.28 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.27 1999/11/28 23:42:03 steve * NetESignal object no longer need to be NetNode * objects. Let them keep a pointer to NetNet objects. diff --git a/vvm/Makefile.in b/vvm/Makefile.in index a37108cac..83cead301 100644 --- a/vvm/Makefile.in +++ b/vvm/Makefile.in @@ -18,7 +18,7 @@ # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # -#ident "$Id: Makefile.in,v 1.15 1999/12/12 19:47:54 steve Exp $" +#ident "$Id: Makefile.in,v 1.16 2000/01/13 03:35:35 steve Exp $" # # SHELL = /bin/sh @@ -58,8 +58,8 @@ all: libvvm.a $(CC) -Wall $(CFLAGS) -MD -c $< -o $*.o mv $*.d dep -O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_gates.o vvm_pevent.o \ -vvm_thread.o vpip.o +O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_gates.o vvm_mult.o \ +vvm_pevent.o vvm_thread.o vpip.o P = vpi_callback.o \ vpi_const.o vpi_iter.o vpi_memory.o vpi_null.o \ diff --git a/vvm/vvm_func.h b/vvm/vvm_func.h index 35eb3bba4..6da4c8d9c 100644 --- a/vvm/vvm_func.h +++ b/vvm/vvm_func.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vvm_func.h,v 1.16 1999/12/02 03:36:01 steve Exp $" +#ident "$Id: vvm_func.h,v 1.17 2000/01/13 03:35:35 steve Exp $" #endif # include "vvm.h" @@ -195,6 +195,24 @@ vvm_bitset_t vvm_binop_minus(const vvm_bitset_t&l, return res; } +/* + * The multiply binary operator takes an A and B parameter and returns + * the result in the vpip_bit_t array. The template form arranges for + * the right parameters to be passed to the extern form. + */ +extern void vvm_binop_mult(vpip_bit_t*res, unsigned nres, + const vpip_bit_t*a, unsigned na, + const vpip_bit_t*b, unsigned nb); + +template +void vvm_binop_mult(vvm_bitset_t&r, + const vvm_bitset_t&a, + const vvm_bitset_t&b) +{ + vvm_binop_mult(r.bits, WR, a.bits, WA, b.bits, WB); +} + + /* * The binary ^ (xor) operator is a bitwise XOR of equal width inputs * to generate the corresponsing output. @@ -608,6 +626,9 @@ vvm_bitset_t vvm_ternary(vpip_bit_t c, const vvm_bitset_t&t, /* * $Log: vvm_func.h,v $ + * Revision 1.17 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.16 1999/12/02 03:36:01 steve * shiftl and shiftr take unsized second parameter. * diff --git a/vvm/vvm_gates.h b/vvm/vvm_gates.h index a2cfb68de..7be245ab2 100644 --- a/vvm/vvm_gates.h +++ b/vvm/vvm_gates.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vvm_gates.h,v 1.34 1999/12/19 20:57:07 steve Exp $" +#ident "$Id: vvm_gates.h,v 1.35 2000/01/13 03:35:35 steve Exp $" #endif # include "vvm.h" @@ -408,6 +408,36 @@ template class vvm_ff { } }; +/* + * This class behaves like a combinational multiplier. The device + * behaves like the LPM_MULT device. + */ +class vvm_mult { + + public: + explicit vvm_mult(unsigned rwid, unsigned awid, + unsigned bwid, unsigned swid); + ~vvm_mult(); + + void init_DataA(unsigned idx, vpip_bit_t val); + void init_DataB(unsigned idx, vpip_bit_t val); + void init_Sum(unsigned idx, vpip_bit_t val); + + void set_DataA(unsigned idx, vpip_bit_t val); + void set_DataB(unsigned idx, vpip_bit_t val); + void set_Sum(unsigned idx, vpip_bit_t val); + + void config_rout(unsigned idx, vvm_out_event::action_t o); + + private: + unsigned rwid_; + unsigned awid_; + unsigned bwid_; + unsigned swid_; + vpip_bit_t*bits_; + vvm_out_event::action_t*out_; +}; + /* * This class supports mux devices. The width is the width of the data * (or bus) path, SIZE is the number of alternative inputs and SELWID @@ -933,6 +963,9 @@ template class vvm_pevent { /* * $Log: vvm_gates.h,v $ + * Revision 1.35 2000/01/13 03:35:35 steve + * Multiplication all the way to simulation. + * * Revision 1.34 1999/12/19 20:57:07 steve * Proper init_ method prototype. * diff --git a/vvm/vvm_mult.cc b/vvm/vvm_mult.cc new file mode 100644 index 000000000..fb88e4338 --- /dev/null +++ b/vvm/vvm_mult.cc @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2000 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: vvm_mult.cc,v 1.1 2000/01/13 03:35:36 steve Exp $" +#endif + +# include "vvm_gates.h" +# include + +void vvm_binop_mult(vpip_bit_t*r, unsigned nr, + const vpip_bit_t*a, unsigned na, + const vpip_bit_t*b, unsigned nb) +{ + assert(nr >= (na+nb)); + + for (unsigned idx = 0 ; idx < nr ; idx += 1) + r[idx] = V0; + + for (unsigned bdx = 0 ; bdx < nb ; bdx += 1) { + unsigned rdx = bdx; + vpip_bit_t c = V0; + for (unsigned idx = 0 ; idx < na ; idx += 1) { + r[rdx] = add_with_carry(r[rdx],a[idx]&b[bdx],c); + rdx += 1; + } + if (rdx < nr) r[rdx] = add_with_carry(r[rdx],c,c); + } +} + +vvm_mult::vvm_mult(unsigned rwid, unsigned awid, + unsigned bwid, unsigned swid) +: rwid_(rwid), awid_(awid), bwid_(bwid), swid_(swid) +{ + bits_ = new vpip_bit_t[rwid_+awid_+bwid_+swid_]; + out_ = new vvm_out_event::action_t[rwid_]; + + for (unsigned idx = 0 ; idx < rwid_+awid_+bwid_+swid_ ; idx += 1) + bits_[idx] = Vx; + + for (unsigned idx = 0 ; idx < rwid_ ; idx += 1) + out_[idx] = 0; +} + +vvm_mult::~vvm_mult() +{ + delete[]bits_; + delete[]out_; +} + +void vvm_mult::config_rout(unsigned idx, vvm_out_event::action_t o) +{ + assert(o); + assert(idx < rwid_); + out_[idx] = o; +} + +void vvm_mult::init_DataA(unsigned idx, vpip_bit_t val) +{ + assert(idx < awid_); + bits_[rwid_+idx] = val; +} + +void vvm_mult::set_DataA(unsigned idx, vpip_bit_t val) +{ + assert(idx < awid_); + bits_[rwid_+idx] = val; + vvm_binop_mult(bits_, rwid_, + bits_+rwid_, awid_, + bits_+rwid_+awid_, bwid_); + for (unsigned idx = 0 ; idx < rwid_ ; idx += 1) + if (out_[idx]) (out_[idx])(bits_[idx]); +} + +void vvm_mult::init_DataB(unsigned idx, vpip_bit_t val) +{ + assert(idx < bwid_); + bits_[rwid_+awid_+idx] = val; +} + +void vvm_mult::set_DataB(unsigned idx, vpip_bit_t val) +{ + assert(idx < bwid_); + bits_[rwid_+awid_+idx] = val; + vvm_binop_mult(bits_, rwid_, + bits_+rwid_, awid_, + bits_+rwid_+awid_, bwid_); + for (unsigned idx = 0 ; idx < rwid_ ; idx += 1) + if (out_[idx]) (out_[idx])(bits_[idx]); +} + + +/* + * $Log: vvm_mult.cc,v $ + * Revision 1.1 2000/01/13 03:35:36 steve + * Multiplication all the way to simulation. + * + */ +