From e0ac4893f0dc8d2a08a5dcec5ae51b7709451d45 Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 7 Feb 2014 12:22:53 +0000 Subject: [PATCH 1/9] Fixed homepage link The link was pointing to a page that said: This page has been moved to http://iverilog.icarus.com, you will be forwarded there automatically in 3 seconds. Please update your links. So now it's updated --- README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.txt b/README.txt index da1e70b4f..f47d03f5f 100644 --- a/README.txt +++ b/README.txt @@ -8,7 +8,7 @@ Icarus Verilog is intended to compile ALL of the Verilog HDL as described in the IEEE-1364 standard. Of course, it's not quite there yet. It does currently handle a mix of structural and behavioral constructs. For a view of the current state of Icarus Verilog, see its -home page at . +home page at . Icarus Verilog is not aimed at being a simulator in the traditional sense, but a compiler that generates code employed by back-end From a3450bf8560739caea01dbc72dfb6266d144070e Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Tue, 25 Feb 2014 20:39:21 +0000 Subject: [PATCH 2/9] Fixes for GitHub issues 13 and 15. The verinum arithmetic operators now observe the standard Verilog rules for calculating the result width if all operands are sized. If any operand is unsized, the result is lossless, as before. They also now all observe the standard rules for handling partially undefined operands (if any operand bit is 'x', the entire result is 'x'). I've also added the unary '-' operator, and renamed v_not() to be the unary '~' operator. This has allowed some simplification in other parts of the compiler. --- elab_expr.cc | 13 +- elab_scope.cc | 6 +- eval.cc | 4 +- eval_tree.cc | 36 ++---- parse.y | 4 +- verinum.cc | 349 +++++++++++++++++++++++++++++--------------------- verinum.h | 16 ++- 7 files changed, 236 insertions(+), 192 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index a1e2cf280..836361199 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -5341,13 +5341,8 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, case '-': if (NetEConst*ipc = dynamic_cast(ip)) { - verinum val = ipc->value(); - - /* Calculate unary minus as 0-val */ - verinum zero (verinum::V0, expr_wid); - zero.has_sign(val.has_sign()); - verinum nval = verinum(zero - val, expr_wid); - tmp = new NetEConst(nval); + verinum val = - ipc->value(); + tmp = new NetEConst(val); tmp->cast_signed(signed_flag_); tmp->set_line(*this); delete ip; @@ -5460,7 +5455,7 @@ NetExpr* PEUnary::elaborate_expr_bits_(NetExpr*operand, unsigned expr_wid) const // The only operand that I know can get here is the // unary not (~). ivl_assert(*this, op_ == '~'); - value = v_not(value); + value = ~value; ctmp = new NetEConst(value); ctmp->set_line(*this); diff --git a/elab_scope.cc b/elab_scope.cc index ffc0a31af..1b78ac894 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -193,9 +193,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, verinum min_value (0); verinum max_value (0); if (enum_type->signed_flag) { - min_value = v_not((pow(verinum(2), - verinum(use_enum->packed_width()-1)))) + - one_value; + min_value = -pow(verinum(2), verinum(use_enum->packed_width()-1)); max_value = pow(verinum(2), verinum(use_enum->packed_width()-1)) - one_value; } else { diff --git a/eval.cc b/eval.cc index 996aacd4e..09b2aae89 100644 --- a/eval.cc +++ b/eval.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 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 @@ -261,7 +261,7 @@ verinum* PEUnary::eval_const(Design*des, NetScope*scope) const for (unsigned idx = 0 ; idx < val->len() ; idx += 1) tmp.set(idx, val->get(idx)); - *val = v_not(tmp) + verinum(verinum::V1, 1); + *val = -tmp; val->has_sign(true); return val; } diff --git a/eval_tree.cc b/eval_tree.cc index 8343f8f5b..ac5d24ae4 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 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 @@ -175,11 +175,11 @@ NetExpr* NetEBAdd::eval_tree() if (op_ == se->op_) { /* (a + lval) + rval --> a + (rval+lval) */ /* (a - lval) - rval --> a - (rval+lval) */ - val = verinum(rval + lval, wid); + val = cast_to_width(rval + lval, wid); } else { /* (a - lval) + rval --> a + (rval-lval) */ /* (a + lval) - rval --> a - (rval-lval) */ - val = verinum(rval - lval, wid); + val = cast_to_width(rval - lval, wid); } NetEConst*tmp = new NetEConst(val); @@ -217,10 +217,10 @@ NetExpr* NetEBAdd::eval_arguments_(const NetExpr*l, const NetExpr*r) const verinum val; switch (op_) { case '+': - val = verinum(lval + rval, wid); + val = cast_to_width(lval + rval, wid); break; case '-': - val = verinum(lval - rval, wid); + val = cast_to_width(lval - rval, wid); break; default: return 0; @@ -816,14 +816,15 @@ NetExpr* NetEBDiv::eval_arguments_(const NetExpr*l, const NetExpr*r) const verinum val; switch (op_) { case '/': - val = verinum(lval / rval, wid); + val = cast_to_width(lval / rval, wid); break; case '%': - val = verinum(lval % rval, wid); + val = cast_to_width(lval % rval, wid); break; default: return 0; } + NetExpr*tmp = new NetEConst(val); ivl_assert(*this, tmp); eval_debug(this, tmp, false); @@ -1027,7 +1028,7 @@ NetExpr* NetEBMult::eval_arguments_(const NetExpr*l, const NetExpr*r) const ivl_assert(*this, lval.len() == wid); ivl_assert(*this, rval.len() == wid); - verinum val(lval * rval, wid); + verinum val = cast_to_width(lval * rval, wid); NetEConst*tmp = new NetEConst(val); ivl_assert(*this, tmp); eval_debug(this, tmp, false); @@ -1064,7 +1065,7 @@ NetExpr* NetEBPow::eval_arguments_(const NetExpr*l, const NetExpr*r) const ivl_assert(*this, wid > 0); ivl_assert(*this, lval.len() == wid); - verinum val(pow(lval, rval), wid); + verinum val = cast_to_width(pow(lval, rval), wid); NetEConst*res = new NetEConst(val); ivl_assert(*this, res); eval_debug(this, res, false); @@ -1092,12 +1093,12 @@ NetEConst* NetEBShift::eval_arguments_(const NetExpr*l, const NetExpr*r) const switch (op_) { case 'l': - val = verinum(lv << shift, wid); + val = cast_to_width(lv << shift, wid); break; case 'r': lv.has_sign(false); case 'R': - val = verinum(lv >> shift, wid); + val = cast_to_width(lv >> shift, wid); break; default: return 0; @@ -1446,14 +1447,7 @@ NetExpr* NetEUnary::eval_arguments_(const NetExpr*ex) const break; case '-': - if (val.is_defined()) { - verinum tmp (verinum::V0, val.len()); - tmp.has_sign(val.has_sign()); - val = verinum(tmp - val, val.len()); - } else { - for (unsigned idx = 0 ; idx < val.len() ; idx += 1) - val.set(idx, verinum::Vx); - } + val = -val; break; case 'm': @@ -1461,9 +1455,7 @@ NetExpr* NetEUnary::eval_arguments_(const NetExpr*ex) const for (unsigned idx = 0 ; idx < val.len() ; idx += 1) val.set(idx, verinum::Vx); } else if (val.is_negative()) { - verinum tmp (verinum::V0, val.len()); - tmp.has_sign(val.has_sign()); - val = verinum(tmp - val, val.len()); + val = -val; } break; diff --git a/parse.y b/parse.y index 73327feb6..d9b8f0166 100644 --- a/parse.y +++ b/parse.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -2259,7 +2259,7 @@ pos_neg_number { $$ = $1; } | '-' number - { verinum tmp = v_not(*($2)) + verinum(1); + { verinum tmp = -(*($2)); *($2) = tmp; $$ = $2; } diff --git a/verinum.cc b/verinum.cc index 12c234964..41efb99a4 100644 --- a/verinum.cc +++ b/verinum.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 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 @@ -24,6 +24,7 @@ # include # include // Needed to get pow for as_double(). # include // Needed to get snprintf for as_string(). +# include #if !defined(HAVE_LROUND) /* @@ -200,7 +201,6 @@ verinum::verinum(double val, bool) fraction = frexp(val, &exponent); nbits_ = exponent+1; bits_ = new V[nbits_]; - const verinum const_one(1); /* If the value is small enough just use lround(). */ if (nbits_ <= BITS_IN_LONG) { @@ -230,9 +230,9 @@ verinum::verinum(double val, bool) for (int wd = nwords; wd >= 0; wd -= 1) { unsigned long bits = (unsigned long) fraction; fraction = fraction - (double) bits; - unsigned max = (wd+1)*BITS_IN_LONG; - if (max > nbits_) max = nbits_; - for (unsigned idx = wd*BITS_IN_LONG; idx < max; idx += 1) { + unsigned max_idx = (wd+1)*BITS_IN_LONG; + if (max_idx > nbits_) max_idx = nbits_; + for (unsigned idx = wd*BITS_IN_LONG; idx < max_idx; idx += 1) { bits_[idx] = (bits&1) ? V1 : V0; bits >>= 1; } @@ -242,7 +242,7 @@ verinum::verinum(double val, bool) /* Convert a negative number if needed. */ if (is_neg) { - *this = v_not(*this) + const_one; + *this = -(*this); } /* Trim the result. */ @@ -968,7 +968,7 @@ static verinum::V add_with_carry(verinum::V l, verinum::V r, verinum::V&c) return verinum::V0; } -verinum v_not(const verinum&left) +verinum operator ~ (const verinum&left) { verinum val = left; for (unsigned idx = 0 ; idx < val.len() ; idx += 1) @@ -988,137 +988,190 @@ 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 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. + * Addition and subtraction works a bit at a time, from the least + * significant up to the most significant. The result is signed only + * if both of the operands are signed. If either operand is unsized, + * the result is expanded as needed to prevent overflow. */ + verinum operator + (const verinum&left, const verinum&right) { - unsigned min = left.len(); - if (right.len() < min) min = right.len(); + const bool has_len_flag = left.has_len() && right.has_len(); + const bool signed_flag = left.has_sign() && right.has_sign(); - unsigned max = left.len(); - if (right.len() > max) max = right.len(); + unsigned min_len = min(left.len(), right.len()); + unsigned max_len = max(left.len(), right.len()); - bool signed_flag = left.has_sign() && right.has_sign(); - verinum::V*val_bits = new verinum::V[max+1]; + // If either the left or right values are undefined, the + // entire result is undefined. + if (!left.is_defined() || !right.is_defined()) { + unsigned len = has_len_flag ? max_len : 1; + verinum result (verinum::Vx, len, has_len_flag); + result.has_sign(signed_flag); + return result; + } + + verinum::V*val_bits = new verinum::V[max_len+1]; verinum::V carry = verinum::V0; - for (unsigned idx = 0 ; idx < min ; idx += 1) + for (unsigned idx = 0 ; idx < min_len ; idx += 1) 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 rpad = sign_bit(right); + verinum::V lpad = sign_bit(left); if (left.len() > right.len()) { - for (unsigned idx = min ; idx < left.len() ; idx += 1) + for (unsigned idx = min_len ; idx < max_len ; idx += 1) val_bits[idx] = add_with_carry(left[idx], rpad, carry); } else { - for (unsigned idx = min ; idx < right.len() ; idx += 1) + for (unsigned idx = min_len ; idx < max_len ; idx += 1) val_bits[idx] = add_with_carry(lpad, right[idx], carry); } - val_bits[max] = add_with_carry(lpad, rpad, carry); -#if 0 - if (signed_flag) { - if (val_bits[max] != val_bits[max-1]) - max += 1; + unsigned len = max_len; + if (!has_len_flag) { + val_bits[max_len] = add_with_carry(lpad, rpad, carry); + if (signed_flag) { + if (val_bits[max_len] != val_bits[max_len-1]) len += 1; + } else { + if (val_bits[max_len] != verinum::V0) len += 1; + } } -#endif - verinum val (val_bits, max+1, false); - val.has_sign(signed_flag); + verinum result (val_bits, len, has_len_flag); + result.has_sign(signed_flag); delete[]val_bits; - return val; + return result; } verinum operator - (const verinum&left, const verinum&right) { - unsigned min = left.len(); - if (right.len() < min) min = right.len(); + const bool has_len_flag = left.has_len() && right.has_len(); + const bool signed_flag = left.has_sign() && right.has_sign(); - unsigned max = left.len(); - if (right.len() > max) max = right.len(); + unsigned min_len = min(left.len(), right.len()); + unsigned max_len = max(left.len(), right.len()); - bool signed_flag = left.has_sign() && right.has_sign(); - verinum::V*val_bits = new verinum::V[max+1]; + // If either the left or right values are undefined, the + // entire result is undefined. + if (!left.is_defined() || !right.is_defined()) { + unsigned len = has_len_flag ? max_len : 1; + verinum result (verinum::Vx, len, has_len_flag); + result.has_sign(signed_flag); + return result; + } + + verinum::V*val_bits = new verinum::V[max_len+1]; verinum::V carry = verinum::V1; - for (unsigned idx = 0 ; idx < min ; idx += 1) + for (unsigned idx = 0 ; idx < min_len ; idx += 1) val_bits[idx] = add_with_carry(left[idx], ~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; + verinum::V rpad = sign_bit(right); + verinum::V lpad = sign_bit(left); if (left.len() > right.len()) { - for (unsigned idx = min ; idx < left.len() ; idx += 1) - val_bits[idx] = add_with_carry(left[idx], rpad, carry); + for (unsigned idx = min_len ; idx < max_len ; idx += 1) + val_bits[idx] = add_with_carry(left[idx], ~rpad, carry); } else { - for (unsigned idx = min ; idx < right.len() ; idx += 1) + for (unsigned idx = min_len ; idx < max_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; + unsigned len = max_len; + if (signed_flag && !has_len_flag) { + val_bits[max_len] = add_with_carry(lpad, ~rpad, carry); + if (val_bits[max_len] != val_bits[max_len-1]) len += 1; } - - verinum val (val_bits, max, false); - val.has_sign(signed_flag); + verinum result (val_bits, len, has_len_flag); + result.has_sign(signed_flag); delete[]val_bits; - return val; + return result; +} + +verinum operator - (const verinum&right) +{ + const bool has_len_flag = right.has_len(); + const bool signed_flag = right.has_sign(); + + unsigned len = right.len(); + + // If either the left or right values are undefined, the + // entire result is undefined. + if (!right.is_defined()) { + verinum result (verinum::Vx, has_len_flag ? len : 1, has_len_flag); + result.has_sign(signed_flag); + return result; + } + + verinum::V*val_bits = new verinum::V[len+1]; + + verinum::V carry = verinum::V1; + for (unsigned idx = 0 ; idx < len ; idx += 1) + val_bits[idx] = add_with_carry(verinum::V0, ~right[idx], carry); + + if (signed_flag && !has_len_flag) { + val_bits[len] = add_with_carry(verinum::V0, ~sign_bit(right), carry); + if (val_bits[len] != val_bits[len-1]) len += 1; + } + verinum result (val_bits, len, has_len_flag); + result.has_sign(signed_flag); + + delete[]val_bits; + + return result; } /* - * This multiplies two verinum numbers together into a verinum - * result. The resulting number is as large as the sum of the sizes of - * the operand. + * This operator multiplies the left number by the right number. The + * result is signed only if both of the operands are signed. If either + * operand is unsized, the resulting number is as large as the sum of + * the sizes of the operands. * * The algorithm used is successive shift and add operations, * implemented as the nested loops. - * - * If either value is not completely defined, then the result is not - * defined either. */ verinum operator * (const verinum&left, const verinum&right) { const bool has_len_flag = left.has_len() && right.has_len(); + const bool signed_flag = left.has_sign() && right.has_sign(); - /* If either operand is not fully defined, then the entire - result is undefined. Create a result that is the right size - and is filled with 'bx bits. */ - if (! (left.is_defined() && right.is_defined())) { - verinum result (verinum::Vx, left.len()+right.len(), has_len_flag); - result.has_sign(left.has_sign() || right.has_sign()); + const unsigned l_len = left.len(); + const unsigned r_len = right.len(); + + unsigned len = has_len_flag ? max(l_len, r_len) : l_len + r_len; + + // If either the left or right values are undefined, the + // entire result is undefined. + if (!left.is_defined() || !right.is_defined()) { + verinum result (verinum::Vx, has_len_flag ? len : 1, has_len_flag); + result.has_sign(signed_flag); return result; } - verinum result(verinum::V0, left.len() + right.len(), has_len_flag); - result.has_sign(left.has_sign() || right.has_sign()); + verinum result(verinum::V0, len, has_len_flag); + result.has_sign(signed_flag); verinum::V r_sign = sign_bit(right); - for (unsigned rdx = 0 ; rdx < result.len() ; rdx += 1) { + for (unsigned rdx = 0 ; rdx < len ; rdx += 1) { - verinum::V r_bit = rdx < right.len()? right.get(rdx) : r_sign; + verinum::V r_bit = rdx < r_len ? right.get(rdx) : r_sign; if (r_bit == verinum::V0) continue; verinum::V l_sign = sign_bit(left); verinum::V carry = verinum::V0; - for (unsigned ldx = 0 ; ldx < result.len()-rdx ; ldx += 1) { - verinum::V l_bit = ldx < left.len()? left[ldx] : l_sign; + for (unsigned ldx = 0 ; ldx < (len - rdx) ; ldx += 1) { + verinum::V l_bit = ldx < l_len ? left[ldx] : l_sign; result.set(ldx+rdx, add_with_carry(l_bit, result[rdx+ldx], carry)); @@ -1150,22 +1203,20 @@ static verinum recursive_pow(const verinum&left, verinum&right) return make_p_one(left.len(), left.has_len(), left.has_sign()); } - verinum res; + verinum result; if (right.get(0) == 1) { - // The exponent is odd, so subtract 1 from it and recurse + // The exponent is odd, so subtract 1 from it and recurse. + // We know it's odd, so the subtraction is easy. right.set(0, verinum::V0); - res = pow(left, right); - res = left * res; + result = pow(left, right); + result = left * result; } else { // The exponent is even, so divide it by 2 and recurse right = right >> 1; - res = pow(left, right); - res = res * res; + result = pow(left, right); + result = result * result; } - if (left.has_len()) { - res = verinum(res, left.len()); - } - return res; + return result; } verinum pow(const verinum&left, const verinum&right) @@ -1176,8 +1227,9 @@ verinum pow(const verinum&left, const verinum&right) verinum p_one = make_p_one(left.len(), left.has_len(), left.has_sign()); verinum m_one = make_m_one(left.len(), left.has_len(), left.has_sign()); - // If either the right or left values are undefined we return 'bx. - if (!right.is_defined() || !left.is_defined()) { + // If either the left or right values are undefined, the + // entire result is undefined. + if (!left.is_defined() || !right.is_defined()) { result = verinum(verinum::Vx, left.len(), left.has_len()); result.has_sign(left.has_sign()); @@ -1221,40 +1273,52 @@ verinum pow(const verinum&left, const verinum&right) verinum operator << (const verinum&that, unsigned shift) { - verinum result(verinum::V0, that.len() + shift, that.has_len()); + bool has_len_flag = that.has_len(); + + unsigned len = that.len(); + if (!has_len_flag) len += shift; + + verinum result(verinum::V0, len, has_len_flag); result.has_sign(that.has_sign()); - for (unsigned idx = 0 ; idx < that.len() ; idx += 1) - result.set(idx+shift, that.get(idx)); + for (unsigned idx = shift ; idx < len ; idx += 1) + result.set(idx, that.get(idx - shift)); - return result; + return trim_vnum(result); } verinum operator >> (const verinum&that, unsigned shift) { - if (shift >= that.len()) { - if (that.has_sign()) { - verinum result (that.get(that.len()-1), 1); - result.has_sign(true); - return result; - } else { - verinum result(verinum::V0, 1); - return result; - } + bool has_len_flag = that.has_len(); + + unsigned len = that.len(); + + verinum::V sign_bit = that.has_sign() ? that.get(len-1) : verinum::V0; + + if (shift >= len) { + if (!has_len_flag) len = 1; + verinum result(sign_bit, len, has_len_flag); + result.has_sign(that.has_sign()); + return result; } - verinum result(that.has_sign()? that.get(that.len()-1) : verinum::V0, - that.len() - shift, that.has_len()); + if (!has_len_flag) len -= shift; + verinum result(sign_bit, len, has_len_flag); result.has_sign(that.has_sign()); for (unsigned idx = shift ; idx < that.len() ; idx += 1) result.set(idx-shift, that.get(idx)); - return result; + return trim_vnum(result); } static verinum unsigned_divide(verinum num, verinum den, bool signed_result) { + // We need the following calculations to be lossless. The + // result will be cast to the required width by the caller. + num.has_len(false); + den.has_len(false); + unsigned nwid = num.len(); while (nwid > 0 && (num.get(nwid-1) == verinum::V0)) nwid -= 1; @@ -1289,6 +1353,11 @@ static verinum unsigned_divide(verinum num, verinum den, bool signed_result) static verinum unsigned_modulus(verinum num, verinum den) { + // We need the following calculations to be lossless. The + // result will be cast to the required width by the caller. + num.has_len(false); + den.has_len(false); + unsigned nwid = num.len(); while (nwid > 0 && (num.get(nwid-1) == verinum::V0)) nwid -= 1; @@ -1316,39 +1385,29 @@ static verinum unsigned_modulus(verinum num, verinum den) } /* - * This operator divides the left number by the right number. If - * either value is signed, the result is signed. If both values have a - * defined length, then the result has a defined length. + * This operator divides the left number by the right number. The result + * is signed only if both of the operands are signed. */ verinum operator / (const verinum&left, const verinum&right) { const bool has_len_flag = left.has_len() && right.has_len(); + const bool signed_flag = left.has_sign() && right.has_sign(); unsigned use_len = left.len(); - /* If either operand is not fully defined, then the entire - result is undefined. Create a result that is the right size - and is filled with 'bx bits. */ - if (! (left.is_defined() && right.is_defined())) { + // If either the left or right values are undefined, or the + // right value is zero, the entire result is undefined. + if (!left.is_defined() || !right.is_defined() || right.is_zero()) { verinum result (verinum::Vx, use_len, has_len_flag); - result.has_sign(left.has_sign() || right.has_sign()); - return result; - } - - /* If the right expression is a zero value, then the result is - filled with 'bx bits. */ - if (right.is_zero()) { - verinum result (verinum::Vx, use_len, has_len_flag); - result.has_sign(left.has_sign() || right.has_sign()); + result.has_sign(signed_flag); return result; } verinum result(verinum::Vz, use_len, has_len_flag); - result.has_sign(left.has_sign() || right.has_sign()); /* do the operation differently, depending on whether the result is signed or not. */ - if (result.has_sign()) { + if (signed_flag) { if (use_len <= (8*sizeof(long) - 1)) { long l = left.as_long(); @@ -1361,23 +1420,23 @@ verinum operator / (const verinum&left, const verinum&right) } else { verinum use_left, use_right; - verinum zero(verinum::V0, 1, false); - zero.has_sign(true); bool negative = false; - if (left < zero) { - use_left = zero - left; + if (left.is_negative()) { + use_left = -left; negative = !negative; } else { use_left = left; } - if (right < zero) { - use_right = zero - right; + use_left.has_sign(false); + if (right.is_negative()) { + use_right = -right; negative = !negative; } else { use_right = right; } + use_right.has_sign(false); result = unsigned_divide(use_left, use_right, true); - if (negative) result = zero - result; + if (negative) result = -result; } } else { @@ -1398,36 +1457,31 @@ verinum operator / (const verinum&left, const verinum&right) } } + if (has_len_flag) + result = cast_to_width(result, use_len); + + result.has_sign(signed_flag); return trim_vnum(result); } verinum operator % (const verinum&left, const verinum&right) { const bool has_len_flag = left.has_len() && right.has_len(); + const bool signed_flag = left.has_sign() && right.has_sign(); unsigned use_len = left.len(); - /* If either operand is not fully defined, then the entire - result is undefined. Create a result that is the right size - and is filled with 'bx bits. */ - if (! (left.is_defined() && right.is_defined())) { + // If either the left or right values are undefined, or the + // right value is zero, the entire result is undefined. + if (!left.is_defined() || !right.is_defined() || right.is_zero()) { verinum result (verinum::Vx, use_len, has_len_flag); - result.has_sign(left.has_sign() || right.has_sign()); - return result; - } - - /* If the right expression is a zero value, then the result is - filled with 'bx bits. */ - if (right.as_ulong() == 0) { - verinum result (verinum::Vx, use_len, has_len_flag); - result.has_sign(left.has_sign() || right.has_sign()); + result.has_sign(signed_flag); return result; } verinum result(verinum::Vz, use_len, has_len_flag); - result.has_sign(left.has_sign() || right.has_sign()); - if (result.has_sign()) { + if (signed_flag) { if (use_len <= 8*sizeof(long)) { /* Use native signed modulus to do the work. */ long l = left.as_long(); @@ -1439,23 +1493,22 @@ verinum operator % (const verinum&left, const verinum&right) } } else { verinum use_left, use_right; - verinum zero(verinum::V0, 1, false); - zero.has_sign(true); bool negative = false; - if (left < zero) { - use_left = zero - left; + if (left.is_negative()) { + use_left = -left; negative = true; } else { use_left = left; } - if (right < zero) { - use_right = zero - right; + use_left.has_sign(false); + if (right.is_negative()) { + use_right = -right; } else { use_right = right; } + use_right.has_sign(false); result = unsigned_modulus(use_left, use_right); - result.has_sign(true); - if (negative) result = zero - result; + if (negative) result = -result; } } else { if (use_len <= 8*sizeof(unsigned long)) { @@ -1472,6 +1525,10 @@ verinum operator % (const verinum&left, const verinum&right) } } + if (has_len_flag) + result = cast_to_width(result, use_len); + + result.has_sign(signed_flag); return trim_vnum(result); } diff --git a/verinum.h b/verinum.h index a459e03f6..41df9a90a 100644 --- a/verinum.h +++ b/verinum.h @@ -1,7 +1,7 @@ #ifndef __verinum_H #define __verinum_H /* - * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2014 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 @@ -171,11 +171,13 @@ 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. */ +/* These are arithmetic operators. If any operand is unsized, they + 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. If all operands are sized, + the normal Verilog rules for result size are used. */ +extern verinum operator - (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); @@ -190,6 +192,6 @@ extern verinum operator>> (const verinum&left, unsigned shift); extern verinum concat(const verinum&left, const verinum&right); /* Bitwise not returns the ones complement. */ -extern verinum v_not(const verinum&left); +extern verinum operator ~ (const verinum&left); #endif From 1f81d4c081dddeb9133960c8e0c6ef8c5e4410ab Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Wed, 26 Feb 2014 08:39:33 +0000 Subject: [PATCH 3/9] Fix for br947. When performing the initial assignment for a procedural continuous assignment, any previous continuous assignment to the destination signal must be unlinked first, otherwise the initial value for the assignment will propagate to any other nets that are driven by the original source signal. --- vvp/vthread.cc | 50 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 5b5171b9b..94ded9a43 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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 @@ -1431,7 +1431,7 @@ bool of_BREAKPOINT(vthread_t, vvp_code_t) } /* - * the %cassign/link instruction connects a source node to a + * The %cassign/link instruction connects a source node to a * destination node. The destination node must be a signal, as it is * marked with the source of the cassign so that it may later be * unlinked without specifically knowing the source that this @@ -1446,17 +1446,8 @@ bool of_CASSIGN_LINK(vthread_t, vvp_code_t cp) = dynamic_cast(dst->fun); assert(sig); - /* Detect the special case that we are already continuous - assigning the source onto the destination. */ - if (sig->cassign_link == src) - return true; - - /* If there is an existing cassign driving this node, then - unlink it. We can have only 1 cassign at a time. */ - if (sig->cassign_link != 0) { - vvp_net_ptr_t tmp (dst, 1); - sig->cassign_link->unlink(tmp); - } + /* Any previous continuous assign should have been removed already. */ + assert(sig->cassign_link == 0); sig->cassign_link = src; @@ -1469,7 +1460,27 @@ bool of_CASSIGN_LINK(vthread_t, vvp_code_t cp) } /* - * the %cassign/v instruction invokes a continuous assign of a + * If there is an existing continuous assign linked to the destination + * node, unlink it. This must be done before applying a new continuous + * assign, otherwise the initial assigned value will be propagated to + * any other nodes driven by the old continuous assign source. + */ +static void cassign_unlink(vvp_net_t*dst) +{ + vvp_fun_signal_base*sig + = dynamic_cast(dst->fun); + assert(sig); + + if (sig->cassign_link == 0) + return; + + vvp_net_ptr_t tmp (dst, 1); + sig->cassign_link->unlink(tmp); + sig->cassign_link = 0; +} + +/* + * The %cassign/v instruction invokes a continuous assign of a * constant value to a signal. The instruction arguments are: * * %cassign/v , , ; @@ -1486,10 +1497,13 @@ bool of_CASSIGN_V(vthread_t thr, vvp_code_t cp) unsigned base = cp->bit_idx[0]; unsigned wid = cp->bit_idx[1]; + /* Remove any previous continuous assign to this net. */ + cassign_unlink(net); + /* Collect the thread bits into a vector4 item. */ vvp_vector4_t value = vthread_bits_to_vector(thr, base, wid); - /* set the value into port 1 of the destination. */ + /* Set the value into port 1 of the destination. */ vvp_net_ptr_t ptr (net, 1); vvp_send_vec4(ptr, value, 0); @@ -1501,6 +1515,9 @@ bool of_CASSIGN_WR(vthread_t thr, vvp_code_t cp) vvp_net_t*net = cp->net; double value = thr->pop_real(); + /* Remove any previous continuous assign to this net. */ + cassign_unlink(net); + /* Set the value into port 1 of the destination. */ vvp_net_ptr_t ptr (net, 1); vvp_send_real(ptr, value, 0); @@ -1514,6 +1531,9 @@ bool of_CASSIGN_X0(vthread_t thr, vvp_code_t cp) unsigned base = cp->bit_idx[0]; unsigned wid = cp->bit_idx[1]; + /* Remove any previous continuous assign to this net. */ + cassign_unlink(net); + // Implicitly, we get the base into the target vector from the // X0 register. long index = thr->words[0].w_int; From 5dcd2e89570a7704027f17238ddced9bc710aa28 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Thu, 27 Feb 2014 19:20:20 +0000 Subject: [PATCH 4/9] Added width cap for unsized expressions. Unsized expressions can expand to extremely large widths. Usually this is actually a mistake in the source code, but it can lead to the compiler temporarily using extremely large amounts of memory, or in the worst case, crashing. This adds a cap on the width of unsized expressions (by default 65536 bits, but overridable by the user), and causes a warning message to be output when the cap is reached. --- compiler.h | 7 ++++++- driver/cflexor.lex | 4 +++- driver/cfparse.y | 10 +++++++++- driver/globals.h | 5 ++++- driver/iverilog.man.in | 10 ++++++++-- driver/main.c | 6 +++++- elab_expr.cc | 7 +++---- main.cc | 10 +++++++++- netmisc.cc | 23 ++++++++++++++++------- 9 files changed, 63 insertions(+), 19 deletions(-) diff --git a/compiler.h b/compiler.h index 6e4bf1cdf..63cc509b5 100644 --- a/compiler.h +++ b/compiler.h @@ -1,7 +1,7 @@ #ifndef __compiler_H #define __compiler_H /* - * Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2014 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 @@ -36,6 +36,11 @@ */ extern unsigned integer_width; +/* + * The width_cap is the width limit for unsized expressions. + */ +extern unsigned width_cap; + /* * This is the maximum number of recursive module loops allowed within * a generate block. diff --git a/driver/cflexor.lex b/driver/cflexor.lex index 08bb455c3..9d50c4c4f 100644 --- a/driver/cflexor.lex +++ b/driver/cflexor.lex @@ -4,7 +4,7 @@ %{ /* - * Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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 @@ -92,6 +92,8 @@ int cmdfile_stack_ptr = 0; "+vhdl-libdir+" { BEGIN(PLUS_ARGS); return TOK_VHDL_LIBDIR; } +"+width-cap+" { BEGIN(PLUS_ARGS); return TOK_WIDTH_CAP; } + /* If it is not any known plus-flag, return the generic form. */ "+"[^\n \t\b\f\r+]* { cflval.text = strdup(yytext); diff --git a/driver/cfparse.y b/driver/cfparse.y index 22f127d26..13fcb85c9 100644 --- a/driver/cfparse.y +++ b/driver/cfparse.y @@ -1,6 +1,6 @@ %{ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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 @@ -61,6 +61,7 @@ static void translate_file_name(char*text) %token TOK_Da TOK_Dc TOK_Dv TOK_Dy %token TOK_DEFINE TOK_INCDIR TOK_INTEGER_WIDTH TOK_LIBDIR TOK_LIBDIR_NOCASE %token TOK_LIBEXT TOK_PARAMETER TOK_TIMESCALE TOK_VHDL_WORK TOK_VHDL_LIBDIR +%token TOK_WIDTH_CAP %token TOK_PLUSARG TOK_PLUSWORD TOK_STRING %% @@ -191,6 +192,13 @@ item free(tmp); } + | TOK_WIDTH_CAP TOK_PLUSARG + { char*tmp = substitutions($2); + free($2); + width_cap = strtoul(tmp,0,10); + free(tmp); + } + /* The + tokens that are not otherwise matched, are ignored. The skip_args rule arranges for all the argument words to be consumed. */ diff --git a/driver/globals.h b/driver/globals.h index 1ef723315..23c72a380 100644 --- a/driver/globals.h +++ b/driver/globals.h @@ -1,7 +1,7 @@ #ifndef __globals_H #define __globals_H /* - * Copyright (c) 2000-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 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 @@ -24,6 +24,9 @@ /* This is the integer-width argument that will be passed to ivl. */ extern unsigned integer_width; + /* This is the width-cap argument that will be passed to ivl. */ +extern unsigned width_cap; + extern const char*vhdlpp_work; extern const char**vhdlpp_libdir; extern unsigned vhdlpp_libdir_cnt; diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index f6c33fa68..21d504728 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -1,4 +1,4 @@ -.TH iverilog 1 "April 2nd, 2013" "" "Version %M.%m.%n %E" +.TH iverilog 1 "February 26th, 2014" "" "Version %M.%m.%n %E" .SH NAME iverilog - Icarus Verilog compiler @@ -462,6 +462,12 @@ This allows the programmer to select the width for integer variables in the Verilog source. The default is 32, the value can be any desired integer value. +.TP 8 +.B +width-cap+\fIvalue\fP +This allows the programmer to select the width cap for unsized expressions. +If the calculated width for an unsized expression exceeds this value, the +compiler will issue a warning and limit the expression width to this value. + .SH "VARIABLES IN COMMAND FILES" In certain cases, iverilog supports variables in command files. These @@ -515,7 +521,7 @@ Tips on using, debugging, and developing the compiler can be found at .SH COPYRIGHT .nf -Copyright \(co 2002\-2011 Stephen Williams +Copyright \(co 2002\-2014 Stephen Williams This document can be freely redistributed according to the terms of the GNU General Public License version 2.0 diff --git a/driver/main.c b/driver/main.c index b86bacba7..d0b286c47 100644 --- a/driver/main.c +++ b/driver/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 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 @@ -141,6 +141,8 @@ char warning_flags[16] = "n"; unsigned integer_width = 32; +unsigned width_cap = 65536; + char*mod_list = 0; char*command_filename = 0; @@ -1192,6 +1194,8 @@ int main(int argc, char **argv) fprintf(iconfig_file, "iwidth:%u\n", integer_width); + fprintf(iconfig_file, "widthcap:%u\n", width_cap); + /* Write the preprocessor command needed to preprocess a single file. This may be used to preprocess library files. */ diff --git a/elab_expr.cc b/elab_expr.cc index 836361199..3dc88164a 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -756,12 +756,11 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode) r_val = rc->value().as_long(); // Clip to a sensible range to avoid underflow/overflow - // in the following calculations. 1024 bits should be - // enough for anyone... + // in the following calculations. if (r_val < 0) r_val = 0; - if (r_val > 1024) - r_val = 1024; + if (r_val > width_cap) + r_val = width_cap; // If the left operand is a simple unsized number, we // can calculate the actual width required for the power diff --git a/main.cc b/main.cc index 7b7e36001..5c7e040a1 100644 --- a/main.cc +++ b/main.cc @@ -1,5 +1,5 @@ const char COPYRIGHT[] = - "Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com)"; + "Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)"; /* * This source code is free software; you can redistribute it @@ -191,6 +191,11 @@ bool verbose_flag = false; unsigned integer_width = 32; +/* + * Width limit for unsized expressions. + */ +unsigned width_cap = 65536; + int def_ts_units = 0; int def_ts_prec = 0; @@ -647,6 +652,9 @@ static void read_iconfig_file(const char*ipath) } else if (strcmp(buf, "iwidth") == 0) { integer_width = strtoul(cp,0,10); + } else if (strcmp(buf, "widthcap") == 0) { + width_cap = strtoul(cp,0,10); + } else if (strcmp(buf, "library_file") == 0) { perm_string path = filename_strings.make(cp); library_file_map[path] = true; diff --git a/netmisc.cc b/netmisc.cc index e6b414e61..91c974184 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -746,9 +746,9 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, // If context_width is positive, this is the RHS of an assignment, // so the LHS width must also be included in the width calculation. - if ((context_width > 0) && (pe->expr_type() != IVL_VT_REAL) - && (expr_width < (unsigned)context_width)) - expr_width = context_width; + unsigned pos_context_width = context_width > 0 ? context_width : 0; + if ((pe->expr_type() != IVL_VT_REAL) && (expr_width < pos_context_width)) + expr_width = pos_context_width; if (debug_elaborate) { cerr << pe->get_fileline() << ": elab_and_eval: test_width of " @@ -765,8 +765,8 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, // If we can get the same result using a smaller expression // width, do so. if ((context_width > 0) && (pe->expr_type() != IVL_VT_REAL) - && (expr_width > (unsigned)context_width)) { - expr_width = max(pe->min_width(), (unsigned)context_width); + && (expr_width > pos_context_width)) { + expr_width = max(pe->min_width(), pos_context_width); if (debug_elaborate) { cerr << pe->get_fileline() << ": " @@ -774,6 +774,15 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, } } + if ((mode >= PExpr::LOSSLESS) && (expr_width > width_cap) + && (expr_width > pos_context_width)) { + cerr << pe->get_fileline() << ": warning: excessive unsized " + << "expression width detected." << endl; + cerr << pe->get_fileline() << ": : The expression width " + << "is capped at " << width_cap << " bits." << endl; + expr_width = width_cap; + } + unsigned flags = PExpr::NO_FLAGS; if (need_const) flags |= PExpr::NEED_CONST; @@ -789,10 +798,10 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, tmp = cast_to_real(tmp); break; case IVL_VT_BOOL: - tmp = cast_to_int2(tmp, context_width > 0 ? context_width : 0); + tmp = cast_to_int2(tmp, pos_context_width); break; case IVL_VT_LOGIC: - tmp = cast_to_int4(tmp, context_width > 0 ? context_width : 0); + tmp = cast_to_int4(tmp, pos_context_width); break; default: break; From ed2e339dd6ea366864969cbd929325e117ec23e9 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Thu, 27 Feb 2014 19:30:28 +0000 Subject: [PATCH 5/9] Fix for GitHub issue #18 : undef propagation of const multiplies is incorrect. When an expression is elaborated, the compiler converts multiplies with one constamt zero operand into a constant zero value. This is only valid if the other operand is not a 4-state variable. --- elab_expr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elab_expr.cc b/elab_expr.cc index 3dc88164a..9044471f8 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -538,7 +538,7 @@ NetExpr* PEBinary::elaborate_expr_base_mult_(Design*, return tmp; } - if (rp_val.is_zero()) { + if (rp_val.is_zero() && (lp->expr_type() != IVL_VT_LOGIC)) { NetEConst*tmp = make_const_0(expr_wid); tmp->cast_signed(signed_flag_); tmp->set_line(*this); From 065c48527c462a1d1cc06717f762616d0fab6023 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 28 Feb 2014 20:39:14 +0000 Subject: [PATCH 6/9] Fix for GitHub issue 19 : incorrect handling of large shift values. For shift operations evaluated at compile time, the compiler was converting the right operand to a native unsigned long value. If the operand exceeded the size of an unsigned long, excess bits were discarded, which could lead to an incorrect result. The fix I've chosen is to add an as_unsigned() function to the verinum class which returns the maximum unsigned value if the internal verinum value is wider than the native unsigned type. This then naturally gives the correct result for shifts, as the verinum bit width is also an unsigned value. I've changed the as_ulong() and as_ulong64() functions to do likewise, as this is more likely to either give the correct behaviour or to give some indication that an overflow has occurred where these functions are used. --- eval_tree.cc | 2 +- verinum.cc | 39 +++++++++++++++++++++++++++------------ verinum.h | 7 ++++++- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/eval_tree.cc b/eval_tree.cc index ac5d24ae4..ff224d909 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1089,7 +1089,7 @@ NetEConst* NetEBShift::eval_arguments_(const NetExpr*l, const NetExpr*r) const verinum val; if (rv.is_defined()) { - unsigned shift = rv.as_ulong(); + unsigned shift = rv.as_unsigned(); switch (op_) { case 'l': diff --git a/verinum.cc b/verinum.cc index 41efb99a4..250df8293 100644 --- a/verinum.cc +++ b/verinum.cc @@ -378,6 +378,25 @@ void verinum::set(unsigned off, const verinum&val) bits_[off+idx] = val[idx]; } +unsigned verinum::as_unsigned() const +{ + if (nbits_ == 0) + return 0; + + if (!is_defined()) + return 0; + + unsigned val = 0; + unsigned mask = 1; + for (unsigned idx = 0 ; idx < nbits_ ; idx += 1, mask <<= 1) + if (bits_[idx] == V1) { + if (mask == 0) return ~mask; + val |= mask; + } + + return val; +} + unsigned long verinum::as_ulong() const { if (nbits_ == 0) @@ -386,15 +405,13 @@ unsigned long verinum::as_ulong() const if (!is_defined()) return 0; - unsigned top = nbits_; - if (top >= (8 * sizeof(unsigned long))) - top = 8 * sizeof(unsigned long); - unsigned long val = 0; unsigned long mask = 1; - for (unsigned idx = 0 ; idx < top ; idx += 1, mask <<= 1) - if (bits_[idx] == V1) + for (unsigned idx = 0 ; idx < nbits_ ; idx += 1, mask <<= 1) + if (bits_[idx] == V1) { + if (mask == 0) return ~mask; val |= mask; + } return val; } @@ -407,15 +424,13 @@ uint64_t verinum::as_ulong64() const if (!is_defined()) return 0; - unsigned top = nbits_; - if (top >= (8 * sizeof(uint64_t))) - top = 8 * sizeof(uint64_t); - uint64_t val = 0; uint64_t mask = 1; - for (unsigned idx = 0 ; idx < top ; idx += 1, mask <<= 1) - if (bits_[idx] == V1) + for (unsigned idx = 0 ; idx < nbits_ ; idx += 1, mask <<= 1) + if (bits_[idx] == V1) { + if (mask == 0) return ~mask; val |= mask; + } return val; } diff --git a/verinum.h b/verinum.h index 41df9a90a..f6b3626c5 100644 --- a/verinum.h +++ b/verinum.h @@ -97,9 +97,14 @@ class verinum { V operator[] (unsigned idx) const { return get(idx); } - + // Return the value as a native unsigned integer. If the value is + // larger than can be represented by the returned type, return + // the maximum value of that type. If the value has any x or z + // bits or has zero width, return the value 0. uint64_t as_ulong64() const; + unsigned as_unsigned() const; unsigned long as_ulong() const; + signed long as_long() const; double as_double() const; string as_string() const; From c61d2151c1591441c44b2065e019c3bdfdaa5e4c Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 28 Feb 2014 23:29:15 +0000 Subject: [PATCH 7/9] Fix invalid optimisations in tgt-vvp. The vvp code generator was optimising away adds and subtracts where one operand was a constant zero. This is not valid for 4-state arithmetic. It was also optimising away multiplies by a constant zero - but in this case getting it wrong and effectively multiplying by 1. --- tgt-vvp/eval_expr.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index c315039bc..67fb21df3 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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 @@ -1490,12 +1490,6 @@ static struct vector_info draw_add_immediate(ivl_expr_t le, assert(number_is_immediate(re, IMM_WID, 0)); imm = get_number_immediate(re); - /* This shouldn't generally happen, because the elaborator - should take care of simple constant propagation like this, - but it doesn't have to and it is easy to catch here. */ - if (imm == 0) - return lv; - switch (lv.base) { case 0: /* Left expression is 0. */ lv.base = allocate_vector(wid); @@ -1556,8 +1550,6 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le, assert(! number_is_unknown(re)); assert(number_is_immediate(re, IMM_WID, 0)); imm = get_number_immediate(re); - if (imm == 0) - return lv; switch (lv.base) { case 0: @@ -1602,8 +1594,6 @@ static struct vector_info draw_mul_immediate(ivl_expr_t le, assert(! number_is_unknown(re)); assert(number_is_immediate(re, IMM_WID, 0)); imm = get_number_immediate(re); - if (imm == 0) - return lv; fprintf(vvp_out, " %%muli %u, %lu, %u;\n", lv.base, imm, lv.wid); From 13c1925045c0f9db1fd366f43191303c8fb49cb2 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 28 Feb 2014 17:18:51 -0800 Subject: [PATCH 8/9] Fix space issue --- vvp/vvp_net.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index c87e26ef9..a9df069a2 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2014 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 @@ -2364,7 +2364,7 @@ vvp_vector2_t pow(const vvp_vector2_t&x, vvp_vector2_t&y) { /* If we have a zero exponent just return 1. */ if (y == vvp_vector2_t(0L, 1)) { - return vvp_vector2_t(1L, x.size()); + return vvp_vector2_t(1L, x.size()); } /* Is the value odd? */ From d0d421ebe27f0268ebeeecdd5eff5ecafd02e13b Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 28 Feb 2014 17:29:17 -0800 Subject: [PATCH 9/9] Remove compile warning --- elab_expr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elab_expr.cc b/elab_expr.cc index 9044471f8..bee085511 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -759,7 +759,7 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode) // in the following calculations. if (r_val < 0) r_val = 0; - if (r_val > width_cap) + if ((unsigned long)r_val > width_cap) r_val = width_cap; // If the left operand is a simple unsized number, we