Merge branch 'master' into elaborate-net-rework
This commit is contained in:
commit
bc3411e28e
74
PExpr.cc
74
PExpr.cc
|
|
@ -20,8 +20,8 @@
|
|||
# include "config.h"
|
||||
|
||||
# include <iostream>
|
||||
# include <cstring>
|
||||
|
||||
# include "compiler.h"
|
||||
# include "PExpr.h"
|
||||
# include "Module.h"
|
||||
# include <typeinfo>
|
||||
|
|
@ -131,18 +131,76 @@ PECallFunction::~PECallFunction()
|
|||
|
||||
bool PECallFunction::is_constant(Module*mod) const
|
||||
{
|
||||
/* Only $clog2 can be a constant system function. */
|
||||
if (peek_tail_name(path_)[0] == '$') {
|
||||
if (strcmp(peek_tail_name(path_).str(), "$clog2") == 0) {
|
||||
/* Only $clog2 and the builtin mathematical functions can
|
||||
* be a constant system function. */
|
||||
perm_string name = peek_tail_name(path_);
|
||||
if (name[0] == '$' && (generation_flag >= GN_VER2005 ||
|
||||
gn_icarus_misc_flag || gn_verilog_ams_flag)) {
|
||||
if (name == "$clog2" ||
|
||||
name == "$ln" ||
|
||||
name == "$log10" ||
|
||||
name == "$exp" ||
|
||||
name == "$sqrt" ||
|
||||
name == "$floor" ||
|
||||
name == "$ceil" ||
|
||||
name == "$sin" ||
|
||||
name == "$cos" ||
|
||||
name == "$tan" ||
|
||||
name == "$asin" ||
|
||||
name == "$acos" ||
|
||||
name == "$atan" ||
|
||||
name == "$sinh" ||
|
||||
name == "$cosh" ||
|
||||
name == "$tanh" ||
|
||||
name == "$asinh" ||
|
||||
name == "$acosh" ||
|
||||
name == "$atanh") {
|
||||
if (parms_.size() != 1 || parms_[0] == 0) {
|
||||
cerr << get_fileline() << ": error: $clog2 takes a "
|
||||
"single argument." << endl;
|
||||
cerr << get_fileline() << ": error: " << name
|
||||
<< " takes a single argument." << endl;
|
||||
return false;
|
||||
}
|
||||
/* If the argument is constant $clog2 is constant. */
|
||||
/* If the argument is constant the function is constant. */
|
||||
return parms_[0]->is_constant(mod);
|
||||
}
|
||||
return false; /* Most system functions are not constant. */
|
||||
|
||||
if (name == "$pow" ||
|
||||
name == "$atan2" ||
|
||||
name == "$hypot") {
|
||||
if (parms_.size() != 2 || parms_[0] == 0 || parms_[1] == 0) {
|
||||
cerr << get_fileline() << ": error: " << name
|
||||
<< " takes two arguments." << endl;
|
||||
return false;
|
||||
/* If the arguments are constant the function is constant. */
|
||||
return parms_[0]->is_constant(mod) &&
|
||||
parms_[1]->is_constant(mod);
|
||||
}
|
||||
}
|
||||
|
||||
/* These are only available with verilog-ams or icarus-misc. */
|
||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
||||
(name == "$log" || name == "$abs")) {
|
||||
if (parms_.size() != 1 || parms_[0] == 0) {
|
||||
cerr << get_fileline() << ": error: " << name
|
||||
<< " takes a single argument." << endl;
|
||||
return false;
|
||||
}
|
||||
/* If the argument is constant the function is constant. */
|
||||
return parms_[0]->is_constant(mod);
|
||||
}
|
||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
||||
(name == "$min" || name == "$max")) {
|
||||
if (parms_.size() != 2 || parms_[0] == 0 || parms_[1] == 0) {
|
||||
cerr << get_fileline() << ": error: " << name
|
||||
<< " takes two arguments." << endl;
|
||||
return false;
|
||||
/* If the arguments are constant the function is constant. */
|
||||
return parms_[0]->is_constant(mod) &&
|
||||
parms_[1]->is_constant(mod);
|
||||
}
|
||||
}
|
||||
|
||||
return false; /* The other system functions are not constant. */
|
||||
}
|
||||
|
||||
/* Checking for constant user functions goes here. */
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ const char*npath = 0;
|
|||
const char*targ = "vvp";
|
||||
const char*depfile = 0;
|
||||
|
||||
const char*generation = "2x";
|
||||
const char*generation = "2005";
|
||||
const char*gen_specify = "specify";
|
||||
const char*gen_xtypes = "xtypes";
|
||||
const char*gen_icarus = "icarus-misc";
|
||||
|
|
@ -765,9 +765,18 @@ int main(int argc, char **argv)
|
|||
how to handle them. */
|
||||
fprintf(iconfig_file, "sys_func:%s%csystem.sft\n", base, sep);
|
||||
|
||||
/* If verilog-ams is enabled, then include the va_math module
|
||||
as well. */
|
||||
if (strcmp(gen_verilog_ams,"verilog-ams") == 0) {
|
||||
/* If verilog-2005 is enabled or icarus-misc or verilog-ams,
|
||||
* then include the v2005_math library. */
|
||||
if (strcmp(generation, "2005") == 0 ||
|
||||
strcmp(gen_icarus, "icarus-misc") == 0 ||
|
||||
strcmp(gen_verilog_ams, "verilog-ams") == 0) {
|
||||
fprintf(iconfig_file, "sys_func:%s%cv2005_math.sft\n", base, sep);
|
||||
fprintf(iconfig_file, "module:v2005_math\n");
|
||||
}
|
||||
/* If verilog-ams or icarus_misc is enabled, then include the
|
||||
* va_math module as well. */
|
||||
if (strcmp(gen_verilog_ams,"verilog-ams") == 0 ||
|
||||
strcmp(gen_icarus, "icarus-misc") == 0) {
|
||||
fprintf(iconfig_file, "sys_func:%s%cva_math.sft\n", base, sep);
|
||||
fprintf(iconfig_file, "module:va_math\n");
|
||||
}
|
||||
|
|
|
|||
115
elab_pexpr.cc
115
elab_pexpr.cc
|
|
@ -25,7 +25,6 @@
|
|||
# include "netmisc.h"
|
||||
|
||||
# include <cstdlib>
|
||||
# include <cstring>
|
||||
# include <iostream>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
|
|
@ -269,23 +268,54 @@ NetExpr*PEUnary::elaborate_pexpr (Design*des, NetScope*scope) const
|
|||
return tmp;
|
||||
}
|
||||
|
||||
/* Reuse the routine from eval_tree.cc. */
|
||||
/* Reuse these routines from eval_tree.cc. */
|
||||
NetExpr* evaluate_clog2(NetExpr*arg);
|
||||
NetExpr* evaluate_math_one_arg(NetExpr*arg, const char*name);
|
||||
NetExpr* evaluate_math_two_args(NetExpr*arg0, NetExpr*arg1, const char*name);
|
||||
NetExpr* evaluate_abs(NetExpr*arg);
|
||||
NetExpr* evaluate_min_max(NetExpr*arg0, NetExpr*arg1, const char*name);
|
||||
|
||||
NetExpr* PECallFunction::elaborate_pexpr(Design*des, NetScope*scope) const
|
||||
{
|
||||
/* For now only $clog2 can be a constant system function. */
|
||||
if (peek_tail_name(path_)[0] == '$') {
|
||||
if (strcmp(peek_tail_name(path_).str(), "$clog2") == 0) {
|
||||
/* Only $clog2 and the builtin mathematical functions can
|
||||
* be a constant system function. */
|
||||
perm_string name = peek_tail_name(path_);
|
||||
if (name[0] == '$' && (generation_flag >= GN_VER2005 ||
|
||||
gn_icarus_misc_flag || gn_verilog_ams_flag)) {
|
||||
if (name == "$clog2" ||
|
||||
name == "$ln" ||
|
||||
name == "$log10" ||
|
||||
name == "$exp" ||
|
||||
name == "$sqrt" ||
|
||||
name == "$floor" ||
|
||||
name == "$ceil" ||
|
||||
name == "$sin" ||
|
||||
name == "$cos" ||
|
||||
name == "$tan" ||
|
||||
name == "$asin" ||
|
||||
name == "$acos" ||
|
||||
name == "$atan" ||
|
||||
name == "$sinh" ||
|
||||
name == "$cosh" ||
|
||||
name == "$tanh" ||
|
||||
name == "$asinh" ||
|
||||
name == "$acosh" ||
|
||||
name == "$atanh") {
|
||||
if (parms_.size() != 1 || parms_[0] == 0) {
|
||||
cerr << get_fileline() << ": error: $clog2 takes a "
|
||||
"single argument." << endl;
|
||||
cerr << get_fileline() << ": error: " << name
|
||||
<< " takes a single argument." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
NetExpr*arg = parms_[0]->elaborate_pexpr(des, scope);
|
||||
if (arg == 0) return 0;
|
||||
eval_expr(arg);
|
||||
NetExpr*rtn = evaluate_clog2(arg);
|
||||
NetExpr*rtn;
|
||||
if (peek_tail_name(path_) == "$clog2") {
|
||||
rtn = evaluate_clog2(arg);
|
||||
} else {
|
||||
rtn = evaluate_math_one_arg(arg, name.str());
|
||||
}
|
||||
delete arg;
|
||||
if (rtn != 0) {
|
||||
rtn->set_line(*this);
|
||||
|
|
@ -293,6 +323,75 @@ NetExpr* PECallFunction::elaborate_pexpr(Design*des, NetScope*scope) const
|
|||
}
|
||||
}
|
||||
|
||||
if (name == "$pow" ||
|
||||
name == "$atan2" ||
|
||||
name == "$hypot") {
|
||||
if (parms_.size() != 2 || parms_[0] == 0 || parms_[1] == 0) {
|
||||
cerr << get_fileline() << ": error: " << name
|
||||
<< " takes two arguments." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
NetExpr*arg0 = parms_[0]->elaborate_pexpr(des, scope);
|
||||
NetExpr*arg1 = parms_[1]->elaborate_pexpr(des, scope);
|
||||
if (arg0 == 0 || arg1 == 0) return 0;
|
||||
eval_expr(arg0);
|
||||
eval_expr(arg1);
|
||||
NetExpr*rtn = evaluate_math_two_args(arg0, arg1, name.str());
|
||||
delete arg0;
|
||||
delete arg1;
|
||||
if (rtn != 0) {
|
||||
rtn->set_line(*this);
|
||||
return rtn;
|
||||
}
|
||||
}
|
||||
|
||||
/* These are only available with verilog-ams or icarus-misc. */
|
||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
||||
(name == "$log" || name == "$abs")) {
|
||||
if (parms_.size() != 1 || parms_[0] == 0) {
|
||||
cerr << get_fileline() << ": error: " << name
|
||||
<< " takes a single argument." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
NetExpr*arg = parms_[0]->elaborate_pexpr(des, scope);
|
||||
if (arg == 0) return 0;
|
||||
eval_expr(arg);
|
||||
NetExpr*rtn;
|
||||
if (peek_tail_name(path_) == "$log") {
|
||||
rtn = evaluate_math_one_arg(arg, name.str());
|
||||
} else {
|
||||
rtn = evaluate_abs(arg);
|
||||
}
|
||||
delete arg;
|
||||
if (rtn != 0) {
|
||||
rtn->set_line(*this);
|
||||
return rtn;
|
||||
}
|
||||
}
|
||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
||||
(name == "$min" || name == "$max")) {
|
||||
if (parms_.size() != 2 || parms_[0] == 0 || parms_[1] == 0) {
|
||||
cerr << get_fileline() << ": error: " << name
|
||||
<< " takes two arguments." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
NetExpr*arg0 = parms_[0]->elaborate_pexpr(des, scope);
|
||||
NetExpr*arg1 = parms_[1]->elaborate_pexpr(des, scope);
|
||||
if (arg0 == 0 || arg1 == 0) return 0;
|
||||
eval_expr(arg0);
|
||||
eval_expr(arg1);
|
||||
NetExpr*rtn = evaluate_min_max(arg0, arg1, name.str());
|
||||
delete arg0;
|
||||
delete arg1;
|
||||
if (rtn != 0) {
|
||||
rtn->set_line(*this);
|
||||
return rtn;
|
||||
}
|
||||
}
|
||||
|
||||
cerr << get_fileline() << ": error: this is not a constant "
|
||||
"system function (" << *this << ")." << endl;
|
||||
des->errors += 1;
|
||||
|
|
|
|||
348
eval_tree.cc
348
eval_tree.cc
|
|
@ -340,19 +340,15 @@ NetEConst* NetEBComp::eval_leeq_real_(NetExpr*le, NetExpr*ri, bool eq_flag)
|
|||
switch (le->expr_type()) {
|
||||
case IVL_VT_REAL:
|
||||
rtmp = dynamic_cast<NetECReal*> (le);
|
||||
if (rtmp == 0)
|
||||
return 0;
|
||||
|
||||
if (rtmp == 0) return 0;
|
||||
lv = rtmp->value().as_double();
|
||||
break;
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
vtmp = dynamic_cast<NetEConst*> (le);
|
||||
if (vtmp == 0)
|
||||
return 0;
|
||||
|
||||
lv = vtmp->value().as_long();
|
||||
if (vtmp == 0) return 0;
|
||||
lv = vtmp->value().as_double();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -361,23 +357,18 @@ NetEConst* NetEBComp::eval_leeq_real_(NetExpr*le, NetExpr*ri, bool eq_flag)
|
|||
assert(0);
|
||||
}
|
||||
|
||||
|
||||
switch (ri->expr_type()) {
|
||||
case IVL_VT_REAL:
|
||||
rtmp = dynamic_cast<NetECReal*> (ri);
|
||||
if (rtmp == 0)
|
||||
return 0;
|
||||
|
||||
if (rtmp == 0) return 0;
|
||||
rv = rtmp->value().as_double();
|
||||
break;
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
vtmp = dynamic_cast<NetEConst*> (ri);
|
||||
if (vtmp == 0)
|
||||
return 0;
|
||||
|
||||
rv = vtmp->value().as_long();
|
||||
if (vtmp == 0) return 0;
|
||||
rv = vtmp->value().as_double();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -481,19 +472,6 @@ NetEConst* NetEBComp::eval_gt_()
|
|||
return tmp;
|
||||
}
|
||||
|
||||
/* Compare with a real value. Do it as double precision. */
|
||||
if (right_->expr_type() == IVL_VT_REAL) {
|
||||
NetECReal*tmp = dynamic_cast<NetECReal*>(right_);
|
||||
if (tmp == 0)
|
||||
return 0;
|
||||
|
||||
double rr = tmp->value().as_double();
|
||||
double ll = lv.has_sign()? lv.as_long() : lv.as_ulong();
|
||||
|
||||
verinum result ((ll > rr)? verinum::V1 : verinum::V0, 1, true);
|
||||
return new NetEConst(result);
|
||||
}
|
||||
|
||||
/* Now go on to the normal test of the values. */
|
||||
NetEConst*r = dynamic_cast<NetEConst*>(right_);
|
||||
if (r == 0) return 0;
|
||||
|
|
@ -532,19 +510,6 @@ NetEConst* NetEBComp::eval_gteq_()
|
|||
return tmp;
|
||||
}
|
||||
|
||||
/* Compare with a real value. Do it as double precision. */
|
||||
if (right_->expr_type() == IVL_VT_REAL) {
|
||||
NetECReal*tmp = dynamic_cast<NetECReal*>(right_);
|
||||
if (tmp == 0)
|
||||
return 0;
|
||||
|
||||
double rr = tmp->value().as_double();
|
||||
double ll = lv.has_sign()? lv.as_long() : lv.as_ulong();
|
||||
|
||||
verinum result ((ll >= rr)? verinum::V1 : verinum::V0, 1, true);
|
||||
return new NetEConst(result);
|
||||
}
|
||||
|
||||
/* Now go on to the normal test of the values. */
|
||||
NetEConst*r = dynamic_cast<NetEConst*>(right_);
|
||||
if (r == 0) return 0;
|
||||
|
|
@ -570,8 +535,66 @@ NetEConst* NetEBComp::eval_gteq_()
|
|||
* are equal, but there are are x/z bits, then the situation is
|
||||
* ambiguous so the result is x.
|
||||
*/
|
||||
NetEConst* NetEBComp::eval_eqeq_real_(NetExpr*le, NetExpr*ri, bool ne_flag)
|
||||
{
|
||||
NetEConst*vtmp;
|
||||
NetECReal*rtmp;
|
||||
double lv, rv;
|
||||
|
||||
switch (le->expr_type()) {
|
||||
case IVL_VT_REAL:
|
||||
rtmp = dynamic_cast<NetECReal*> (le);
|
||||
if (rtmp == 0) return 0;
|
||||
lv = rtmp->value().as_double();
|
||||
break;
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
vtmp = dynamic_cast<NetEConst*> (le);
|
||||
if (vtmp == 0) return 0;
|
||||
lv = vtmp->value().as_double();
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Unexpected expression type? " << le->expr_type() << endl;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
switch (ri->expr_type()) {
|
||||
case IVL_VT_REAL:
|
||||
rtmp = dynamic_cast<NetECReal*> (ri);
|
||||
if (rtmp == 0) return 0;
|
||||
rv = rtmp->value().as_double();
|
||||
break;
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
vtmp = dynamic_cast<NetEConst*> (ri);
|
||||
if (vtmp == 0) return 0;
|
||||
rv = vtmp->value().as_double();
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Unexpected expression type? " << ri->expr_type() << endl;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
verinum result((lv == rv ^ ne_flag) ? verinum::V1 : verinum::V0, 1);
|
||||
vtmp = new NetEConst(result);
|
||||
vtmp->set_line(*this);
|
||||
|
||||
return vtmp;
|
||||
}
|
||||
|
||||
NetEConst* NetEBComp::eval_eqeq_(bool ne_flag)
|
||||
{
|
||||
if (right_->expr_type() == IVL_VT_REAL)
|
||||
return eval_eqeq_real_(right_, left_, ne_flag);
|
||||
if (left_->expr_type() == IVL_VT_REAL)
|
||||
return eval_eqeq_real_(right_, left_, ne_flag);
|
||||
|
||||
NetEConst*l = dynamic_cast<NetEConst*>(left_);
|
||||
if (l == 0) return 0;
|
||||
NetEConst*r = dynamic_cast<NetEConst*>(right_);
|
||||
|
|
@ -1673,25 +1696,238 @@ NetExpr* evaluate_clog2(NetExpr*arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetExpr* NetESFunc::eval_tree(int prune_to_width)
|
||||
NetExpr* evaluate_math_one_arg(NetExpr*arg, const char*name)
|
||||
{
|
||||
/* For now only $clog2 can be a constant system function. */
|
||||
if (strcmp(name(), "$clog2") == 0) {
|
||||
if (nparms() != 1 || parm(0) == 0) {
|
||||
cerr << get_fileline() << ": error: $clog2 takes a single "
|
||||
"argument." << endl;
|
||||
return 0;
|
||||
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg);
|
||||
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg);
|
||||
if (tmpi || tmpr) {
|
||||
double arg;
|
||||
if (tmpi) {
|
||||
arg = tmpi->value().as_double();
|
||||
} else {
|
||||
arg = tmpr->value().as_double();
|
||||
}
|
||||
NetExpr*rtn = evaluate_clog2(parm(0));
|
||||
if (rtn != 0) {
|
||||
rtn->set_line(*this);
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluate "
|
||||
"constant $clog2()." << endl;
|
||||
}
|
||||
return rtn;
|
||||
|
||||
if (strcmp(name, "$ln") == 0) {
|
||||
return new NetECReal(verireal(log(arg)));
|
||||
} else if (strcmp(name, "$log") == 0) {
|
||||
return new NetECReal(verireal(log10(arg)));
|
||||
} else if (strcmp(name, "$log10") == 0) {
|
||||
return new NetECReal(verireal(log10(arg)));
|
||||
} else if (strcmp(name, "$exp") == 0) {
|
||||
return new NetECReal(verireal(exp(arg)));
|
||||
} else if (strcmp(name, "$sqrt") == 0) {
|
||||
return new NetECReal(verireal(sqrt(arg)));
|
||||
} else if (strcmp(name, "$floor") == 0) {
|
||||
return new NetECReal(verireal(floor(arg)));
|
||||
} else if (strcmp(name, "$ceil") == 0) {
|
||||
return new NetECReal(verireal(ceil(arg)));
|
||||
} else if (strcmp(name, "$sin") == 0) {
|
||||
return new NetECReal(verireal(sin(arg)));
|
||||
} else if (strcmp(name, "$cos") == 0) {
|
||||
return new NetECReal(verireal(cos(arg)));
|
||||
} else if (strcmp(name, "$tan") == 0) {
|
||||
return new NetECReal(verireal(tan(arg)));
|
||||
} else if (strcmp(name, "$asin") == 0) {
|
||||
return new NetECReal(verireal(asin(arg)));
|
||||
} else if (strcmp(name, "$acos") == 0) {
|
||||
return new NetECReal(verireal(acos(arg)));
|
||||
} else if (strcmp(name, "$atan") == 0) {
|
||||
return new NetECReal(verireal(atan(arg)));
|
||||
} else if (strcmp(name, "$sinh") == 0) {
|
||||
return new NetECReal(verireal(sinh(arg)));
|
||||
} else if (strcmp(name, "$cosh") == 0) {
|
||||
return new NetECReal(verireal(cosh(arg)));
|
||||
} else if (strcmp(name, "$tanh") == 0) {
|
||||
return new NetECReal(verireal(tanh(arg)));
|
||||
} else if (strcmp(name, "$asinh") == 0) {
|
||||
return new NetECReal(verireal(asinh(arg)));
|
||||
} else if (strcmp(name, "$acosh") == 0) {
|
||||
return new NetECReal(verireal(acosh(arg)));
|
||||
} else if (strcmp(name, "$atanh") == 0) {
|
||||
return new NetECReal(verireal(atanh(arg)));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr* evaluate_math_two_args(NetExpr*arg0, NetExpr*arg1, const char*name)
|
||||
{
|
||||
NetEConst*tmpi0 = dynamic_cast<NetEConst *>(arg0);
|
||||
NetECReal*tmpr0 = dynamic_cast<NetECReal *>(arg0);
|
||||
NetEConst*tmpi1 = dynamic_cast<NetEConst *>(arg1);
|
||||
NetECReal*tmpr1 = dynamic_cast<NetECReal *>(arg1);
|
||||
if ((tmpi0 || tmpr0) && (tmpi1 || tmpr1)) {
|
||||
double arg0, arg1;
|
||||
if (tmpi0) {
|
||||
arg0 = tmpi0->value().as_double();
|
||||
} else {
|
||||
arg0 = tmpr0->value().as_double();
|
||||
}
|
||||
if (tmpi1) {
|
||||
arg1 = tmpi1->value().as_double();
|
||||
} else {
|
||||
arg1 = tmpr1->value().as_double();
|
||||
}
|
||||
|
||||
if (strcmp(name, "$pow") == 0) {
|
||||
return new NetECReal(verireal(pow(arg0, arg1)));
|
||||
} else if (strcmp(name, "$atan2") == 0) {
|
||||
return new NetECReal(verireal(atan2(arg0, arg1)));
|
||||
} else if (strcmp(name, "$hypot") == 0) {
|
||||
return new NetECReal(verireal(hypot(arg0, arg1)));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr* evaluate_abs(NetExpr*arg)
|
||||
{
|
||||
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg);
|
||||
if (tmpi) {
|
||||
verinum arg = tmpi->value();
|
||||
if (arg.has_sign()) {
|
||||
arg = v_not(arg) + verinum(1);
|
||||
}
|
||||
return new NetEConst(arg);
|
||||
}
|
||||
|
||||
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg);
|
||||
if (tmpr) {
|
||||
double arg = tmpr->value().as_double();
|
||||
return new NetECReal(verireal(fabs(arg)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr* evaluate_min_max(NetExpr*arg0, NetExpr*arg1, const char*name)
|
||||
{
|
||||
NetEConst*tmpi0 = dynamic_cast<NetEConst *>(arg0);
|
||||
NetECReal*tmpr0 = dynamic_cast<NetECReal *>(arg0);
|
||||
NetEConst*tmpi1 = dynamic_cast<NetEConst *>(arg1);
|
||||
NetECReal*tmpr1 = dynamic_cast<NetECReal *>(arg1);
|
||||
if (tmpi0 && tmpi1) {
|
||||
verinum arg0 = tmpi0->value();
|
||||
verinum arg1 = tmpi1->value();
|
||||
if (strcmp(name, "$min") == 0) {
|
||||
return new NetEConst( arg0 < arg1 ? arg0 : arg1);
|
||||
} else if (strcmp(name, "$max") == 0) {
|
||||
return new NetEConst( arg0 < arg1 ? arg1 : arg0);
|
||||
}
|
||||
}
|
||||
|
||||
if ((tmpi0 || tmpr0) && (tmpi1 || tmpr1)) {
|
||||
double arg0, arg1;
|
||||
if (tmpi0) {
|
||||
arg0 = tmpi0->value().as_double();
|
||||
} else {
|
||||
arg0 = tmpr0->value().as_double();
|
||||
}
|
||||
if (tmpi1) {
|
||||
arg1 = tmpi1->value().as_double();
|
||||
} else {
|
||||
arg1 = tmpr1->value().as_double();
|
||||
}
|
||||
if (strcmp(name, "$min") == 0) {
|
||||
return new NetECReal(verireal(arg0 < arg1 ? arg0 : arg1));
|
||||
} else if (strcmp(name, "$max") == 0) {
|
||||
return new NetECReal(verireal(arg0 < arg1 ? arg1 : arg0));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr* NetESFunc::eval_tree(int prune_to_width)
|
||||
{
|
||||
/* If we are not targeting at least Verilog-2005, Verilog-AMS
|
||||
* or using the Icarus misc flag then we do not support these
|
||||
* functions as constant. */
|
||||
if (generation_flag < GN_VER2005 &&
|
||||
!gn_icarus_misc_flag && !gn_verilog_ams_flag) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char*nm = name();
|
||||
NetExpr*rtn = 0;
|
||||
/* Only $clog2 and the builtin mathematical functions can
|
||||
* be a constant system function. */
|
||||
if (strcmp(nm, "$clog2") == 0 ||
|
||||
strcmp(nm, "$ln") == 0 ||
|
||||
strcmp(nm, "$log10") == 0 ||
|
||||
strcmp(nm, "$exp") == 0 ||
|
||||
strcmp(nm, "$sqrt") == 0 ||
|
||||
strcmp(nm, "$floor") == 0 ||
|
||||
strcmp(nm, "$ceil") == 0 ||
|
||||
strcmp(nm, "$sin") == 0 ||
|
||||
strcmp(nm, "$cos") == 0 ||
|
||||
strcmp(nm, "$tan") == 0 ||
|
||||
strcmp(nm, "$asin") == 0 ||
|
||||
strcmp(nm, "$acos") == 0 ||
|
||||
strcmp(nm, "$atan") == 0 ||
|
||||
strcmp(nm, "$sinh") == 0 ||
|
||||
strcmp(nm, "$cosh") == 0 ||
|
||||
strcmp(nm, "$tanh") == 0 ||
|
||||
strcmp(nm, "$asinh") == 0 ||
|
||||
strcmp(nm, "$acosh") == 0 ||
|
||||
strcmp(nm, "$atanh") == 0) {
|
||||
if (nparms() != 1 || parm(0) == 0) {
|
||||
cerr << get_fileline() << ": error: " << nm
|
||||
<< " takes a single argument." << endl;
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(nm, "$clog2") == 0) {
|
||||
rtn = evaluate_clog2(parm(0));
|
||||
} else {
|
||||
rtn = evaluate_math_one_arg(parm(0), nm);
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(nm, "$pow") == 0 ||
|
||||
strcmp(nm, "$atan2") == 0 ||
|
||||
strcmp(nm, "$hypot") == 0) {
|
||||
if (nparms() != 2 || parm(0) == 0 || parm(1) == 0) {
|
||||
cerr << get_fileline() << ": error: " << nm
|
||||
<< " takes two arguments." << endl;
|
||||
return 0;
|
||||
}
|
||||
rtn = evaluate_math_two_args(parm(0), parm(1), nm);
|
||||
}
|
||||
|
||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
||||
(strcmp(nm, "$log") == 0 || strcmp(nm, "$abs") == 0)) {
|
||||
if (nparms() != 1 || parm(0) == 0) {
|
||||
cerr << get_fileline() << ": error: " << nm
|
||||
<< " takes a single argument." << endl;
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(nm, "$log") == 0) {
|
||||
rtn = evaluate_math_one_arg(parm(0), nm);
|
||||
} else {
|
||||
rtn = evaluate_abs(parm(0));
|
||||
}
|
||||
}
|
||||
|
||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
||||
(strcmp(nm, "$min") == 0 || strcmp(nm, "$max") == 0)) {
|
||||
if (nparms() != 2 || parm(0) == 0 || parm(1) == 0) {
|
||||
cerr << get_fileline() << ": error: " << nm
|
||||
<< " takes two arguments." << endl;
|
||||
return 0;
|
||||
}
|
||||
rtn = evaluate_min_max(parm(0), parm(1), nm);
|
||||
}
|
||||
|
||||
if (rtn != 0) {
|
||||
rtn->set_line(*this);
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluate constant "
|
||||
<< nm << "." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3219,6 +3219,7 @@ class NetEBComp : public NetEBinary {
|
|||
NetEConst* must_be_leeq_(NetExpr*le, const verinum&rv, bool eq_flag);
|
||||
|
||||
NetEConst*eval_eqeq_(bool ne_flag);
|
||||
NetEConst*eval_eqeq_real_(NetExpr*le, NetExpr*ri, bool ne_flag);
|
||||
NetEConst*eval_less_();
|
||||
NetEConst*eval_leeq_();
|
||||
NetEConst*eval_leeq_real_(NetExpr*le, NetExpr*ri, bool eq_flag);
|
||||
|
|
|
|||
|
|
@ -217,13 +217,19 @@ static int draw_realnum_real(ivl_expr_t exp)
|
|||
/* Handle the special case that the value is +-inf. */
|
||||
if (isinf(value)) {
|
||||
if (value > 0)
|
||||
fprintf(vvp_out, " %%loadi/wr %d, 0, %d; load=+inf\n",
|
||||
fprintf(vvp_out, " %%loadi/wr %d, 0, %d; load=+inf\n",
|
||||
res, 0x3fff);
|
||||
else
|
||||
fprintf(vvp_out, " %%loadi/wr %d, 0, %d; load=-inf\n",
|
||||
fprintf(vvp_out, " %%loadi/wr %d, 0, %d; load=-inf\n",
|
||||
res, 0x7fff);
|
||||
return res;
|
||||
}
|
||||
/* Handle the special case that the value is NaN. */
|
||||
if (value != value) {
|
||||
fprintf(vvp_out, " %%loadi/wr %d, 1, %d; load=NaN\n",
|
||||
res, 0x3fff);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (value < 0) {
|
||||
sign = 0x4000;
|
||||
|
|
|
|||
|
|
@ -330,6 +330,10 @@ char* draw_Cr_to_string(double value)
|
|||
snprintf(tmp, sizeof(tmp), "Cr<m0g7fff>");
|
||||
return strdup(tmp);
|
||||
}
|
||||
if (value != value) {
|
||||
snprintf(tmp, sizeof(tmp), "Cr<m1g3fff>");
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
int sign = 0;
|
||||
if (value < 0) {
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ CPPFLAGS = @ident_support@ -I. -I$(srcdir)/.. -I$(srcdir) -I.. @file64_support@
|
|||
CFLAGS = -Wall @CFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: dep system.vpi va_math.vpi $(ALL32)
|
||||
all: dep system.vpi va_math.vpi v2005_math.vpi $(ALL32)
|
||||
|
||||
check: all
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ sys_finish.o sys_icarus.o sys_plusargs.o sys_random.o sys_random_mti.o \
|
|||
sys_readmem.o sys_readmem_lex.o sys_scanf.o sys_sdf.o \
|
||||
sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o \
|
||||
mt19937int.o sys_priv.o sdf_lexor.o sdf_parse.o stringheap.o \
|
||||
sys_clog2.o vams_simparam.o
|
||||
vams_simparam.o
|
||||
|
||||
ifeq (@HAVE_LIBZ@,yes)
|
||||
ifeq (@HAVE_LIBBZ2@,yes)
|
||||
|
|
@ -69,6 +69,9 @@ endif
|
|||
O += sys_lxt2.o lxt2_write.o
|
||||
endif
|
||||
|
||||
# Object files for v2005_math.vpi
|
||||
M = sys_clog2.o v2005_math.o
|
||||
|
||||
# Object files for va_math.vpi
|
||||
V = va_math.o
|
||||
|
||||
|
|
@ -94,12 +97,16 @@ sdf_lexor.c: sdf_lexor.lex
|
|||
sdf_parse.c sdf_parse.h: $(srcdir)/sdf_parse.y
|
||||
$(YACC) --verbose -d -p sdf -o sdf_parse.c $(srcdir)/sdf_parse.y
|
||||
|
||||
v2005_math.vpi: $M ../vvp/libvpi.a
|
||||
$(CC) @shared@ -o $@ $M -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS)
|
||||
|
||||
va_math.vpi: $V ../vvp/libvpi.a
|
||||
$(CC) @shared@ -o $@ $V -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -rf *.o sys_readmem_lex.c dep system.vpi va_math.vpi bin32
|
||||
rm -rf *.o sys_readmem_lex.c dep system.vpi bin32
|
||||
rm -f sdf_lexor.c sdf_parse.c sdf_parse.output sdf_parse.h
|
||||
rm -f va_math.vpi v2005_math.vpi
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile config.status config.log vpi_config.h
|
||||
|
|
@ -109,6 +116,7 @@ check: all
|
|||
install: all installdirs \
|
||||
$(vpidir)/system.vpi $(libdir)/ivl/system.sft \
|
||||
$(vpidir)/va_math.vpi $(libdir)/ivl/va_math.sft \
|
||||
$(vpidir)/v2005_math.vpi $(libdir)/ivl/v2005_math.sft \
|
||||
$(vpidir)/include/
|
||||
|
||||
$(vpidir)/system.vpi: ./system.vpi
|
||||
|
|
@ -123,6 +131,12 @@ $(vpidir)/va_math.vpi: ./va_math.vpi
|
|||
$(libdir)/ivl/va_math.sft: va_math.sft
|
||||
$(INSTALL_DATA) $< $@
|
||||
|
||||
$(vpidir)/v2005_math.vpi: ./v2005_math.vpi
|
||||
$(INSTALL_PROGRAM) ./v2005_math.vpi $(vpidir)/v2005_math.vpi
|
||||
|
||||
$(libdir)/ivl/v2005_math.sft: v2005_math.sft
|
||||
$(INSTALL_DATA) $< $@
|
||||
|
||||
installdirs: ../mkinstalldirs
|
||||
$(srcdir)/../mkinstalldirs $(vpidir)
|
||||
|
||||
|
|
@ -131,6 +145,7 @@ uninstall:
|
|||
rm -f $(libdir)/ivl/system.sft
|
||||
rm -f $(vpidir)/va_math.vpi
|
||||
rm -f $(libdir)/ivl/va_math.sft
|
||||
|
||||
rm -f $(vpidir)/v2005_math.vpi
|
||||
rm -f $(libdir)/ivl/v2005_math.sft
|
||||
|
||||
-include $(patsubst %.o, dep/%.d, $O)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,39 @@
|
|||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <vpi_user.h>
|
||||
#include "sys_priv.h"
|
||||
|
||||
/*
|
||||
* This routine returns 1 if the argument supports has a numeric value,
|
||||
* otherwise it returns 0.
|
||||
*
|
||||
* This is copied from sys_priv.c.
|
||||
*/
|
||||
static unsigned is_numeric_obj(vpiHandle obj)
|
||||
{
|
||||
assert(obj);
|
||||
unsigned rtn = 0;
|
||||
|
||||
switch(vpi_get(vpiType, obj)) {
|
||||
case vpiConstant:
|
||||
case vpiParameter:
|
||||
/* These cannot be a string constant. */
|
||||
if (vpi_get(vpiConstType, obj) != vpiStringConst) rtn = 1;
|
||||
break;
|
||||
|
||||
/* These can have a valid numeric value. */
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiNet:
|
||||
case vpiPartSelect:
|
||||
case vpiRealVar:
|
||||
case vpiReg:
|
||||
case vpiTimeVar:
|
||||
rtn = 1;;
|
||||
break;
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the function is called with the correct argument.
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time)
|
|||
/*
|
||||
* This routine returns 1 if the argument is a constant value,
|
||||
* otherwise it returns 0.
|
||||
*
|
||||
* This routine was also copied to sys_clog2.c since it is not
|
||||
* part of the standard system functions.
|
||||
*/
|
||||
unsigned is_constant_obj(vpiHandle obj)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ extern void sys_time_register();
|
|||
extern void sys_vcd_register();
|
||||
extern void sys_vcdoff_register();
|
||||
extern void sys_special_register();
|
||||
extern void sys_clog2_register();
|
||||
extern void vams_simparam_register();
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
|
|
@ -182,7 +181,6 @@ void (*vlog_startup_routines[])() = {
|
|||
sys_lxt_or_vcd_register,
|
||||
sys_sdf_register,
|
||||
sys_special_register,
|
||||
sys_clog2_register,
|
||||
vams_simparam_register,
|
||||
0
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* Verilog-2005 math library for Icarus Verilog
|
||||
* http://www.icarus.com/eda/verilog/
|
||||
*
|
||||
* Copyright (C) 2007-2008 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "vpi_config.h"
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <vpi_user.h>
|
||||
|
||||
/* Single argument functions. */
|
||||
typedef struct s_single_data {
|
||||
const char *name;
|
||||
double (*func)(double);
|
||||
} t_single_data;
|
||||
|
||||
static t_single_data va_single_data[]= {
|
||||
{"$sqrt", sqrt},
|
||||
{"$ln", log},
|
||||
{"$log10", log10},
|
||||
{"$exp", exp},
|
||||
{"$ceil", ceil},
|
||||
{"$floor", floor},
|
||||
{"$sin", sin},
|
||||
{"$cos", cos},
|
||||
{"$tan", tan},
|
||||
{"$asin", asin},
|
||||
{"$acos", acos},
|
||||
{"$atan", atan},
|
||||
{"$sinh", sinh},
|
||||
{"$cosh", cosh},
|
||||
{"$tanh", tanh},
|
||||
{"$asinh", asinh},
|
||||
{"$acosh", acosh},
|
||||
{"$atanh", atanh},
|
||||
{0, 0} /* Must be NULL terminated! */
|
||||
};
|
||||
|
||||
|
||||
/* Double argument functions. */
|
||||
typedef struct s_double_data {
|
||||
const char *name;
|
||||
double (*func)(double, double);
|
||||
} t_double_data;
|
||||
|
||||
static t_double_data va_double_data[]= {
|
||||
{"$pow", pow},
|
||||
{"$atan2", atan2},
|
||||
{"$hypot", hypot},
|
||||
{0, 0} /* Must be NULL terminated! */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This structure holds the single argument information.
|
||||
*/
|
||||
typedef struct {
|
||||
vpiHandle arg;
|
||||
double (*func)(double);
|
||||
} va_single_t;
|
||||
|
||||
|
||||
/*
|
||||
* This structure holds the double argument information.
|
||||
*/
|
||||
typedef struct {
|
||||
vpiHandle arg1;
|
||||
vpiHandle arg2;
|
||||
double (*func)(double, double);
|
||||
} va_double_t;
|
||||
|
||||
|
||||
/*
|
||||
* Standard error message routine. The format string must take one
|
||||
* string argument (the name of the function).
|
||||
*/
|
||||
static void va_error_message(vpiHandle callh, const char *format,
|
||||
const char *name) {
|
||||
vpi_printf("%s:%d: error: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf(format, name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process an argument.
|
||||
*/
|
||||
vpiHandle va_process_argument(vpiHandle callh, const char *name,
|
||||
vpiHandle arg, const char *post) {
|
||||
PLI_INT32 type;
|
||||
|
||||
if (arg == NULL) return 0;
|
||||
type = vpi_get(vpiType, arg);
|
||||
/* Math function cannot do anything with a string. */
|
||||
if ((type == vpiConstant || type == vpiParameter) &&
|
||||
(vpi_get(vpiConstType, arg) == vpiStringConst)) {
|
||||
const char* basemsg = "%s cannot process strings";
|
||||
char* msg = malloc(strlen(basemsg)+strlen(post)+3);
|
||||
strcpy(msg, basemsg);
|
||||
strcat(msg, post);
|
||||
strcat(msg, ".\n");
|
||||
va_error_message(callh, msg, name);
|
||||
free(msg);
|
||||
return 0;
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Routine to check all the single argument math functions.
|
||||
*/
|
||||
static PLI_INT32 va_single_argument_compiletf(PLI_BYTE8 *ud)
|
||||
{
|
||||
assert(ud != 0);
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
assert(callh != 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
t_single_data *data = (t_single_data *) ud;
|
||||
const char *name = data->name;
|
||||
|
||||
va_single_t* fun_data = malloc(sizeof(va_single_t));
|
||||
|
||||
/* Check that malloc gave use some memory. */
|
||||
if (fun_data == 0) {
|
||||
va_error_message(callh, "%s failed to allocate memory.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check that there are arguments. */
|
||||
if (argv == 0) {
|
||||
va_error_message(callh, "%s requires one argument.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In Icarus if we have an argv we have at least one argument. */
|
||||
arg = vpi_scan(argv);
|
||||
fun_data->arg = va_process_argument(callh, name, arg, "");
|
||||
|
||||
/* These functions only take one argument. */
|
||||
arg = vpi_scan(argv);
|
||||
if (arg != 0) {
|
||||
va_error_message(callh, "%s takes only one argument.\n", name);
|
||||
}
|
||||
|
||||
/* Get the function that is to be used by the calltf routine. */
|
||||
fun_data->func = data->func;
|
||||
|
||||
vpi_put_userdata(callh, fun_data);
|
||||
|
||||
/* vpi_scan() returning 0 (NULL) has already freed argv. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Routine to implement the single argument math functions.
|
||||
*/
|
||||
static PLI_INT32 va_single_argument_calltf(PLI_BYTE8 *ud)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
s_vpi_value val;
|
||||
(void) ud; /* Not used! */
|
||||
|
||||
/* Retrieve the function and argument data. */
|
||||
va_single_t* fun_data = vpi_get_userdata(callh);
|
||||
|
||||
/* Calculate the result */
|
||||
val.format = vpiRealVal;
|
||||
vpi_get_value(fun_data->arg, &val);
|
||||
val.value.real = (fun_data->func)(val.value.real);
|
||||
|
||||
/* Return the result */
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Routine to check all the double argument math functions.
|
||||
*/
|
||||
static PLI_INT32 va_double_argument_compiletf(PLI_BYTE8 *ud)
|
||||
{
|
||||
assert(ud != 0);
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
assert(callh != 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
t_double_data *data = (t_double_data *) ud;
|
||||
const char *name = data->name;
|
||||
|
||||
va_double_t* fun_data = malloc(sizeof(va_double_t));
|
||||
|
||||
/* Check that malloc gave use some memory. */
|
||||
if (fun_data == 0) {
|
||||
va_error_message(callh, "%s failed to allocate memory.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check that there are arguments. */
|
||||
if (argv == 0) {
|
||||
va_error_message(callh, "%s requires two arguments.\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In Icarus if we have an argv we have at least one argument. */
|
||||
arg = vpi_scan(argv);
|
||||
fun_data->arg1 = va_process_argument(callh, name, arg, " (arg1)");
|
||||
|
||||
/* Check that there are at least two arguments. */
|
||||
arg = vpi_scan(argv);
|
||||
if (arg == 0) {
|
||||
va_error_message(callh, "%s requires two arguments.\n", name);
|
||||
}
|
||||
fun_data->arg2 = va_process_argument(callh, name, arg, " (arg2)");
|
||||
|
||||
/* These functions only take two arguments. */
|
||||
arg = vpi_scan(argv);
|
||||
if (arg != 0) {
|
||||
va_error_message(callh, "%s takes only two arguments.\n", name);
|
||||
}
|
||||
|
||||
/* Get the function that is to be used by the calltf routine. */
|
||||
fun_data->func = data->func;
|
||||
|
||||
vpi_put_userdata(callh, fun_data);
|
||||
|
||||
/* vpi_scan() returning 0 (NULL) has already freed argv. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Routine to implement the double argument math functions.
|
||||
*/
|
||||
static PLI_INT32 va_double_argument_calltf(PLI_BYTE8 *ud)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
s_vpi_value val;
|
||||
double first_arg;
|
||||
(void) ud; /* Not used! */
|
||||
|
||||
/* Retrieve the function and argument data. */
|
||||
va_double_t* fun_data = vpi_get_userdata(callh);
|
||||
|
||||
/* Calculate the result */
|
||||
val.format = vpiRealVal;
|
||||
vpi_get_value(fun_data->arg1, &val);
|
||||
first_arg = val.value.real;
|
||||
vpi_get_value(fun_data->arg2, &val);
|
||||
val.value.real = (fun_data->func)(first_arg, val.value.real);
|
||||
|
||||
/* Return the result */
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Register all the functions with Verilog.
|
||||
*/
|
||||
static void sys_v2005_math_register(void)
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
unsigned idx;
|
||||
|
||||
/* Register the single argument functions. */
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiRealFunc;
|
||||
tf_data.calltf = va_single_argument_calltf;
|
||||
tf_data.compiletf = va_single_argument_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
|
||||
for (idx=0; va_single_data[idx].name != 0; idx++) {
|
||||
tf_data.tfname = va_single_data[idx].name;
|
||||
tf_data.user_data = (PLI_BYTE8 *) &va_single_data[idx];
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
/* Register the double argument functions. */
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiRealFunc;
|
||||
tf_data.calltf = va_double_argument_calltf;
|
||||
tf_data.compiletf = va_double_argument_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
|
||||
for (idx=0; va_double_data[idx].name != 0; idx++) {
|
||||
tf_data.tfname = va_double_data[idx].name;
|
||||
tf_data.user_data = (PLI_BYTE8 *) &va_double_data[idx];
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Hook to get Icarus Verilog to find the registration function.
|
||||
*/
|
||||
extern void sys_clog2_register();
|
||||
|
||||
void (*vlog_startup_routines[])(void) = {
|
||||
sys_v2005_math_register,
|
||||
sys_clog2_register,
|
||||
0
|
||||
};
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
# This is the system function descriptor table for the
|
||||
# Verilog-2005 math functions.
|
||||
#
|
||||
|
||||
# Single argument functions.
|
||||
$sqrt vpiSysFuncReal
|
||||
$ln vpiSysFuncReal
|
||||
$log10 vpiSysFuncReal
|
||||
$exp vpiSysFuncReal
|
||||
$ceil vpiSysFuncReal
|
||||
$floor vpiSysFuncReal
|
||||
$sin vpiSysFuncReal
|
||||
$cos vpiSysFuncReal
|
||||
$tan vpiSysFuncReal
|
||||
$asin vpiSysFuncReal
|
||||
$acos vpiSysFuncReal
|
||||
$atan vpiSysFuncReal
|
||||
$sinh vpiSysFuncReal
|
||||
$cosh vpiSysFuncReal
|
||||
$tanh vpiSysFuncReal
|
||||
$asinh vpiSysFuncReal
|
||||
$acosh vpiSysFuncReal
|
||||
$atanh vpiSysFuncReal
|
||||
# Double argument functions.
|
||||
$pow vpiSysFuncReal
|
||||
$atan2 vpiSysFuncReal
|
||||
$hypot vpiSysFuncReal
|
||||
|
|
@ -32,6 +32,10 @@
|
|||
* The functions fmax() and fmin() may not be available in pre-c99
|
||||
* libraries, so if they are not available you need to uncomment the
|
||||
* -DUSE_MY_FMAX_AND_FMIN in the Makefile.
|
||||
*
|
||||
* Most of the math functions have been moved to v2005_math. This
|
||||
* allows them to be supported separately from the Verilog-A
|
||||
* specific functions.
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -66,30 +70,12 @@ typedef struct s_single_data {
|
|||
} t_single_data;
|
||||
|
||||
static t_single_data va_single_data[]= {
|
||||
{"$sqrt", sqrt},
|
||||
{"$ln", log},
|
||||
{"$log", log10}, /* NOTE: The $log function is replaced by the
|
||||
$log10 function to eliminate confusion with
|
||||
the natural log. In C, "log" is ln and log10
|
||||
is log-base-10. The $log is being left in for
|
||||
compatibility. */
|
||||
{"$log10", log10},
|
||||
{"$exp", exp},
|
||||
{"$abs", fabs},
|
||||
{"$ceil", ceil},
|
||||
{"$floor", floor},
|
||||
{"$sin", sin},
|
||||
{"$cos", cos},
|
||||
{"$tan", tan},
|
||||
{"$asin", asin},
|
||||
{"$acos", acos},
|
||||
{"$atan", atan},
|
||||
{"$sinh", sinh},
|
||||
{"$cosh", cosh},
|
||||
{"$tanh", tanh},
|
||||
{"$asinh", asinh},
|
||||
{"$acosh", acosh},
|
||||
{"$atanh", atanh},
|
||||
{0, 0} /* Must be NULL terminated! */
|
||||
};
|
||||
|
||||
|
|
@ -111,9 +97,6 @@ static t_double_data va_double_data[]= {
|
|||
#else
|
||||
{"$min", va_fmin},
|
||||
#endif
|
||||
{"$pow", pow},
|
||||
{"$atan2", atan2},
|
||||
{"$hypot", hypot},
|
||||
{0, 0} /* Must be NULL terminated! */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,29 +4,8 @@
|
|||
#
|
||||
|
||||
# Single argument functions.
|
||||
$sqrt vpiSysFuncReal
|
||||
$ln vpiSysFuncReal
|
||||
$log vpiSysFuncReal
|
||||
$log10 vpiSysFuncReal
|
||||
$exp vpiSysFuncReal
|
||||
$abs vpiSysFuncReal
|
||||
$ceil vpiSysFuncReal
|
||||
$floor vpiSysFuncReal
|
||||
$sin vpiSysFuncReal
|
||||
$cos vpiSysFuncReal
|
||||
$tan vpiSysFuncReal
|
||||
$asin vpiSysFuncReal
|
||||
$acos vpiSysFuncReal
|
||||
$atan vpiSysFuncReal
|
||||
$sinh vpiSysFuncReal
|
||||
$cosh vpiSysFuncReal
|
||||
$tanh vpiSysFuncReal
|
||||
$asinh vpiSysFuncReal
|
||||
$acosh vpiSysFuncReal
|
||||
$atanh vpiSysFuncReal
|
||||
# Double argument functions.
|
||||
$min vpiSysFuncReal
|
||||
$max vpiSysFuncReal
|
||||
$pow vpiSysFuncReal
|
||||
$atan2 vpiSysFuncReal
|
||||
$hypot vpiSysFuncReal
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ is removed from the <exp> before calculating the real value.
|
|||
|
||||
If <exp>==0x3fff and <mant> == 0, the value is +inf.
|
||||
If <exp>==0x7fff and <mant> == 0, the value is -inf.
|
||||
If <exp>--0x3fff and <mant> != 0, the value is NaN.
|
||||
If <exp>==0x3fff and <mant> != 0, the value is NaN.
|
||||
|
||||
* %mod <bit-l>, <bit-r>, <wid>
|
||||
* %mod/s <bit-l>, <bit-r>, <wid>
|
||||
|
|
|
|||
|
|
@ -2658,8 +2658,9 @@ bool of_LOADI_WR(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
// Detect NaN
|
||||
if ( (exp&0x3fff) == 0x3fff ) {
|
||||
if (exp==0x3fff) {
|
||||
thr->words[idx].w_real = nan("");
|
||||
return true;
|
||||
}
|
||||
|
||||
double sign = (exp & 0x4000)? -1.0 : 1.0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue