From a196af8e15aa2234f66a425557bdfd19ddac5849 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 11 Oct 2013 10:50:45 -0700 Subject: [PATCH] Rework constant system function code and add $rtoi and $itor --- eval_tree.cc | 164 ++++++++++++++++++++++++++++++++++------------- net_func_eval.cc | 2 +- netlist.h | 63 ++++++++++++++---- 3 files changed, 170 insertions(+), 59 deletions(-) diff --git a/eval_tree.cc b/eval_tree.cc index 6e9eb73c2..8f18a760d 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1686,6 +1686,57 @@ NetEConst* NetESFunc::evaluate_clog2_(const NetExpr*arg_) const return rtn; } +NetEConst* NetESFunc::evaluate_rtoi_(const NetExpr*arg_) const +{ + const NetEConst*tmpi = dynamic_cast(arg_); + const NetECReal*tmpr = dynamic_cast(arg_); + + if (tmpi == 0 && tmpr == 0) return 0; + + /* If the argument is already a bit based value just extend/trim it + * to the integer width and translate all undefined bits to zero. */ + if (tmpi) { + verinum arg = verinum(tmpi->value(), integer_width); + arg.cast_to_int2(); + return new NetEConst(arg); + } + + /* Get the value of the real argument as a bit based value and then + * extend/trim it to the integer width. */ + double arg = tmpr->value().as_double(); + if (arg >= 0.0) arg = floor(arg); + else arg = ceil(arg); + return new NetEConst(verinum(verinum(arg, false), integer_width)); +} + +NetECReal* NetESFunc::evaluate_itor_(const NetExpr*arg_) const +{ + const NetEConst*tmpi = dynamic_cast(arg_); + const NetECReal*tmpr = dynamic_cast(arg_); + + if (tmpi == 0 && tmpr == 0) return 0; + + /* If the argument is already a real value round it, but NaN and + * +/- infinity need to be translated to 0.0. */ + if (tmpr) { + double arg = tmpr->value().as_double(); + /* Convert a NaN or +/- infinity to 0.0 since these convert + * to 'bz which is then translated to 0.0. */ + if (arg != arg || (arg && (arg == 0.5*arg))) { + return new NetECReal(verireal(0.0)); + } + + if (arg >= 0.0) arg = floor(arg + 0.5); + else arg = ceil(arg - 0.5); + + return new NetECReal(verireal(arg)); + } + + /* Convert the bit based value to a real value. */ + double arg = tmpi->value().as_double(); + return new NetECReal(verireal(arg)); +} + NetECReal* NetESFunc::evaluate_math_one_arg_(ID id, const NetExpr*arg_) const { const NetEConst*tmpi = dynamic_cast(arg_); @@ -1879,6 +1930,10 @@ NetExpr* NetESFunc::evaluate_one_arg_(ID id, const NetExpr*arg) const return evaluate_abs_(arg); case CLOG2: return evaluate_clog2_(arg); + case ITOR: + return evaluate_itor_(arg); + case RTOI: + return evaluate_rtoi_(arg); default: return evaluate_math_one_arg_(id, arg); } @@ -1898,82 +1953,101 @@ NetExpr* NetESFunc::evaluate_two_arg_(ID id, const NetExpr*arg0, 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 built_in_func; + static bool funcs_need_init = true; + + /* These functions are always available. */ + if (funcs_need_init) { + built_in_func["$itor"] = ITOR; + built_in_func["$rtoi"] = RTOI; } - static map built_in_func; - - if (built_in_func.empty()) { + /* These are available in 1364-2005 and later or if the Icarus misc + * flag was given. */ + if (funcs_need_init && ((generation_flag >= GN_VER2005) || + gn_icarus_misc_flag)) { + built_in_func["$acos" ] = ACOS; + built_in_func["$acosh"] = ACOSH; + built_in_func["$asin" ] = ASIN; + built_in_func["$asinh"] = ASINH; + built_in_func["$atan" ] = ATAN; + built_in_func["$atanh"] = ATANH; + built_in_func["$atan2"] = ATAN2; + built_in_func["$ceil" ] = CEIL; built_in_func["$clog2"] = CLOG2; + built_in_func["$cos" ] = COS; + built_in_func["$cosh" ] = COSH; + built_in_func["$exp" ] = EXP; + built_in_func["$floor"] = FLOOR; + built_in_func["$hypot"] = HYPOT; 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; + built_in_func["$sin" ] = SIN; + built_in_func["$sinh" ] = SINH; + built_in_func["$sqrt" ] = SQRT; + built_in_func["$tan" ] = TAN; + built_in_func["$tanh" ] = TANH; } + /* These are available in Verilog-A as Icarus extensions or if the + * Icarus misc flag was given. */ + if (funcs_need_init && (gn_verilog_ams_flag || gn_icarus_misc_flag)) { + built_in_func["$abs"] = ABS; + built_in_func["$max"] = MAX; + built_in_func["$min"] = MIN; + } + + /* The function table has been initialized at this point. */ + funcs_need_init = false; + + /* Look for the given function and if it is not available return + * NOT_BUILT_IN otherwise return the ID for the function. */ map::iterator idx = built_in_func.find(name_); - if (idx == built_in_func.end()) - return NOT_BUILT_IN; - ID id = idx->second; + if (idx == built_in_func.end()) return NOT_BUILT_IN; - if (is_ams_(id) && !gn_icarus_misc_flag && !gn_verilog_ams_flag) - return NOT_BUILT_IN; - - return id; + return idx->second; } NetExpr* NetESFunc::eval_tree() { + /* Get the ID for this system function if it is can be used as a + * constant function. */ ID id = built_in_id_(); - if (id == NOT_BUILT_IN) - return 0; + if (id == NOT_BUILT_IN) return 0; - switch (nargs_(id)) { + switch (parms_.size()) { case 1: - if (parms_.size() != 1) { + if (! takes_nargs_(id, 1)) { cerr << get_fileline() << ": error: " << name_ - << " takes one argument." << endl; + << "() does not support a single argument." << endl; return 0; } eval_expr(parms_[0]); return evaluate_one_arg_(id, parms_[0]); + case 2: - if (parms_.size() != 2) { + if (! takes_nargs_(id, 2)) { cerr << get_fileline() << ": error: " << name_ - << " takes two arguments." << endl; + << "() does not support 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); + /* Check to see if the function was called correctly. */ + if (! takes_nargs_(id, parms_.size())) { + cerr << get_fileline() << ": error: " << name_ + << "() does not support " << parms_.size() + << " arguments." << endl; + return 0; + } + cerr << get_fileline() << ": sorry: functions with " + << parms_.size() << " arguments are not supported: " + << name_ << "()." << endl; return 0; } } diff --git a/net_func_eval.cc b/net_func_eval.cc index f50d561d9..e6229602a 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -908,7 +908,7 @@ NetExpr* NetESFunc::evaluate_function(const LineInfo&loc, NetExpr*val0 = 0; NetExpr*val1 = 0; NetExpr*res = 0; - switch (nargs_(id)) { + switch (parms_.size()) { case 1: val0 = parms_[0]->evaluate_function(loc, context_map); if (val0 == 0) break; diff --git a/netlist.h b/netlist.h index a9ae88cdb..2f87bf56b 100644 --- a/netlist.h +++ b/netlist.h @@ -4131,20 +4131,55 @@ class NetESFunc : public NetExpr { virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*root); private: + /* Use the 32 bit ID as follows: + * The lower sixteen bits are used to identify the individual + * functions. + * + * The top sixteen bits are used to indicate the number of + * arguments the function can take by bit position. If more + * than one bit is set the argument can take a different number + * of arguments. This varies from 0 to 14 with the MSB indicating + * fifteen or more (an unbounded value). For example all bit set + * except for the LSB indicate 1 or more arguments are allowed. + */ 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 }; + /* Available in all version of Verilog/SystemVerilog. */ + ITOR = 0x00020001, /* $itor takes one argument. */ + RTOI = 0x00020002, /* $rtoi takes one argument. */ + /* Available in Verilog 2005 and later. */ + ACOS = 0x00020003, /* $acos takes one argument. */ + ACOSH = 0x00020004, /* $acosh takes one argument. */ + ASIN = 0x00020005, /* $asin takes one argument. */ + ASINH = 0x00020006, /* $asinh takes one argument. */ + ATAN = 0x00020007, /* $atan takes one argument. */ + ATANH = 0x00020008, /* $atanh takes one argument. */ + ATAN2 = 0x00040009, /* $atan2 takes two argument. */ + CEIL = 0x0002000a, /* $ceil takes one argument. */ + CLOG2 = 0x0002000b, /* $clog2 takes one argument. */ + COS = 0x0002000c, /* $cos takes one argument. */ + COSH = 0x0002000d, /* $cosh takes one argument. */ + EXP = 0x0002000e, /* $exp takes one argument. */ + FLOOR = 0x0002000f, /* $floor takes one argument. */ + HYPOT = 0x00040010, /* $hypot takes two argument. */ + LN = 0x00020011, /* $ln takes one argument. */ + LOG10 = 0x00020012, /* $log10 takes one argument. */ + POW = 0x00040013, /* $pow takes two argument. */ + SIN = 0x00020014, /* $sin takes one argument. */ + SINH = 0x00020015, /* $sinh takes one argument. */ + SQRT = 0x00020016, /* $sqrt takes one argument. */ + TAN = 0x00020017, /* $tan takes one argument. */ + TANH = 0x00020018, /* $tanh takes one argument. */ + /* Added as Icarus extensions to Verilog-A. */ + ABS = 0x00020019, /* $abs takes one argument. */ + MAX = 0x0004001a, /* $max takes two argument. */ + MIN = 0x0004001b, /* $min takes two argument. */ + /* A dummy value to properly close the enum. */ + DUMMY = 0xffffffff }; - bool is_ams_(ID id) const { return id & 0x80; }; - unsigned nargs_(ID id) const { return id >> 8; }; + bool takes_nargs_(ID func, unsigned nargs) { + if (nargs > 15) nargs = 15; + return func & (1 << (nargs + 16)); + } const char* name_; ivl_variable_type_t type_; @@ -4157,6 +4192,9 @@ class NetESFunc : public NetExpr { NetExpr* evaluate_two_arg_(ID id, const NetExpr*arg0, const NetExpr*arg1) const; + NetEConst* evaluate_rtoi_(const NetExpr*arg) const; + NetECReal* evaluate_itor_(const NetExpr*arg) const; + NetEConst* evaluate_clog2_(const NetExpr*arg) const; NetECReal* evaluate_math_one_arg_(ID id, const NetExpr*arg) const; @@ -4164,7 +4202,6 @@ class NetESFunc : public NetExpr { const NetExpr*arg1) const; NetExpr* evaluate_abs_(const NetExpr*arg) const; - NetExpr* evaluate_min_max_(ID id, const NetExpr*arg0, const NetExpr*arg1) const;