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:
Cary R 2011-07-18 19:33:03 -07:00 committed by Stephen Williams
parent b99846e0eb
commit fd4f07906d
1 changed files with 45 additions and 8 deletions

View File

@ -152,6 +152,21 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
verinum cur_value (0);
verinum one_value (1);
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()
; 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) {
// There is an explicit value. elaborate/evaluate
// the value and assign it to the enumeration name.
NetExpr*val = elab_and_eval(des, scope, cur->parm,
use_enum->base_width());
NetExpr*val = elab_and_eval(des, scope, cur->parm, -1);
NetEConst*val_const = dynamic_cast<NetEConst*> (val);
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;
continue;
}
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
<< " cannot have a logic value." << endl;
<< " cannot have an undefined value." << endl;
des->errors += 1;
continue;
}
} else if (! cur_value.is_defined()) {
cerr << "<>:0: error: Enumeration name " << cur->name
<< " cannot have an inferred value." << endl;
<< " cannot have an undefined inferred value." << endl;
des->errors += 1;
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
// 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);
rc_flag = use_enum->insert_name(name_idx, cur->name, tmp_val);
rc_flag &= scope->add_enumeration_name(use_enum, cur->name);
if (! rc_flag) {
cerr << "<>:0: error: Duplicate enumeration name " << cur->name << endl;
cerr << "<>:0: error: Duplicate enumeration name "
<< cur->name << endl;
des->errors += 1;
}