From ea1bf7577a70d41d09e11a9e85e43b1cf170d55e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 8 Jan 2022 09:59:34 +0100 Subject: [PATCH 1/3] Allow lsb > msb for enum base type Having an enum with a lsb > msb base type, e.g. `enum logic [0:9]` is a legal construct. It is handled correctly for the most part already, there is just an assert that triggers on it. Remove that assert. Signed-off-by: Lars-Peter Clausen --- netenum.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/netenum.cc b/netenum.cc index 0ec7ca33d..802a7f446 100644 --- a/netenum.cc +++ b/netenum.cc @@ -74,8 +74,7 @@ bool netenum_t::insert_name(size_t name_idx, perm_string name, const verinum&val { std::pair::iterator, bool> res; - assert((msb_-lsb_+1) > 0); - assert(val.has_len() && val.len() == (unsigned)(msb_-lsb_+1)); + assert(val.has_len() && val.len() == packed_width()); // Insert a map of the name to the value. This also gets a // flag that returns true if the name is unique, or false From 90edf48ac6e66ffd5375afeba85ea469c68f8dec Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 8 Jan 2022 10:01:23 +0100 Subject: [PATCH 2/3] Handle invalid enum dimensions Specifying and enum with an invalid dimension range results in an assert or segfault. E.g. `enum [$] E { ... }`. Use the `evaluate_ranges()` function to elaborate the enum dimensions. This functions has proper error checking and recovery built-in. In addition verify that there is at most one packed dimension. Signed-off-by: Lars-Peter Clausen --- elab_scope.cc | 23 +++++++++++++++-------- pform.cc | 5 ----- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index 728b897e2..8d8b52bea 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -180,18 +180,25 @@ static void collect_scope_specparams(Design*des, NetScope*scope, static void elaborate_scope_enumeration(Design*des, NetScope*scope, enum_type_t*enum_type) { + std::vector ranges; bool rc_flag; - assert(enum_type->range->size() == 1); - pform_range_t&range = enum_type->range->front(); - NetExpr*msb_ex = elab_and_eval(des, scope, range.first, -1); - NetExpr*lsb_ex = elab_and_eval(des, scope, range.second, -1); + + if (enum_type->range.get()) + evaluate_ranges(des, scope, enum_type, ranges, *enum_type->range); long msb = 0; - rc_flag = eval_as_long(msb, msb_ex); - assert(rc_flag); long lsb = 0; - rc_flag = eval_as_long(lsb, lsb_ex); - assert(rc_flag); + + if (!ranges.empty()) { + msb = ranges.front().get_msb(); + lsb = ranges.front().get_lsb(); + if (ranges.size() > 1) { + cerr << enum_type->get_fileline() << ": error: " + << "Enum type must not have more than 1 packed dimension." + << endl; + des->errors++; + } + } netenum_t*use_enum = new netenum_t(enum_type->base_type, enum_type->signed_flag, diff --git a/pform.cc b/pform.cc index 65fe6ebcb..91851d075 100644 --- a/pform.cc +++ b/pform.cc @@ -3575,8 +3575,6 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, cur->set_signed(enum_type->signed_flag); - assert(enum_type->range.get() != 0); - assert(enum_type->range->size() == 1); //XXXXcur->set_range(*enum_type->range, SR_NET); // If this is an integer enumeration switch the wire to an integer. if (enum_type->integer_flag) { @@ -3594,9 +3592,6 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, // IVL_VT_BOOL. assert(enum_type->base_type==IVL_VT_LOGIC || enum_type->base_type==IVL_VT_BOOL); - assert(enum_type->range.get() != 0); - assert(enum_type->range->size() == 1); - // Add the file and line information to the enumeration type. FILE_NAME(&(enum_type->li), li); From 3176611771d9516b86253cb069e6f3058c559839 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 8 Jan 2022 13:01:20 +0100 Subject: [PATCH 3/3] netenum_t: Use netrange_t to store range Use netrange_t, which is meant for storing ranges, for storing the range of a netenum_t. This makes the integration with the rest of the codebase a bit more seamlessly and also allow to reuse methods defined for netrange_t such as the width() method rather than having to reimplement it. Signed-off-by: Lars-Peter Clausen --- elab_scope.cc | 9 +++------ netenum.cc | 14 ++++---------- netenum.h | 4 ++-- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index 8d8b52bea..b145bb887 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -181,17 +181,14 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, enum_type_t*enum_type) { std::vector ranges; + netrange_t range; bool rc_flag; if (enum_type->range.get()) evaluate_ranges(des, scope, enum_type, ranges, *enum_type->range); - long msb = 0; - long lsb = 0; - if (!ranges.empty()) { - msb = ranges.front().get_msb(); - lsb = ranges.front().get_lsb(); + range = ranges.front(); if (ranges.size() > 1) { cerr << enum_type->get_fileline() << ": error: " << "Enum type must not have more than 1 packed dimension." @@ -202,7 +199,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, netenum_t*use_enum = new netenum_t(enum_type->base_type, enum_type->signed_flag, - enum_type->integer_flag, msb, lsb, + enum_type->integer_flag, range, enum_type->names->size(), enum_type); diff --git a/netenum.cc b/netenum.cc index 802a7f446..bb53088bc 100644 --- a/netenum.cc +++ b/netenum.cc @@ -24,10 +24,10 @@ using namespace std; netenum_t::netenum_t(ivl_variable_type_t btype, bool signed_flag, - bool integer_flag, long msb, long lsb, size_t name_count, + bool integer_flag, const netrange_t &range, size_t name_count, enum_type_t*enum_type) : base_type_(btype), enum_type_(enum_type), signed_flag_(signed_flag), - integer_flag_(integer_flag), msb_(msb), lsb_(lsb), + integer_flag_(integer_flag), range_(range), names_(name_count), bits_(name_count) { } @@ -56,20 +56,14 @@ bool netenum_t::packed() const long netenum_t::packed_width() const { - if (msb_ >= lsb_) - return msb_ - lsb_ + 1; - else - return lsb_ - msb_ + 1; + return range_.width(); } vector netenum_t::slice_dimensions() const { - vector tmp (1); - tmp[0] = netrange_t(msb_, lsb_); - return tmp; + return vector(1, range_); } - bool netenum_t::insert_name(size_t name_idx, perm_string name, const verinum&val) { std::pair::iterator, bool> res; diff --git a/netenum.h b/netenum.h index 8ff8a9063..b05675cfe 100644 --- a/netenum.h +++ b/netenum.h @@ -35,7 +35,7 @@ class netenum_t : public LineInfo, public ivl_type_s { public: explicit netenum_t(ivl_variable_type_t base_type, bool signed_flag, - bool isint_flag, long msb, long lsb, + bool isint_flag, const netrange_t &range, size_t name_count, enum_type_t*enum_type); ~netenum_t(); @@ -77,7 +77,7 @@ class netenum_t : public LineInfo, public ivl_type_s { enum_type_t*enum_type_; bool signed_flag_; bool integer_flag_; - long msb_, lsb_; + netrange_t range_; std::map names_map_; std::vector names_;