diff --git a/eval.cc b/eval.cc index d89073ba1..a8d5572f4 100644 --- a/eval.cc +++ b/eval.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: eval.cc,v 1.34 2003/03/26 06:16:18 steve Exp $" +#ident "$Id: eval.cc,v 1.35 2003/04/14 03:40:21 steve Exp $" #endif # include "config.h" @@ -47,9 +47,7 @@ verinum* PEBinary::eval_const(const Design*des, const NetScope*scope) const switch (op_) { case '+': { if (l->is_defined() && r->is_defined()) { - long lv = l->as_long(); - long rv = r->as_long(); - res = new verinum(lv+rv, l->len()); + res = new verinum(*l + *r); } else { res = new verinum(verinum::Vx, l->len()); } @@ -57,9 +55,7 @@ verinum* PEBinary::eval_const(const Design*des, const NetScope*scope) const } case '-': { if (l->is_defined() && r->is_defined()) { - long lv = l->as_long(); - long rv = r->as_long(); - res = new verinum(lv-rv, l->len()); + res = new verinum(*l - *r); } else { res = new verinum(verinum::Vx, l->len()); } @@ -67,9 +63,7 @@ verinum* PEBinary::eval_const(const Design*des, const NetScope*scope) const } case '*': { if (l->is_defined() && r->is_defined()) { - long lv = l->as_long(); - long rv = r->as_long(); - res = new verinum(lv * rv, l->len()); + res = new verinum(*l * *r); } else { res = new verinum(verinum::Vx, l->len()); } @@ -247,6 +241,10 @@ verinum* PEUnary::eval_const(const Design*des, const NetScope*scope) const /* * $Log: eval.cc,v $ + * Revision 1.35 2003/04/14 03:40:21 steve + * Make some effort to preserve bits while + * operating on constant values. + * * Revision 1.34 2003/03/26 06:16:18 steve * Evaluate > and < in constant expressions. * diff --git a/eval_tree.cc b/eval_tree.cc index bbc845651..c2cc05ef8 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 */ #ifdef HAVE_CVS_IDENT -#ident "$Id: eval_tree.cc,v 1.49 2003/03/15 18:07:58 steve Exp $" +#ident "$Id: eval_tree.cc,v 1.50 2003/04/14 03:40:21 steve Exp $" #endif # include "config.h" @@ -706,19 +706,26 @@ NetEConst* NetEBShift::eval_tree() verinum rv = re->value(); verinum lv = le->value(); - /* Calculate the width of the result. If it is not fixed, then - get it from the left operand. */ + /* Make an early estimate of the expression width. */ unsigned wid = expr_width(); - if (wid == 0) - wid = left_->expr_width(); if (rv.is_defined()) { unsigned shift = rv.as_ulong(); + if ((wid == 0) || ! lv.has_len()) { + /* If the caller doesn't care what the width is, + then calcuate a width from the trimmed left + expression, plus the shift. This avoids + data loss. */ + lv = trim_vnum(lv); + wid = lv.len(); + if (op() == 'l') + wid = lv.len() + shift; + } assert(wid); - verinum nv (verinum::V0, wid); + verinum nv (verinum::V0, wid, lv.has_len()); if (op() == 'r') { unsigned cnt = wid; @@ -747,7 +754,9 @@ NetEConst* NetEBShift::eval_tree() res = new NetEConst(nv); } else { - assert(wid); + if (wid == 0) + wid = left_->expr_width(); + verinum nv (verinum::Vx, wid); res = new NetEConst(nv); } @@ -1242,6 +1251,10 @@ NetEConst* NetEUReduce::eval_tree() /* * $Log: eval_tree.cc,v $ + * Revision 1.50 2003/04/14 03:40:21 steve + * Make some effort to preserve bits while + * operating on constant values. + * * Revision 1.49 2003/03/15 18:07:58 steve * More resilient WRT right expression width of GT. * diff --git a/ieee1364-notes.txt b/ieee1364-notes.txt index 8af00b8bf..9306deb02 100644 --- a/ieee1364-notes.txt +++ b/ieee1364-notes.txt @@ -203,6 +203,34 @@ interpreted as a loop head, and this is what Icarus Verilog does, as well as all the other major Verilog tools, but the standard does not say this. +* UNSIZED NUMERIC CONSTANTS ARE NOT LIMITED TO 32 BITS + +The Verilog standard allows Verilog implementations to limit the size +of unsized constants to a bit width of at least 32. That means that a +constant 17179869183 (36'h3_ffff_ffff) may overflow some compilers. In +fact, it is common to limit these values to 32bits. However, a +compiler may just as easily choose another width limit, for example +64bits. That value is equally good. + +However, it is not *required* that an implementation truncate at 32 +bits, and in fact Icarus Verilog does not truncate at all. It will +make the unsized constant as big as it needs to be to hold the value +accurately. This is especially useful in situations like this; + + reg [width-1:0] foo = 17179869183; + +The programmer wants the constant to take on the width of the reg, +which in this example is parameterized. Since constant sizes cannot be +parameterized, the programmer ideally gives an unsized constant, which +the compiler then expands/contracts to match the l-value. + +Also, by choosing to not ever truncate, Icarus Verilog can handle code +written for a 64bit compiler as easily as for a 32bit compiler. In +particular, any constants that the user does not expect to be +arbitrarily truncated by his compiler will also not be truncated by +Icarus Verilog, no matter what that other compiler chooses as a +truncation point. + * UNSIZED EXPRESSIONS AS PARAMETERS TO CONCATENATION {} @@ -470,8 +498,12 @@ of 4-value behavior in the dead zone, and appears more user friendly when viewed by reasonable viewers. -$Id: ieee1364-notes.txt,v 1.15 2003/02/16 23:39:08 steve Exp $ +$Id: ieee1364-notes.txt,v 1.16 2003/04/14 03:40:21 steve Exp $ $Log: ieee1364-notes.txt,v $ +Revision 1.16 2003/04/14 03:40:21 steve + Make some effort to preserve bits while + operating on constant values. + Revision 1.15 2003/02/16 23:39:08 steve NaN in dead zones of VCD dumps. diff --git a/verinum.cc b/verinum.cc index 19e7b6ab5..7bee22ac1 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.38 2003/04/03 04:30:00 steve Exp $" +#ident "$Id: verinum.cc,v 1.39 2003/04/14 03:40:21 steve Exp $" #endif # include "config.h" @@ -309,7 +309,7 @@ bool verinum::is_zero() const * If the input value has a definite length, then that value is just * returned as is. */ -static verinum trim_vnum(const verinum&that) +verinum trim_vnum(const verinum&that) { unsigned tlen; @@ -409,7 +409,7 @@ ostream& operator<< (ostream&o, const verinum&v) out as a decimal number. */ if (v.is_defined()) { if (v.has_sign()) - o << "'sd" << v.as_ulong(); + o << "'sd" << v.as_long(); else o << "'d" << v.as_ulong(); return o; @@ -571,8 +571,10 @@ verinum v_not(const verinum&left) /* * Addition works a bit at a time, from the least significant up to - * the most significant. The result is signed only if either of the - * operands is signed. + * the most significant. The result is signed only if both of the + * operands are signed. The result is also expanded as needed to + * prevent overflow. It is up to the caller to shrink the result back + * down if that is the desire. */ verinum operator + (const verinum&left, const verinum&right) { @@ -582,21 +584,38 @@ verinum operator + (const verinum&left, const verinum&right) unsigned max = left.len(); if (right.len() > max) max = right.len(); - verinum val (verinum::V0, max); - val.has_sign( left.has_sign() || right.has_sign() ); + bool signed_flag = left.has_sign() && right.has_sign(); + verinum::V*val_bits = new verinum::V[max+1]; verinum::V carry = verinum::V0; 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); + + verinum::V rpad = signed_flag? right[right.len()-1] : verinum::V0; + verinum::V lpad = signed_flag? left[left.len()-1] : verinum::V0; if (left.len() > right.len()) { - for (unsigned idx = min ; idx < max ; idx += 1) - val.set(idx,add_with_carry(left[idx], verinum::V0, carry)); + + 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 < max ; idx += 1) - val.set(idx, add_with_carry(verinum::V0, right[idx], carry)); + + 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; + return val; } @@ -826,6 +845,10 @@ verinum::V operator & (verinum::V l, verinum::V r) /* * $Log: verinum.cc,v $ + * Revision 1.39 2003/04/14 03:40:21 steve + * Make some effort to preserve bits while + * operating on constant values. + * * Revision 1.38 2003/04/03 04:30:00 steve * Prevent overrun comparing verinums to zero. * @@ -872,47 +895,5 @@ verinum::V operator & (verinum::V l, verinum::V r) * * Revision 1.24 2001/02/07 21:47:13 steve * Fix expression widths for rvalues and parameters (PR#131,132) - * - * Revision 1.23 2001/02/07 02:46:31 steve - * Support constant evaluation of / and % (PR#124) - * - * Revision 1.22 2001/01/02 03:23:40 steve - * Evaluate constant &, | and unary ~. - * - * Revision 1.21 2000/12/10 22:01:36 steve - * Support decimal constants in behavioral delays. - * - * Revision 1.20 2000/09/28 03:55:55 steve - * handel, by truncation, verinums that are to long for long integers. - * - * Revision 1.19 2000/09/27 18:28:37 steve - * multiply in parameter expressions. - * - * Revision 1.18 2000/09/07 22:37:10 steve - * The + operator now preserves signedness. - * - * Revision 1.17 2000/06/12 03:56:51 steve - * Fix subract of short value form long one. - * - * Revision 1.16 2000/02/23 04:43:43 steve - * Some compilers do not accept the not symbol. - * - * Revision 1.15 2000/02/23 02:56:56 steve - * Macintosh compilers do not support ident. - * - * Revision 1.14 2000/01/07 03:45:49 steve - * Initial support for signed constants. - * - * Revision 1.13 2000/01/06 05:57:06 steve - * Only sign-extend unsized numbers. - * - * Revision 1.12 1999/11/06 16:00:17 steve - * Put number constants into a static table. - * - * Revision 1.11 1999/10/22 23:57:53 steve - * do the <= in bits, not numbers. - * - * Revision 1.10 1999/10/10 23:29:37 steve - * Support evaluating + operator at compile time. */ diff --git a/verinum.h b/verinum.h index 5c40c9036..a6c58100d 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.23 2003/04/03 04:30:00 steve Exp $" +#ident "$Id: verinum.h,v 1.24 2003/04/14 03:40:21 steve Exp $" #endif # include @@ -103,6 +103,9 @@ class verinum { bool string_flag_; }; +/* Return a verinum that is minimal. That is, it has only the length + needed to accurately represent the contained value, signed or not. */ +extern verinum trim_vnum(const verinum&); extern ostream& operator<< (ostream&, const verinum&); extern ostream& operator<< (ostream&, verinum::V); @@ -113,11 +116,6 @@ extern verinum::V operator & (verinum::V l, verinum::V r); extern verinum::V operator == (const verinum&left, const verinum&right); extern verinum::V operator <= (const verinum&left, const verinum&right); extern verinum::V operator < (const verinum&left, const verinum&right); -extern verinum operator + (const verinum&left, const verinum&right); -extern verinum operator - (const verinum&left, const verinum&right); -extern verinum operator * (const verinum&left, const verinum&right); -extern verinum operator / (const verinum&left, const verinum&right); -extern verinum operator % (const verinum&left, const verinum&right); inline verinum::V operator > (const verinum&left, const verinum&right) { return right < left; } @@ -128,10 +126,27 @@ inline verinum::V operator >= (const verinum&left, const verinum&right) inline verinum::V operator != (const verinum&left, const verinum&right) { return (left == right)? verinum::V0 : verinum::V1; } + +/* These are arithmetic operators. These generally work to produce + results that do not overflow. That means the result may expand or + contract to hold the bits needed to hold the operation results + accurately. It is up to the caller to truncate or pad if a specific + width is expected. */ +extern verinum operator + (const verinum&left, const verinum&right); +extern verinum operator - (const verinum&left, const verinum&right); +extern verinum operator * (const verinum&left, const verinum&right); +extern verinum operator / (const verinum&left, const verinum&right); +extern verinum operator % (const verinum&left, const verinum&right); + +/* Bitwise not returns the ones complement. */ extern verinum v_not(const verinum&left); /* * $Log: verinum.h,v $ + * Revision 1.24 2003/04/14 03:40:21 steve + * Make some effort to preserve bits while + * operating on constant values. + * * Revision 1.23 2003/04/03 04:30:00 steve * Prevent overrun comparing verinums to zero. *