diff --git a/elab_scope.cc b/elab_scope.cc index 984a93af9..da9030141 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -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::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 (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; }