From 2d3cd7cb9aaf35fdecd06ce3229c15ef2e76663b Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 28 Aug 2008 18:11:55 -0700 Subject: [PATCH 1/5] Handle NaN constant in the code generator and fix loadi/wr NaN bug. This patch fixes a bug in %loadi/wr regarding NaN values. It also fixes the code generator to correctly output a NaN value. --- tgt-vvp/eval_real.c | 10 ++++++++-- vvp/opcodes.txt | 2 +- vvp/vthread.cc | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index 8a7dda0f2..54768be5b 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -206,13 +206,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; diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index f3a266569..f8ba97f10 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -492,7 +492,7 @@ is removed from the before calculating the real value. If ==0x3fff and == 0, the value is +inf. If ==0x7fff and == 0, the value is -inf. -If --0x3fff and != 0, the value is NaN. +If ==0x3fff and != 0, the value is NaN. * %mod , , * %mod/s , , diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 65425ff84..05344f160 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2663,8 +2663,9 @@ bool of_LOADI_WR(vthread_t thr, vvp_code_t cp) return true; } // Detect NaN - if ( (exp&0x3fff) == 0x3fff ) { + if (exp==0x3fff && cp->number!=0) { thr->words[idx].w_real = nan(""); + return true; } double sign = (exp & 0x4000)? -1.0 : 1.0; From 2e97b2818593374d37af00a601e3c460337e586e Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 28 Aug 2008 18:33:13 -0700 Subject: [PATCH 2/5] More NaN constant fixes. This patch cleans up %loadi/wr regarding NaN values. It also fixes the code generator to correctly output a NaN value as a Cr<> constant. --- tgt-vvp/vvp_scope.c | 4 ++++ vvp/vthread.cc | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 433263b24..e018166bb 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -330,6 +330,10 @@ char* draw_Cr_to_string(double value) snprintf(tmp, sizeof(tmp), "Cr"); return strdup(tmp); } + if (value != value) { + snprintf(tmp, sizeof(tmp), "Cr"); + return strdup(tmp); + } int sign = 0; if (value < 0) { diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 05344f160..a19eb59ce 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2663,7 +2663,7 @@ bool of_LOADI_WR(vthread_t thr, vvp_code_t cp) return true; } // Detect NaN - if (exp==0x3fff && cp->number!=0) { + if (exp==0x3fff) { thr->words[idx].w_real = nan(""); return true; } From 0804eccfecfbc004239524195cf17b3c761a7d62 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 29 Aug 2008 10:52:09 -0700 Subject: [PATCH 3/5] Evaluate constant real EQ and NE constructs. This patch adds code to evaluate constant == and != with real values. --- eval_tree.cc | 79 ++++++++++++++++++++++++++++++++++++++++++---------- netlist.h | 1 + 2 files changed, 65 insertions(+), 15 deletions(-) diff --git a/eval_tree.cc b/eval_tree.cc index 99e408a60..057ed003c 100644 --- a/eval_tree.cc +++ b/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 (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 (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 (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 (ri); - if (vtmp == 0) - return 0; - - rv = vtmp->value().as_long(); + if (vtmp == 0) return 0; + rv = vtmp->value().as_double(); break; default: @@ -563,8 +554,66 @@ NetEConst* NetEBComp::eval_gteq_() } } +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 (le); + if (rtmp == 0) return 0; + lv = rtmp->value().as_double(); + break; + + case IVL_VT_LOGIC: + case IVL_VT_BOOL: + vtmp = dynamic_cast (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 (ri); + if (rtmp == 0) return 0; + rv = rtmp->value().as_double(); + break; + + case IVL_VT_LOGIC: + case IVL_VT_BOOL: + vtmp = dynamic_cast (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(left_); if (l == 0) return 0; NetEConst*r = dynamic_cast(right_); diff --git a/netlist.h b/netlist.h index e86b3936c..ebeb07683 100644 --- a/netlist.h +++ b/netlist.h @@ -3206,6 +3206,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); From f900b6d5410986125e1cb3d43b511754ce286058 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 29 Aug 2008 21:11:44 -0700 Subject: [PATCH 4/5] Add the Verilog-2005 and Verilog-AMS constant system functions. This patch adds the constant system functions for Verilog-2005 and Verilog-AMS. These are evaluated at compile time. $abs(), $min() and $max() support their polymorphic behavior in the compiler where it really matters. They are always evaluated as reals in the run time and the result/argument(s) will be converted as needed. The Verilog-2005 functions are available if using the 2005 generation (default) and if either the icarus-misc (also on by default) or verilog-ams flags are set. The Verilog-AMS functions are available if either the icarus-misc or verilog-ams flags are set. --- PExpr.cc | 74 ++++++++-- driver/main.c | 17 ++- elab_pexpr.cc | 115 ++++++++++++++-- eval_tree.cc | 243 ++++++++++++++++++++++++++++++--- vpi/Makefile.in | 23 +++- vpi/sys_clog2.c | 34 ++++- vpi/sys_priv.c | 3 + vpi/sys_table.c | 2 - vpi/v2005_math.c | 326 +++++++++++++++++++++++++++++++++++++++++++++ vpi/v2005_math.sft | 28 ++++ vpi/va_math.c | 25 +--- vpi/va_math.sft | 21 --- 12 files changed, 827 insertions(+), 84 deletions(-) create mode 100644 vpi/v2005_math.c create mode 100644 vpi/v2005_math.sft diff --git a/PExpr.cc b/PExpr.cc index bdb955c41..70c73a978 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -20,8 +20,8 @@ # include "config.h" # include -# include +# include "compiler.h" # include "PExpr.h" # include "Module.h" # include @@ -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. */ diff --git a/driver/main.c b/driver/main.c index 38c4d1bba..fe596c031 100644 --- a/driver/main.c +++ b/driver/main.c @@ -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"); } diff --git a/elab_pexpr.cc b/elab_pexpr.cc index 588fb3d8d..5244a9e2d 100644 --- a/elab_pexpr.cc +++ b/elab_pexpr.cc @@ -25,7 +25,6 @@ # include "netmisc.h" # include -# include # include # 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; diff --git a/eval_tree.cc b/eval_tree.cc index 057ed003c..c088e20fe 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1709,25 +1709,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(arg); + NetECReal*tmpr = dynamic_cast(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(arg0); + NetECReal*tmpr0 = dynamic_cast(arg0); + NetEConst*tmpi1 = dynamic_cast(arg1); + NetECReal*tmpr1 = dynamic_cast(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(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(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(arg0); + NetECReal*tmpr0 = dynamic_cast(arg0); + NetEConst*tmpi1 = dynamic_cast(arg1); + NetECReal*tmpr1 = dynamic_cast(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; +} diff --git a/vpi/Makefile.in b/vpi/Makefile.in index a2b8bea94..0b5c703ed 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -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) diff --git a/vpi/sys_clog2.c b/vpi/sys_clog2.c index 9d30f60a5..3941d443a 100644 --- a/vpi/sys_clog2.c +++ b/vpi/sys_clog2.c @@ -20,7 +20,39 @@ #include #include #include -#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. diff --git a/vpi/sys_priv.c b/vpi/sys_priv.c index 5e1dcba4b..70f0a4316 100644 --- a/vpi/sys_priv.c +++ b/vpi/sys_priv.c @@ -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) { diff --git a/vpi/sys_table.c b/vpi/sys_table.c index 56d480217..4560744e7 100644 --- a/vpi/sys_table.c +++ b/vpi/sys_table.c @@ -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 }; diff --git a/vpi/v2005_math.c b/vpi/v2005_math.c new file mode 100644 index 000000000..7d124d869 --- /dev/null +++ b/vpi/v2005_math.c @@ -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 +#include +#include +#include +#include + +/* 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 +}; diff --git a/vpi/v2005_math.sft b/vpi/v2005_math.sft new file mode 100644 index 000000000..d772832b4 --- /dev/null +++ b/vpi/v2005_math.sft @@ -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 diff --git a/vpi/va_math.c b/vpi/va_math.c index a844e34ab..62502a34e 100644 --- a/vpi/va_math.c +++ b/vpi/va_math.c @@ -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! */ }; diff --git a/vpi/va_math.sft b/vpi/va_math.sft index 0c3b78e47..b78ac8da8 100644 --- a/vpi/va_math.sft +++ b/vpi/va_math.sft @@ -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 From 97e662d667b18e7a4f1134a64941c60733569d19 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 29 Aug 2008 18:03:05 -0700 Subject: [PATCH 5/5] Remove unneeded real compare code. The code removed is unneeded since real values are already handled by the real specific comparison that is called at the beginning of each function. --- eval_tree.cc | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/eval_tree.cc b/eval_tree.cc index c088e20fe..50fdaf02b 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -472,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(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(right_); if (r == 0) return 0; @@ -523,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(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(right_); if (r == 0) return 0;