Add support for system function calls in constant functions.
This commit is contained in:
parent
89244e0f70
commit
af91920a17
404
eval_tree.cc
404
eval_tree.cc
|
|
@ -34,6 +34,18 @@ NetExpr* NetExpr::eval_tree()
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void eval_debug(const NetExpr*expr, NetExpr*res, bool is_real)
|
||||
{
|
||||
if (res != 0) {
|
||||
res->set_line(*expr);
|
||||
if (debug_eval_tree) {
|
||||
cerr << expr->get_fileline() << ": debug: Evaluated";
|
||||
if (is_real) cerr << " (real)";
|
||||
cerr << ": " << *expr << " --> " << *res << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool get_real_arg_(const NetExpr*expr, verireal&val)
|
||||
{
|
||||
switch (expr->expr_type()) {
|
||||
|
|
@ -1179,7 +1191,7 @@ NetEConst* NetEConcat::eval_arguments_(const vector<NetExpr*>&vals,
|
|||
|
||||
NetEConst*res = new NetEConst(val);
|
||||
ivl_assert(*this, res);
|
||||
res->set_line(*this);
|
||||
res->set_line(*this);
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluated: "
|
||||
<< *this << " --> " << *res << endl;
|
||||
|
|
@ -1596,12 +1608,10 @@ NetEConst* NetEUReduce::eval_arguments_(const NetExpr*ex) const
|
|||
return tmp;
|
||||
}
|
||||
|
||||
static NetEConst* evaluate_clog2(NetExpr*&arg_)
|
||||
NetEConst* NetESFunc::evaluate_clog2_(const NetExpr*arg_) const
|
||||
{
|
||||
eval_expr(arg_);
|
||||
|
||||
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg_);
|
||||
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg_);
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg_);
|
||||
const NetECReal*tmpr = dynamic_cast<const NetECReal*>(arg_);
|
||||
|
||||
if (tmpi == 0 && tmpr == 0) return 0;
|
||||
|
||||
|
|
@ -1620,7 +1630,7 @@ static NetEConst* evaluate_clog2(NetExpr*&arg_)
|
|||
tmp.has_sign(true);
|
||||
|
||||
rtn = new NetEConst(tmp);
|
||||
ivl_assert(*arg_, rtn);
|
||||
ivl_assert(*this, rtn);
|
||||
} else {
|
||||
bool is_neg = false;
|
||||
uint64_t res = 0;
|
||||
|
|
@ -1649,18 +1659,17 @@ static NetEConst* evaluate_clog2(NetExpr*&arg_)
|
|||
tmp.has_sign(true);
|
||||
|
||||
rtn = new NetEConst(tmp);
|
||||
ivl_assert(*arg_, rtn);
|
||||
ivl_assert(*this, rtn);
|
||||
}
|
||||
|
||||
eval_debug(this, rtn, false);
|
||||
return rtn;
|
||||
}
|
||||
|
||||
static NetECReal* evaluate_math_one_arg(NetExpr*&arg_, const char*name)
|
||||
NetECReal* NetESFunc::evaluate_math_one_arg_(ID id, const NetExpr*arg_) const
|
||||
{
|
||||
eval_expr(arg_);
|
||||
|
||||
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg_);
|
||||
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg_);
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg_);
|
||||
const NetECReal*tmpr = dynamic_cast<const NetECReal*>(arg_);
|
||||
|
||||
NetECReal*res = 0;
|
||||
|
||||
|
|
@ -1672,79 +1681,79 @@ static NetECReal* evaluate_math_one_arg(NetExpr*&arg_, const char*name)
|
|||
arg = tmpr->value().as_double();
|
||||
}
|
||||
|
||||
if (strcmp(name, "$ln") == 0) {
|
||||
switch (id) {
|
||||
case LN:
|
||||
res = new NetECReal(verireal(log(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$log10") == 0) {
|
||||
break;
|
||||
case LOG10:
|
||||
res = new NetECReal(verireal(log10(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$exp") == 0) {
|
||||
break;
|
||||
case EXP:
|
||||
res = new NetECReal(verireal(exp(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$sqrt") == 0) {
|
||||
break;
|
||||
case SQRT:
|
||||
res = new NetECReal(verireal(sqrt(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$floor") == 0) {
|
||||
break;
|
||||
case FLOOR:
|
||||
res = new NetECReal(verireal(floor(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$ceil") == 0) {
|
||||
break;
|
||||
case CEIL:
|
||||
res = new NetECReal(verireal(ceil(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$sin") == 0) {
|
||||
break;
|
||||
case SIN:
|
||||
res = new NetECReal(verireal(sin(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$cos") == 0) {
|
||||
break;
|
||||
case COS:
|
||||
res = new NetECReal(verireal(cos(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$tan") == 0) {
|
||||
break;
|
||||
case TAN:
|
||||
res = new NetECReal(verireal(tan(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$asin") == 0) {
|
||||
break;
|
||||
case ASIN:
|
||||
res = new NetECReal(verireal(asin(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$acos") == 0) {
|
||||
break;
|
||||
case ACOS:
|
||||
res = new NetECReal(verireal(acos(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$atan") == 0) {
|
||||
break;
|
||||
case ATAN:
|
||||
res = new NetECReal(verireal(atan(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$sinh") == 0) {
|
||||
break;
|
||||
case SINH:
|
||||
res = new NetECReal(verireal(sinh(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$cosh") == 0) {
|
||||
break;
|
||||
case COSH:
|
||||
res = new NetECReal(verireal(cosh(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$tanh") == 0) {
|
||||
break;
|
||||
case TANH:
|
||||
res = new NetECReal(verireal(tanh(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$asinh") == 0) {
|
||||
break;
|
||||
case ASINH:
|
||||
res = new NetECReal(verireal(asinh(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$acosh") == 0) {
|
||||
break;
|
||||
case ACOSH:
|
||||
res = new NetECReal(verireal(acosh(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else if (strcmp(name, "$atanh") == 0) {
|
||||
break;
|
||||
case ATANH:
|
||||
res = new NetECReal(verireal(atanh(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
} else {
|
||||
cerr << arg_->get_fileline() << ": warning: Unhandled"
|
||||
"constant system function " << name << "." << endl;
|
||||
break;
|
||||
default:
|
||||
ivl_assert(*this, 0);
|
||||
break;
|
||||
}
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
eval_debug(this, res, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
static NetECReal* evaluate_math_two_args(NetExpr*&arg0_, NetExpr*&arg1_,
|
||||
const char*name)
|
||||
NetECReal* NetESFunc::evaluate_math_two_arg_(ID id, const NetExpr*arg0_,
|
||||
const NetExpr*arg1_) const
|
||||
{
|
||||
eval_expr(arg0_);
|
||||
eval_expr(arg1_);
|
||||
|
||||
NetEConst*tmpi0 = dynamic_cast<NetEConst *>(arg0_);
|
||||
NetECReal*tmpr0 = dynamic_cast<NetECReal *>(arg0_);
|
||||
NetEConst*tmpi1 = dynamic_cast<NetEConst *>(arg1_);
|
||||
NetECReal*tmpr1 = dynamic_cast<NetECReal *>(arg1_);
|
||||
const NetEConst*tmpi0 = dynamic_cast<const NetEConst*>(arg0_);
|
||||
const NetECReal*tmpr0 = dynamic_cast<const NetECReal*>(arg0_);
|
||||
const NetEConst*tmpi1 = dynamic_cast<const NetEConst*>(arg1_);
|
||||
const NetECReal*tmpr1 = dynamic_cast<const NetECReal*>(arg1_);
|
||||
|
||||
NetECReal*res = 0;
|
||||
|
||||
|
|
@ -1761,73 +1770,78 @@ static NetECReal* evaluate_math_two_args(NetExpr*&arg0_, NetExpr*&arg1_,
|
|||
arg1 = tmpr1->value().as_double();
|
||||
}
|
||||
|
||||
if (strcmp(name, "$pow") == 0) {
|
||||
switch (id) {
|
||||
case POW:
|
||||
res = new NetECReal(verireal(pow(arg0, arg1)));
|
||||
ivl_assert(*arg0_, res);
|
||||
} else if (strcmp(name, "$atan2") == 0) {
|
||||
break;
|
||||
case ATAN2:
|
||||
res = new NetECReal(verireal(atan2(arg0, arg1)));
|
||||
ivl_assert(*arg0_, res);
|
||||
} else if (strcmp(name, "$hypot") == 0) {
|
||||
break;
|
||||
case HYPOT:
|
||||
res = new NetECReal(verireal(hypot(arg0, arg1)));
|
||||
ivl_assert(*arg0_, res);
|
||||
} else {
|
||||
cerr << arg0_->get_fileline() << ": warning: Unhandled"
|
||||
"constant system function " << name << "." << endl;
|
||||
break;
|
||||
default:
|
||||
ivl_assert(*this, 0);
|
||||
break;
|
||||
}
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
eval_debug(this, res, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
static NetExpr* evaluate_abs(NetExpr*&arg_)
|
||||
NetExpr* NetESFunc::evaluate_abs_(const NetExpr*arg_) const
|
||||
{
|
||||
eval_expr(arg_);
|
||||
|
||||
NetExpr*res = 0;
|
||||
|
||||
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg_);
|
||||
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg_);
|
||||
if (tmpi) {
|
||||
verinum arg = tmpi->value();
|
||||
if (arg.is_negative()) {
|
||||
arg = v_not(arg) + verinum(1);
|
||||
}
|
||||
res = new NetEConst(arg);
|
||||
ivl_assert(*arg_, res);
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg_);
|
||||
const NetECReal*tmpr = dynamic_cast<const NetECReal*>(arg_);
|
||||
if (tmpr) {
|
||||
double arg = tmpr->value().as_double();
|
||||
res = new NetECReal(verireal(fabs(arg)));
|
||||
ivl_assert(*arg_, res);
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
eval_debug(this, res, tmpr != 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
static NetExpr* evaluate_min_max(NetExpr*&arg0_, NetExpr*&arg1_,
|
||||
const char*name)
|
||||
NetExpr* NetESFunc::evaluate_min_max_(ID id, const NetExpr*arg0_,
|
||||
const NetExpr*arg1_) const
|
||||
{
|
||||
eval_expr(arg0_);
|
||||
eval_expr(arg1_);
|
||||
|
||||
NetEConst*tmpi0 = dynamic_cast<NetEConst *>(arg0_);
|
||||
NetECReal*tmpr0 = dynamic_cast<NetECReal *>(arg0_);
|
||||
NetEConst*tmpi1 = dynamic_cast<NetEConst *>(arg1_);
|
||||
NetECReal*tmpr1 = dynamic_cast<NetECReal *>(arg1_);
|
||||
const NetEConst*tmpi0 = dynamic_cast<const NetEConst*>(arg0_);
|
||||
const NetECReal*tmpr0 = dynamic_cast<const NetECReal*>(arg0_);
|
||||
const NetEConst*tmpi1 = dynamic_cast<const NetEConst*>(arg1_);
|
||||
const NetECReal*tmpr1 = dynamic_cast<const NetECReal*>(arg1_);
|
||||
|
||||
NetExpr*res = 0;
|
||||
|
||||
if (tmpi0 && tmpi1) {
|
||||
verinum arg0 = tmpi0->value();
|
||||
verinum arg1 = tmpi1->value();
|
||||
if (strcmp(name, "$min") == 0) {
|
||||
switch (id) {
|
||||
case MIN:
|
||||
res = new NetEConst( arg0 < arg1 ? arg0 : arg1);
|
||||
ivl_assert(*arg0_, res);
|
||||
} else if (strcmp(name, "$max") == 0) {
|
||||
break;
|
||||
case MAX:
|
||||
res = new NetEConst( arg0 < arg1 ? arg1 : arg0);
|
||||
ivl_assert(*arg0_, res);
|
||||
break;
|
||||
default:
|
||||
ivl_assert(*this, 0);
|
||||
break;
|
||||
}
|
||||
ivl_assert(*this, res);
|
||||
|
||||
} else if ((tmpi0 || tmpr0) && (tmpi1 || tmpr1)) {
|
||||
double arg0, arg1;
|
||||
if (tmpi0) {
|
||||
|
|
@ -1840,118 +1854,128 @@ static NetExpr* evaluate_min_max(NetExpr*&arg0_, NetExpr*&arg1_,
|
|||
} else {
|
||||
arg1 = tmpr1->value().as_double();
|
||||
}
|
||||
if (strcmp(name, "$min") == 0) {
|
||||
switch (id) {
|
||||
case MIN:
|
||||
res = new NetECReal(verireal(arg0 < arg1 ? arg0 : arg1));
|
||||
ivl_assert(*arg0_, res);
|
||||
} else if (strcmp(name, "$max") == 0) {
|
||||
break;
|
||||
case MAX:
|
||||
res = new NetECReal(verireal(arg0 < arg1 ? arg1 : arg0));
|
||||
ivl_assert(*arg0_, res);
|
||||
} else {
|
||||
cerr << arg0_->get_fileline() << ": warning: Unhandled"
|
||||
"constant system function " << name << "." << endl;
|
||||
break;
|
||||
default:
|
||||
ivl_assert(*this, 0);
|
||||
break;
|
||||
}
|
||||
ivl_assert(*this, res);
|
||||
}
|
||||
|
||||
eval_debug(this, res, tmpr0 || tmpr1);
|
||||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetESFunc::evaluate_one_arg_(ID id, const NetExpr*arg) const
|
||||
{
|
||||
switch (id) {
|
||||
case ABS:
|
||||
return evaluate_abs_(arg);
|
||||
case CLOG2:
|
||||
return evaluate_clog2_(arg);
|
||||
default:
|
||||
return evaluate_math_one_arg_(id, arg);
|
||||
}
|
||||
}
|
||||
|
||||
NetExpr* NetESFunc::evaluate_two_arg_(ID id, const NetExpr*arg0,
|
||||
const NetExpr*arg1) const
|
||||
{
|
||||
switch (id) {
|
||||
case MIN:
|
||||
case MAX:
|
||||
return evaluate_min_max_(id, arg0, arg1);
|
||||
default:
|
||||
return evaluate_math_two_arg_(id, arg0, arg1);
|
||||
}
|
||||
}
|
||||
|
||||
NetESFunc::ID NetESFunc::built_in_id_() const
|
||||
{
|
||||
/* If we are not targeting at least Verilog-2005, Verilog-AMS
|
||||
* or using the Icarus misc flag then we do not treat these
|
||||
* functions as built-in. */
|
||||
if (generation_flag < GN_VER2005 &&
|
||||
!gn_icarus_misc_flag && !gn_verilog_ams_flag) {
|
||||
return NOT_BUILT_IN;
|
||||
}
|
||||
|
||||
static map<string,ID> built_in_func;
|
||||
|
||||
if (built_in_func.empty()) {
|
||||
built_in_func["$clog2"] = CLOG2;
|
||||
built_in_func["$ln" ] = LN;
|
||||
built_in_func["$log10"] = LOG10;
|
||||
built_in_func["$exp" ] = EXP;
|
||||
built_in_func["$sqrt" ] = SQRT;
|
||||
built_in_func["$floor"] = FLOOR;
|
||||
built_in_func["$ceil" ] = CEIL;
|
||||
built_in_func["$sin" ] = SIN;
|
||||
built_in_func["$cos" ] = COS;
|
||||
built_in_func["$tan" ] = TAN;
|
||||
built_in_func["$asin" ] = ASIN;
|
||||
built_in_func["$acos" ] = ACOS;
|
||||
built_in_func["$atan" ] = ATAN;
|
||||
built_in_func["$sinh" ] = SINH;
|
||||
built_in_func["$cosh" ] = COSH;
|
||||
built_in_func["$tanh" ] = TANH;
|
||||
built_in_func["$asinh"] = ASINH;
|
||||
built_in_func["$acosh"] = ACOSH;
|
||||
built_in_func["$atanh"] = ATANH;
|
||||
built_in_func["$abs" ] = ABS;
|
||||
built_in_func["$pow" ] = POW;
|
||||
built_in_func["$atan2"] = ATAN2;
|
||||
built_in_func["$hypot"] = HYPOT;
|
||||
built_in_func["$min" ] = MIN;
|
||||
built_in_func["$max" ] = MAX;
|
||||
}
|
||||
|
||||
map<string,ID>::iterator idx = built_in_func.find(name_);
|
||||
if (idx == built_in_func.end())
|
||||
return NOT_BUILT_IN;
|
||||
|
||||
ID id = idx->second;
|
||||
|
||||
if (is_ams_(id) && !gn_icarus_misc_flag && !gn_verilog_ams_flag)
|
||||
return NOT_BUILT_IN;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
NetExpr* NetESFunc::eval_tree()
|
||||
{
|
||||
/* 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) {
|
||||
ID id = built_in_id_();
|
||||
if (id == NOT_BUILT_IN)
|
||||
return 0;
|
||||
|
||||
switch (nargs_(id)) {
|
||||
case 1:
|
||||
if (parms_.size() != 1) {
|
||||
cerr << get_fileline() << ": error: " << name_
|
||||
<< " takes one argument." << endl;
|
||||
return 0;
|
||||
}
|
||||
eval_expr(parms_[0]);
|
||||
return evaluate_one_arg_(id, parms_[0]);
|
||||
case 2:
|
||||
if (parms_.size() != 2) {
|
||||
cerr << get_fileline() << ": error: " << name_
|
||||
<< " takes two arguments." << endl;
|
||||
return 0;
|
||||
}
|
||||
eval_expr(parms_[0]);
|
||||
eval_expr(parms_[1]);
|
||||
return evaluate_two_arg_(id, parms_[0], parms_[1]);
|
||||
default:
|
||||
ivl_assert(*this, 0);
|
||||
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;
|
||||
}
|
||||
NetExpr*arg = parm(0)->dup_expr();
|
||||
if (strcmp(nm, "$clog2") == 0) {
|
||||
rtn = evaluate_clog2(arg);
|
||||
} else {
|
||||
rtn = evaluate_math_one_arg(arg, nm);
|
||||
}
|
||||
delete arg;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
NetExpr*arg0 = parm(0)->dup_expr();
|
||||
NetExpr*arg1 = parm(1)->dup_expr();
|
||||
rtn = evaluate_math_two_args(arg0, arg1, nm);
|
||||
delete arg0;
|
||||
delete arg1;
|
||||
}
|
||||
|
||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
||||
(strcmp(nm, "$abs") == 0)) {
|
||||
if (nparms() != 1 || parm(0) == 0) {
|
||||
cerr << get_fileline() << ": error: " << nm
|
||||
<< " takes a single argument." << endl;
|
||||
return 0;
|
||||
}
|
||||
NetExpr*arg = parm(0)->dup_expr();
|
||||
rtn = evaluate_abs(arg);
|
||||
delete arg;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
NetExpr*arg0 = parm(0)->dup_expr();
|
||||
NetExpr*arg1 = parm(1)->dup_expr();
|
||||
rtn = evaluate_min_max(arg0, arg1, nm);
|
||||
delete arg0;
|
||||
delete arg1;
|
||||
}
|
||||
|
||||
if (rtn != 0) {
|
||||
rtn->set_line(*this);
|
||||
|
||||
if (debug_eval_tree)
|
||||
cerr << get_fileline() << ": debug: Evaluated: " << *this
|
||||
<< " --> " << *rtn << endl;
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
NetExpr* NetEUFunc::eval_tree()
|
||||
|
|
|
|||
|
|
@ -439,6 +439,41 @@ NetExpr* NetEUnary::evaluate_function(const LineInfo&loc,
|
|||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetESFunc::evaluate_function(const LineInfo&loc,
|
||||
map<perm_string,NetExpr*>&context_map) const
|
||||
{
|
||||
ID id = built_in_id_();
|
||||
if (id == NOT_BUILT_IN) {
|
||||
cerr << get_fileline() << ": error: " << name_
|
||||
<< " is not a built-in function, so cannot"
|
||||
<< " be used in a constant function." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr*val0 = 0;
|
||||
NetExpr*val1 = 0;
|
||||
NetExpr*res = 0;
|
||||
switch (nargs_(id)) {
|
||||
case 1:
|
||||
val0 = parms_[0]->evaluate_function(loc, context_map);
|
||||
if (val0 == 0) break;
|
||||
res = evaluate_one_arg_(id, val0);
|
||||
break;
|
||||
case 2:
|
||||
val0 = parms_[0]->evaluate_function(loc, context_map);
|
||||
val1 = parms_[1]->evaluate_function(loc, context_map);
|
||||
if (val0 == 0 || val1 == 0) break;
|
||||
res = evaluate_two_arg_(id, val0, val1);
|
||||
break;
|
||||
default:
|
||||
ivl_assert(*this, 0);
|
||||
break;
|
||||
}
|
||||
delete val0;
|
||||
delete val1;
|
||||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetEUFunc::evaluate_function(const LineInfo&loc,
|
||||
map<perm_string,NetExpr*>&context_map) const
|
||||
{
|
||||
|
|
|
|||
34
netlist.h
34
netlist.h
|
|
@ -4005,6 +4005,8 @@ class NetESFunc : public NetExpr {
|
|||
const NetExpr* parm(unsigned idx) const;
|
||||
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual NetExpr* evaluate_function(const LineInfo&loc,
|
||||
std::map<perm_string,NetExpr*>&ctx) const;
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
|
|
@ -4016,11 +4018,43 @@ class NetESFunc : public NetExpr {
|
|||
virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
||||
private:
|
||||
enum ID { NOT_BUILT_IN = 0x0,
|
||||
MATH_ONE_ARG = 0x100,
|
||||
CLOG2, LN, LOG10, EXP, SQRT, FLOOR, CEIL,
|
||||
SIN, COS, TAN, ASIN, ACOS, ATAN,
|
||||
SINH, COSH, TANH, ASINH, ACOSH, ATANH,
|
||||
AMS_ONE_ARG = 0x180,
|
||||
ABS,
|
||||
MATH_TWO_ARG = 0x200,
|
||||
POW, ATAN2, HYPOT,
|
||||
AMS_TWO_ARG = 0x280,
|
||||
MIN, MAX };
|
||||
|
||||
bool is_ams_(ID id) const { return id & 0x80; };
|
||||
unsigned nargs_(ID id) const { return id >> 8; };
|
||||
|
||||
const char* name_;
|
||||
ivl_variable_type_t type_;
|
||||
netenum_t*enum_type_;
|
||||
std::vector<NetExpr*>parms_;
|
||||
|
||||
ID built_in_id_() const;
|
||||
|
||||
NetExpr* evaluate_one_arg_(ID id, const NetExpr*arg) const;
|
||||
NetExpr* evaluate_two_arg_(ID id, const NetExpr*arg0,
|
||||
const NetExpr*arg1) const;
|
||||
|
||||
NetEConst* evaluate_clog2_(const NetExpr*arg) const;
|
||||
|
||||
NetECReal* evaluate_math_one_arg_(ID id, const NetExpr*arg) const;
|
||||
NetECReal* evaluate_math_two_arg_(ID id, const NetExpr*arg0,
|
||||
const NetExpr*arg1) const;
|
||||
|
||||
NetExpr* evaluate_abs_(const NetExpr*arg) const;
|
||||
|
||||
NetExpr* evaluate_min_max_(ID id, const NetExpr*arg0,
|
||||
const NetExpr*arg1) const;
|
||||
|
||||
private: // not implemented
|
||||
NetESFunc(const NetESFunc&);
|
||||
NetESFunc& operator= (const NetESFunc&);
|
||||
|
|
|
|||
Loading…
Reference in New Issue