Merge branch 'master' into vec4-stack

Conflicts:
	netmisc.cc
	tgt-vvp/eval_expr.c
	vvp/vthread.cc
This commit is contained in:
Stephen Williams 2014-03-01 09:02:14 -08:00
commit 7ceb18fb37
19 changed files with 374 additions and 245 deletions

View File

@ -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 <http://www.icarus.com/eda/verilog>.
home page at <http://iverilog.icarus.com/>.
Icarus Verilog is not aimed at being a simulator in the traditional
sense, but a compiler that generates code employed by back-end

View File

@ -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.

View File

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

View File

@ -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 <text> 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 +<word> tokens that are not otherwise matched, are
ignored. The skip_args rule arranges for all the argument words
to be consumed. */

View File

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

View File

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

View File

@ -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. */

View File

@ -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
@ -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);
@ -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 ((unsigned long)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
@ -5373,13 +5372,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;
@ -5492,7 +5486,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);

View File

@ -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 {

View File

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

View File

@ -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);
@ -1088,16 +1089,16 @@ 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':
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;

10
main.cc
View File

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

View File

@ -761,9 +761,9 @@ static NetExpr* do_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 "
@ -783,8 +783,8 @@ static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
// width, do so.
if ((context_width > 0) && (!force_expand)
&& (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() << ": "
@ -792,6 +792,15 @@ static NetExpr* do_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;
@ -812,10 +821,10 @@ static NetExpr* do_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;

View File

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

View File

@ -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
@ -1080,6 +1080,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr,
return lv;
}
static struct vector_info draw_binary_expr(ivl_expr_t expr,
unsigned wid,
int stuff_ok_flag)

View File

@ -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 <cassert>
# include <cmath> // Needed to get pow for as_double().
# include <cstdio> // Needed to get snprintf for as_string().
# include <algorithm>
#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. */
@ -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;
}
@ -968,7 +983,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 +1003,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 +1218,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 +1242,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 +1288,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 +1368,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 +1400,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 +1435,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 +1472,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 +1508,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 +1540,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);
}

View File

@ -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
@ -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;
@ -171,11 +176,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 +197,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

View File

@ -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
@ -1768,7 +1768,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
@ -1783,17 +1783,8 @@ bool of_CASSIGN_LINK(vthread_t, vvp_code_t cp)
= dynamic_cast<vvp_fun_signal_base*>(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;
@ -1806,7 +1797,27 @@ bool of_CASSIGN_LINK(vthread_t, vvp_code_t cp)
}
/*
* the %cassign/vec4 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<vvp_fun_signal_base*>(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/vec4 <net>;
@ -1822,7 +1833,10 @@ bool of_CASSIGN_VEC4(vthread_t thr, vvp_code_t cp)
vvp_net_t*net = cp->net;
vvp_vector4_t value = thr->pop_vec4();
/* set the value into port 1 of the destination. */
/* 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_vec4(ptr, value, 0);
@ -1843,6 +1857,9 @@ bool of_CASSIGN_VEC4_OFF(vthread_t thr, vvp_code_t cp)
if (thr->flags[4] == BIT4_1)
return true;
/* Remove any previous continuous assign to this net. */
cassign_unlink(net);
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (net->fil);
assert(sig);
@ -1873,6 +1890,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);

View File

@ -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? */