From 4bf0d62cd1f33408897d39981dd44df3a7846755 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 15 Mar 2022 08:24:33 +0100 Subject: [PATCH] Support type identifier base type for enum The base type for an enum type can be a type identifier for a typedef as long as it resolves to a vector or integer type with at most one packed dimension. This is described in section 6.19 ("Enumerations") of the LRM (1800-2017). E.g. ``` typedef bit [3:0] T; enum T { A } e; ``` Add support for this by allowing to specify a type identifier as the base type for an enum in the parser. During elaboration it is checked whether the type identifier resolves to a valid enum base type. Signed-off-by: Lars-Peter Clausen --- elab_scope.cc | 55 +++++++++++++++++++++++------------------ netenum.cc | 13 +++++----- netenum.h | 11 +++------ parse.y | 66 +++++++++++++++++++++----------------------------- pform_types.cc | 2 +- pform_types.h | 7 +++--- 6 files changed, 72 insertions(+), 82 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index fe39506e9..826154eae 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -21,6 +21,8 @@ # include "config.h" # include "compiler.h" # include "netmisc.h" +# include "netvector.h" +# include "netparray.h" # include # include # include @@ -166,27 +168,31 @@ 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; - netrange_t range; + ivl_type_t base_type; bool rc_flag; - if (enum_type->range.get()) - evaluate_ranges(des, scope, enum_type, ranges, *enum_type->range); + base_type = enum_type->base_type->elaborate_type(des, scope); - if (!ranges.empty()) { - range = ranges.front(); - if (ranges.size() > 1) { - cerr << enum_type->get_fileline() << ": error: " - << "Enum type must not have more than 1 packed dimension." - << endl; - des->errors++; - } + const struct netvector_t *vec_type = dynamic_cast(base_type); + + if (!vec_type && !dynamic_cast(base_type)) { + cerr << enum_type->get_fileline() << ": error: " + << "Invalid enum base type `" << *base_type << "`." + << endl; + des->errors++; + } else if (base_type->slice_dimensions().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, - enum_type->integer_flag, range, - enum_type->names->size()); + bool integer_flag = false; + if (vec_type) + integer_flag = vec_type->get_isint(); + + netenum_t*use_enum = new netenum_t(base_type, enum_type->names->size(), + integer_flag); use_enum->set_line(*enum_type); scope->add_enumeration_set(enum_type, use_enum); @@ -196,20 +202,21 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, long raw_width = use_enum->packed_width(); assert(raw_width > 0); unsigned enum_width = (unsigned)raw_width; + bool is_signed = use_enum->get_signed(); // Define the default start value and the increment value to be the // correct type for this enumeration. verinum cur_value ((uint64_t)0, enum_width); - cur_value.has_sign(enum_type->signed_flag); + cur_value.has_sign(is_signed); verinum one_value ((uint64_t)1, enum_width); - one_value.has_sign(enum_type->signed_flag); + one_value.has_sign(is_signed); // Find the maximum allowed enumeration value. verinum max_value (0); - if (enum_type->signed_flag) { + if (is_signed) { max_value = pow(verinum(2), verinum(enum_width-1)) - one_value; } else { max_value = pow(verinum(2), verinum(enum_width)) - one_value; } - max_value.has_sign(enum_type->signed_flag); + max_value.has_sign(is_signed); // Variable to indicate when a defined value wraps. bool implicit_wrapped = false; // Process the enumeration definition. @@ -234,7 +241,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, implicit_wrapped = false; // A 2-state value can not have a constant with X/Z bits. - if (enum_type->base_type==IVL_VT_BOOL && + if (use_enum->base_type() == IVL_VT_BOOL && ! cur_value.is_defined()) { cerr << use_enum->get_fileline() << ": error: Enumeration name " << cur->name @@ -259,7 +266,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, // value does not have a defined width. if (((cur_value.len() != enum_width) || ! cur_value.has_len()) && - ! enum_type->signed_flag && cur_value.is_negative()) { + ! is_signed && cur_value.is_negative()) { cerr << use_enum->get_fileline() << ": error: Enumeration name " << cur->name << " has a negative value." << endl; @@ -282,7 +289,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, if (cur_value[idx] != cur_value[check_width]) { // If this is an unsigned enumeration // then zero padding is okay. - if (! enum_type->signed_flag && + if (!is_signed && (idx == enum_width) && (cur_value[idx] == verinum::V0)) { check_width += 1; @@ -328,7 +335,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, // At this point the value has the correct size and needs // to have the correct sign attribute set. cur_value.has_len(true); - cur_value.has_sign(enum_type->signed_flag); + cur_value.has_sign(is_signed); } else if (! cur_value.is_defined()) { cerr << use_enum->get_fileline() diff --git a/netenum.cc b/netenum.cc index 7ff455926..1cedf2e85 100644 --- a/netenum.cc +++ b/netenum.cc @@ -23,10 +23,9 @@ using namespace std; -netenum_t::netenum_t(ivl_variable_type_t btype, bool signed_flag, - bool integer_flag, const netrange_t &range, size_t name_count) -: base_type_(btype), signed_flag_(signed_flag), integer_flag_(integer_flag), - range_(range), names_(name_count), bits_(name_count) +netenum_t::netenum_t(ivl_type_t btype, size_t name_count, bool integer_flag) +: base_type_(btype), integer_flag_(integer_flag), names_(name_count), + bits_(name_count) { } @@ -36,7 +35,7 @@ netenum_t::~netenum_t() bool netenum_t::get_signed() const { - return signed_flag_; + return base_type_->get_signed(); } bool netenum_t::get_isint() const @@ -54,12 +53,12 @@ bool netenum_t::packed() const long netenum_t::packed_width() const { - return range_.width(); + return base_type_->packed_width(); } vector netenum_t::slice_dimensions() const { - return vector(1, range_); + return base_type_->slice_dimensions(); } bool netenum_t::insert_name(size_t name_idx, perm_string name, const verinum&val) diff --git a/netenum.h b/netenum.h index 94f7cd8cd..b2d64397a 100644 --- a/netenum.h +++ b/netenum.h @@ -32,9 +32,8 @@ class NetScope; 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, const netrange_t &range, - size_t name_count); + explicit netenum_t(ivl_type_t base_type, size_t name_count, + bool integer_flag); ~netenum_t(); virtual ivl_variable_type_t base_type() const; @@ -71,10 +70,8 @@ class netenum_t : public LineInfo, public ivl_type_s { bool matches(const netenum_t*other) const; private: - ivl_variable_type_t base_type_; - bool signed_flag_; + ivl_type_t base_type_; bool integer_flag_; - netrange_t range_; std::map names_map_; std::vector names_; @@ -82,7 +79,7 @@ class netenum_t : public LineInfo, public ivl_type_s { }; inline ivl_variable_type_t netenum_t::base_type() const -{ return base_type_; } +{ return base_type_->base_type(); } inline size_t netenum_t::size() const { return names_.size(); } diff --git a/parse.y b/parse.y index dc4938e7d..004fb8001 100644 --- a/parse.y +++ b/parse.y @@ -439,8 +439,6 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector*statement_list; - enum_type_t*enum_type; - decl_assignment_t*decl_assignment; std::list*decl_assignments; @@ -620,7 +618,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector tf_port_item_expr_opt value_range_expression %type enum_name_list enum_name -%type enum_data_type enum_base_type +%type enum_data_type enum_base_type %type tf_item_declaration tf_item_list tf_item_list_opt %type tf_port_declaration tf_port_item tf_port_item_list tf_port_list tf_port_list_opt @@ -659,6 +657,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector simple_type_or_string let_formal_type %type packed_array_data_type %type ps_type_identifier +%type simple_packed_type %type class_identifier %type struct_union_member %type struct_union_member_list @@ -1222,17 +1221,12 @@ packed_array_data_type /* IEEE1800-2005: A.2.2.1 */ | ps_type_identifier ; -data_type /* IEEE1800-2005: A.2.2.1 */ +simple_packed_type /* Integer and vector types */ : integer_vector_type unsigned_signed_opt dimensions_opt { vector_type_t*tmp = new vector_type_t($1, $2, $3); FILE_NAME(tmp, @1); $$ = tmp; } - | non_integer_type - { real_type_t*tmp = new real_type_t($1); - FILE_NAME(tmp, @1); - $$ = tmp; - } | atom2_type signed_unsigned_opt { atom2_type_t*tmp = new atom2_type_t($1, $2); FILE_NAME(tmp, @1); @@ -1249,6 +1243,17 @@ data_type /* IEEE1800-2005: A.2.2.1 */ vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, $2, pd); $$ = tmp; } + ; + +data_type /* IEEE1800-2005: A.2.2.1 */ + : simple_packed_type + { $$ = $1; + } + | non_integer_type + { real_type_t*tmp = new real_type_t($1); + FILE_NAME(tmp, @1); + $$ = tmp; + } | packed_array_data_type dimensions_opt { if ($2) { parray_type_t*tmp = new parray_type_t($1, $2); @@ -2736,43 +2741,26 @@ type_declaration can be any of the integral or vector types. */ enum_base_type /* IEEE 1800-2012 A.2.2.1 */ - : - { enum_type_t*enum_type = new enum_type_t; - 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; + : simple_packed_type + { $$ = $1; } - | atom2_type signed_unsigned_opt - { enum_type_t*enum_type = new enum_type_t; - enum_type->base_type = IVL_VT_BOOL; - enum_type->signed_flag = $2; - enum_type->integer_flag = false; - enum_type->range.reset(make_range_from_width($1)); - $$ = enum_type; + | ps_type_identifier dimensions_opt + { if ($2) { + $$ = new parray_type_t($1, $2); + FILE_NAME($$, @1); + } else { + $$ = $1; + } } - | K_integer signed_unsigned_opt - { enum_type_t*enum_type = new enum_type_t; - enum_type->base_type = IVL_VT_LOGIC; - enum_type->signed_flag = $2; - enum_type->integer_flag = true; - enum_type->range.reset(make_range_from_width(integer_width)); - $$ = enum_type; - } - | integer_vector_type unsigned_signed_opt dimensions_opt - { enum_type_t*enum_type = new enum_type_t; - enum_type->base_type = $1; - enum_type->signed_flag = $2; - enum_type->integer_flag = false; - enum_type->range.reset($3 ? $3 : make_range_from_width(1)); - $$ = enum_type; + | + { $$ = new atom2_type_t(32, true); + FILE_NAME($$, @0); } ; enum_data_type /* IEEE 1800-2012 A.2.2.1 */ : K_enum enum_base_type '{' enum_name_list '}' - { enum_type_t*enum_type = $2; + { enum_type_t*enum_type = new enum_type_t($2); FILE_NAME(enum_type, @1); enum_type->names.reset($4); pform_put_enum_type_in_scope(enum_type); diff --git a/pform_types.cc b/pform_types.cc index 21dc725ab..28dfe15fc 100644 --- a/pform_types.cc +++ b/pform_types.cc @@ -50,7 +50,7 @@ ivl_variable_type_t vector_type_t::figure_packed_base_type(void) const ivl_variable_type_t enum_type_t::figure_packed_base_type() const { - return base_type; + return base_type->figure_packed_base_type(); } ivl_variable_type_t atom2_type_t::figure_packed_base_type() const diff --git a/pform_types.h b/pform_types.h index 3bbd32286..b32f674bd 100644 --- a/pform_types.h +++ b/pform_types.h @@ -178,6 +178,8 @@ struct void_type_t : public data_type_t { * until it is elaborated in a scope. */ struct enum_type_t : public data_type_t { + explicit enum_type_t(data_type_t *btype) : base_type(btype) { } + // Return the elaborated version of the type. ivl_type_t elaborate_type_raw(Design*des, NetScope*scope) const; @@ -185,10 +187,7 @@ struct enum_type_t : public data_type_t { SymbolType symbol_type() const; - ivl_variable_type_t base_type; - bool signed_flag; - bool integer_flag; // True if "integer" was used - std::unique_ptr< std::list > range; + data_type_t *base_type; std::unique_ptr< std::list > names; };