diff --git a/eval_tree.cc b/eval_tree.cc index 8f18a760d..b0e675394 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1923,6 +1923,173 @@ NetExpr* NetESFunc::evaluate_min_max_(ID id, const NetExpr*arg0_, return res; } +NetEConst* NetESFunc::evaluate_countbits_(const NetExpr* /*arg0*/, + const NetExpr* /*arg1*/) const +{ + return 0; +} + +NetEConst* NetESFunc::evaluate_countones_(const NetExpr* /*arg*/) const +{ + return 0; +} + +/* Get the total number of dimensions for the given expression. */ +NetEConst* NetESFunc::evaluate_dimensions_(const NetExpr*arg) const +{ + const NetESignal*esig = dynamic_cast(arg); + long res = 0; + if (esig != 0) { + const NetNet *sig = esig->sig(); + res = sig->packed_dimensions() + sig->unpacked_dimensions(); + /* Icarus does not think a string has a packed size so to + * make these routines work correct add one if this is a + * string data type. */ + if (sig->data_type() == IVL_VT_STRING) { + assert(sig->packed_dimensions() == 0); + res += 1; + } + } + /* Return the result as an integer sized constant. */ + return new NetEConst(verinum(verinum(res), integer_width)); +} + +NetEConst* NetESFunc::evaluate_isunknown_(const NetExpr* /*arg*/) const +{ + return 0; +} + +NetEConst* NetESFunc::evaluate_onehot_(const NetExpr* /*arg*/) const +{ + return 0; +} + +NetEConst* NetESFunc::evaluate_onehot0_(const NetExpr* /*arg*/) const +{ + return 0; +} + +/* Get the number of unpacked dimensions for the given expression. */ +NetEConst* NetESFunc::evaluate_unpacked_dimensions_(const NetExpr*arg) const +{ + const NetESignal*esig = dynamic_cast(arg); + long res = 0; + if (esig != 0) { + const NetNet *sig = esig->sig(); + res = sig->unpacked_dimensions(); + } + /* Return the result as an integer sized constant. */ + return new NetEConst(verinum(verinum(res), integer_width)); +} + +/* This code assumes that the dimension value will fit in a long. + * Return true if no constant dimension value is available. */ +static bool check_dimension(const NetExpr*dim_expr, long &dim) +{ + const NetEConst*dimi = dynamic_cast(dim_expr); + const NetECReal*dimr = dynamic_cast(dim_expr); + if (dimi == 0 && dimr == 0) return true; + + if (dimi) dim = dimi->value().as_long(); + if (dimr) dim = dimr->value().as_long(); + return false; +} + +/* Get the left and right values for the argument at the given dimension + * if it exists. Return true if no values are available. */ +static bool get_array_info(const NetExpr*arg, long dim, + long &left, long &right, bool&defer) +{ + /* The argument must be a signal that has enough dimensions. */ + const NetESignal*esig = dynamic_cast(arg); + if (esig == 0) return true; + const NetNet *sig = esig->sig(); + /* A string or dynamic array must be handled by the run time. */ + defer = false; + switch (sig->data_type()) { + case IVL_VT_DARRAY: + case IVL_VT_STRING: + defer = true; + return true; + break; + default: + break; + } + long pdims = sig->packed_dimensions(); + long updims = sig->unpacked_dimensions(); + if (dim > (pdims + updims)) return true; + /* Get the appropriate unpacked or packed dimension information. */ + if (dim > updims) { + const vector&dim_vals = sig->packed_dims(); + const netrange_t&range = dim_vals[dim-updims-1]; + left = range.get_msb(); + right = range.get_lsb(); + } else { + const vector&dim_vals = sig->unpacked_dims(); + const netrange_t&range = dim_vals[dim-1]; + left = range.get_msb(); + right = range.get_lsb(); + } + return false; +} + +/* Calculate the array property functions. */ +NetEConst* NetESFunc::evaluate_array_funcs_(ID id, + const NetExpr*arg0, + const NetExpr*arg1) const +{ + long dim = 0; + /* Check to see if the dimension argument is constant. */ + if (check_dimension(arg1, dim)) return 0; + /* If dimension is less than 1 return undefined. */ + if (dim < 1) { + return new NetEConst(verinum(verinum::Vx, integer_width)); + } + /* Get the left/right information for this dimension if it exists. */ + long left = 0; + long right = 0; + bool defer; + if (get_array_info(arg0, dim, left, right, defer)) { + /* If this is a string or dynamic array defer this function + * call since the left/right information is dynamic and is + * not available yet. */ + if (defer) return 0; + return new NetEConst(verinum(verinum::Vx, integer_width)); + } + /* Calculate the appropriate array function result. */ + long res; + switch (id) { + case HIGH: + res = (right > left) ? right : left; + break; + case INCR: + res = (right > left) ? -1 : 1; + break; + case LEFT: + res = left; + break; + case LOW: + res = (right > left) ? left : right; + break; + case RIGHT: + res = right; + break; + case SIZE: + res = (right > left) ? right - left : left - right; + res += 1; + break; + default: + res = 0; + assert(0); + } + /* Return the result as an integer sized constant. */ + return new NetEConst(verinum(verinum(res), integer_width)); +} + +/* Make a constant one value that can be used by the one argument + * array properties calls. */ +const NetEConst* NetESFunc::const_one_ = new NetEConst(verinum(1U, 32U)); + NetExpr* NetESFunc::evaluate_one_arg_(ID id, const NetExpr*arg) const { switch (id) { @@ -1930,21 +2097,51 @@ NetExpr* NetESFunc::evaluate_one_arg_(ID id, const NetExpr*arg) const return evaluate_abs_(arg); case CLOG2: return evaluate_clog2_(arg); + case CTONES: + return evaluate_countones_(arg); + case DIMS: + return evaluate_dimensions_(arg); + /* The array functions are handled together. */ + case HIGH: + case INCR: + case LEFT: + case LOW: + case RIGHT: + case SIZE: + return evaluate_array_funcs_(id, arg, const_one_); + case ISUNKN: + return evaluate_isunknown_(arg); case ITOR: return evaluate_itor_(arg); + case ONEHT: + return evaluate_onehot_(arg); + case ONEHT0: + return evaluate_onehot0_(arg); case RTOI: return evaluate_rtoi_(arg); + case UPDIMS: + return evaluate_unpacked_dimensions_(arg); default: return evaluate_math_one_arg_(id, arg); } } NetExpr* NetESFunc::evaluate_two_arg_(ID id, const NetExpr*arg0, - const NetExpr*arg1) const + const NetExpr*arg1) const { switch (id) { - case MIN: + case CTBITS: + return evaluate_countbits_(arg0, arg1); + /* The array functions are handled together. */ + case HIGH: + case INCR: + case LEFT: + case LOW: + case RIGHT: + case SIZE: + return evaluate_array_funcs_(id, arg0, arg1); case MAX: + case MIN: return evaluate_min_max_(id, arg0, arg1); default: return evaluate_math_two_arg_(id, arg0, arg1); @@ -1990,6 +2187,31 @@ NetESFunc::ID NetESFunc::built_in_id_() const built_in_func["$tanh" ] = TANH; } + /* These are available in 1800-2005 and later. */ + if (funcs_need_init && (generation_flag >= GN_VER2005_SV)) { + built_in_func["$dimensions" ] = DIMS; + built_in_func["$high" ] = HIGH; + built_in_func["$increment" ] = INCR; + built_in_func["$isunknown" ] = ISUNKN; + built_in_func["$left" ] = LEFT; + built_in_func["$low" ] = LOW; + built_in_func["$onehot" ] = ONEHT; + built_in_func["$onehot0" ] = ONEHT0; + built_in_func["$right" ] = RIGHT; + built_in_func["$size" ] = SIZE; + built_in_func["$unpacked_dimensions" ] = UPDIMS; + } + + /* These are available in 1800-2009 and later. */ + if (funcs_need_init && (generation_flag >= GN_VER2009)) { + built_in_func["$countones" ] = CTONES; + } + + /* These are available in 1800-2012 and later. */ + if (funcs_need_init && (generation_flag >= GN_VER2012)) { + built_in_func["$countbits" ] = CTBITS; + } + /* 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)) { @@ -2045,6 +2267,7 @@ NetExpr* NetESFunc::eval_tree() << " arguments." << endl; return 0; } +// HERE: Need to add support for a multi argument $countbits(). cerr << get_fileline() << ": sorry: functions with " << parms_.size() << " arguments are not supported: " << name_ << "()." << endl; diff --git a/netlist.h b/netlist.h index 78cbb6a5c..1f2a3ddbe 100644 --- a/netlist.h +++ b/netlist.h @@ -4176,37 +4176,53 @@ class NetESFunc : public NetExpr { */ enum ID { NOT_BUILT_IN = 0x0, /* Available in all version of Verilog/SystemVerilog. */ - ITOR = 0x00020001, /* $itor takes one argument. */ - RTOI = 0x00020002, /* $rtoi takes one argument. */ + 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. */ + 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 in SystemVerilog 2005 and later. */ + DIMS = 0x00020019, /* $dimensions takes one argument. */ + HIGH = 0x0006001a, /* $high takes one or two arguments. */ + INCR = 0x0006001b, /* $increment takes one or two arguments. */ + LEFT = 0x0006001c, /* $left takes one or two arguments. */ + LOW = 0x0006001d, /* $low takes one or two arguments. */ + RIGHT = 0x0006001e, /* $right takes one or two arguments. */ + SIZE = 0x0006001f, /* $size takes one or two arguments. */ + UPDIMS = 0x00020020, /* $unpacked_dimensions takes one argument. */ + ISUNKN = 0x00020021, /* $isunknown takes one argument. */ + ONEHT = 0x00020022, /* $onehot takes one argument. */ + ONEHT0 = 0x00020023, /* $onehot0 takes one argument. */ + /* Added in SystemVerilog 2009 and later. */ + CTONES = 0x00020024, /* $countones takes one argument. */ + /* Added in SystemVerilog 2012 and later. */ + CTBITS = 0xfffe0025, /* $countbits takes one or more arguments. */ /* 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. */ + ABS = 0x00020026, /* $abs takes one argument. */ + MAX = 0x00040027, /* $max takes two argument. */ + MIN = 0x00040028, /* $min takes two argument. */ /* A dummy value to properly close the enum. */ - DUMMY = 0xffffffff }; + DUMMY = 0xffffffff }; bool takes_nargs_(ID func, unsigned nargs) { if (nargs > 15) nargs = 15; @@ -4237,6 +4253,24 @@ class NetESFunc : public NetExpr { NetExpr* evaluate_min_max_(ID id, const NetExpr*arg0, const NetExpr*arg1) const; + /* Constant SystemVerilog functions. */ + NetEConst* evaluate_countones_(const NetExpr*arg) const; + NetEConst* evaluate_dimensions_(const NetExpr*arg) const; + NetEConst* evaluate_isunknown_(const NetExpr*arg) const; + NetEConst* evaluate_onehot_(const NetExpr*arg) const; + NetEConst* evaluate_onehot0_(const NetExpr*arg) const; + NetEConst* evaluate_unpacked_dimensions_(const NetExpr*arg) const; + + /* This value is used as a default when the array functions are + * called with a single argument. */ + static const NetEConst*const_one_; + + NetEConst* evaluate_array_funcs_(ID id, + const NetExpr*arg0, + const NetExpr*arg1) const; + NetEConst* evaluate_countbits_(const NetExpr*arg0, + const NetExpr*arg1) const; + public: bool is_built_in() const { return built_in_id_() != NOT_BUILT_IN; };