diff --git a/elab_pexpr.cc b/elab_pexpr.cc index 5244a9e2d..79f69c852 100644 --- a/elab_pexpr.cc +++ b/elab_pexpr.cc @@ -268,66 +268,57 @@ NetExpr*PEUnary::elaborate_pexpr (Design*des, NetScope*scope) const return tmp; } -/* 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 { /* 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") { + perm_string nm = peek_tail_name(path_); + if (nm[0] == '$' && (generation_flag >= GN_VER2005 || + gn_icarus_misc_flag || gn_verilog_ams_flag)) { + if (nm == "$clog2" || + nm == "$ln" || + nm == "$log10" || + nm == "$exp" || + nm == "$sqrt" || + nm == "$floor" || + nm == "$ceil" || + nm == "$sin" || + nm == "$cos" || + nm == "$tan" || + nm == "$asin" || + nm == "$acos" || + nm == "$atan" || + nm == "$sinh" || + nm == "$cosh" || + nm == "$tanh" || + nm == "$asinh" || + nm == "$acosh" || + nm == "$atanh") { if (parms_.size() != 1 || parms_[0] == 0) { - cerr << get_fileline() << ": error: " << name + cerr << get_fileline() << ": error: " << nm << " 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_) == "$clog2") { - rtn = evaluate_clog2(arg); + NetESFunc*rtn; + if (nm == "$clog2") { + rtn = new NetESFunc(nm, IVL_VT_BOOL, integer_width, 1); } else { - rtn = evaluate_math_one_arg(arg, name.str()); - } - delete arg; - if (rtn != 0) { - rtn->set_line(*this); - return rtn; + rtn = new NetESFunc(nm, IVL_VT_REAL, 1, 1); } + rtn->set_line(*this); + rtn->cast_signed(true); + rtn->parm(0, arg); + return rtn; } - if (name == "$pow" || - name == "$atan2" || - name == "$hypot") { + if (nm == "$pow" || + nm == "$atan2" || + nm == "$hypot") { if (parms_.size() != 2 || parms_[0] == 0 || parms_[1] == 0) { - cerr << get_fileline() << ": error: " << name + cerr << get_fileline() << ": error: " << nm << " takes two arguments." << endl; des->errors += 1; return 0; @@ -335,45 +326,44 @@ NetExpr* PECallFunction::elaborate_pexpr(Design*des, NetScope*scope) const 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; - } + NetESFunc*rtn = new NetESFunc(nm, IVL_VT_REAL, 1, 2); + rtn->set_line(*this); + rtn->cast_signed(true); + rtn->parm(0, arg0); + rtn->parm(1, arg1); + 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")) { + (nm == "$log" || nm == "$abs")) { if (parms_.size() != 1 || parms_[0] == 0) { - cerr << get_fileline() << ": error: " << name + cerr << get_fileline() << ": error: " << nm << " 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()); + NetESFunc*rtn; + if (nm == "$log") { + rtn = new NetESFunc(nm, IVL_VT_REAL, 1, 1); } else { - rtn = evaluate_abs(arg); - } - delete arg; - if (rtn != 0) { - rtn->set_line(*this); - return rtn; + /* This can return either a real or an arbitrary + * width vector, so set things to fail if this + * does not get replaced with a constant during + * elaboration. */ + rtn = new NetESFunc(nm, IVL_VT_NO_TYPE, 0, 1); } + rtn->set_line(*this); + rtn->cast_signed(true); + rtn->parm(0, arg); + return rtn; } if ((gn_icarus_misc_flag || gn_verilog_ams_flag) && - (name == "$min" || name == "$max")) { + (nm == "$min" || nm == "$max")) { if (parms_.size() != 2 || parms_[0] == 0 || parms_[1] == 0) { - cerr << get_fileline() << ": error: " << name + cerr << get_fileline() << ": error: " << nm << " takes two arguments." << endl; des->errors += 1; return 0; @@ -381,15 +371,13 @@ NetExpr* PECallFunction::elaborate_pexpr(Design*des, NetScope*scope) const 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; - } + /* See $log above for why this has no type or width. */ + NetESFunc*rtn = new NetESFunc(nm, IVL_VT_NO_TYPE, 0, 2); + rtn->set_line(*this); + rtn->cast_signed(true); + rtn->parm(0, arg0); + rtn->parm(1, arg1); + return rtn; } cerr << get_fileline() << ": error: this is not a constant " diff --git a/eval_tree.cc b/eval_tree.cc index e8f045b2b..78d1e5b28 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1646,8 +1646,9 @@ NetEConst* NetEUReduce::eval_tree(int prune_to_width) return new NetEConst(verinum(res, 1)); } -NetExpr* evaluate_clog2(NetExpr*arg) +NetExpr* evaluate_clog2(NetExpr*&arg) { + eval_expr(arg); NetEConst*tmpi = dynamic_cast(arg); NetECReal*tmpr = dynamic_cast(arg); if (tmpi || tmpr) { @@ -1658,9 +1659,9 @@ NetExpr* evaluate_clog2(NetExpr*arg) arg = verinum(tmpr->value().as_double(), true); } - /* If we have an x in the verinum we return 32'bx. */ + /* If we have an x in the verinum we return 'bx. */ if (!arg.is_defined()) { - verinum tmp (verinum::Vx, 32); + verinum tmp (verinum::Vx, integer_width); tmp.has_sign(true); NetEConst*rtn = new NetEConst(tmp); return rtn; @@ -1688,7 +1689,7 @@ NetExpr* evaluate_clog2(NetExpr*arg) if (is_neg && res < integer_width) res = integer_width; - verinum tmp (res, 32); + verinum tmp (res, integer_width); NetEConst*rtn = new NetEConst(tmp); return rtn; } @@ -1696,8 +1697,9 @@ NetExpr* evaluate_clog2(NetExpr*arg) return 0; } -NetExpr* evaluate_math_one_arg(NetExpr*arg, const char*name) +NetExpr* evaluate_math_one_arg(NetExpr*&arg, const char*name) { + eval_expr(arg); NetEConst*tmpi = dynamic_cast(arg); NetECReal*tmpr = dynamic_cast(arg); if (tmpi || tmpr) { @@ -1752,8 +1754,10 @@ NetExpr* evaluate_math_one_arg(NetExpr*arg, const char*name) return 0; } -NetExpr* evaluate_math_two_args(NetExpr*arg0, NetExpr*arg1, const char*name) +NetExpr* evaluate_math_two_args(NetExpr*&arg0, NetExpr*&arg1, const char*name) { + eval_expr(arg0); + eval_expr(arg1); NetEConst*tmpi0 = dynamic_cast(arg0); NetECReal*tmpr0 = dynamic_cast(arg0); NetEConst*tmpi1 = dynamic_cast(arg1); @@ -1783,8 +1787,9 @@ NetExpr* evaluate_math_two_args(NetExpr*arg0, NetExpr*arg1, const char*name) return 0; } -NetExpr* evaluate_abs(NetExpr*arg) +NetExpr* evaluate_abs(NetExpr*&arg) { + eval_expr(arg); NetEConst*tmpi = dynamic_cast(arg); if (tmpi) { verinum arg = tmpi->value(); @@ -1803,8 +1808,10 @@ NetExpr* evaluate_abs(NetExpr*arg) return 0; } -NetExpr* evaluate_min_max(NetExpr*arg0, NetExpr*arg1, const char*name) +NetExpr* evaluate_min_max(NetExpr*&arg0, NetExpr*&arg1, const char*name) { + eval_expr(arg0); + eval_expr(arg1); NetEConst*tmpi0 = dynamic_cast(arg0); NetECReal*tmpr0 = dynamic_cast(arg0); NetEConst*tmpi1 = dynamic_cast(arg1); @@ -1879,11 +1886,13 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width) << " takes a single argument." << endl; return 0; } + NetExpr*arg = parm(0)->dup_expr(); if (strcmp(nm, "$clog2") == 0) { - rtn = evaluate_clog2(parm(0)); + rtn = evaluate_clog2(arg); } else { - rtn = evaluate_math_one_arg(parm(0), nm); + rtn = evaluate_math_one_arg(arg, nm); } + delete arg; } if (strcmp(nm, "$pow") == 0 || @@ -1894,7 +1903,11 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width) << " takes two arguments." << endl; return 0; } - rtn = evaluate_math_two_args(parm(0), parm(1), nm); + 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) && @@ -1904,11 +1917,13 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width) << " takes a single argument." << endl; return 0; } + NetExpr*arg = parm(0)->dup_expr(); if (strcmp(nm, "$log") == 0) { - rtn = evaluate_math_one_arg(parm(0), nm); + rtn = evaluate_math_one_arg(arg, nm); } else { - rtn = evaluate_abs(parm(0)); + rtn = evaluate_abs(arg); } + delete arg; } if ((gn_icarus_misc_flag || gn_verilog_ams_flag) && @@ -1918,7 +1933,11 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width) << " takes two arguments." << endl; return 0; } - rtn = evaluate_min_max(parm(0), parm(1), nm); + 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) {