From 7fad4779c52b1649b3284cab7803622a8186edac Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Thu, 30 Oct 2014 20:42:12 +0000 Subject: [PATCH 01/10] Add error recovery when elaboration of a type range fails. If elaboration of the msb or lsb expression in the range of a vector type specification failed (due to an error in the Verilog code being compiled), an assertion failure was being triggered when the compiler attempted to evaluate the expressions. Bypassing the evaluation (and using a default value) should allow us to recover from the error. --- elab_type.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) 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; } From 7ab0824adfb382beaf63952cc355672ad8016389 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Thu, 30 Oct 2014 21:09:17 +0000 Subject: [PATCH 02/10] Fix for br961 - function return type elaborated in wrong scope. The return type of a function should be elaborated in the context of the enclosing scope, not in the context of the function itself. --- elab_sig.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elab_sig.cc b/elab_sig.cc index 87c5c9b80..ed6e4274b 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 { From 08afbde08d9614ab9bfa24a4b5b0644f11e5e58b Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 30 Oct 2014 18:12:28 -0700 Subject: [PATCH 03/10] Update cppcheck suppression file for tgt-vlog. --- tgt-vlog95/cppcheck.sup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From e7df9774aaf8888da2b83733ebd0d5761fbd7784 Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 30 Oct 2014 18:13:20 -0700 Subject: [PATCH 04/10] When comparing that an enumeration is in range cast the value to 2-state When checking that an enumeration value is in range we need to cast it to a 2-state value so that when we compare it we get a true or false value instead of an undefined value. Undefined bits in the comparison return undefined which is not logically false. --- elab_scope.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index 906357992..8233c10fd 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -238,8 +238,12 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, } // The enumeration value must fit into the enumeration bits. - if ((cur_value > max_value) || - (cur_value.has_sign() && (cur_value < min_value))) { + // 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(); + 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 From 4f62a0d1f2d08da6d404a6138e436dba7a26f93e Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 30 Oct 2014 19:53:39 -0700 Subject: [PATCH 05/10] Check enum trimmed bits for values with undefined bits If an enumeration constant has undefined bits then we need to verify that the bits that are trimmed match the MSB of the remaining bits. --- elab_scope.cc | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index 8233c10fd..a16e1173f 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -189,16 +189,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); @@ -246,7 +248,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, (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; } @@ -264,15 +266,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); From b286b76134b846ff89d9026080ed0108447bc6fb Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 31 Oct 2014 18:38:37 +0000 Subject: [PATCH 06/10] Fix null pointer dereference in pform debug output. --- elab_sig.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/elab_sig.cc b/elab_sig.cc index ed6e4274b..d2923b007 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -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); From 871d447ff7b1084adfdcc732a4485d569eeb5c91 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 31 Oct 2014 21:42:23 +0000 Subject: [PATCH 07/10] Reinstate error recovery for range expressions. If an error is found whilst elaborating a range expression in a signal declaration, create a dummy range and continue elaboration. This stops the compiler reporting an error every time that signal is referenced. --- elab_sig.cc | 4 ---- netmisc.cc | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/elab_sig.cc b/elab_sig.cc index d2923b007..46ba52071 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -996,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/netmisc.cc b/netmisc.cc index 9ec560c1a..5494cb6e9 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -972,6 +972,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)); } From c25538d75025e2a5c8203f833518a5f74b216b08 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 31 Oct 2014 18:07:46 -0700 Subject: [PATCH 08/10] Pass the integer type for enumerations to the IVL target stage --- elab_scope.cc | 6 ++++-- netenum.cc | 13 +++++++++---- netenum.h | 5 ++++- parse.y | 6 ++++++ pform.cc | 5 +++++ pform_types.h | 1 + t-dll-api.cc | 4 +++- 7 files changed, 32 insertions(+), 8 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index a16e1173f..d3977c25e 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) diff --git a/netenum.cc b/netenum.cc index 1b8f4441b..4294e323b 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. */ 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/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..56dcd0349 100644 --- a/pform.cc +++ b/pform.cc @@ -3170,6 +3170,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_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; } From 632e15a55c7bac198c4e8817c8c750ac04214900 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 31 Oct 2014 20:05:22 -0700 Subject: [PATCH 09/10] Catch enumerations with the same name. --- pform.cc | 13 +++++++++++-- pform_class_type.cc | 3 ++- pform_string_type.cc | 3 ++- pform_struct_type.cc | 4 +++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/pform.cc b/pform.cc index 56dcd0349..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); 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); } From 9a471bd81cc7a227eaa38c781a4a3e95e4ef333f Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 31 Oct 2014 20:07:22 -0700 Subject: [PATCH 10/10] Don't crash if there are problems elaborating an enumeration. --- netenum.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/netenum.cc b/netenum.cc index 4294e323b..cab73a55c 100644 --- a/netenum.cc +++ b/netenum.cc @@ -89,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);