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;
}
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
{
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);
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<string,ID> 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<string,ID> 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<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 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;
}
}

View File

@ -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;

View File

@ -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;