From 53ae1f29c90d80ce0036c85445f3d8c641356b0d Mon Sep 17 00:00:00 2001 From: steve Date: Thu, 1 Jun 2006 03:54:51 +0000 Subject: [PATCH] Fix broken subtraction of small constants. --- elab_expr.cc | 7 +++++- verinum.cc | 66 ++++++++++++++++++++++++++++++++++++---------------- verinum.h | 6 ++++- 3 files changed, 57 insertions(+), 22 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index ec413d8c4..2fab79ade 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 */ #ifdef HAVE_CVS_IDENT -#ident "$Id: elab_expr.cc,v 1.103 2006/04/12 05:05:03 steve Exp $" +#ident "$Id: elab_expr.cc,v 1.104 2006/06/01 03:54:51 steve Exp $" #endif # include "config.h" @@ -1275,6 +1275,8 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, bool) const verinum val = ipc->value(); verinum zero (verinum::V0, val.len()+1, val.has_len()); val = zero - val; + if (ipc->value().has_len()) + val = verinum(val, ipc->value().len()); val.has_sign(true); tmp = new NetEConst(val); delete ip; @@ -1357,6 +1359,9 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, bool) const /* * $Log: elab_expr.cc,v $ + * Revision 1.104 2006/06/01 03:54:51 steve + * Fix broken subtraction of small constants. + * * Revision 1.103 2006/04/12 05:05:03 steve * Use elab_and_eval to evaluate genvar expressions. * diff --git a/verinum.cc b/verinum.cc index 5d554b110..680d084d3 100644 --- a/verinum.cc +++ b/verinum.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: verinum.cc,v 1.44 2005/12/07 04:04:24 steve Exp $" +#ident "$Id: verinum.cc,v 1.45 2006/06/01 03:54:51 steve Exp $" #endif # include "config.h" @@ -612,7 +612,7 @@ verinum operator + (const verinum&left, const verinum&right) val_bits[idx] = add_with_carry(left[idx], right[idx], carry); verinum::V rpad = signed_flag? right[right.len()-1] : verinum::V0; - verinum::V lpad = signed_flag? left[left.len()-1] : verinum::V0; + verinum::V lpad = signed_flag? left[left.len()-1] : verinum::V0; if (left.len() > right.len()) { @@ -639,35 +639,46 @@ verinum operator + (const verinum&left, const verinum&right) return val; } -verinum operator - (const verinum&left, const verinum&r) +verinum operator - (const verinum&left, const verinum&right) { - verinum right; unsigned min = left.len(); - if (r.len() < min) { - right = verinum(verinum::V0, min); - for (unsigned idx = 0 ; idx < r.len() ; idx += 1) - right.set(idx, r[idx]); - - } else { - right = r; - } - - right = v_not(right); + if (right.len() < min) min = right.len(); unsigned max = left.len(); if (right.len() > max) max = right.len(); - verinum val (verinum::V0, max); + bool signed_flag = left.has_sign() && right.has_sign(); + verinum::V*val_bits = new verinum::V[max+1]; verinum::V carry = verinum::V1; for (unsigned idx = 0 ; idx < min ; idx += 1) - val.set(idx, add_with_carry(left[idx], right[idx], carry)); + val_bits[idx] = add_with_carry(left[idx], ~right[idx], carry); - assert(left.len() <= right.len()); - for (unsigned idx = min ; idx < max ; idx += 1) - val.set(idx, add_with_carry(verinum::V0, right[idx], carry)); + verinum::V rpad = signed_flag? ~right[right.len()-1] : verinum::V1; + verinum::V lpad = signed_flag? left[left.len()-1] : verinum::V0; + + if (left.len() > right.len()) { + + for (unsigned idx = min ; idx < left.len() ; idx += 1) + val_bits[idx] = add_with_carry(left[idx], rpad, carry); + + } else { + + for (unsigned idx = min ; idx < right.len() ; idx += 1) + val_bits[idx] = add_with_carry(lpad, ~right[idx], carry); + } + + if (signed_flag) { + val_bits[max] = add_with_carry(lpad, rpad, carry); + if (val_bits[max] != val_bits[max-1]) + max += 1; + } + + verinum val (val_bits, max, false); + val.has_sign(signed_flag); + + delete[]val_bits; - val.has_sign(left.has_sign() && r.has_sign()); return val; } @@ -920,6 +931,18 @@ verinum concat(const verinum&left, const verinum&right) return res; } +verinum::V operator ~ (verinum::V l) +{ + switch (l) { + case verinum::V0: + return verinum::V1; + case verinum::V1: + return verinum::V0; + default: + return verinum::Vx; + } +} + verinum::V operator | (verinum::V l, verinum::V r) { if (l == verinum::V1) @@ -960,6 +983,9 @@ verinum::V operator ^ (verinum::V l, verinum::V r) /* * $Log: verinum.cc,v $ + * Revision 1.45 2006/06/01 03:54:51 steve + * Fix broken subtraction of small constants. + * * Revision 1.44 2005/12/07 04:04:24 steve * Allow constant concat expressions. * diff --git a/verinum.h b/verinum.h index 40e84424e..a8de922fa 100644 --- a/verinum.h +++ b/verinum.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: verinum.h,v 1.28 2005/12/07 04:04:24 steve Exp $" +#ident "$Id: verinum.h,v 1.29 2006/06/01 03:54:51 steve Exp $" #endif # include @@ -112,6 +112,7 @@ extern verinum trim_vnum(const verinum&); extern ostream& operator<< (ostream&, const verinum&); extern ostream& operator<< (ostream&, verinum::V); +extern verinum::V operator ~ (verinum::V l); extern verinum::V operator | (verinum::V l, verinum::V r); extern verinum::V operator & (verinum::V l, verinum::V r); extern verinum::V operator ^ (verinum::V l, verinum::V r); @@ -151,6 +152,9 @@ extern verinum v_not(const verinum&left); /* * $Log: verinum.h,v $ + * Revision 1.29 2006/06/01 03:54:51 steve + * Fix broken subtraction of small constants. + * * Revision 1.28 2005/12/07 04:04:24 steve * Allow constant concat expressions. *