Check that enum initializations are in range.
This patch adds checks to verify that all enum initializations (explicit or implicit) are in range.
This commit is contained in:
parent
b99846e0eb
commit
fd4f07906d
|
|
@ -152,6 +152,21 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||||
verinum cur_value (0);
|
verinum cur_value (0);
|
||||||
verinum one_value (1);
|
verinum one_value (1);
|
||||||
size_t name_idx = 0;
|
size_t name_idx = 0;
|
||||||
|
// Find the minimum and maximum allowed enumeration values.
|
||||||
|
verinum min_value (0);
|
||||||
|
verinum max_value (0);
|
||||||
|
if (enum_type->signed_flag) {
|
||||||
|
min_value = v_not((pow(verinum(2),
|
||||||
|
verinum(use_enum->base_width()-1)))) +
|
||||||
|
one_value;
|
||||||
|
max_value = pow(verinum(2), verinum(use_enum->base_width()-1)) -
|
||||||
|
one_value;
|
||||||
|
} else {
|
||||||
|
max_value = pow(verinum(2), verinum(use_enum->base_width())) -
|
||||||
|
one_value;
|
||||||
|
}
|
||||||
|
min_value.has_sign(true);
|
||||||
|
max_value.has_sign(enum_type->signed_flag);
|
||||||
for (list<named_pexpr_t>::const_iterator cur = enum_type->names->begin()
|
for (list<named_pexpr_t>::const_iterator cur = enum_type->names->begin()
|
||||||
; cur != enum_type->names->end() ; ++ cur, name_idx += 1) {
|
; cur != enum_type->names->end() ; ++ cur, name_idx += 1) {
|
||||||
|
|
||||||
|
|
@ -159,38 +174,60 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
||||||
if (cur->parm) {
|
if (cur->parm) {
|
||||||
// There is an explicit value. elaborate/evaluate
|
// There is an explicit value. elaborate/evaluate
|
||||||
// the value and assign it to the enumeration name.
|
// the value and assign it to the enumeration name.
|
||||||
NetExpr*val = elab_and_eval(des, scope, cur->parm,
|
NetExpr*val = elab_and_eval(des, scope, cur->parm, -1);
|
||||||
use_enum->base_width());
|
|
||||||
NetEConst*val_const = dynamic_cast<NetEConst*> (val);
|
NetEConst*val_const = dynamic_cast<NetEConst*> (val);
|
||||||
if (val_const == 0) {
|
if (val_const == 0) {
|
||||||
cerr << "<>:0: error: Enumeration expression is not constant." << endl;
|
cerr << "<>:0: error: Enumeration expression is not "
|
||||||
|
"constant." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
cur_value = val_const->value();
|
cur_value = val_const->value();
|
||||||
|
|
||||||
if (enum_type->base_type==IVL_VT_BOOL && ! cur_value.is_defined()) {
|
if (enum_type->base_type==IVL_VT_BOOL &&
|
||||||
|
! cur_value.is_defined()) {
|
||||||
cerr << "<>:0: error: Enumeration name " << cur->name
|
cerr << "<>:0: error: Enumeration name " << cur->name
|
||||||
<< " cannot have a logic value." << endl;
|
<< " cannot have an undefined value." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (! cur_value.is_defined()) {
|
} else if (! cur_value.is_defined()) {
|
||||||
cerr << "<>:0: error: Enumeration name " << cur->name
|
cerr << "<>:0: error: Enumeration name " << cur->name
|
||||||
<< " cannot have an inferred value." << endl;
|
<< " cannot have an undefined inferred value." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The enumeration value must fit into the enumeration bits.
|
||||||
|
if ((cur_value > max_value) ||
|
||||||
|
(cur_value.has_sign() && (cur_value < min_value))) {
|
||||||
|
cerr << "<>:0: error: Enumeration name " << cur->name
|
||||||
|
<< " cannot have a value equal to " << cur_value
|
||||||
|
<< "." << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
}
|
||||||
|
|
||||||
// The values are explicitly sized to the width of the
|
// The values are explicitly sized to the width of the
|
||||||
// base type of the enumeration.
|
// base type of the enumeration.
|
||||||
verinum tmp_val (cur_value, use_enum->base_width());
|
verinum tmp_val (0);
|
||||||
|
if (cur_value.len() < use_enum->base_width()) {
|
||||||
|
// Pad the current value if it is narrower than the final
|
||||||
|
// width of the enum.
|
||||||
|
tmp_val = pad_to_width (cur_value, use_enum->base_width());
|
||||||
|
tmp_val.has_len(true);
|
||||||
|
} else {
|
||||||
|
// Truncate an oversized value. We report out of bound
|
||||||
|
// values above. This may create duplicates.
|
||||||
|
tmp_val = verinum(cur_value, use_enum->base_width());
|
||||||
|
}
|
||||||
tmp_val.has_sign(enum_type->signed_flag);
|
tmp_val.has_sign(enum_type->signed_flag);
|
||||||
|
|
||||||
rc_flag = use_enum->insert_name(name_idx, cur->name, tmp_val);
|
rc_flag = use_enum->insert_name(name_idx, cur->name, tmp_val);
|
||||||
rc_flag &= scope->add_enumeration_name(use_enum, cur->name);
|
rc_flag &= scope->add_enumeration_name(use_enum, cur->name);
|
||||||
if (! rc_flag) {
|
if (! rc_flag) {
|
||||||
cerr << "<>:0: error: Duplicate enumeration name " << cur->name << endl;
|
cerr << "<>:0: error: Duplicate enumeration name "
|
||||||
|
<< cur->name << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue