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 <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2022-03-15 08:24:33 +01:00
parent 4c36b2a8a7
commit 4bf0d62cd1
6 changed files with 72 additions and 82 deletions

View File

@ -21,6 +21,8 @@
# include "config.h"
# include "compiler.h"
# include "netmisc.h"
# include "netvector.h"
# include "netparray.h"
# include <cstring>
# include <iostream>
# include <cstdlib>
@ -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<netrange_t> 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<const netvector_t*>(base_type);
if (!vec_type && !dynamic_cast<const netparray_t*>(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()

View File

@ -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<netrange_t> netenum_t::slice_dimensions() const
{
return vector<netrange_t>(1, range_);
return base_type_->slice_dimensions();
}
bool netenum_t::insert_name(size_t name_idx, perm_string name, const verinum&val)

View File

@ -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<perm_string,verinum> names_map_;
std::vector<perm_string> 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(); }

66
parse.y
View File

@ -439,8 +439,6 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
Statement*statement;
std::vector<Statement*>*statement_list;
enum_type_t*enum_type;
decl_assignment_t*decl_assignment;
std::list<decl_assignment_t*>*decl_assignments;
@ -620,7 +618,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
%type <expr> tf_port_item_expr_opt value_range_expression
%type <named_pexprs> enum_name_list enum_name
%type <enum_type> enum_data_type enum_base_type
%type <data_type> enum_data_type enum_base_type
%type <tf_ports> tf_item_declaration tf_item_list tf_item_list_opt
%type <tf_ports> 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<Statem
%type <data_type> simple_type_or_string let_formal_type
%type <data_type> packed_array_data_type
%type <data_type> ps_type_identifier
%type <data_type> simple_packed_type
%type <class_type> class_identifier
%type <struct_member> struct_union_member
%type <struct_members> 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);

View File

@ -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

View File

@ -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<pform_range_t> > range;
data_type_t *base_type;
std::unique_ptr< std::list<named_pexpr_t> > names;
};