Merge branch 'master' into vec4-stack
Conflicts: netmisc.cc tgt-vvp/eval_expr.c vvp/vthread.cc
This commit is contained in:
commit
7ceb18fb37
|
|
@ -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
|
described in the IEEE-1364 standard. Of course, it's not quite there
|
||||||
yet. It does currently handle a mix of structural and behavioral
|
yet. It does currently handle a mix of structural and behavioral
|
||||||
constructs. For a view of the current state of Icarus Verilog, see its
|
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
|
Icarus Verilog is not aimed at being a simulator in the traditional
|
||||||
sense, but a compiler that generates code employed by back-end
|
sense, but a compiler that generates code employed by back-end
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef __compiler_H
|
#ifndef __compiler_H
|
||||||
#define __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
|
* 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
|
||||||
|
|
@ -36,6 +36,11 @@
|
||||||
*/
|
*/
|
||||||
extern unsigned integer_width;
|
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
|
* This is the maximum number of recursive module loops allowed within
|
||||||
* a generate block.
|
* a generate block.
|
||||||
|
|
|
||||||
|
|
@ -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
|
* 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
|
||||||
|
|
@ -92,6 +92,8 @@ int cmdfile_stack_ptr = 0;
|
||||||
|
|
||||||
"+vhdl-libdir+" { BEGIN(PLUS_ARGS); return TOK_VHDL_LIBDIR; }
|
"+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. */
|
/* If it is not any known plus-flag, return the generic form. */
|
||||||
"+"[^\n \t\b\f\r+]* {
|
"+"[^\n \t\b\f\r+]* {
|
||||||
cflval.text = strdup(yytext);
|
cflval.text = strdup(yytext);
|
||||||
|
|
|
||||||
|
|
@ -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
|
* 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
|
||||||
|
|
@ -61,6 +61,7 @@ static void translate_file_name(char*text)
|
||||||
%token TOK_Da TOK_Dc TOK_Dv TOK_Dy
|
%token TOK_Da TOK_Dc TOK_Dv TOK_Dy
|
||||||
%token TOK_DEFINE TOK_INCDIR TOK_INTEGER_WIDTH TOK_LIBDIR TOK_LIBDIR_NOCASE
|
%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_LIBEXT TOK_PARAMETER TOK_TIMESCALE TOK_VHDL_WORK TOK_VHDL_LIBDIR
|
||||||
|
%token TOK_WIDTH_CAP
|
||||||
%token <text> TOK_PLUSARG TOK_PLUSWORD TOK_STRING
|
%token <text> TOK_PLUSARG TOK_PLUSWORD TOK_STRING
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
@ -191,6 +192,13 @@ item
|
||||||
free(tmp);
|
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
|
/* The +<word> tokens that are not otherwise matched, are
|
||||||
ignored. The skip_args rule arranges for all the argument words
|
ignored. The skip_args rule arranges for all the argument words
|
||||||
to be consumed. */
|
to be consumed. */
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef __globals_H
|
#ifndef __globals_H
|
||||||
#define __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
|
* 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,9 @@
|
||||||
/* This is the integer-width argument that will be passed to ivl. */
|
/* This is the integer-width argument that will be passed to ivl. */
|
||||||
extern unsigned integer_width;
|
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_work;
|
||||||
extern const char**vhdlpp_libdir;
|
extern const char**vhdlpp_libdir;
|
||||||
extern unsigned vhdlpp_libdir_cnt;
|
extern unsigned vhdlpp_libdir_cnt;
|
||||||
|
|
|
||||||
|
|
@ -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
|
.SH NAME
|
||||||
iverilog - Icarus Verilog compiler
|
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
|
in the Verilog source. The default is 32, the value can be any desired
|
||||||
integer value.
|
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"
|
.SH "VARIABLES IN COMMAND FILES"
|
||||||
|
|
||||||
In certain cases, iverilog supports variables in command files. These
|
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
|
.SH COPYRIGHT
|
||||||
.nf
|
.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
|
This document can be freely redistributed according to the terms of the
|
||||||
GNU General Public License version 2.0
|
GNU General Public License version 2.0
|
||||||
|
|
|
||||||
|
|
@ -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
|
* 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
|
||||||
|
|
@ -141,6 +141,8 @@ char warning_flags[16] = "n";
|
||||||
|
|
||||||
unsigned integer_width = 32;
|
unsigned integer_width = 32;
|
||||||
|
|
||||||
|
unsigned width_cap = 65536;
|
||||||
|
|
||||||
char*mod_list = 0;
|
char*mod_list = 0;
|
||||||
char*command_filename = 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, "iwidth:%u\n", integer_width);
|
||||||
|
|
||||||
|
fprintf(iconfig_file, "widthcap:%u\n", width_cap);
|
||||||
|
|
||||||
/* Write the preprocessor command needed to preprocess a
|
/* Write the preprocessor command needed to preprocess a
|
||||||
single file. This may be used to preprocess library
|
single file. This may be used to preprocess library
|
||||||
files. */
|
files. */
|
||||||
|
|
|
||||||
22
elab_expr.cc
22
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
|
||||||
|
|
@ -538,7 +538,7 @@ NetExpr* PEBinary::elaborate_expr_base_mult_(Design*,
|
||||||
return tmp;
|
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);
|
NetEConst*tmp = make_const_0(expr_wid);
|
||||||
tmp->cast_signed(signed_flag_);
|
tmp->cast_signed(signed_flag_);
|
||||||
tmp->set_line(*this);
|
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();
|
r_val = rc->value().as_long();
|
||||||
|
|
||||||
// Clip to a sensible range to avoid underflow/overflow
|
// Clip to a sensible range to avoid underflow/overflow
|
||||||
// in the following calculations. 1024 bits should be
|
// in the following calculations.
|
||||||
// enough for anyone...
|
|
||||||
if (r_val < 0)
|
if (r_val < 0)
|
||||||
r_val = 0;
|
r_val = 0;
|
||||||
if (r_val > 1024)
|
if ((unsigned long)r_val > width_cap)
|
||||||
r_val = 1024;
|
r_val = width_cap;
|
||||||
|
|
||||||
// If the left operand is a simple unsized number, we
|
// If the left operand is a simple unsized number, we
|
||||||
// can calculate the actual width required for the power
|
// can calculate the actual width required for the power
|
||||||
|
|
@ -5373,13 +5372,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;
|
||||||
|
|
@ -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
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
38
eval_tree.cc
38
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);
|
||||||
|
|
@ -1088,16 +1089,16 @@ NetEConst* NetEBShift::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
||||||
|
|
||||||
verinum val;
|
verinum val;
|
||||||
if (rv.is_defined()) {
|
if (rv.is_defined()) {
|
||||||
unsigned shift = rv.as_ulong();
|
unsigned shift = rv.as_unsigned();
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
|
|
||||||
10
main.cc
10
main.cc
|
|
@ -1,5 +1,5 @@
|
||||||
const char COPYRIGHT[] =
|
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
|
* This source code is free software; you can redistribute it
|
||||||
|
|
@ -191,6 +191,11 @@ bool verbose_flag = false;
|
||||||
|
|
||||||
unsigned integer_width = 32;
|
unsigned integer_width = 32;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Width limit for unsized expressions.
|
||||||
|
*/
|
||||||
|
unsigned width_cap = 65536;
|
||||||
|
|
||||||
int def_ts_units = 0;
|
int def_ts_units = 0;
|
||||||
int def_ts_prec = 0;
|
int def_ts_prec = 0;
|
||||||
|
|
||||||
|
|
@ -647,6 +652,9 @@ static void read_iconfig_file(const char*ipath)
|
||||||
} else if (strcmp(buf, "iwidth") == 0) {
|
} else if (strcmp(buf, "iwidth") == 0) {
|
||||||
integer_width = strtoul(cp,0,10);
|
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) {
|
} else if (strcmp(buf, "library_file") == 0) {
|
||||||
perm_string path = filename_strings.make(cp);
|
perm_string path = filename_strings.make(cp);
|
||||||
library_file_map[path] = true;
|
library_file_map[path] = true;
|
||||||
|
|
|
||||||
23
netmisc.cc
23
netmisc.cc
|
|
@ -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,
|
// If context_width is positive, this is the RHS of an assignment,
|
||||||
// so the LHS width must also be included in the width calculation.
|
// so the LHS width must also be included in the width calculation.
|
||||||
if ((context_width > 0) && (pe->expr_type() != IVL_VT_REAL)
|
unsigned pos_context_width = context_width > 0 ? context_width : 0;
|
||||||
&& (expr_width < (unsigned)context_width))
|
if ((pe->expr_type() != IVL_VT_REAL) && (expr_width < pos_context_width))
|
||||||
expr_width = context_width;
|
expr_width = pos_context_width;
|
||||||
|
|
||||||
if (debug_elaborate) {
|
if (debug_elaborate) {
|
||||||
cerr << pe->get_fileline() << ": elab_and_eval: test_width of "
|
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.
|
// width, do so.
|
||||||
if ((context_width > 0) && (!force_expand)
|
if ((context_width > 0) && (!force_expand)
|
||||||
&& (pe->expr_type() != IVL_VT_REAL)
|
&& (pe->expr_type() != IVL_VT_REAL)
|
||||||
&& (expr_width > (unsigned)context_width)) {
|
&& (expr_width > pos_context_width)) {
|
||||||
expr_width = max(pe->min_width(), (unsigned)context_width);
|
expr_width = max(pe->min_width(), pos_context_width);
|
||||||
|
|
||||||
if (debug_elaborate) {
|
if (debug_elaborate) {
|
||||||
cerr << pe->get_fileline() << ": "
|
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;
|
unsigned flags = PExpr::NO_FLAGS;
|
||||||
if (need_const)
|
if (need_const)
|
||||||
flags |= PExpr::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);
|
tmp = cast_to_real(tmp);
|
||||||
break;
|
break;
|
||||||
case IVL_VT_BOOL:
|
case IVL_VT_BOOL:
|
||||||
tmp = cast_to_int2(tmp, context_width > 0 ? context_width : 0);
|
tmp = cast_to_int2(tmp, pos_context_width);
|
||||||
break;
|
break;
|
||||||
case IVL_VT_LOGIC:
|
case IVL_VT_LOGIC:
|
||||||
tmp = cast_to_int4(tmp, context_width > 0 ? context_width : 0);
|
tmp = cast_to_int4(tmp, pos_context_width);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
* 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
|
||||||
|
|
@ -1080,6 +1080,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr,
|
||||||
return lv;
|
return lv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct vector_info draw_binary_expr(ivl_expr_t expr,
|
static struct vector_info draw_binary_expr(ivl_expr_t expr,
|
||||||
unsigned wid,
|
unsigned wid,
|
||||||
int stuff_ok_flag)
|
int stuff_ok_flag)
|
||||||
|
|
|
||||||
388
verinum.cc
388
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. */
|
||||||
|
|
@ -378,6 +378,25 @@ void verinum::set(unsigned off, const verinum&val)
|
||||||
bits_[off+idx] = val[idx];
|
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
|
unsigned long verinum::as_ulong() const
|
||||||
{
|
{
|
||||||
if (nbits_ == 0)
|
if (nbits_ == 0)
|
||||||
|
|
@ -386,15 +405,13 @@ unsigned long verinum::as_ulong() const
|
||||||
if (!is_defined())
|
if (!is_defined())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
unsigned top = nbits_;
|
|
||||||
if (top >= (8 * sizeof(unsigned long)))
|
|
||||||
top = 8 * sizeof(unsigned long);
|
|
||||||
|
|
||||||
unsigned long val = 0;
|
unsigned long val = 0;
|
||||||
unsigned long mask = 1;
|
unsigned long mask = 1;
|
||||||
for (unsigned idx = 0 ; idx < top ; idx += 1, mask <<= 1)
|
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1, mask <<= 1)
|
||||||
if (bits_[idx] == V1)
|
if (bits_[idx] == V1) {
|
||||||
|
if (mask == 0) return ~mask;
|
||||||
val |= mask;
|
val |= mask;
|
||||||
|
}
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
@ -407,15 +424,13 @@ uint64_t verinum::as_ulong64() const
|
||||||
if (!is_defined())
|
if (!is_defined())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
unsigned top = nbits_;
|
|
||||||
if (top >= (8 * sizeof(uint64_t)))
|
|
||||||
top = 8 * sizeof(uint64_t);
|
|
||||||
|
|
||||||
uint64_t val = 0;
|
uint64_t val = 0;
|
||||||
uint64_t mask = 1;
|
uint64_t mask = 1;
|
||||||
for (unsigned idx = 0 ; idx < top ; idx += 1, mask <<= 1)
|
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1, mask <<= 1)
|
||||||
if (bits_[idx] == V1)
|
if (bits_[idx] == V1) {
|
||||||
|
if (mask == 0) return ~mask;
|
||||||
val |= mask;
|
val |= mask;
|
||||||
|
}
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
@ -968,7 +983,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 +1003,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 +1218,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 +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 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 +1288,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 +1368,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 +1400,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 +1435,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 +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);
|
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 +1508,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 +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);
|
return trim_vnum(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
23
verinum.h
23
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
|
||||||
|
|
@ -97,9 +97,14 @@ class verinum {
|
||||||
|
|
||||||
V operator[] (unsigned idx) const { return get(idx); }
|
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;
|
uint64_t as_ulong64() const;
|
||||||
|
unsigned as_unsigned() const;
|
||||||
unsigned long as_ulong() const;
|
unsigned long as_ulong() const;
|
||||||
|
|
||||||
signed long as_long() const;
|
signed long as_long() const;
|
||||||
double as_double() const;
|
double as_double() const;
|
||||||
string as_string() 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; }
|
{ 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 +197,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
|
||||||
|
|
|
||||||
|
|
@ -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
|
* 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
|
||||||
|
|
@ -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
|
* 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
|
* marked with the source of the cassign so that it may later be
|
||||||
* unlinked without specifically knowing the source that this
|
* 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);
|
= dynamic_cast<vvp_fun_signal_base*>(dst->fun);
|
||||||
assert(sig);
|
assert(sig);
|
||||||
|
|
||||||
/* Detect the special case that we are already continuous
|
/* Any previous continuous assign should have been removed already. */
|
||||||
assigning the source onto the destination. */
|
assert(sig->cassign_link == 0);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
sig->cassign_link = src;
|
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:
|
* constant value to a signal. The instruction arguments are:
|
||||||
*
|
*
|
||||||
* %cassign/vec4 <net>;
|
* %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_net_t*net = cp->net;
|
||||||
vvp_vector4_t value = thr->pop_vec4();
|
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_net_ptr_t ptr (net, 1);
|
||||||
vvp_send_vec4(ptr, value, 0);
|
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)
|
if (thr->flags[4] == BIT4_1)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
/* Remove any previous continuous assign to this net. */
|
||||||
|
cassign_unlink(net);
|
||||||
|
|
||||||
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (net->fil);
|
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*> (net->fil);
|
||||||
assert(sig);
|
assert(sig);
|
||||||
|
|
||||||
|
|
@ -1873,6 +1890,9 @@ bool of_CASSIGN_WR(vthread_t thr, vvp_code_t cp)
|
||||||
vvp_net_t*net = cp->net;
|
vvp_net_t*net = cp->net;
|
||||||
double value = thr->pop_real();
|
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. */
|
/* Set the value into port 1 of the destination. */
|
||||||
vvp_net_ptr_t ptr (net, 1);
|
vvp_net_ptr_t ptr (net, 1);
|
||||||
vvp_send_real(ptr, value, 0);
|
vvp_send_real(ptr, value, 0);
|
||||||
|
|
|
||||||
|
|
@ -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
|
* 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
|
||||||
|
|
@ -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 we have a zero exponent just return 1. */
|
||||||
if (y == vvp_vector2_t(0L, 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? */
|
/* Is the value odd? */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue