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.
This commit is contained in:
parent
320f6d008c
commit
a3450bf856
13
elab_expr.cc
13
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)
|
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
|
|
@ -5341,13 +5341,8 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
|
||||||
case '-':
|
case '-':
|
||||||
if (NetEConst*ipc = dynamic_cast<NetEConst*>(ip)) {
|
if (NetEConst*ipc = dynamic_cast<NetEConst*>(ip)) {
|
||||||
|
|
||||||
verinum val = ipc->value();
|
verinum val = - ipc->value();
|
||||||
|
tmp = new NetEConst(val);
|
||||||
/* 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);
|
|
||||||
tmp->cast_signed(signed_flag_);
|
tmp->cast_signed(signed_flag_);
|
||||||
tmp->set_line(*this);
|
tmp->set_line(*this);
|
||||||
delete ip;
|
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
|
// The only operand that I know can get here is the
|
||||||
// unary not (~).
|
// unary not (~).
|
||||||
ivl_assert(*this, op_ == '~');
|
ivl_assert(*this, op_ == '~');
|
||||||
value = v_not(value);
|
value = ~value;
|
||||||
|
|
||||||
ctmp = new NetEConst(value);
|
ctmp = new NetEConst(value);
|
||||||
ctmp->set_line(*this);
|
ctmp->set_line(*this);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* 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 min_value (0);
|
||||||
verinum max_value (0);
|
verinum max_value (0);
|
||||||
if (enum_type->signed_flag) {
|
if (enum_type->signed_flag) {
|
||||||
min_value = v_not((pow(verinum(2),
|
min_value = -pow(verinum(2), verinum(use_enum->packed_width()-1));
|
||||||
verinum(use_enum->packed_width()-1)))) +
|
|
||||||
one_value;
|
|
||||||
max_value = pow(verinum(2), verinum(use_enum->packed_width()-1)) -
|
max_value = pow(verinum(2), verinum(use_enum->packed_width()-1)) -
|
||||||
one_value;
|
one_value;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
4
eval.cc
4
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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)
|
for (unsigned idx = 0 ; idx < val->len() ; idx += 1)
|
||||||
tmp.set(idx, val->get(idx));
|
tmp.set(idx, val->get(idx));
|
||||||
|
|
||||||
*val = v_not(tmp) + verinum(verinum::V1, 1);
|
*val = -tmp;
|
||||||
val->has_sign(true);
|
val->has_sign(true);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
36
eval_tree.cc
36
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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_) {
|
if (op_ == se->op_) {
|
||||||
/* (a + lval) + rval --> a + (rval+lval) */
|
/* (a + lval) + rval --> a + (rval+lval) */
|
||||||
/* (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 {
|
} else {
|
||||||
/* (a - lval) + rval --> a + (rval-lval) */
|
/* (a - lval) + rval --> a + (rval-lval) */
|
||||||
/* (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);
|
NetEConst*tmp = new NetEConst(val);
|
||||||
|
|
@ -217,10 +217,10 @@ NetExpr* NetEBAdd::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
||||||
verinum val;
|
verinum val;
|
||||||
switch (op_) {
|
switch (op_) {
|
||||||
case '+':
|
case '+':
|
||||||
val = verinum(lval + rval, wid);
|
val = cast_to_width(lval + rval, wid);
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
val = verinum(lval - rval, wid);
|
val = cast_to_width(lval - rval, wid);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -816,14 +816,15 @@ NetExpr* NetEBDiv::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
||||||
verinum val;
|
verinum val;
|
||||||
switch (op_) {
|
switch (op_) {
|
||||||
case '/':
|
case '/':
|
||||||
val = verinum(lval / rval, wid);
|
val = cast_to_width(lval / rval, wid);
|
||||||
break;
|
break;
|
||||||
case '%':
|
case '%':
|
||||||
val = verinum(lval % rval, wid);
|
val = cast_to_width(lval % rval, wid);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetExpr*tmp = new NetEConst(val);
|
NetExpr*tmp = new NetEConst(val);
|
||||||
ivl_assert(*this, tmp);
|
ivl_assert(*this, tmp);
|
||||||
eval_debug(this, tmp, false);
|
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, lval.len() == wid);
|
||||||
ivl_assert(*this, rval.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);
|
NetEConst*tmp = new NetEConst(val);
|
||||||
ivl_assert(*this, tmp);
|
ivl_assert(*this, tmp);
|
||||||
eval_debug(this, tmp, false);
|
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, wid > 0);
|
||||||
ivl_assert(*this, lval.len() == wid);
|
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);
|
NetEConst*res = new NetEConst(val);
|
||||||
ivl_assert(*this, res);
|
ivl_assert(*this, res);
|
||||||
eval_debug(this, res, false);
|
eval_debug(this, res, false);
|
||||||
|
|
@ -1092,12 +1093,12 @@ NetEConst* NetEBShift::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
||||||
|
|
||||||
switch (op_) {
|
switch (op_) {
|
||||||
case 'l':
|
case 'l':
|
||||||
val = verinum(lv << shift, wid);
|
val = cast_to_width(lv << shift, wid);
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
lv.has_sign(false);
|
lv.has_sign(false);
|
||||||
case 'R':
|
case 'R':
|
||||||
val = verinum(lv >> shift, wid);
|
val = cast_to_width(lv >> shift, wid);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1446,14 +1447,7 @@ NetExpr* NetEUnary::eval_arguments_(const NetExpr*ex) const
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '-':
|
case '-':
|
||||||
if (val.is_defined()) {
|
val = -val;
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
|
|
@ -1461,9 +1455,7 @@ NetExpr* NetEUnary::eval_arguments_(const NetExpr*ex) const
|
||||||
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
|
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
|
||||||
val.set(idx, verinum::Vx);
|
val.set(idx, verinum::Vx);
|
||||||
} else if (val.is_negative()) {
|
} else if (val.is_negative()) {
|
||||||
verinum tmp (verinum::V0, val.len());
|
val = -val;
|
||||||
tmp.has_sign(val.has_sign());
|
|
||||||
val = verinum(tmp - val, val.len());
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
4
parse.y
4
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)
|
* Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
|
|
@ -2259,7 +2259,7 @@ pos_neg_number
|
||||||
{ $$ = $1;
|
{ $$ = $1;
|
||||||
}
|
}
|
||||||
| '-' number
|
| '-' number
|
||||||
{ verinum tmp = v_not(*($2)) + verinum(1);
|
{ verinum tmp = -(*($2));
|
||||||
*($2) = tmp;
|
*($2) = tmp;
|
||||||
$$ = $2;
|
$$ = $2;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
349
verinum.cc
349
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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
# include <cassert>
|
# include <cassert>
|
||||||
# include <cmath> // Needed to get pow for as_double().
|
# include <cmath> // Needed to get pow for as_double().
|
||||||
# include <cstdio> // Needed to get snprintf for as_string().
|
# include <cstdio> // Needed to get snprintf for as_string().
|
||||||
|
# include <algorithm>
|
||||||
|
|
||||||
#if !defined(HAVE_LROUND)
|
#if !defined(HAVE_LROUND)
|
||||||
/*
|
/*
|
||||||
|
|
@ -200,7 +201,6 @@ verinum::verinum(double val, bool)
|
||||||
fraction = frexp(val, &exponent);
|
fraction = frexp(val, &exponent);
|
||||||
nbits_ = exponent+1;
|
nbits_ = exponent+1;
|
||||||
bits_ = new V[nbits_];
|
bits_ = new V[nbits_];
|
||||||
const verinum const_one(1);
|
|
||||||
|
|
||||||
/* If the value is small enough just use lround(). */
|
/* If the value is small enough just use lround(). */
|
||||||
if (nbits_ <= BITS_IN_LONG) {
|
if (nbits_ <= BITS_IN_LONG) {
|
||||||
|
|
@ -230,9 +230,9 @@ verinum::verinum(double val, bool)
|
||||||
for (int wd = nwords; wd >= 0; wd -= 1) {
|
for (int wd = nwords; wd >= 0; wd -= 1) {
|
||||||
unsigned long bits = (unsigned long) fraction;
|
unsigned long bits = (unsigned long) fraction;
|
||||||
fraction = fraction - (double) bits;
|
fraction = fraction - (double) bits;
|
||||||
unsigned max = (wd+1)*BITS_IN_LONG;
|
unsigned max_idx = (wd+1)*BITS_IN_LONG;
|
||||||
if (max > nbits_) max = nbits_;
|
if (max_idx > nbits_) max_idx = nbits_;
|
||||||
for (unsigned idx = wd*BITS_IN_LONG; idx < max; idx += 1) {
|
for (unsigned idx = wd*BITS_IN_LONG; idx < max_idx; idx += 1) {
|
||||||
bits_[idx] = (bits&1) ? V1 : V0;
|
bits_[idx] = (bits&1) ? V1 : V0;
|
||||||
bits >>= 1;
|
bits >>= 1;
|
||||||
}
|
}
|
||||||
|
|
@ -242,7 +242,7 @@ verinum::verinum(double val, bool)
|
||||||
|
|
||||||
/* Convert a negative number if needed. */
|
/* Convert a negative number if needed. */
|
||||||
if (is_neg) {
|
if (is_neg) {
|
||||||
*this = v_not(*this) + const_one;
|
*this = -(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Trim the result. */
|
/* 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;
|
return verinum::V0;
|
||||||
}
|
}
|
||||||
|
|
||||||
verinum v_not(const verinum&left)
|
verinum operator ~ (const verinum&left)
|
||||||
{
|
{
|
||||||
verinum val = left;
|
verinum val = left;
|
||||||
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
|
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
|
* Addition and subtraction works a bit at a time, from the least
|
||||||
* the most significant. The result is signed only if both of the
|
* significant up to the most significant. The result is signed only
|
||||||
* operands are signed. The result is also expanded as needed to
|
* if both of the operands are signed. If either operand is unsized,
|
||||||
* prevent overflow. It is up to the caller to shrink the result back
|
* the result is expanded as needed to prevent overflow.
|
||||||
* down if that is the desire.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
verinum operator + (const verinum&left, const verinum&right)
|
verinum operator + (const verinum&left, const verinum&right)
|
||||||
{
|
{
|
||||||
unsigned min = left.len();
|
const bool has_len_flag = left.has_len() && right.has_len();
|
||||||
if (right.len() < min) min = right.len();
|
const bool signed_flag = left.has_sign() && right.has_sign();
|
||||||
|
|
||||||
unsigned max = left.len();
|
unsigned min_len = min(left.len(), right.len());
|
||||||
if (right.len() > max) max = right.len();
|
unsigned max_len = max(left.len(), right.len());
|
||||||
|
|
||||||
bool signed_flag = left.has_sign() && right.has_sign();
|
// If either the left or right values are undefined, the
|
||||||
verinum::V*val_bits = new verinum::V[max+1];
|
// 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;
|
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);
|
val_bits[idx] = add_with_carry(left[idx], right[idx], carry);
|
||||||
|
|
||||||
verinum::V rpad = signed_flag? right[right.len()-1] : verinum::V0;
|
verinum::V rpad = sign_bit(right);
|
||||||
verinum::V lpad = signed_flag? left[left.len()-1] : verinum::V0;
|
verinum::V lpad = sign_bit(left);
|
||||||
|
|
||||||
if (left.len() > right.len()) {
|
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);
|
val_bits[idx] = add_with_carry(left[idx], rpad, carry);
|
||||||
|
|
||||||
} else {
|
} 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[idx] = add_with_carry(lpad, right[idx], carry);
|
||||||
}
|
}
|
||||||
|
|
||||||
val_bits[max] = add_with_carry(lpad, rpad, carry);
|
unsigned len = max_len;
|
||||||
#if 0
|
if (!has_len_flag) {
|
||||||
if (signed_flag) {
|
val_bits[max_len] = add_with_carry(lpad, rpad, carry);
|
||||||
if (val_bits[max] != val_bits[max-1])
|
if (signed_flag) {
|
||||||
max += 1;
|
if (val_bits[max_len] != val_bits[max_len-1]) len += 1;
|
||||||
|
} else {
|
||||||
|
if (val_bits[max_len] != verinum::V0) len += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
verinum result (val_bits, len, has_len_flag);
|
||||||
verinum val (val_bits, max+1, false);
|
result.has_sign(signed_flag);
|
||||||
val.has_sign(signed_flag);
|
|
||||||
|
|
||||||
delete[]val_bits;
|
delete[]val_bits;
|
||||||
|
|
||||||
return val;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
verinum operator - (const verinum&left, const verinum&right)
|
verinum operator - (const verinum&left, const verinum&right)
|
||||||
{
|
{
|
||||||
unsigned min = left.len();
|
const bool has_len_flag = left.has_len() && right.has_len();
|
||||||
if (right.len() < min) min = right.len();
|
const bool signed_flag = left.has_sign() && right.has_sign();
|
||||||
|
|
||||||
unsigned max = left.len();
|
unsigned min_len = min(left.len(), right.len());
|
||||||
if (right.len() > max) max = right.len();
|
unsigned max_len = max(left.len(), right.len());
|
||||||
|
|
||||||
bool signed_flag = left.has_sign() && right.has_sign();
|
// If either the left or right values are undefined, the
|
||||||
verinum::V*val_bits = new verinum::V[max+1];
|
// 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;
|
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);
|
val_bits[idx] = add_with_carry(left[idx], ~right[idx], carry);
|
||||||
|
|
||||||
verinum::V rpad = signed_flag? ~right[right.len()-1] : verinum::V1;
|
verinum::V rpad = sign_bit(right);
|
||||||
verinum::V lpad = signed_flag? left[left.len()-1] : verinum::V0;
|
verinum::V lpad = sign_bit(left);
|
||||||
|
|
||||||
if (left.len() > right.len()) {
|
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);
|
val_bits[idx] = add_with_carry(left[idx], ~rpad, carry);
|
||||||
|
|
||||||
} else {
|
} 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[idx] = add_with_carry(lpad, ~right[idx], carry);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signed_flag) {
|
unsigned len = max_len;
|
||||||
val_bits[max] = add_with_carry(lpad, rpad, carry);
|
if (signed_flag && !has_len_flag) {
|
||||||
if (val_bits[max] != val_bits[max-1])
|
val_bits[max_len] = add_with_carry(lpad, ~rpad, carry);
|
||||||
max += 1;
|
if (val_bits[max_len] != val_bits[max_len-1]) len += 1;
|
||||||
}
|
}
|
||||||
|
verinum result (val_bits, len, has_len_flag);
|
||||||
verinum val (val_bits, max, false);
|
result.has_sign(signed_flag);
|
||||||
val.has_sign(signed_flag);
|
|
||||||
|
|
||||||
delete[]val_bits;
|
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
|
* This operator multiplies the left number by the right number. The
|
||||||
* result. The resulting number is as large as the sum of the sizes of
|
* result is signed only if both of the operands are signed. If either
|
||||||
* the operand.
|
* 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,
|
* The algorithm used is successive shift and add operations,
|
||||||
* implemented as the nested loops.
|
* 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)
|
verinum operator * (const verinum&left, const verinum&right)
|
||||||
{
|
{
|
||||||
const bool has_len_flag = left.has_len() && right.has_len();
|
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
|
const unsigned l_len = left.len();
|
||||||
result is undefined. Create a result that is the right size
|
const unsigned r_len = right.len();
|
||||||
and is filled with 'bx bits. */
|
|
||||||
if (! (left.is_defined() && right.is_defined())) {
|
unsigned len = has_len_flag ? max(l_len, r_len) : l_len + r_len;
|
||||||
verinum result (verinum::Vx, left.len()+right.len(), has_len_flag);
|
|
||||||
result.has_sign(left.has_sign() || right.has_sign());
|
// 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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
verinum result(verinum::V0, left.len() + right.len(), has_len_flag);
|
verinum result(verinum::V0, len, has_len_flag);
|
||||||
result.has_sign(left.has_sign() || right.has_sign());
|
result.has_sign(signed_flag);
|
||||||
|
|
||||||
verinum::V r_sign = sign_bit(right);
|
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)
|
if (r_bit == verinum::V0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
verinum::V l_sign = sign_bit(left);
|
verinum::V l_sign = sign_bit(left);
|
||||||
verinum::V carry = verinum::V0;
|
verinum::V carry = verinum::V0;
|
||||||
for (unsigned ldx = 0 ; ldx < result.len()-rdx ; ldx += 1) {
|
for (unsigned ldx = 0 ; ldx < (len - rdx) ; ldx += 1) {
|
||||||
verinum::V l_bit = ldx < left.len()? left[ldx] : l_sign;
|
verinum::V l_bit = ldx < l_len ? left[ldx] : l_sign;
|
||||||
result.set(ldx+rdx, add_with_carry(l_bit,
|
result.set(ldx+rdx, add_with_carry(l_bit,
|
||||||
result[rdx+ldx],
|
result[rdx+ldx],
|
||||||
carry));
|
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());
|
return make_p_one(left.len(), left.has_len(), left.has_sign());
|
||||||
}
|
}
|
||||||
|
|
||||||
verinum res;
|
verinum result;
|
||||||
if (right.get(0) == 1) {
|
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);
|
right.set(0, verinum::V0);
|
||||||
res = pow(left, right);
|
result = pow(left, right);
|
||||||
res = left * res;
|
result = left * result;
|
||||||
} else {
|
} else {
|
||||||
// The exponent is even, so divide it by 2 and recurse
|
// The exponent is even, so divide it by 2 and recurse
|
||||||
right = right >> 1;
|
right = right >> 1;
|
||||||
res = pow(left, right);
|
result = pow(left, right);
|
||||||
res = res * res;
|
result = result * result;
|
||||||
}
|
}
|
||||||
if (left.has_len()) {
|
return result;
|
||||||
res = verinum(res, left.len());
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
verinum pow(const verinum&left, const verinum&right)
|
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 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());
|
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 either the left or right values are undefined, the
|
||||||
if (!right.is_defined() || !left.is_defined()) {
|
// entire result is undefined.
|
||||||
|
if (!left.is_defined() || !right.is_defined()) {
|
||||||
result = verinum(verinum::Vx, left.len(), left.has_len());
|
result = verinum(verinum::Vx, left.len(), left.has_len());
|
||||||
result.has_sign(left.has_sign());
|
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 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());
|
result.has_sign(that.has_sign());
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < that.len() ; idx += 1)
|
for (unsigned idx = shift ; idx < len ; idx += 1)
|
||||||
result.set(idx+shift, that.get(idx));
|
result.set(idx, that.get(idx - shift));
|
||||||
|
|
||||||
return result;
|
return trim_vnum(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
verinum operator >> (const verinum&that, unsigned shift)
|
verinum operator >> (const verinum&that, unsigned shift)
|
||||||
{
|
{
|
||||||
if (shift >= that.len()) {
|
bool has_len_flag = that.has_len();
|
||||||
if (that.has_sign()) {
|
|
||||||
verinum result (that.get(that.len()-1), 1);
|
unsigned len = that.len();
|
||||||
result.has_sign(true);
|
|
||||||
return result;
|
verinum::V sign_bit = that.has_sign() ? that.get(len-1) : verinum::V0;
|
||||||
} else {
|
|
||||||
verinum result(verinum::V0, 1);
|
if (shift >= len) {
|
||||||
return result;
|
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,
|
if (!has_len_flag) len -= shift;
|
||||||
that.len() - shift, that.has_len());
|
verinum result(sign_bit, len, has_len_flag);
|
||||||
result.has_sign(that.has_sign());
|
result.has_sign(that.has_sign());
|
||||||
|
|
||||||
for (unsigned idx = shift ; idx < that.len() ; idx += 1)
|
for (unsigned idx = shift ; idx < that.len() ; idx += 1)
|
||||||
result.set(idx-shift, that.get(idx));
|
result.set(idx-shift, that.get(idx));
|
||||||
|
|
||||||
return result;
|
return trim_vnum(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static verinum unsigned_divide(verinum num, verinum den, bool signed_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();
|
unsigned nwid = num.len();
|
||||||
while (nwid > 0 && (num.get(nwid-1) == verinum::V0))
|
while (nwid > 0 && (num.get(nwid-1) == verinum::V0))
|
||||||
nwid -= 1;
|
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)
|
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();
|
unsigned nwid = num.len();
|
||||||
while (nwid > 0 && (num.get(nwid-1) == verinum::V0))
|
while (nwid > 0 && (num.get(nwid-1) == verinum::V0))
|
||||||
nwid -= 1;
|
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
|
* This operator divides the left number by the right number. The result
|
||||||
* either value is signed, the result is signed. If both values have a
|
* is signed only if both of the operands are signed.
|
||||||
* defined length, then the result has a defined length.
|
|
||||||
*/
|
*/
|
||||||
verinum operator / (const verinum&left, const verinum&right)
|
verinum operator / (const verinum&left, const verinum&right)
|
||||||
{
|
{
|
||||||
const bool has_len_flag = left.has_len() && right.has_len();
|
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();
|
unsigned use_len = left.len();
|
||||||
|
|
||||||
/* If either operand is not fully defined, then the entire
|
// If either the left or right values are undefined, or the
|
||||||
result is undefined. Create a result that is the right size
|
// right value is zero, the entire result is undefined.
|
||||||
and is filled with 'bx bits. */
|
if (!left.is_defined() || !right.is_defined() || right.is_zero()) {
|
||||||
if (! (left.is_defined() && right.is_defined())) {
|
|
||||||
verinum result (verinum::Vx, use_len, has_len_flag);
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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());
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
verinum result(verinum::Vz, use_len, has_len_flag);
|
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
|
/* do the operation differently, depending on whether the
|
||||||
result is signed or not. */
|
result is signed or not. */
|
||||||
if (result.has_sign()) {
|
if (signed_flag) {
|
||||||
|
|
||||||
if (use_len <= (8*sizeof(long) - 1)) {
|
if (use_len <= (8*sizeof(long) - 1)) {
|
||||||
long l = left.as_long();
|
long l = left.as_long();
|
||||||
|
|
@ -1361,23 +1420,23 @@ verinum operator / (const verinum&left, const verinum&right)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
verinum use_left, use_right;
|
verinum use_left, use_right;
|
||||||
verinum zero(verinum::V0, 1, false);
|
|
||||||
zero.has_sign(true);
|
|
||||||
bool negative = false;
|
bool negative = false;
|
||||||
if (left < zero) {
|
if (left.is_negative()) {
|
||||||
use_left = zero - left;
|
use_left = -left;
|
||||||
negative = !negative;
|
negative = !negative;
|
||||||
} else {
|
} else {
|
||||||
use_left = left;
|
use_left = left;
|
||||||
}
|
}
|
||||||
if (right < zero) {
|
use_left.has_sign(false);
|
||||||
use_right = zero - right;
|
if (right.is_negative()) {
|
||||||
|
use_right = -right;
|
||||||
negative = !negative;
|
negative = !negative;
|
||||||
} else {
|
} else {
|
||||||
use_right = right;
|
use_right = right;
|
||||||
}
|
}
|
||||||
|
use_right.has_sign(false);
|
||||||
result = unsigned_divide(use_left, use_right, true);
|
result = unsigned_divide(use_left, use_right, true);
|
||||||
if (negative) result = zero - result;
|
if (negative) result = -result;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} 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);
|
return trim_vnum(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
verinum operator % (const verinum&left, const verinum&right)
|
verinum operator % (const verinum&left, const verinum&right)
|
||||||
{
|
{
|
||||||
const bool has_len_flag = left.has_len() && right.has_len();
|
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();
|
unsigned use_len = left.len();
|
||||||
|
|
||||||
/* If either operand is not fully defined, then the entire
|
// If either the left or right values are undefined, or the
|
||||||
result is undefined. Create a result that is the right size
|
// right value is zero, the entire result is undefined.
|
||||||
and is filled with 'bx bits. */
|
if (!left.is_defined() || !right.is_defined() || right.is_zero()) {
|
||||||
if (! (left.is_defined() && right.is_defined())) {
|
|
||||||
verinum result (verinum::Vx, use_len, has_len_flag);
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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());
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
verinum result(verinum::Vz, use_len, has_len_flag);
|
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)) {
|
if (use_len <= 8*sizeof(long)) {
|
||||||
/* Use native signed modulus to do the work. */
|
/* Use native signed modulus to do the work. */
|
||||||
long l = left.as_long();
|
long l = left.as_long();
|
||||||
|
|
@ -1439,23 +1493,22 @@ verinum operator % (const verinum&left, const verinum&right)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
verinum use_left, use_right;
|
verinum use_left, use_right;
|
||||||
verinum zero(verinum::V0, 1, false);
|
|
||||||
zero.has_sign(true);
|
|
||||||
bool negative = false;
|
bool negative = false;
|
||||||
if (left < zero) {
|
if (left.is_negative()) {
|
||||||
use_left = zero - left;
|
use_left = -left;
|
||||||
negative = true;
|
negative = true;
|
||||||
} else {
|
} else {
|
||||||
use_left = left;
|
use_left = left;
|
||||||
}
|
}
|
||||||
if (right < zero) {
|
use_left.has_sign(false);
|
||||||
use_right = zero - right;
|
if (right.is_negative()) {
|
||||||
|
use_right = -right;
|
||||||
} else {
|
} else {
|
||||||
use_right = right;
|
use_right = right;
|
||||||
}
|
}
|
||||||
|
use_right.has_sign(false);
|
||||||
result = unsigned_modulus(use_left, use_right);
|
result = unsigned_modulus(use_left, use_right);
|
||||||
result.has_sign(true);
|
if (negative) result = -result;
|
||||||
if (negative) result = zero - result;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (use_len <= 8*sizeof(unsigned long)) {
|
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);
|
return trim_vnum(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
16
verinum.h
16
verinum.h
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef __verinum_H
|
#ifndef __verinum_H
|
||||||
#define __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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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; }
|
{ return (left == right)? verinum::V0 : verinum::V1; }
|
||||||
|
|
||||||
|
|
||||||
/* These are arithmetic operators. These generally work to produce
|
/* These are arithmetic operators. If any operand is unsized, they
|
||||||
results that do not overflow. That means the result may expand or
|
generally work to produce results that do not overflow. That means
|
||||||
contract to hold the bits needed to hold the operation results
|
the result may expand or contract to hold the bits needed to hold
|
||||||
accurately. It is up to the caller to truncate or pad if a specific
|
the operation results accurately. It is up to the caller to truncate
|
||||||
width is expected. */
|
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);
|
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);
|
extern verinum concat(const verinum&left, const verinum&right);
|
||||||
|
|
||||||
/* Bitwise not returns the ones complement. */
|
/* Bitwise not returns the ones complement. */
|
||||||
extern verinum v_not(const verinum&left);
|
extern verinum operator ~ (const verinum&left);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue