Make some effort to preserve bits while
operating on constant values.
This commit is contained in:
parent
561a268c9c
commit
bab0924d86
18
eval.cc
18
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.
|
||||
*
|
||||
|
|
|
|||
27
eval_tree.cc
27
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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
89
verinum.cc
89
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.
|
||||
*/
|
||||
|
||||
|
|
|
|||
27
verinum.h
27
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 <string>
|
||||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue