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:
parent
4c36b2a8a7
commit
4bf0d62cd1
|
|
@ -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()
|
||||
|
|
|
|||
13
netenum.cc
13
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<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)
|
||||
|
|
|
|||
11
netenum.h
11
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<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
66
parse.y
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue