Rework constant system function code and add $rtoi and $itor
This commit is contained in:
parent
7b07fca285
commit
a196af8e15
164
eval_tree.cc
164
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<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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
63
netlist.h
63
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;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue