diff --git a/PExpr.cc b/PExpr.cc index 538f4f37f..4c7f303f6 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -540,6 +540,15 @@ bool PETernary::has_aa_term(Design*des, NetScope*scope) const || fal_->has_aa_term(des, scope); } +PETypename::PETypename(data_type_t*dt) +: data_type_(dt) +{ +} + +PETypename::~PETypename() +{ +} + PEUnary::PEUnary(char op, PExpr*ex) : op_(op), expr_(ex) { diff --git a/PExpr.h b/PExpr.h index 714778994..fa44c70b5 100644 --- a/PExpr.h +++ b/PExpr.h @@ -660,6 +660,23 @@ class PEString : public PExpr { char*text_; }; +class PETypename : public PExpr { + public: + explicit PETypename(data_type_t*data_type); + ~PETypename(); + + virtual void dump(ostream&) const; + virtual unsigned test_width(Design*des, NetScope*scope, + width_mode_t&mode); + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, + ivl_type_t type, unsigned flags) const; + + inline data_type_t* get_type() const { return data_type_; } + + private: + data_type_t*data_type_; +}; + class PEUnary : public PExpr { public: diff --git a/PFunction.cc b/PFunction.cc index e15fab119..a5dc8f351 100644 --- a/PFunction.cc +++ b/PFunction.cc @@ -65,7 +65,7 @@ void PFunction::push_statement_front(Statement*stmt) blk->push_statement_front(stmt); } -void PFunction::set_return(const data_type_t*t) +void PFunction::set_return(data_type_t*t) { return_type_ = t; } diff --git a/PTask.h b/PTask.h index 87b0df958..9e417615f 100644 --- a/PTask.h +++ b/PTask.h @@ -114,7 +114,7 @@ class PFunction : public PTaskFunc { ~PFunction(); void set_statement(Statement *s); - void set_return(const data_type_t*t); + void set_return(data_type_t*t); inline Statement* get_statement() { return statement_; } @@ -141,7 +141,7 @@ class PFunction : public PTaskFunc { void dump(ostream&, unsigned) const; private: - const data_type_t* return_type_; + data_type_t* return_type_; Statement *statement_; bool is_auto_; }; diff --git a/design_dump.cc b/design_dump.cc index 2a9219f34..e42347bcb 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1313,9 +1313,9 @@ void NetScope::dump(ostream&o) const o << " enum sets {" << endl; /* Dump the enumerations and enum names in this scope. */ - for (list::const_iterator cur = enum_sets_.begin() + for (map::const_iterator cur = enum_sets_.begin() ; cur != enum_sets_.end() ; ++ cur) { - o << " " << *cur << endl; + o << " " << cur->second << endl; } o << " }" << endl; diff --git a/elab_expr.cc b/elab_expr.cc index d2af0b178..4461aefa3 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -188,7 +188,7 @@ NetExpr* PExpr::elaborate_expr(Design*des, NetScope*, unsigned, unsigned) const * supported, can assign to packed arrays and structs, unpacked arrays * and dynamic arrays. */ -unsigned PEAssignPattern::test_width(Design*des, NetScope*scope, width_mode_t&mode) +unsigned PEAssignPattern::test_width(Design*, NetScope*, width_mode_t&) { expr_type_ = IVL_VT_DARRAY; expr_width_ = 1; @@ -1078,10 +1078,14 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, if (expr == 0) return 0; - // The argument type/width is self-determined and doesn't - // affect the result type/width. - width_mode_t arg_mode = SIZED; - expr->test_width(des, scope, arg_mode); + if (! dynamic_cast(expr)) { + // The argument type/width is self-determined and doesn't + // affect the result type/width. Note that if the + // argument is a type name (a special case) then + // don't bother with this step. + width_mode_t arg_mode = SIZED; + expr->test_width(des, scope, arg_mode); + } expr_type_ = IVL_VT_BOOL; expr_width_ = integer_width; @@ -1393,7 +1397,25 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, PExpr*expr = parms_[0]; - verinum val ( (uint64_t)expr->expr_width(), integer_width); + uint64_t use_width = 0; + if (PETypename*type_expr = dynamic_cast(expr)) { + ivl_type_t tmp_type = type_expr->get_type()->elaborate_type(des, scope); + ivl_assert(*this, tmp_type); + use_width = tmp_type->packed_width(); + if (debug_elaborate) { + cerr << get_fileline() << ": PECallFunction::elaborate_sfunc_: " + << " Packed width of type argument is " << use_width << endl; + } + + } else { + use_width = expr->expr_width(); + if (debug_elaborate) { + cerr << get_fileline() << ": PECallFunction::elaborate_sfunc_: " + << " Width of expression argument is " << use_width << endl; + } + } + + verinum val (use_width, integer_width); NetEConst*sub = new NetEConst(val); sub->set_line(*this); @@ -3299,9 +3321,14 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, << "got " << use_path.back().index.size() << "." << endl; } - return check_for_struct_members(this, des, use_scope, - net, use_path.back().index, - member_comp); + NetExpr*tmp = check_for_struct_members(this, des, use_scope, + net, use_path.back().index, + member_comp); + if (!tmp) return 0; + + tmp = pad_to_width(tmp, expr_wid, *this); + tmp->cast_signed(signed_flag_); + return tmp; } if (net->class_type() != 0) { @@ -4693,11 +4720,11 @@ unsigned PENewClass::test_width(Design*, NetScope*, width_mode_t&) */ NetExpr* PENewClass::elaborate_expr_constructor_(Design*des, NetScope*scope, const netclass_t*ctype, - NetExpr*obj, unsigned flags) const + NetExpr*obj, unsigned /*flags*/) const { // If there is an initializer function, then pass the object - // through that function first. Note tha the initializer - // function has no arguments other then the object itself. + // through that function first. Note that the initializer + // function has no arguments other than the object itself. if (NetScope*new1_scope = ctype->method_from_name(perm_string::literal("new@"))) { NetFuncDef*def1 = new1_scope->func_def(); ivl_assert(*this, def1); @@ -4839,7 +4866,7 @@ NetExpr* PENewCopy::elaborate_expr(Design*des, NetScope*scope, ivl_type_t obj_ty /* * A "null" expression represents class objects/handles. This brings - * up a ton of special cases, but we handle it here bu setting the + * up a ton of special cases, but we handle it here by setting the * expr_type_ and expr_width_ to fixed values. */ unsigned PENull::test_width(Design*, NetScope*, width_mode_t&) @@ -5158,6 +5185,31 @@ NetExpr* PETernary::elab_and_eval_alternative_(Design*des, NetScope*scope, return tmp; } +/* + * A typename expression is only legal in very narrow cases. This is + * just a placeholder. + */ +unsigned PETypename::test_width(Design*des, NetScope*, width_mode_t&) +{ + cerr << get_fileline() << ": error: " + << "Type names are not valid expressions here." << endl; + des->errors += 1; + + expr_type_ = IVL_VT_NO_TYPE; + expr_width_ = 1; + min_width_ = 1; + signed_flag_ = false; + return expr_width_; +} + +NetExpr*PETypename::elaborate_expr(Design*des, NetScope*, + ivl_type_t, unsigned) const +{ + cerr << get_fileline() << ": error: Type name not a valid expression here." << endl; + des->errors += 1; + return 0; +} + unsigned PEUnary::test_width(Design*des, NetScope*scope, width_mode_t&mode) { switch (op_) { diff --git a/elab_scope.cc b/elab_scope.cc index eb0028ee8..ffc0a31af 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -48,6 +48,7 @@ # include "netlist.h" # include "netclass.h" # include "netenum.h" +# include "parse_api.h" # include "util.h" # include # include @@ -156,6 +157,10 @@ static void collect_scope_specparams_(Design*des, NetScope*scope, } } +/* + * Elaborate the enumeration into the given scope. If scope==0, then + * the enumeration goes into $root instead of a scope. + */ static void elaborate_scope_enumeration(Design*des, NetScope*scope, enum_type_t*enum_type) { @@ -176,10 +181,10 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, msb, lsb, enum_type->names->size()); use_enum->set_line(enum_type->li); - scope->add_enumeration_set(use_enum); - - ivl_assert(*enum_type, enum_type->net_type == 0); - enum_type->net_type = use_enum; + if (scope) + scope->add_enumeration_set(enum_type, use_enum); + else + des->add_enumeration_set(enum_type, use_enum); verinum cur_value (0); verinum one_value (1); @@ -270,7 +275,11 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, tmp_val.has_sign(enum_type->signed_flag); rc_flag = use_enum->insert_name(name_idx, cur->name, tmp_val); - rc_flag &= scope->add_enumeration_name(use_enum, cur->name); + if (scope) + rc_flag &= scope->add_enumeration_name(use_enum, cur->name); + else + rc_flag &= des->add_enumeration_name(use_enum, cur->name); + if (! rc_flag) { cerr << use_enum->get_fileline() << ": error: Duplicate enumeration name " @@ -297,6 +306,15 @@ static void elaborate_scope_enumerations(Design*des, NetScope*scope, } } +void elaborate_rootscope_enumerations(Design*des) +{ + for (set::const_iterator cur = pform_enum_sets.begin() + ; cur != pform_enum_sets.end() ; ++ cur) { + enum_type_t*curp = *cur; + elaborate_scope_enumeration(des, 0, curp); + } +} + /* * If the pclass includes an implicit and explicit constructor, then * merge the implicit constructor into the explicit constructor as diff --git a/elab_sig.cc b/elab_sig.cc index 7f2c8780a..4b8b0ec36 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -563,7 +563,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const // Special case: this is a constructor, so the return // signal is also the first argument. For example, the // source code for the definition may be: - // function new(...); + // function new(...); // endfunction // In this case, the "@" port is the synthetic "this" // argument and we also use it as a return value at the @@ -876,7 +876,7 @@ static ivl_type_s*elaborate_type(Design*des, NetScope*scope, data_type_t*pform_type) { if (struct_type_t*struct_type = dynamic_cast(pform_type)) { - netstruct_t*use_type = struct_type->elaborate_type(des, scope); + ivl_type_s*use_type = struct_type->elaborate_type(des, scope); return use_type; } @@ -965,7 +965,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const << "'." << endl; des->errors += 1; } - // A signal can not have the same name as a parameter. + // A signal can not have the same name as a parameter. Note + // that we treat enumeration literals similar to parameters, + // so if the name matches an enumeration literal, it will be + // caught here. const NetExpr *ex_msb, *ex_lsb; const NetExpr *parm = scope->get_parameter(des, name_, ex_msb, ex_lsb); if (parm) { @@ -1207,7 +1210,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } else if (struct_type_t*struct_type = dynamic_cast(set_data_type_)) { // If this is a struct type, then build the net with the // struct type. - netstruct_t*use_type = struct_type->elaborate_type(des, scope); + ivl_type_s*tmp_type = struct_type->elaborate_type(des, scope); + netstruct_t*use_type = dynamic_cast(tmp_type); if (debug_elaborate) { cerr << get_fileline() << ": debug: Create signal " << wtype; if (use_type->packed()) @@ -1256,7 +1260,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const // The trick here is that the parray type has an // arbitrary sub-type, and not just a scalar bit... netparray_t*use_type = elaborate_parray_type(des, scope, parray_type); - // Should not be getting packed dimensions other then + // Should not be getting packed dimensions other than // through the parray type declaration. ivl_assert(*this, packed_dimensions.empty()); diff --git a/elab_type.cc b/elab_type.cc index 997069ea0..c4c97eaa7 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -31,7 +31,7 @@ using namespace std; -ivl_type_s* data_type_t::elaborate_type(Design*des, NetScope*) const +ivl_type_s* data_type_t::elaborate_type_raw(Design*des, NetScope*) const { cerr << get_fileline() << ": internal error: " << "Elaborate method not implemented for " << typeid(*this).name() @@ -40,7 +40,7 @@ ivl_type_s* data_type_t::elaborate_type(Design*des, NetScope*) const return 0; } -ivl_type_s* atom2_type_t::elaborate_type(Design*des, NetScope*) const +ivl_type_s* atom2_type_t::elaborate_type_raw(Design*des, NetScope*) const { switch (type_code) { case 64: @@ -75,18 +75,28 @@ ivl_type_s* atom2_type_t::elaborate_type(Design*des, NetScope*) const } } -ivl_type_s* class_type_t::elaborate_type(Design*, NetScope*scope) const +ivl_type_s* class_type_t::elaborate_type_raw(Design*, NetScope*scope) const { return scope->find_class(name); } -ivl_type_s* enum_type_t::elaborate_type(Design*des, NetScope*scope) const +/* + * elaborate_type_raw for enumerations is actually mostly performed + * during scope elaboration so that the enumeration literals are + * available at the right time. At that time, the netenum_t* object is + * stashed in the scope so that I can retrieve it here. + */ +ivl_type_s* enum_type_t::elaborate_type_raw(Design*des, NetScope*scope) const { - ivl_assert(*this, net_type); - return net_type; + ivl_assert(*this, scope); + ivl_type_s*tmp = scope->enumeration_for_key(this); + if (tmp) return tmp; + + tmp = des->enumeration_for_key(this); + return tmp; } -ivl_type_s* vector_type_t::elaborate_type(Design*des, NetScope*scope) const +ivl_type_s* vector_type_t::elaborate_type_raw(Design*des, NetScope*scope) const { vector packed; @@ -122,7 +132,7 @@ ivl_type_s* vector_type_t::elaborate_type(Design*des, NetScope*scope) const return tmp; } -ivl_type_s* real_type_t::elaborate_type(Design*, NetScope*) const +ivl_type_s* real_type_t::elaborate_type_raw(Design*, NetScope*) const { switch (type_code) { case REAL: @@ -133,12 +143,12 @@ ivl_type_s* real_type_t::elaborate_type(Design*, NetScope*) const return 0; } -ivl_type_s* string_type_t::elaborate_type(Design*, NetScope*) const +ivl_type_s* string_type_t::elaborate_type_raw(Design*, NetScope*) const { return &netstring_t::type_string; } -netstruct_t* struct_type_t::elaborate_type(Design*des, NetScope*scope) const +netstruct_t* struct_type_t::elaborate_type_raw(Design*des, NetScope*scope) const { netstruct_t*res = new netstruct_t; @@ -173,7 +183,7 @@ netstruct_t* struct_type_t::elaborate_type(Design*des, NetScope*scope) const return res; } -ivl_type_s* uarray_type_t::elaborate_type(Design*des, NetScope*scope) const +ivl_type_s* uarray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const { ivl_type_t btype = base_type->elaborate_type(des, scope); diff --git a/elaborate.cc b/elaborate.cc index 4aa898d5c..ffd497a03 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -129,8 +129,8 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const << ", expr=" << *rval_expr << endl; } - assert(lval && rval); - assert(rval->pin_count() == 1); + ivl_assert(*this, lval && rval); + ivl_assert(*this, rval->pin_count() == 1); // Detect the case that the rvalue-expression is a simple // expression. In this case, we will need to create a driver @@ -139,23 +139,14 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const if (dynamic_cast(rval_expr)) need_driver_flag = true; -#if 0 - // MTW, 01-Mar-2013. The expression elaboration rework should have - // ensured that this can no longer occur. Leaving this here for the - // moment, but it should be safe to remove it. - - /* If the r-value insists on being smaller than the l-value - (perhaps it is explicitly sized) the pad it out to be the - right width so that something is connected to all the bits - of the l-value. */ - if (lval->vector_width() > rval->vector_width()) { - if (rval->get_signed()) - rval = pad_to_width_signed(des, rval, lval->vector_width(), - *this); - else - rval = pad_to_width(des, rval, lval->vector_width(), *this); + // expression elaboration should have caused the rval width to + // match the l-value by now. + if (rval->vector_width() < lval->vector_width()) { + cerr << get_fileline() << ": internal error: " + << "lval-rval width mismatch: " + << "rval->vector_width()==" << rval->vector_width() + << ", lval->vector_width()==" << lval->vector_width() << endl; } -#endif ivl_assert(*this, rval->vector_width() >= lval->vector_width()); /* If the r-value insists on being larger than the l-value, @@ -3060,7 +3051,7 @@ NetProc* PChainConstructor::elaborate(Design*des, NetScope*scope) const NetNet*var_this = scope->find_signal(perm_string::literal("@")); // If super.new is an implicit constructor, then there are no - // arguments (other then "this" to worry about, so make a + // arguments (other than "this" to worry about, so make a // NetEUFunc and there we go. if (NetScope*new_scope = class_super->method_from_name(perm_string::literal("new@"))) { NetESignal*eres = new NetESignal(var_this); @@ -5663,6 +5654,9 @@ Design* elaborate(listroots) // module and elaborate what I find. Design*des = new Design; + // Elaborate enum sets in $root scope. + elaborate_rootscope_enumerations(des); + // Elaborate the packages. Package elaboration is simpler // because there are fewer sub-scopes involved. i = 0; diff --git a/emit.cc b/emit.cc index b49df2168..4da13d0d3 100644 --- a/emit.cc +++ b/emit.cc @@ -420,9 +420,9 @@ void NetScope::emit_scope(struct target_t*tgt) const tgt->class_type(this, cur->second); } - for (list::const_iterator cur = enum_sets_.begin() + for (map::const_iterator cur = enum_sets_.begin() ; cur != enum_sets_.end() ; ++cur) - tgt->enumeration(this, *cur); + tgt->enumeration(this, cur->second); for (map::const_iterator cur = children_.begin() ; cur != children_.end() ; ++ cur ) diff --git a/eval_tree.cc b/eval_tree.cc index 8f18a760d..6897e9ab3 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -288,6 +288,13 @@ NetEConst* NetEBBits::eval_arguments_(const NetExpr*l, const NetExpr*r) const break; } + case 'X': { + for (unsigned idx = 0 ; idx < wid ; idx += 1) + res.set(idx, ~(lval.get(idx) ^ rval.get(idx))); + + break; + } + case '^': { for (unsigned idx = 0 ; idx < wid ; idx += 1) res.set(idx, lval.get(idx) ^ rval.get(idx)); @@ -1923,6 +1930,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. Set defer to true + * if this should be handled in the run time. */ +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. */ + 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 = false; + 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 +2104,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 +2194,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 +2274,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/lexor.lex b/lexor.lex index f3fee4168..7c7a79649 100644 --- a/lexor.lex +++ b/lexor.lex @@ -341,7 +341,7 @@ TU [munpf] } } - /* If this identifer names a previously declared package, then + /* If this identifier names a previously declared package, then return this as a PACKAGE_IDENTIFIER instead. */ if (rc == IDENTIFIER && gn_system_verilog()) { if (PPackage*pkg = pform_test_package_identifier(yylval.text)) { diff --git a/net_expr.cc b/net_expr.cc index 6ff935185..c0e92ed4d 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -260,7 +260,7 @@ void NetEConcat::set(unsigned idx, NetExpr*e) expr_width( expr_width() + repeat_ * e->expr_width() ); } -NetEConstEnum::NetEConstEnum(NetScope*s, perm_string n, const netenum_t*eset, const verinum&v) +NetEConstEnum::NetEConstEnum(Definitions*s, perm_string n, const netenum_t*eset, const verinum&v) : NetEConst(v), scope_(s), enum_set_(eset), name_(n) { assert(has_width()); diff --git a/net_func_eval.cc b/net_func_eval.cc index e6229602a..d130f3723 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -138,7 +138,7 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector"; cerr << endl; diff --git a/net_scope.cc b/net_scope.cc index 64667c50e..e72a31133 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -30,6 +30,72 @@ class PExpr; +Definitions::Definitions() +{ +} + +Definitions::~Definitions() +{ +} + +void Definitions::add_enumeration_set(const enum_type_t*key, netenum_t*enum_set) +{ + netenum_t*&tmp = enum_sets_[key]; + assert(tmp == 0); + tmp = enum_set; +} + +bool Definitions::add_enumeration_name(netenum_t*enum_set, perm_string name) +{ + netenum_t::iterator enum_val = enum_set->find_name(name); + assert(enum_val != enum_set->end_name()); + + NetEConstEnum*val = new NetEConstEnum(this, name, enum_set, enum_val->second); + + pair::iterator, bool> cur; + cur = enum_names_.insert(make_pair(name,val)); + + // Return TRUE if the name is added (i.e. is NOT a duplicate.) + return cur.second; +} + +netenum_t* Definitions::enumeration_for_key(const enum_type_t*key) const +{ + map::const_iterator cur; + + cur = enum_sets_.find(key); + if (cur != enum_sets_.end()) + return cur->second; + else + return 0; +} + +/* + * This locates the enumeration TYPE for the given enumeration literal. + */ +const netenum_t*Definitions::enumeration_for_name(perm_string name) +{ + NetEConstEnum*tmp = enum_names_[name]; + assert(tmp != 0); + + return tmp->enumeration(); +} + +/* + * This locates the VALUE for the given enumeration literal. + */ +const NetExpr* Definitions::enumeration_expr(perm_string key) +{ + map::const_iterator eidx; + + eidx = enum_names_.find(key); + if (eidx != enum_names_.end()) { + return eidx->second; + } else { + return 0; + } +} + /* * The NetScope class keeps a scope tree organized. Each node of the * scope tree points to its parent, its right sibling and its leftmost @@ -265,14 +331,13 @@ const NetExpr* NetScope::get_parameter(Design*des, return idx->second.val; } - map::const_iterator eidx; + msb = 0; + lsb = 0; + const NetExpr*tmp = enumeration_expr(key); + if (tmp) return tmp; - eidx = enum_names_.find(key); - if (eidx != enum_names_.end()) { - msb = 0; - lsb = 0; - return eidx->second; - } + tmp = des->enumeration_expr(key); + if (tmp) return tmp; return 0; } @@ -551,33 +616,6 @@ NetNet* NetScope::find_signal(perm_string key) return 0; } -void NetScope::add_enumeration_set(netenum_t*enum_set) -{ - enum_sets_.push_back(enum_set); -} - -bool NetScope::add_enumeration_name(netenum_t*enum_set, perm_string name) -{ - netenum_t::iterator enum_val = enum_set->find_name(name); - assert(enum_val != enum_set->end_name()); - - NetEConstEnum*val = new NetEConstEnum(this, name, enum_set, enum_val->second); - - pair::iterator, bool> cur; - cur = enum_names_.insert(make_pair(name,val)); - - // Return TRUE if the name is added (i.e. is NOT a duplicate.) - return cur.second; -} - -const netenum_t*NetScope::enumeration_for_name(perm_string name) -{ - NetEConstEnum*tmp = enum_names_[name]; - assert(tmp != 0); - - return tmp->enumeration(); -} - void NetScope::add_class(netclass_t*net_class) { classes_[net_class->get_name()] = net_class; diff --git a/netlist.cc b/netlist.cc index bc59461e7..0bd8ca28a 100644 --- a/netlist.cc +++ b/netlist.cc @@ -755,7 +755,7 @@ const netclass_t* NetNet::class_type(void) const /* * "depth" is the number of index expressions that the user is using - * to index this identifer. So consider if Net was declared like so: + * to index this identifier. So consider if Net was declared like so: * * reg [5:0][3:0] foo; * diff --git a/netlist.h b/netlist.h index 78cbb6a5c..f02970b86 100644 --- a/netlist.h +++ b/netlist.h @@ -76,6 +76,7 @@ class NetEvTrig; class NetEvWait; class PExpr; class PFunction; +struct enum_type_t; class netclass_t; class netdarray_t; class netparray_t; @@ -819,12 +820,53 @@ class NetBaseDef { NetProc*proc_; }; +/* + * Some definitions (and methods to manipulate them) are common to a + * couple of types. Keep them here. + */ +class Definitions { + + public: + Definitions(); + ~Definitions(); + + // Add the enumeration to the set of enumerations in this + // scope. Include a key that the elaboration can use to look + // up this enumeration based on the pform type. + void add_enumeration_set(const enum_type_t*key, netenum_t*enum_set); + + bool add_enumeration_name(netenum_t*enum_set, perm_string enum_name); + + // Look up the enumeration literal in this scope. if the name + // is present, then return the enumeration type that declares it. + const netenum_t* enumeration_for_name(perm_string name); + + // Look up the enumeration set that was added with the given + // key. This is used by enum_type_t::elaborate_type to locate + // a previously elaborated enumeration. + netenum_t* enumeration_for_key(const enum_type_t*key) const; + + // Look up an enumeration literal in this scope. If the + // literal is present, return the expression that defines its + // value. + const NetExpr* enumeration_expr(perm_string key); + + protected: + // Enumerations. The enum_sets_ is a list of all the + // enumerations present in this scope. The enum_names_ is a + // map of all the enumeration names back to the sets that + // contain them. + std::map enum_sets_; + std::map enum_names_; + +}; + /* * This object type is used to contain a logical scope within a * design. The scope doesn't represent any executable hardware, but is * just a handle that netlist processors can use to grab at the design. */ -class NetScope : public Attrib { +class NetScope : public Definitions, public Attrib { public: enum TYPE { MODULE, CLASS, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK, PACKAGE }; @@ -897,11 +939,6 @@ class NetScope : public Attrib { void rem_signal(NetNet*); NetNet* find_signal(perm_string name); - void add_enumeration_set(netenum_t*enum_set); - bool add_enumeration_name(netenum_t*enum_set, perm_string enum_name); - - const netenum_t* enumeration_for_name(perm_string name); - void add_class(netclass_t*class_type); netclass_t* find_class(perm_string name); @@ -1153,13 +1190,6 @@ class NetScope : public Attrib { const PFunction*func_pform_; unsigned elab_stage_; - // Enumerations. The enum_sets_ is a list of all the - // enumerations present in this scope. The enum_names_ is a - // map of all the enumeration names back to the sets that - // contain them. - std::list enum_sets_; - std::map enum_names_; - std::map classes_; NetScope*up_; @@ -1973,12 +2003,11 @@ class NetEConst : public NetExpr { class NetEConstEnum : public NetEConst { public: - explicit NetEConstEnum(NetScope*scope, perm_string name, + explicit NetEConstEnum(Definitions*scope, perm_string name, const netenum_t*enum_set, const verinum&val); ~NetEConstEnum(); perm_string name() const; - const NetScope*scope() const; const netenum_t*enumeration() const; virtual void expr_scan(struct expr_scan_t*) const; @@ -1987,7 +2016,7 @@ class NetEConstEnum : public NetEConst { virtual NetEConstEnum* dup_expr() const; private: - NetScope*scope_; + Definitions*scope_; const netenum_t*enum_set_; perm_string name_; }; @@ -4176,37 +4205,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 +4282,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; }; @@ -4465,7 +4528,7 @@ struct elaborator_work_item_t { * This class contains an entire design. It includes processes and a * netlist, and can be passed around from function to function. */ -class Design { +class Design : public Definitions { public: Design(); diff --git a/netmisc.cc b/netmisc.cc index 6161fdabb..6bb07a8f0 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -48,7 +48,7 @@ NetNet* sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig) } else { verinum zero ((int64_t)val); - zero = pad_to_width(zero, sig->vector_width()); + zero = cast_to_width(zero, sig->vector_width()); zero.has_sign(sig->get_signed()); NetConst*zero_obj = new NetConst(scope, scope->local_symbol(), zero); zero_obj->set_line(*sig); @@ -1360,7 +1360,7 @@ NetExpr*collapse_array_exprs(Design*des, NetScope*scope, /* * Given a list of indices, treat them as packed indices and convert * them to an expression that normalizes the list to a single index - * expression over a canonical equivilent 1-dimensional array. + * expression over a canonical equivalent 1-dimensional array. */ NetExpr*collapse_array_indices(Design*des, NetScope*scope, NetNet*net, const list&indices) diff --git a/nettypes.cc b/nettypes.cc index d7d5c0883..1a36b177a 100644 --- a/nettypes.cc +++ b/nettypes.cc @@ -63,7 +63,7 @@ bool ivl_type_s::type_compatible(ivl_type_t that) const return test_compatibility(that); } -bool ivl_type_s::test_compatibility(const ivl_type_s*that) const +bool ivl_type_s::test_compatibility(const ivl_type_s* /*that*/) const { return false; } diff --git a/parse.y b/parse.y index 32e4d15bb..15e4a9814 100644 --- a/parse.y +++ b/parse.y @@ -1081,7 +1081,7 @@ description /* IEEE1800-2005: A.1.2 */ | nature_declaration | package_declaration | discipline_declaration - | timeunits_declaration + | package_item | KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')' { perm_string tmp3 = lex_strings.make($3); pform_set_type_attrib(tmp3, $5, $7); @@ -2362,6 +2362,11 @@ struct_union_member /* IEEE 1800-2012 A.2.2.1 */ tmp->names .reset($3); $$ = tmp; } + | error ';' + { yyerror(@2, "Error in struct/union member."); + yyerrok; + $$ = 0; + } ; case_item @@ -3092,6 +3097,14 @@ expr_primary delete[]$1; } + /* There are a few special cases (notably $bits argument) where the + expression may be a type name. Let the elaborator sort this out. */ + | TYPE_IDENTIFIER + { PETypename*tmp = new PETypename($1); + FILE_NAME(tmp,@1); + $$ = tmp; + } + /* The hierarchy_identifier rule matches simple identifiers as well as indexed arrays and part selects */ diff --git a/parse_api.h b/parse_api.h index e3526f348..a9de02dcf 100644 --- a/parse_api.h +++ b/parse_api.h @@ -24,10 +24,14 @@ # include # include # include +# include +class Design; class Module; class PPackage; class PUdp; +class data_type_t; +struct enum_type_t; /* * These are maps of the modules and primitives parsed from the @@ -36,10 +40,14 @@ class PUdp; */ extern std::map pform_modules; extern std::map pform_primitives; +extern std::map pform_typedefs; +extern std::set pform_enum_sets; extern std::map pform_packages; extern void pform_dump(std::ostream&out, const PPackage*pac); +extern void elaborate_rootscope_enumerations(Design*des); + /* * This code actually invokes the parser to make modules. The first * parameter is the name of the file that is to be parsed. The diff --git a/pform.cc b/pform.cc index 4d2a03737..c9e716f08 100644 --- a/pform.cc +++ b/pform.cc @@ -46,12 +46,16 @@ /* * The pform_modules is a map of the modules that have been defined in * the top level. This should not contain nested modules/programs. + * pform_primitives is similar, but for UDP primitives. */ map pform_modules; -/* - */ map pform_primitives; +/* + * typedefs in the $root scope go here. + */ +mappform_typedefs; +setpform_enum_sets; std::string vlltype::get_fileline() const { @@ -484,7 +488,12 @@ static void pform_put_wire_in_scope(perm_string name, PWire*net) static void pform_put_enum_type_in_scope(enum_type_t*enum_set) { - lexical_scope->enum_sets.insert(enum_set); + if (lexical_scope) { + ivl_assert(*enum_set, lexical_scope); + lexical_scope->enum_sets.insert(enum_set); + } else { + pform_enum_sets.insert(enum_set); + } } PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type) @@ -505,7 +514,13 @@ PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetN void pform_set_typedef(perm_string name, data_type_t*data_type) { - data_type_t*&ref = lexical_scope->typedefs[name]; + // If we are in a lexical scope (i.e. a package or module) + // then put the typedef into that scope. Otherwise, put it + // into the $root scope. + data_type_t*&ref = lexical_scope + ? lexical_scope->typedefs[name] + : pform_typedefs[name]; + ivl_assert(*data_type, ref == 0); ref = data_type; @@ -514,15 +529,25 @@ void pform_set_typedef(perm_string name, data_type_t*data_type) } } +static data_type_t* test_type_identifier_in_root(perm_string name) +{ + map::iterator cur = pform_typedefs.find(name); + if (cur != pform_typedefs.end()) + return cur->second; + else + return 0; +} + data_type_t* pform_test_type_identifier(const char*txt) { - // If there is no lexical_scope yet, then there is NO WAY the - // identifier can be a type_identifier. - if (lexical_scope == 0) - return 0; - perm_string name = lex_strings.make(txt); + // If there is no lexical_scope yet, then look only in the + // $root scope for typedefs. + if (lexical_scope == 0) { + return test_type_identifier_in_root(name); + } + LexicalScope*cur_scope = lexical_scope; do { map::iterator cur; @@ -530,7 +555,7 @@ data_type_t* pform_test_type_identifier(const char*txt) // First look to see if this identifier is imported from // a package. If it is, see if it is a type in that // package. If it is, then great. If imported as - // something other then a type, then give up now becase + // something other than a type, then give up now because // the name has at least shadowed any other possible // meaning for this name. map::iterator cur_pkg; @@ -552,6 +577,10 @@ data_type_t* pform_test_type_identifier(const char*txt) cur_scope = cur_scope->parent_scope(); } while (cur_scope); + // See if there is a typedef in the $root scope. + if (data_type_t*tmp = test_type_identifier_in_root(name)) + return tmp; + return 0; } diff --git a/pform_dump.cc b/pform_dump.cc index fb2882123..a8b08c04b 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -170,7 +170,10 @@ void uarray_type_t::pform_dump(ostream&out, unsigned indent) const void struct_type_t::pform_dump(ostream&out, unsigned indent) const { out << setw(indent) << "" << "Struct " << (packed_flag?"packed":"unpacked") - << " with " << members->size() << " members" << endl; + << " with " << (members.get()==0? 0 : members->size()) << " members" << endl; + if (members.get()==0) + return; + for (list::iterator cur = members->begin() ; cur != members->end() ; ++ cur) { struct_member_t*curp = *cur; @@ -382,6 +385,11 @@ void PETernary::dump(ostream&out) const out << "(" << *expr_ << ")?(" << *tru_ << "):(" << *fal_ << ")"; } +void PETypename::dump(ostream&fd) const +{ + fd << ""; +} + void PEUnary::dump(ostream&out) const { switch (op_) { diff --git a/pform_struct_type.cc b/pform_struct_type.cc index 60219524b..4a4d91251 100644 --- a/pform_struct_type.cc +++ b/pform_struct_type.cc @@ -26,8 +26,12 @@ ivl_variable_type_t struct_type_t::figure_packed_base_type(void) const if (! packed_flag) return IVL_VT_NO_TYPE; + if (members.get() == 0) + return IVL_VT_NO_TYPE; + ivl_variable_type_t base_type = IVL_VT_BOOL; + ivl_assert(*this, members.get()); for (list::iterator cur = members->begin() ; cur != members->end() ; ++ cur) { diff --git a/pform_types.cc b/pform_types.cc index 5a7868bef..c809ffbf6 100644 --- a/pform_types.cc +++ b/pform_types.cc @@ -24,6 +24,15 @@ data_type_t::~data_type_t() { } +ivl_type_s* data_type_t::elaborate_type(Design*des, NetScope*scope) +{ + if (cache_type_elaborate_) + return cache_type_elaborate_; + + cache_type_elaborate_ = elaborate_type_raw(des, scope); + return cache_type_elaborate_; +} + string_type_t::~string_type_t() { } diff --git a/pform_types.h b/pform_types.h index 207e47700..32758f5e4 100644 --- a/pform_types.h +++ b/pform_types.h @@ -88,14 +88,21 @@ struct pform_tf_port_t { */ class data_type_t : public LineInfo { public: + inline explicit data_type_t() : cache_type_elaborate_(0) { } virtual ~data_type_t() = 0; // This method is used to figure out the base type of a packed // compound object. Return IVL_VT_NO_TYPE if the type is not packed. virtual ivl_variable_type_t figure_packed_base_type(void)const; // This method is used by the pform dumper to diagnostic dump. virtual void pform_dump(std::ostream&out, unsigned indent) const; + + ivl_type_s* elaborate_type(Design*des, NetScope*scope); + + private: // Elaborate the type to an ivl_type_s type. - virtual ivl_type_s* elaborate_type(Design*des, NetScope*scope) const; + virtual ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const; + + ivl_type_s*cache_type_elaborate_; }; struct void_type_t : public data_type_t { @@ -109,20 +116,14 @@ struct void_type_t : public data_type_t { * until it is elaborated in a scope. */ struct enum_type_t : public data_type_t { - inline enum_type_t(void) : net_type(0) { } // Return the elaborated version of the type. - virtual ivl_type_s*elaborate_type(Design*des, NetScope*scope) const; + virtual ivl_type_s*elaborate_type_raw(Design*des, NetScope*scope) const; ivl_variable_type_t base_type; bool signed_flag; std::auto_ptr< list > range; std::auto_ptr< list > names; LineInfo li; - // This is the elaborated type. The enumeration type is - // elaborated early so that names can be placed in the scope, - // but that means the result needs to be saved for the actual - // elaborate_type method to use. - netenum_t*net_type; }; struct struct_member_t : public LineInfo { @@ -134,7 +135,7 @@ struct struct_member_t : public LineInfo { struct struct_type_t : public data_type_t { virtual ivl_variable_type_t figure_packed_base_type(void)const; virtual void pform_dump(std::ostream&out, unsigned indent) const; - virtual netstruct_t* elaborate_type(Design*des, NetScope*scope) const; + virtual netstruct_t* elaborate_type_raw(Design*des, NetScope*scope) const; bool packed_flag; bool union_flag; @@ -147,7 +148,7 @@ struct atom2_type_t : public data_type_t { int type_code; bool signed_flag; - ivl_type_s* elaborate_type(Design*des, NetScope*scope) const; + ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const; }; /* @@ -174,7 +175,7 @@ struct vector_type_t : public data_type_t { std::list*pd) : base_type(bt), signed_flag(sf), reg_flag(false), integer_flag(false), implicit_flag(false), pdims(pd) { } virtual ivl_variable_type_t figure_packed_base_type(void)const; - ivl_type_s* elaborate_type(Design*des, NetScope*scope) const; + ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const; ivl_variable_type_t base_type; bool signed_flag; @@ -216,7 +217,7 @@ struct uarray_type_t : public array_base_t { public: virtual void pform_dump(std::ostream&out, unsigned indent) const; - virtual ivl_type_s* elaborate_type(Design*des, NetScope*scope) const; + virtual ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const; }; struct real_type_t : public data_type_t { @@ -224,14 +225,14 @@ struct real_type_t : public data_type_t { inline explicit real_type_t(type_t tc) : type_code(tc) { } type_t type_code; - ivl_type_s* elaborate_type(Design*des, NetScope*scope) const; + ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const; }; struct string_type_t : public data_type_t { inline explicit string_type_t() { } ~string_type_t(); - ivl_type_s* elaborate_type(Design*des, NetScope*scope) const; + ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const; }; struct class_type_t : public data_type_t { @@ -271,7 +272,7 @@ struct class_type_t : public data_type_t { // without waiting for any constructor. std::vector initialize_static; - ivl_type_s* elaborate_type(Design*, NetScope*) const; + ivl_type_s* elaborate_type_raw(Design*, NetScope*) const; }; /* diff --git a/synth2.cc b/synth2.cc index 2f5081087..0062b1632 100644 --- a/synth2.cc +++ b/synth2.cc @@ -232,7 +232,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope, unsigned mux_size = max_guard_value + 1; - // If the sel_width can select more then just the explicit + // If the sel_width can select more than just the explicit // guard values, and there is a default statement, then adjust // the mux size to allow for the implicit selections. if (statement_default && ((1U< mux_size)) { diff --git a/tgt-blif/blif.cc b/tgt-blif/blif.cc index 3d121ebd5..82bc83535 100644 --- a/tgt-blif/blif.cc +++ b/tgt-blif/blif.cc @@ -55,7 +55,7 @@ int blif_errors = 0; static void emit_blif(const char*blif_path, ivl_design_t des, ivl_scope_t model); -static int process_scan_fun(ivl_process_t net, void*raw) +static int process_scan_fun(ivl_process_t net, void* /*raw*/) { fprintf(stderr, "%s:%u: sorry: BLIF: Processes not supported yet.\n", ivl_process_file(net), ivl_process_lineno(net)); diff --git a/tgt-pcb/footprint.cc b/tgt-pcb/footprint.cc index 5ba01ab42..a05c52709 100644 --- a/tgt-pcb/footprint.cc +++ b/tgt-pcb/footprint.cc @@ -45,7 +45,7 @@ int load_footprints(void) } /* - * The fpparse funciton calls back the callback_fp_element function + * The fpparse function calls back the callback_fp_element function * for each Element that it parses. The check_footprint function * stores in the cur_footprint variable the name of the footprint that * we are trying to find in the file. The callback uses that name to diff --git a/tgt-vlog95/expr.c b/tgt-vlog95/expr.c index 5d97e191f..e8f6810ad 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.c @@ -267,8 +267,9 @@ static expr_sign_t expr_get_sign_type(ivl_expr_t expr, unsigned wid, break; } - /* Check for a self-determined context. */ - if ((rtn == NO_SIGN) && (wid != expr_wid) && + /* Check for a self-determined context. A zero width expression + * is special and is not considered a self determined context. */ + if ((rtn == NO_SIGN) && (wid != expr_wid) && expr_wid && ! (is_full_prec && ((expr_wid < wid) || (type == IVL_EX_SIGNAL)))) { if (ivl_expr_signed(expr)) rtn = NEED_SIGNED; else rtn = NEED_UNSIGNED; diff --git a/tgt-vlog95/scope.c b/tgt-vlog95/scope.c index 72a58ccd3..59657e7b2 100644 --- a/tgt-vlog95/scope.c +++ b/tgt-vlog95/scope.c @@ -917,8 +917,8 @@ static unsigned has_func_disable(ivl_scope_t scope, ivl_statement_t stmt) rtn = scope == ivl_stmt_call(stmt); break; default: - fprintf(stderr, "%s:%u: vlog95 error: Unknown statment type (%d) " - "in functin disable check.\n", + fprintf(stderr, "%s:%u: vlog95 error: Unknown statement type (%d) " + "in function disable check.\n", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), (int)ivl_statement_type(stmt)); @@ -1187,7 +1187,7 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent) name_return); free(name_return); } else emit_stmt(scope, body); - /* A non-block statment may need a named block for a return. */ + /* A non-block statement may need a named block for a return. */ } else if (has_func_disable(scope, body)) { char *name_return = get_func_return_name(scope); fprintf(vlog_out, "%*cbegin: %s\n", indent, ' ', diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index 0cf39039d..530c9e471 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -214,16 +214,27 @@ static void emit_stmt_lval_darray(ivl_scope_t scope, ivl_lval_t lval, * Class or class properties are not supported in vlog95, but this assignment * can be translated correctly. */ -static void emit_stmt_lval_class(ivl_scope_t scope, ivl_lval_t lval, - ivl_signal_t sig) +static ivl_type_t emit_stmt_lval_class(ivl_scope_t scope, ivl_lval_t lval) { + ivl_lval_t nest = ivl_lval_nest(lval); + ivl_signal_t sig = ivl_lval_sig(lval); + ivl_type_t type; int idx = ivl_lval_property_idx(lval); - emit_scope_call_path(scope, ivl_signal_scope(sig)); - emit_id(ivl_signal_basename(sig)); - if (idx >= 0) { - ivl_type_t sig_type = ivl_signal_net_type(sig); - fprintf(vlog_out, ".%s", ivl_type_prop_name(sig_type, idx)); + + if (nest) { + type = emit_stmt_lval_class(scope, nest); + assert(type); + } else { + assert(sig); + emit_scope_call_path(scope, ivl_signal_scope(sig)); + emit_id(ivl_signal_basename(sig)); + type = ivl_signal_net_type(sig); } + + if (idx >= 0) { + fprintf(vlog_out, ".%s", ivl_type_prop_name(type, idx)); + return ivl_type_prop_type(type, idx); + } else return 0; } static void emit_stmt_lval_piece(ivl_scope_t scope, ivl_lval_t lval) @@ -234,14 +245,20 @@ static void emit_stmt_lval_piece(ivl_scope_t scope, ivl_lval_t lval) unsigned width = ivl_lval_width(lval); int msb, lsb; assert(width > 0); - assert(sig); + + /* A class supports a nested L-value so it may not have a signal + * at this level. */ + if (! sig) { + (void) emit_stmt_lval_class(scope, lval); + return; + } switch (ivl_signal_data_type(sig)) { case IVL_VT_DARRAY: emit_stmt_lval_darray(scope, lval, sig); return; case IVL_VT_CLASS: - emit_stmt_lval_class(scope, lval, sig); + (void) emit_stmt_lval_class(scope, lval); return; default: break; diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 07916d159..f6cd315d0 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -566,7 +566,7 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc) out << ")"; } else { - // If this function has an elaborated defintion, and if + // If this function has an elaborated definition, and if // that definition is in a package, then include the // package name as a scope qualifier. This assures that // the SV elaborator finds the correct VHDL elaborated diff --git a/vvp/class_type.h b/vvp/class_type.h index 8304f812e..5c4b4831b 100644 --- a/vvp/class_type.h +++ b/vvp/class_type.h @@ -52,7 +52,7 @@ class class_type : public __vpiHandle { void set_property(size_t idx, const std::string&name, const std::string&type); // This method is called after all the properties are - // defined. This calculates information about the defintion. + // defined. This calculates information about the definition. void finish_setup(void); public: diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 461664af4..449114bbe 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -1024,7 +1024,7 @@ includes an implicit pop, but sometimes it is necessary to pop explicitly. The is the number of top positions on the stack to keep, -beforing starting to pop. This allows for popping positions other then +beforing starting to pop. This allows for popping positions other than the top of the stack. * %pow , ,