diff --git a/elab_scope.cc b/elab_scope.cc index 3c4c43e69..5428a803d 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -177,8 +177,10 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, rc_flag = eval_as_long(lsb, lsb_ex); assert(rc_flag); - netenum_t*use_enum = new netenum_t(enum_type->base_type, enum_type->signed_flag, - msb, lsb, enum_type->names->size()); + netenum_t*use_enum = new netenum_t(enum_type->base_type, + enum_type->signed_flag, + enum_type->integer_flag, msb, lsb, + enum_type->names->size()); use_enum->set_line(enum_type->li); if (scope) @@ -189,16 +191,18 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, verinum cur_value (0); verinum one_value (1); size_t name_idx = 0; + // Find the enumeration width. + long raw_width = use_enum->packed_width(); + assert(raw_width > 0); + unsigned enum_width = (unsigned)raw_width; // Find the minimum and maximum allowed enumeration values. verinum min_value (0); verinum max_value (0); if (enum_type->signed_flag) { - min_value = -pow(verinum(2), verinum(use_enum->packed_width()-1)); - max_value = pow(verinum(2), verinum(use_enum->packed_width()-1)) - - one_value; + min_value = -pow(verinum(2), verinum(enum_width-1)); + max_value = pow(verinum(2), verinum(enum_width-1)) - one_value; } else { - max_value = pow(verinum(2), verinum(use_enum->packed_width())) - - one_value; + max_value = pow(verinum(2), verinum(enum_width)) - one_value; } min_value.has_sign(true); max_value.has_sign(enum_type->signed_flag); @@ -237,6 +241,11 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, continue; } + // Cast any undefined bits to zero so the comparisons below + // return just true (1) or false (0). + verinum two_state_value = cur_value; + two_state_value.cast_to_int2(); + // The enumeration value must fit into the enumeration bits. if (!cur_value.is_defined()) { if (cur_value.len() > (unsigned long)use_enum->packed_width()) { @@ -247,11 +256,11 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, des->errors += 1; } - } else if ((cur_value > max_value) || - (cur_value.has_sign() && (cur_value < min_value))) { + } else if ((two_state_value > max_value) || + (cur_value.has_sign() && (two_state_value < min_value))) { cerr << use_enum->get_fileline() << ": error: Enumeration name " << cur->name - << " cannot have a value equal to " << cur_value + << " cannot have an out of range value " << cur_value << "." << endl; des->errors += 1; } @@ -269,15 +278,31 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, // The values are explicitly sized to the width of the // base type of the enumeration. verinum tmp_val (0); - if (cur_value.len() < (unsigned long)use_enum->packed_width()) { + if (cur_value.len() < enum_width) { // Pad the current value if it is narrower than the final // width of the enum. - tmp_val = pad_to_width (cur_value, use_enum->packed_width()); + tmp_val = pad_to_width (cur_value, enum_width); tmp_val.has_len(true); } else { // Truncate an oversized value. We report out of bound - // values above. This may create duplicates. - tmp_val = verinum(cur_value, use_enum->packed_width()); + // defined values above. Undefined values need to be + // checked here. This may create duplicates. + tmp_val = verinum(cur_value, enum_width); + // For an undefined value verify that all the trimmed bits + // match the MSB of the final enumeration value. + if (! cur_value.is_defined()) for (unsigned idx = enum_width; + idx < cur_value.len(); + idx += 1) { + if (cur_value[idx] != tmp_val[enum_width-1]) { + cerr << use_enum->get_fileline() + << ": error: Enumeration name " << cur->name + << " cannot have trimmed bits that do not " + << "match the enumeration MSB " << cur_value + << "." << endl; + des->errors += 1; + break; + } + } } tmp_val.has_sign(enum_type->signed_flag); diff --git a/elab_sig.cc b/elab_sig.cc index 87c5c9b80..46ba52071 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -597,7 +597,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const if (dynamic_cast (return_type_)) { ret_type = 0; } else { - ret_type = return_type_->elaborate_type(des, scope); + ret_type = return_type_->elaborate_type(des, scope->parent()); ivl_assert(*this, ret_type); } } else { @@ -610,7 +610,8 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const if (debug_elaborate) { cerr << get_fileline() << ": PFunction::elaborate_sig: " << "return type: " << *ret_type << endl; - return_type_->pform_dump(cerr, 8); + if (return_type_) + return_type_->pform_dump(cerr, 8); } list ret_unpacked; ret_sig = new NetNet(scope, fname, NetNet::REG, ret_unpacked, ret_type); @@ -995,10 +996,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const << ". Now check for consistency." << endl; } - /* If we find errors here, then give up on this signal. */ - if (bad_range) - return 0; - /* We have a port size error */ if (port_set_ && net_set_ && !test_ranges_eeq(plist, nlist)) { diff --git a/elab_type.cc b/elab_type.cc index 09e0c86da..5daa88164 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -126,18 +126,20 @@ ivl_type_s* vector_type_t::elaborate_type_raw(Design*des, NetScope*scope) const ; cur != pdims->end() ; ++ cur) { NetExpr*me = elab_and_eval(des, scope, cur->first, 0, true); - assert(me); NetExpr*le = elab_and_eval(des, scope, cur->second, 0, true); - assert(le); + + /* If elaboration failed for either expression, we + should have already reported the error, so just + skip the following evaluation to recover. */ long mnum = 0, lnum = 0; - if ( ! eval_as_long(mnum, me) ) { + if ( me && ! eval_as_long(mnum, me) ) { assert(0); des->errors += 1; } - if ( ! eval_as_long(lnum, le) ) { + if ( le && ! eval_as_long(lnum, le) ) { assert(0); des->errors += 1; } diff --git a/netenum.cc b/netenum.cc index 1b8f4441b..cab73a55c 100644 --- a/netenum.cc +++ b/netenum.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2010-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 @@ -24,9 +24,9 @@ using namespace std; netenum_t::netenum_t(ivl_variable_type_t btype, bool signed_flag, - long msb, long lsb, size_t name_count) -: base_type_(btype), signed_flag_(signed_flag), msb_(msb), lsb_(lsb), - names_(name_count), bits_(name_count) + bool integer_flag, long msb, long lsb, size_t name_count) +: base_type_(btype), signed_flag_(signed_flag), integer_flag_(integer_flag), + msb_(msb), lsb_(lsb), names_(name_count), bits_(name_count) { } @@ -39,6 +39,11 @@ bool netenum_t::get_signed() const return signed_flag_; } +bool netenum_t::get_isint() const +{ + return integer_flag_; +} + /* * Enumerations are by definition always packed. */ @@ -84,6 +89,9 @@ bool netenum_t::insert_name(size_t name_idx, perm_string name, const verinum&val void netenum_t::insert_name_close(void) { for (size_t idx = 0 ; idx < names_.size() ; idx += 1) { + // If we failed to elaborate the name then skip this step. + if (names_[idx].nil()) continue; + netenum_t::iterator cur = names_map_.find(names_[idx]); vectorstr (cur->second.len() + 1); diff --git a/netenum.h b/netenum.h index 8b43086cf..64c2aac6a 100644 --- a/netenum.h +++ b/netenum.h @@ -33,7 +33,8 @@ class netenum_t : public LineInfo, public ivl_type_s { public: explicit netenum_t(ivl_variable_type_t base_type, bool signed_flag, - long msb, long lsb, size_t name_count); + bool isint_flag, long msb, long lsb, + size_t name_count); ~netenum_t(); virtual ivl_variable_type_t base_type() const; @@ -41,6 +42,7 @@ class netenum_t : public LineInfo, public ivl_type_s { virtual long packed_width() const; std::vector slice_dimensions() const; bool get_signed() const; + bool get_isint() const; // The size() is the number of enumeration literals. size_t size() const; @@ -68,6 +70,7 @@ class netenum_t : public LineInfo, public ivl_type_s { private: ivl_variable_type_t base_type_; bool signed_flag_; + bool integer_flag_; long msb_, lsb_; std::map names_map_; diff --git a/netmisc.cc b/netmisc.cc index 8a676685e..07e5c17a9 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -1024,6 +1024,10 @@ bool evaluate_ranges(Design*des, NetScope*scope, delete texpr; + /* Error recovery */ + if (bad_lsb) use_lsb = 0; + if (bad_msb) use_msb = use_lsb; + llist.push_back(netrange_t(use_msb, use_lsb)); } diff --git a/parse.y b/parse.y index 89b27e0c5..319067817 100644 --- a/parse.y +++ b/parse.y @@ -2296,6 +2296,7 @@ enum_data_type enum_type->names .reset($3); enum_type->base_type = IVL_VT_BOOL; enum_type->signed_flag = true; + enum_type->integer_flag = false; enum_type->range.reset(make_range_from_width(32)); $$ = enum_type; } @@ -2305,6 +2306,7 @@ enum_data_type enum_type->names .reset($5); enum_type->base_type = IVL_VT_BOOL; enum_type->signed_flag = $3; + enum_type->integer_flag = false; enum_type->range.reset(make_range_from_width($2)); $$ = enum_type; } @@ -2314,6 +2316,7 @@ enum_data_type enum_type->names .reset($5); enum_type->base_type = IVL_VT_LOGIC; enum_type->signed_flag = $3; + enum_type->integer_flag = true; enum_type->range.reset(make_range_from_width(integer_width)); $$ = enum_type; } @@ -2323,6 +2326,7 @@ enum_data_type enum_type->names .reset($6); enum_type->base_type = IVL_VT_LOGIC; enum_type->signed_flag = $3; + enum_type->integer_flag = false; enum_type->range.reset($4); $$ = enum_type; } @@ -2332,6 +2336,7 @@ enum_data_type enum_type->names .reset($6); enum_type->base_type = IVL_VT_LOGIC; enum_type->signed_flag = $3; + enum_type->integer_flag = false; enum_type->range.reset($4); $$ = enum_type; } @@ -2341,6 +2346,7 @@ enum_data_type enum_type->names .reset($6); enum_type->base_type = IVL_VT_BOOL; enum_type->signed_flag = $3; + enum_type->integer_flag = false; enum_type->range.reset($4); $$ = enum_type; } diff --git a/pform.cc b/pform.cc index 30a1f4ed6..ecb81b721 100644 --- a/pform.cc +++ b/pform.cc @@ -567,6 +567,9 @@ PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetN cur = new PWire(name, net_type, port_type, vt_type); pform_put_wire_in_scope(name, cur); } else { + // If this is a duplicate wire, the data type has already + // been set, then return NULL. + if (cur->get_data_type() != IVL_VT_NO_TYPE) return 0; bool rc = cur->set_wire_type(net_type); assert(rc); rc = cur->set_data_type(vt_type); @@ -3144,6 +3147,7 @@ template static void pform_set2_data_type(const struct vlltype&li, T*d } PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, base_type); + assert(net); net->set_data_type(data_type); pform_bind_attributes(net->attributes, attr, true); } @@ -3160,9 +3164,14 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, perm_string name, NetNet::Type net_type, std::list*attr) { - (void) li; // The line information is not currently needed. PWire*cur = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, enum_type->base_type); - assert(cur); + // A NULL is returned for a duplicate enumeration. + if (! cur) { + cerr << li.get_fileline() << ": error: Found duplicate " + << "enumeration named " << name << "." << endl; + error_count += 1; + return; + } cur->set_signed(enum_type->signed_flag); @@ -3170,6 +3179,11 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, assert(enum_type->range->size() == 1); //XXXXcur->set_range(*enum_type->range, SR_NET); cur->set_data_type(enum_type); + // If this is an integer enumeration switch the wire to an integer. + if (enum_type->integer_flag) { + bool res = cur->set_wire_type(NetNet::INTEGER); + assert(res); + } pform_bind_attributes(cur->attributes, attr, true); } diff --git a/pform_class_type.cc b/pform_class_type.cc index 44f0d3555..ec2f99de4 100644 --- a/pform_class_type.cc +++ b/pform_class_type.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Picture Elements, Inc. + * Copyright (c) 2012-2014 Picture Elements, Inc. * Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -25,6 +25,7 @@ static void pform_set_class_type(class_type_t*class_type, perm_string name, NetNet::Type net_type, list*attr) { PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_CLASS); + assert(net); net->set_data_type(class_type); pform_bind_attributes(net->attributes, attr, true); } diff --git a/pform_string_type.cc b/pform_string_type.cc index 4d1f1d2dc..50a7f4fce 100644 --- a/pform_string_type.cc +++ b/pform_string_type.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-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 @@ -24,6 +24,7 @@ static void pform_set_string_type(const string_type_t*, perm_string name, NetNet::Type net_type, list*attr) { PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_STRING); + assert(net); pform_bind_attributes(net->attributes, attr, true); } diff --git a/pform_struct_type.cc b/pform_struct_type.cc index 4a4d91251..766fc77e3 100644 --- a/pform_struct_type.cc +++ b/pform_struct_type.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-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 @@ -67,6 +67,7 @@ static void pform_set_packed_struct(struct_type_t*struct_type, perm_string name, ivl_variable_type_t base_type = struct_type->figure_packed_base_type(); PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, base_type); + assert(net); net->set_data_type(struct_type); pform_bind_attributes(net->attributes, attr, true); } @@ -99,6 +100,7 @@ static void pform_makewire(const struct vlltype&li, ivl_variable_type_t base_type = struct_type->figure_packed_base_type(); PWire*cur = pform_get_make_wire_in_scope(name, NetNet::WIRE, ptype, base_type); + assert(cur); FILE_NAME(cur, li); cur->set_data_type(struct_type); } diff --git a/pform_types.h b/pform_types.h index b36bb01e1..df3e1a00b 100644 --- a/pform_types.h +++ b/pform_types.h @@ -154,6 +154,7 @@ struct enum_type_t : public data_type_t { ivl_variable_type_t base_type; bool signed_flag; + bool integer_flag; // True if "integer" was used std::auto_ptr< list > range; std::auto_ptr< list > names; LineInfo li; diff --git a/t-dll-api.cc b/t-dll-api.cc index 31389cba5..5a77f26eb 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -2433,6 +2433,8 @@ extern "C" int ivl_signal_integer(ivl_signal_t net) { if (const netvector_t*vec = dynamic_cast (net->net_type)) return vec->get_isint()? 1 : 0; + else if (const netenum_t*enm = dynamic_cast (net->net_type)) + return enm->get_isint()? 1 : 0; else return 0; } diff --git a/tgt-vlog95/cppcheck.sup b/tgt-vlog95/cppcheck.sup index f1a757bf9..0f6bb9fc0 100644 --- a/tgt-vlog95/cppcheck.sup +++ b/tgt-vlog95/cppcheck.sup @@ -5,4 +5,4 @@ unusedFunction:vlog95.c:59 // target_query() -unusedFunction:vlog95.c:226 +unusedFunction:vlog95.c:251