Rework constant system function code and add $rtoi and $itor

This commit is contained in:
Cary R 2013-10-11 10:50:45 -07:00
parent 7b07fca285
commit a196af8e15
3 changed files with 170 additions and 59 deletions

View File

@ -1686,6 +1686,57 @@ NetEConst* NetESFunc::evaluate_clog2_(const NetExpr*arg_) const
return rtn; return rtn;
} }
NetEConst* NetESFunc::evaluate_rtoi_(const NetExpr*arg_) const
{
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg_);
const NetECReal*tmpr = dynamic_cast<const NetECReal*>(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<const NetEConst*>(arg_);
const NetECReal*tmpr = dynamic_cast<const NetECReal*>(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 NetECReal* NetESFunc::evaluate_math_one_arg_(ID id, const NetExpr*arg_) const
{ {
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg_); const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg_);
@ -1879,6 +1930,10 @@ NetExpr* NetESFunc::evaluate_one_arg_(ID id, const NetExpr*arg) const
return evaluate_abs_(arg); return evaluate_abs_(arg);
case CLOG2: case CLOG2:
return evaluate_clog2_(arg); return evaluate_clog2_(arg);
case ITOR:
return evaluate_itor_(arg);
case RTOI:
return evaluate_rtoi_(arg);
default: default:
return evaluate_math_one_arg_(id, arg); 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 NetESFunc::ID NetESFunc::built_in_id_() const
{ {
/* If we are not targeting at least Verilog-2005, Verilog-AMS static map<string,ID> built_in_func;
* or using the Icarus misc flag then we do not treat these static bool funcs_need_init = true;
* functions as built-in. */
if (generation_flag < GN_VER2005 && /* These functions are always available. */
!gn_icarus_misc_flag && !gn_verilog_ams_flag) { if (funcs_need_init) {
return NOT_BUILT_IN; built_in_func["$itor"] = ITOR;
built_in_func["$rtoi"] = RTOI;
} }
static map<string,ID> built_in_func; /* These are available in 1364-2005 and later or if the Icarus misc
* flag was given. */
if (built_in_func.empty()) { 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["$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["$ln" ] = LN;
built_in_func["$log10"] = LOG10; 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["$pow" ] = POW;
built_in_func["$atan2"] = ATAN2; built_in_func["$sin" ] = SIN;
built_in_func["$hypot"] = HYPOT; built_in_func["$sinh" ] = SINH;
built_in_func["$min" ] = MIN; built_in_func["$sqrt" ] = SQRT;
built_in_func["$max" ] = MAX; 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<string,ID>::iterator idx = built_in_func.find(name_); 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 (idx == built_in_func.end()) return NOT_BUILT_IN;
if (is_ams_(id) && !gn_icarus_misc_flag && !gn_verilog_ams_flag) return idx->second;
return NOT_BUILT_IN;
return id;
} }
NetExpr* NetESFunc::eval_tree() 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_(); ID id = built_in_id_();
if (id == NOT_BUILT_IN) if (id == NOT_BUILT_IN) return 0;
return 0;
switch (nargs_(id)) { switch (parms_.size()) {
case 1: case 1:
if (parms_.size() != 1) { if (! takes_nargs_(id, 1)) {
cerr << get_fileline() << ": error: " << name_ cerr << get_fileline() << ": error: " << name_
<< " takes one argument." << endl; << "() does not support a single argument." << endl;
return 0; return 0;
} }
eval_expr(parms_[0]); eval_expr(parms_[0]);
return evaluate_one_arg_(id, parms_[0]); return evaluate_one_arg_(id, parms_[0]);
case 2: case 2:
if (parms_.size() != 2) { if (! takes_nargs_(id, 2)) {
cerr << get_fileline() << ": error: " << name_ cerr << get_fileline() << ": error: " << name_
<< " takes two arguments." << endl; << "() does not support two arguments." << endl;
return 0; return 0;
} }
eval_expr(parms_[0]); eval_expr(parms_[0]);
eval_expr(parms_[1]); eval_expr(parms_[1]);
return evaluate_two_arg_(id, parms_[0], parms_[1]); return evaluate_two_arg_(id, parms_[0], parms_[1]);
default: 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; return 0;
} }
} }

View File

@ -908,7 +908,7 @@ NetExpr* NetESFunc::evaluate_function(const LineInfo&loc,
NetExpr*val0 = 0; NetExpr*val0 = 0;
NetExpr*val1 = 0; NetExpr*val1 = 0;
NetExpr*res = 0; NetExpr*res = 0;
switch (nargs_(id)) { switch (parms_.size()) {
case 1: case 1:
val0 = parms_[0]->evaluate_function(loc, context_map); val0 = parms_[0]->evaluate_function(loc, context_map);
if (val0 == 0) break; if (val0 == 0) break;

View File

@ -4131,20 +4131,55 @@ class NetESFunc : public NetExpr {
virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*root);
private: 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, enum ID { NOT_BUILT_IN = 0x0,
MATH_ONE_ARG = 0x100, /* Available in all version of Verilog/SystemVerilog. */
CLOG2, LN, LOG10, EXP, SQRT, FLOOR, CEIL, ITOR = 0x00020001, /* $itor takes one argument. */
SIN, COS, TAN, ASIN, ACOS, ATAN, RTOI = 0x00020002, /* $rtoi takes one argument. */
SINH, COSH, TANH, ASINH, ACOSH, ATANH, /* Available in Verilog 2005 and later. */
AMS_ONE_ARG = 0x180, ACOS = 0x00020003, /* $acos takes one argument. */
ABS, ACOSH = 0x00020004, /* $acosh takes one argument. */
MATH_TWO_ARG = 0x200, ASIN = 0x00020005, /* $asin takes one argument. */
POW, ATAN2, HYPOT, ASINH = 0x00020006, /* $asinh takes one argument. */
AMS_TWO_ARG = 0x280, ATAN = 0x00020007, /* $atan takes one argument. */
MIN, MAX }; 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; }; bool takes_nargs_(ID func, unsigned nargs) {
unsigned nargs_(ID id) const { return id >> 8; }; if (nargs > 15) nargs = 15;
return func & (1 << (nargs + 16));
}
const char* name_; const char* name_;
ivl_variable_type_t type_; ivl_variable_type_t type_;
@ -4157,6 +4192,9 @@ class NetESFunc : public NetExpr {
NetExpr* evaluate_two_arg_(ID id, const NetExpr*arg0, NetExpr* evaluate_two_arg_(ID id, const NetExpr*arg0,
const NetExpr*arg1) const; 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; NetEConst* evaluate_clog2_(const NetExpr*arg) const;
NetECReal* evaluate_math_one_arg_(ID id, 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; const NetExpr*arg1) const;
NetExpr* evaluate_abs_(const NetExpr*arg) const; NetExpr* evaluate_abs_(const NetExpr*arg) const;
NetExpr* evaluate_min_max_(ID id, const NetExpr*arg0, NetExpr* evaluate_min_max_(ID id, const NetExpr*arg0,
const NetExpr*arg1) const; const NetExpr*arg1) const;