Merge pull request #657 from larsclausen/enum-base-type

Support type identifier base type for enum
This commit is contained in:
Stephen Williams 2022-03-27 15:47:34 -07:00 committed by GitHub
commit 4f971ea4f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 453 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

@ -0,0 +1,31 @@
// Check that it is possible to declare an enum type with an atom2 type as the
// base type.
module test;
enum byte {
A
} e1;
enum shortint {
B
} e2;
enum int {
C
} e3;
enum longint {
D
} e4;
initial begin
if ($bits(e1) == 8 && $bits(e2) == 16 &&
$bits(e3) == 32 && $bits(e4) == 64) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,16 @@
// Check that using an array type as the base type for an enum results in an
// error.
module test;
typedef logic T[1:0];
enum T {
A
} e;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,17 @@
// Check that using a class type as the base type for an enum results in an
// error.
class C;
endclass
module test;
enum C {
A
} e;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,16 @@
// Check that using a dynamic array type as the base type for an enum results in
// an error.
module test;
typedef logic T[];
enum T {
A
} e;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that using an enum type as the base type for an enum results in an
// error.
module test;
typedef enum {
X
} T;
enum T {
A
} e;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,16 @@
// Check that using a queue type as the base type for an enum results in an
// error
module test;
typedef logic T[$];
enum T {
A
} e;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,17 @@
// Check that using a type identifier that resolves to a type with a packed
// dimensions together with another packed dimensions as the base type for an
// enum results in an error.
module test;
typedef int T;
enum T [1:0] {
A
} e;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,16 @@
// Check that using a type identifier that resolves to a type with multiple
// packed dimensions as the base type for an enum results in an error.
module test;
typedef bit [1:0][1:0] T;
enum T {
A
} e;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,14 @@
// Check that specifying a vector type with multiple packed dimensions as the
// base type for an enum results in an error.
module test;
enum logic [1:0][1:0] {
A
} e;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,14 @@
// Check that using a real type as the base type for an enum results in an
// error.
module test;
enum real {
A
} e;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,16 @@
// Check that using a real type as the base type for an enum results in an
// error.
module test;
typedef real T;
enum T {
A
} e;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,14 @@
// Check that using a string type as the base type for an enum results in an
// error.
module test;
enum string {
A
} e;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,16 @@
// Check that using a string type as the base type for an enum results in an
// error.
module test;
typedef string T;
enum T {
A
} e;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that using a struct type as the base type for an enum results in an
// error.
module test;
typedef struct packed {
int x;
} T;
enum T {
A
} e;
initial begin
$display("FAILED");
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that it is possible to declare an enum type with the integer type as
// the base type.
module test;
enum integer {
A
} E;
initial begin
if ($bits(E) == $bits(integer)) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that it is possible to declare an enum type without an explicit base
// type. In this case the base type should default to `int`.
module test;
enum {
A
} E;
initial begin
if ($bits(E) == 32) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,26 @@
// Check that it is possible to declare an enum type with a scalar vector type
// as the base type.
module test;
enum reg {
A
} e1;
enum logic {
B
} e2;
enum bit {
C
} e3;
initial begin
if ($bits(e1) == 1 && $bits(e2) == 1 && $bits(e3) == 1) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that it is possible to declare an enum type with the time type as the
// base type.
module test;
enum time {
A
} E;
initial begin
if ($bits(E) == 64) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,20 @@
// Check that it is possible to declare an enum type with a type identifier that
// resolves to an integer type as the base type.
module test;
typedef integer T;
enum T {
A
} E;
initial begin
if ($bits(E) == $bits(integer)) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,20 @@
// Check that it is possible to declare an enum type with a type identifier plus
// packed dimensions as the the base type.
module test;
typedef bit T;
enum T [31:0] {
A
} E;
initial begin
if ($bits(E) == 32) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -231,7 +231,27 @@ clkgen_reg normal,-g2009 ivltests
disable_fork_cmd normal,-g2009 ivltests
display_bug normal,-g2009 ivltests gold=display_bug.gold
edge normal,-g2009 ivltests
enum_base_atom2 normal,-g2005-sv ivltests
enum_base_fail_array CE,-g2005-sv ivltests
enum_base_fail_darray CE,-g2005-sv ivltests
enum_base_fail_darray CE,-g2005-sv ivltests
enum_base_fail_enum CE,-g2005-sv ivltests
enum_base_fail_queue CE,-g2005-sv ivltests
enum_base_fail_range1 CE,-g2005-sv ivltests
enum_base_fail_range2 CE,-g2005-sv ivltests
enum_base_fail_range3 CE,-g2005-sv ivltests
enum_base_fail_real1 CE,-g2005-sv ivltests
enum_base_fail_real2 CE,-g2005-sv ivltests
enum_base_fail_string1 CE,-g2005-sv ivltests
enum_base_fail_string2 CE,-g2005-sv ivltests
enum_base_fail_struct CE,-g2005-sv ivltests
enum_base_integer normal,-g2005-sv ivltests
enum_base_none normal,-g2005-sv ivltests
enum_base_range normal,-g2005-sv ivltests
enum_base_scalar normal,-g2005-sv ivltests
enum_base_time normal,-g2005-sv ivltests
enum_base_typename1 normal,-g2005-sv ivltests
enum_base_typename2 normal,-g2005-sv ivltests
enum_compatibility1 normal,-g2005-sv ivltests
enum_compatibility2 normal,-g2005-sv ivltests
enum_compatibility3 normal,-g2005-sv ivltests

View File

@ -776,6 +776,8 @@ constfunc6_ams normal,-pallowsigned=1 ivltests
constfunc7 normal,-pallowsigned=1 ivltests
constfunc13 normal,-pallowsigned=1 ivltests
constfunc14 normal,-pallowsigned=1 ivltests
enum_base_atom2 normal,-g2005-sv,-pallowsigned=1 ivltests
enum_base_none normal,-g2005-sv,-pallowsigned=1 ivltests
enum_elem_ranges normal,-g2009,-pallowsigned=1 ivltests
enum_value_expr normal,-g2009,-pallowsigned=1 ivltests
enum_values normal,-g2009,-pallowsigned=1 ivltests

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;
};