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 "config.h"
|
||||||
|
|
||||||
# include <iostream>
|
# include <iostream>
|
||||||
# include <cstring>
|
|
||||||
|
|
||||||
|
# include "compiler.h"
|
||||||
# include "PExpr.h"
|
# include "PExpr.h"
|
||||||
# include "Module.h"
|
# include "Module.h"
|
||||||
# include <typeinfo>
|
# include <typeinfo>
|
||||||
|
|
@ -131,18 +131,76 @@ PECallFunction::~PECallFunction()
|
||||||
|
|
||||||
bool PECallFunction::is_constant(Module*mod) const
|
bool PECallFunction::is_constant(Module*mod) const
|
||||||
{
|
{
|
||||||
/* Only $clog2 can be a constant system function. */
|
/* Only $clog2 and the builtin mathematical functions can
|
||||||
if (peek_tail_name(path_)[0] == '$') {
|
* be a constant system function. */
|
||||||
if (strcmp(peek_tail_name(path_).str(), "$clog2") == 0) {
|
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) {
|
if (parms_.size() != 1 || parms_[0] == 0) {
|
||||||
cerr << get_fileline() << ": error: $clog2 takes a "
|
cerr << get_fileline() << ": error: " << name
|
||||||
"single argument." << endl;
|
<< " takes a single argument." << endl;
|
||||||
return false;
|
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 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. */
|
/* Checking for constant user functions goes here. */
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ const char*npath = 0;
|
||||||
const char*targ = "vvp";
|
const char*targ = "vvp";
|
||||||
const char*depfile = 0;
|
const char*depfile = 0;
|
||||||
|
|
||||||
const char*generation = "2x";
|
const char*generation = "2005";
|
||||||
const char*gen_specify = "specify";
|
const char*gen_specify = "specify";
|
||||||
const char*gen_xtypes = "xtypes";
|
const char*gen_xtypes = "xtypes";
|
||||||
const char*gen_icarus = "icarus-misc";
|
const char*gen_icarus = "icarus-misc";
|
||||||
|
|
@ -765,9 +765,18 @@ int main(int argc, char **argv)
|
||||||
how to handle them. */
|
how to handle them. */
|
||||||
fprintf(iconfig_file, "sys_func:%s%csystem.sft\n", base, sep);
|
fprintf(iconfig_file, "sys_func:%s%csystem.sft\n", base, sep);
|
||||||
|
|
||||||
/* If verilog-ams is enabled, then include the va_math module
|
/* If verilog-2005 is enabled or icarus-misc or verilog-ams,
|
||||||
as well. */
|
* then include the v2005_math library. */
|
||||||
if (strcmp(gen_verilog_ams,"verilog-ams") == 0) {
|
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, "sys_func:%s%cva_math.sft\n", base, sep);
|
||||||
fprintf(iconfig_file, "module:va_math\n");
|
fprintf(iconfig_file, "module:va_math\n");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
115
elab_pexpr.cc
115
elab_pexpr.cc
|
|
@ -25,7 +25,6 @@
|
||||||
# include "netmisc.h"
|
# include "netmisc.h"
|
||||||
|
|
||||||
# include <cstdlib>
|
# include <cstdlib>
|
||||||
# include <cstring>
|
|
||||||
# include <iostream>
|
# include <iostream>
|
||||||
# include "ivl_assert.h"
|
# include "ivl_assert.h"
|
||||||
|
|
||||||
|
|
@ -269,23 +268,54 @@ NetExpr*PEUnary::elaborate_pexpr (Design*des, NetScope*scope) const
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reuse the routine from eval_tree.cc. */
|
/* Reuse these routines from eval_tree.cc. */
|
||||||
NetExpr* evaluate_clog2(NetExpr*arg);
|
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
|
NetExpr* PECallFunction::elaborate_pexpr(Design*des, NetScope*scope) const
|
||||||
{
|
{
|
||||||
/* For now only $clog2 can be a constant system function. */
|
/* Only $clog2 and the builtin mathematical functions can
|
||||||
if (peek_tail_name(path_)[0] == '$') {
|
* be a constant system function. */
|
||||||
if (strcmp(peek_tail_name(path_).str(), "$clog2") == 0) {
|
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) {
|
if (parms_.size() != 1 || parms_[0] == 0) {
|
||||||
cerr << get_fileline() << ": error: $clog2 takes a "
|
cerr << get_fileline() << ": error: " << name
|
||||||
"single argument." << endl;
|
<< " takes a single argument." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
NetExpr*arg = parms_[0]->elaborate_pexpr(des, scope);
|
NetExpr*arg = parms_[0]->elaborate_pexpr(des, scope);
|
||||||
|
if (arg == 0) return 0;
|
||||||
eval_expr(arg);
|
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;
|
delete arg;
|
||||||
if (rtn != 0) {
|
if (rtn != 0) {
|
||||||
rtn->set_line(*this);
|
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 "
|
cerr << get_fileline() << ": error: this is not a constant "
|
||||||
"system function (" << *this << ")." << endl;
|
"system function (" << *this << ")." << endl;
|
||||||
des->errors += 1;
|
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()) {
|
switch (le->expr_type()) {
|
||||||
case IVL_VT_REAL:
|
case IVL_VT_REAL:
|
||||||
rtmp = dynamic_cast<NetECReal*> (le);
|
rtmp = dynamic_cast<NetECReal*> (le);
|
||||||
if (rtmp == 0)
|
if (rtmp == 0) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
lv = rtmp->value().as_double();
|
lv = rtmp->value().as_double();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IVL_VT_LOGIC:
|
case IVL_VT_LOGIC:
|
||||||
case IVL_VT_BOOL:
|
case IVL_VT_BOOL:
|
||||||
vtmp = dynamic_cast<NetEConst*> (le);
|
vtmp = dynamic_cast<NetEConst*> (le);
|
||||||
if (vtmp == 0)
|
if (vtmp == 0) return 0;
|
||||||
return 0;
|
lv = vtmp->value().as_double();
|
||||||
|
|
||||||
lv = vtmp->value().as_long();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -361,23 +357,18 @@ NetEConst* NetEBComp::eval_leeq_real_(NetExpr*le, NetExpr*ri, bool eq_flag)
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
switch (ri->expr_type()) {
|
switch (ri->expr_type()) {
|
||||||
case IVL_VT_REAL:
|
case IVL_VT_REAL:
|
||||||
rtmp = dynamic_cast<NetECReal*> (ri);
|
rtmp = dynamic_cast<NetECReal*> (ri);
|
||||||
if (rtmp == 0)
|
if (rtmp == 0) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
rv = rtmp->value().as_double();
|
rv = rtmp->value().as_double();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IVL_VT_LOGIC:
|
case IVL_VT_LOGIC:
|
||||||
case IVL_VT_BOOL:
|
case IVL_VT_BOOL:
|
||||||
vtmp = dynamic_cast<NetEConst*> (ri);
|
vtmp = dynamic_cast<NetEConst*> (ri);
|
||||||
if (vtmp == 0)
|
if (vtmp == 0) return 0;
|
||||||
return 0;
|
rv = vtmp->value().as_double();
|
||||||
|
|
||||||
rv = vtmp->value().as_long();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -481,19 +472,6 @@ NetEConst* NetEBComp::eval_gt_()
|
||||||
return tmp;
|
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. */
|
/* Now go on to the normal test of the values. */
|
||||||
NetEConst*r = dynamic_cast<NetEConst*>(right_);
|
NetEConst*r = dynamic_cast<NetEConst*>(right_);
|
||||||
if (r == 0) return 0;
|
if (r == 0) return 0;
|
||||||
|
|
@ -532,19 +510,6 @@ NetEConst* NetEBComp::eval_gteq_()
|
||||||
return tmp;
|
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. */
|
/* Now go on to the normal test of the values. */
|
||||||
NetEConst*r = dynamic_cast<NetEConst*>(right_);
|
NetEConst*r = dynamic_cast<NetEConst*>(right_);
|
||||||
if (r == 0) return 0;
|
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
|
* are equal, but there are are x/z bits, then the situation is
|
||||||
* ambiguous so the result is x.
|
* 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)
|
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_);
|
NetEConst*l = dynamic_cast<NetEConst*>(left_);
|
||||||
if (l == 0) return 0;
|
if (l == 0) return 0;
|
||||||
NetEConst*r = dynamic_cast<NetEConst*>(right_);
|
NetEConst*r = dynamic_cast<NetEConst*>(right_);
|
||||||
|
|
@ -1673,25 +1696,238 @@ NetExpr* evaluate_clog2(NetExpr*arg)
|
||||||
return 0;
|
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. */
|
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg);
|
||||||
if (strcmp(name(), "$clog2") == 0) {
|
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg);
|
||||||
if (nparms() != 1 || parm(0) == 0) {
|
if (tmpi || tmpr) {
|
||||||
cerr << get_fileline() << ": error: $clog2 takes a single "
|
double arg;
|
||||||
"argument." << endl;
|
if (tmpi) {
|
||||||
return 0;
|
arg = tmpi->value().as_double();
|
||||||
|
} else {
|
||||||
|
arg = tmpr->value().as_double();
|
||||||
}
|
}
|
||||||
NetExpr*rtn = evaluate_clog2(parm(0));
|
|
||||||
if (rtn != 0) {
|
if (strcmp(name, "$ln") == 0) {
|
||||||
rtn->set_line(*this);
|
return new NetECReal(verireal(log(arg)));
|
||||||
if (debug_eval_tree) {
|
} else if (strcmp(name, "$log") == 0) {
|
||||||
cerr << get_fileline() << ": debug: Evaluate "
|
return new NetECReal(verireal(log10(arg)));
|
||||||
"constant $clog2()." << endl;
|
} else if (strcmp(name, "$log10") == 0) {
|
||||||
}
|
return new NetECReal(verireal(log10(arg)));
|
||||||
return rtn;
|
} 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;
|
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* must_be_leeq_(NetExpr*le, const verinum&rv, bool eq_flag);
|
||||||
|
|
||||||
NetEConst*eval_eqeq_(bool ne_flag);
|
NetEConst*eval_eqeq_(bool ne_flag);
|
||||||
|
NetEConst*eval_eqeq_real_(NetExpr*le, NetExpr*ri, bool ne_flag);
|
||||||
NetEConst*eval_less_();
|
NetEConst*eval_less_();
|
||||||
NetEConst*eval_leeq_();
|
NetEConst*eval_leeq_();
|
||||||
NetEConst*eval_leeq_real_(NetExpr*le, NetExpr*ri, bool eq_flag);
|
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. */
|
/* Handle the special case that the value is +-inf. */
|
||||||
if (isinf(value)) {
|
if (isinf(value)) {
|
||||||
if (value > 0)
|
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);
|
res, 0x3fff);
|
||||||
else
|
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);
|
res, 0x7fff);
|
||||||
return res;
|
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) {
|
if (value < 0) {
|
||||||
sign = 0x4000;
|
sign = 0x4000;
|
||||||
|
|
|
||||||
|
|
@ -330,6 +330,10 @@ char* draw_Cr_to_string(double value)
|
||||||
snprintf(tmp, sizeof(tmp), "Cr<m0g7fff>");
|
snprintf(tmp, sizeof(tmp), "Cr<m0g7fff>");
|
||||||
return strdup(tmp);
|
return strdup(tmp);
|
||||||
}
|
}
|
||||||
|
if (value != value) {
|
||||||
|
snprintf(tmp, sizeof(tmp), "Cr<m1g3fff>");
|
||||||
|
return strdup(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
int sign = 0;
|
int sign = 0;
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ CPPFLAGS = @ident_support@ -I. -I$(srcdir)/.. -I$(srcdir) -I.. @file64_support@
|
||||||
CFLAGS = -Wall @CFLAGS@
|
CFLAGS = -Wall @CFLAGS@
|
||||||
LDFLAGS = @LDFLAGS@
|
LDFLAGS = @LDFLAGS@
|
||||||
|
|
||||||
all: dep system.vpi va_math.vpi $(ALL32)
|
all: dep system.vpi va_math.vpi v2005_math.vpi $(ALL32)
|
||||||
|
|
||||||
check: all
|
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_readmem.o sys_readmem_lex.o sys_scanf.o sys_sdf.o \
|
||||||
sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.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 \
|
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_LIBZ@,yes)
|
||||||
ifeq (@HAVE_LIBBZ2@,yes)
|
ifeq (@HAVE_LIBBZ2@,yes)
|
||||||
|
|
@ -69,6 +69,9 @@ endif
|
||||||
O += sys_lxt2.o lxt2_write.o
|
O += sys_lxt2.o lxt2_write.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Object files for v2005_math.vpi
|
||||||
|
M = sys_clog2.o v2005_math.o
|
||||||
|
|
||||||
# Object files for va_math.vpi
|
# Object files for va_math.vpi
|
||||||
V = va_math.o
|
V = va_math.o
|
||||||
|
|
||||||
|
|
@ -94,12 +97,16 @@ sdf_lexor.c: sdf_lexor.lex
|
||||||
sdf_parse.c sdf_parse.h: $(srcdir)/sdf_parse.y
|
sdf_parse.c sdf_parse.h: $(srcdir)/sdf_parse.y
|
||||||
$(YACC) --verbose -d -p sdf -o sdf_parse.c $(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
|
va_math.vpi: $V ../vvp/libvpi.a
|
||||||
$(CC) @shared@ -o $@ $V -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS)
|
$(CC) @shared@ -o $@ $V -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS)
|
||||||
|
|
||||||
clean:
|
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 sdf_lexor.c sdf_parse.c sdf_parse.output sdf_parse.h
|
||||||
|
rm -f va_math.vpi v2005_math.vpi
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f Makefile config.status config.log vpi_config.h
|
rm -f Makefile config.status config.log vpi_config.h
|
||||||
|
|
@ -109,6 +116,7 @@ check: all
|
||||||
install: all installdirs \
|
install: all installdirs \
|
||||||
$(vpidir)/system.vpi $(libdir)/ivl/system.sft \
|
$(vpidir)/system.vpi $(libdir)/ivl/system.sft \
|
||||||
$(vpidir)/va_math.vpi $(libdir)/ivl/va_math.sft \
|
$(vpidir)/va_math.vpi $(libdir)/ivl/va_math.sft \
|
||||||
|
$(vpidir)/v2005_math.vpi $(libdir)/ivl/v2005_math.sft \
|
||||||
$(vpidir)/include/
|
$(vpidir)/include/
|
||||||
|
|
||||||
$(vpidir)/system.vpi: ./system.vpi
|
$(vpidir)/system.vpi: ./system.vpi
|
||||||
|
|
@ -123,6 +131,12 @@ $(vpidir)/va_math.vpi: ./va_math.vpi
|
||||||
$(libdir)/ivl/va_math.sft: va_math.sft
|
$(libdir)/ivl/va_math.sft: va_math.sft
|
||||||
$(INSTALL_DATA) $< $@
|
$(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
|
installdirs: ../mkinstalldirs
|
||||||
$(srcdir)/../mkinstalldirs $(vpidir)
|
$(srcdir)/../mkinstalldirs $(vpidir)
|
||||||
|
|
||||||
|
|
@ -131,6 +145,7 @@ uninstall:
|
||||||
rm -f $(libdir)/ivl/system.sft
|
rm -f $(libdir)/ivl/system.sft
|
||||||
rm -f $(vpidir)/va_math.vpi
|
rm -f $(vpidir)/va_math.vpi
|
||||||
rm -f $(libdir)/ivl/va_math.sft
|
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)
|
-include $(patsubst %.o, dep/%.d, $O)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,39 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <vpi_user.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.
|
* 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,
|
* This routine returns 1 if the argument is a constant value,
|
||||||
* otherwise it returns 0.
|
* 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)
|
unsigned is_constant_obj(vpiHandle obj)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@ extern void sys_time_register();
|
||||||
extern void sys_vcd_register();
|
extern void sys_vcd_register();
|
||||||
extern void sys_vcdoff_register();
|
extern void sys_vcdoff_register();
|
||||||
extern void sys_special_register();
|
extern void sys_special_register();
|
||||||
extern void sys_clog2_register();
|
|
||||||
extern void vams_simparam_register();
|
extern void vams_simparam_register();
|
||||||
|
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
|
|
@ -182,7 +181,6 @@ void (*vlog_startup_routines[])() = {
|
||||||
sys_lxt_or_vcd_register,
|
sys_lxt_or_vcd_register,
|
||||||
sys_sdf_register,
|
sys_sdf_register,
|
||||||
sys_special_register,
|
sys_special_register,
|
||||||
sys_clog2_register,
|
|
||||||
vams_simparam_register,
|
vams_simparam_register,
|
||||||
0
|
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
|
* The functions fmax() and fmin() may not be available in pre-c99
|
||||||
* libraries, so if they are not available you need to uncomment the
|
* libraries, so if they are not available you need to uncomment the
|
||||||
* -DUSE_MY_FMAX_AND_FMIN in the Makefile.
|
* -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;
|
} t_single_data;
|
||||||
|
|
||||||
static t_single_data va_single_data[]= {
|
static t_single_data va_single_data[]= {
|
||||||
{"$sqrt", sqrt},
|
|
||||||
{"$ln", log},
|
|
||||||
{"$log", log10}, /* NOTE: The $log function is replaced by the
|
{"$log", log10}, /* NOTE: The $log function is replaced by the
|
||||||
$log10 function to eliminate confusion with
|
$log10 function to eliminate confusion with
|
||||||
the natural log. In C, "log" is ln and log10
|
the natural log. In C, "log" is ln and log10
|
||||||
is log-base-10. The $log is being left in for
|
is log-base-10. The $log is being left in for
|
||||||
compatibility. */
|
compatibility. */
|
||||||
{"$log10", log10},
|
|
||||||
{"$exp", exp},
|
|
||||||
{"$abs", fabs},
|
{"$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! */
|
{0, 0} /* Must be NULL terminated! */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -111,9 +97,6 @@ static t_double_data va_double_data[]= {
|
||||||
#else
|
#else
|
||||||
{"$min", va_fmin},
|
{"$min", va_fmin},
|
||||||
#endif
|
#endif
|
||||||
{"$pow", pow},
|
|
||||||
{"$atan2", atan2},
|
|
||||||
{"$hypot", hypot},
|
|
||||||
{0, 0} /* Must be NULL terminated! */
|
{0, 0} /* Must be NULL terminated! */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,29 +4,8 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
# Single argument functions.
|
# Single argument functions.
|
||||||
$sqrt vpiSysFuncReal
|
|
||||||
$ln vpiSysFuncReal
|
|
||||||
$log vpiSysFuncReal
|
$log vpiSysFuncReal
|
||||||
$log10 vpiSysFuncReal
|
|
||||||
$exp vpiSysFuncReal
|
|
||||||
$abs 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.
|
# Double argument functions.
|
||||||
$min vpiSysFuncReal
|
$min vpiSysFuncReal
|
||||||
$max 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>==0x3fff and <mant> == 0, the value is +inf.
|
||||||
If <exp>==0x7fff 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 <bit-l>, <bit-r>, <wid>
|
||||||
* %mod/s <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;
|
return true;
|
||||||
}
|
}
|
||||||
// Detect NaN
|
// Detect NaN
|
||||||
if ( (exp&0x3fff) == 0x3fff ) {
|
if (exp==0x3fff) {
|
||||||
thr->words[idx].w_real = nan("");
|
thr->words[idx].w_real = nan("");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double sign = (exp & 0x4000)? -1.0 : 1.0;
|
double sign = (exp & 0x4000)? -1.0 : 1.0;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue