Skip to content
Permalink
Browse files

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.
  • Loading branch information
martinwhitaker committed Feb 25, 2014
1 parent 320f6d0 commit a3450bf8560739caea01dbc72dfb6266d144070e
Showing with 235 additions and 191 deletions.
  1. +4 −9 elab_expr.cc
  2. +2 −4 elab_scope.cc
  3. +2 −2 eval.cc
  4. +14 −22 eval_tree.cc
  5. +2 −2 parse.y
  6. +202 −145 verinum.cc
  7. +9 −7 verinum.h
@@ -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<NetEConst*>(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);
@@ -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 {
@@ -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;
}
@@ -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,24 +1447,15 @@ 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':
if (!val.is_defined()) {
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;

@@ -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;
}

0 comments on commit a3450bf

Please sign in to comment.