Fix some enum bugs.

This patch fixes a few more bugs in the enumeration code.

It add support for saving the file and line information to make
diagnostic messages better.

It updates some of the compiler warning messages to use the file
and line information.

It passes if the enumeration type is signed all the way to the
code generators.

It fixes the parser to correctly have the range after the signed
designation for the vector types.

It adds a warning that vvp does not currently support a negative
two state enumeration value.
This commit is contained in:
Cary R 2011-09-01 14:29:40 -07:00 committed by Stephen Williams
parent f3522e98f1
commit b2ebc29c5a
10 changed files with 92 additions and 26 deletions

View File

@ -1834,7 +1834,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
expr_type_ = use_enum->base_type();
expr_width_ = use_enum->base_width();
min_width_ = expr_width_;
signed_flag_ = false;
signed_flag_ = par_enum->has_sign();
return expr_width_;
}

View File

@ -147,6 +147,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
netenum_t*use_enum = new netenum_t(enum_type->base_type, enum_type->signed_flag,
msb, lsb, enum_type->names->size());
use_enum->set_line(enum_type->li);
scope->add_enumeration_set(use_enum);
verinum cur_value (0);
@ -177,7 +178,8 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
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 "
cerr << use_enum->get_fileline()
<< ": error: Enumeration expression is not "
"constant." << endl;
des->errors += 1;
continue;
@ -186,14 +188,16 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
if (enum_type->base_type==IVL_VT_BOOL &&
! cur_value.is_defined()) {
cerr << "<>:0: error: Enumeration name " << cur->name
cerr << use_enum->get_fileline()
<< ": error: Enumeration name " << cur->name
<< " cannot have an undefined value." << endl;
des->errors += 1;
continue;
}
} else if (! cur_value.is_defined()) {
cerr << "<>:0: error: Enumeration name " << cur->name
cerr << use_enum->get_fileline()
<< ": error: Enumeration name " << cur->name
<< " cannot have an undefined inferred value." << endl;
des->errors += 1;
continue;
@ -202,7 +206,8 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
// 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
cerr << use_enum->get_fileline()
<< ": error: Enumeration name " << cur->name
<< " cannot have a value equal to " << cur_value
<< "." << endl;
des->errors += 1;
@ -226,7 +231,8 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
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 "
cerr << use_enum->get_fileline()
<< ": error: Duplicate enumeration name "
<< cur->name << endl;
des->errors += 1;
}

View File

@ -30,9 +30,12 @@ ivl_discipline_flow
ivl_discipline_name
ivl_discipline_potential
ivl_enum_bits
ivl_enum_file
ivl_enum_lineno
ivl_enum_name
ivl_enum_names
ivl_enum_bits
ivl_enum_signed
ivl_enum_type
ivl_enum_width

View File

@ -652,6 +652,9 @@ extern const char* ivl_nature_name(ivl_nature_t net);
* of the enumeration should match the length of this string. Every
* name also has bits that make up the value.
*
* ivl_enum_signed
* Is the base type for the enum signed?
*
* ivl_enum_type
* Get the data-type for the base type that the enum uses. This
* will be either IVL_VT_BOOL or IVL_VT_LOGIC
@ -664,9 +667,13 @@ extern const char* ivl_nature_name(ivl_nature_t net);
extern unsigned ivl_enum_names(ivl_enumtype_t net);
extern const char*ivl_enum_name(ivl_enumtype_t net, unsigned idx);
extern const char*ivl_enum_bits(ivl_enumtype_t net, unsigned idx);
extern int ivl_enum_signed(ivl_enumtype_t net);
extern ivl_variable_type_t ivl_enum_type(ivl_enumtype_t net);
extern unsigned ivl_enum_width(ivl_enumtype_t net);
extern const char*ivl_enum_file(ivl_enumtype_t net);
extern unsigned ivl_enum_lineno(ivl_enumtype_t net);
/* EVENTS
*
* Events are a unification of named events and implicit events

View File

@ -1,7 +1,7 @@
#ifndef __netenum_H
#define __netenum_H
/*
* Copyright (c) 2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2010-2011 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -22,12 +22,13 @@
# include "ivl_target.h"
# include "verinum.h"
# include "StringHeap.h"
# include "LineInfo.h"
# include <vector>
# include <map>
class NetScope;
class netenum_t {
class netenum_t : public LineInfo {
public:
explicit netenum_t(ivl_variable_type_t base_type, bool signed_flag,
@ -36,6 +37,7 @@ class netenum_t {
ivl_variable_type_t base_type() const;
unsigned base_width() const;
bool has_sign() const;
// The size() is the number of enumeration literals.
size_t size() const;
@ -79,4 +81,6 @@ inline unsigned netenum_t::base_width() const
inline size_t netenum_t::size() const { return names_.size(); }
inline bool netenum_t::has_sign() const { return signed_flag_; }
#endif

18
parse.y
View File

@ -773,28 +773,28 @@ enum_data_type
enum_type->range.reset( make_range_from_width(integer_width) );
$$ = enum_type;
}
| K_enum K_logic range unsigned_signed_opt '{' enum_name_list '}'
| K_enum K_logic unsigned_signed_opt range '{' enum_name_list '}'
{ enum_type_t*enum_type = new enum_type_t;
enum_type->names .reset($6);
enum_type->base_type = IVL_VT_LOGIC;
enum_type->signed_flag = $4;
enum_type->range.reset( $3 );
enum_type->signed_flag = $3;
enum_type->range.reset( $4 );
$$ = enum_type;
}
| K_enum K_reg range unsigned_signed_opt '{' enum_name_list '}'
| K_enum K_reg unsigned_signed_opt range '{' enum_name_list '}'
{ enum_type_t*enum_type = new enum_type_t;
enum_type->names .reset($6);
enum_type->base_type = IVL_VT_LOGIC;
enum_type->signed_flag = $4;
enum_type->range.reset( $3 );
enum_type->signed_flag = $3;
enum_type->range.reset( $4 );
$$ = enum_type;
}
| K_enum K_bit range unsigned_signed_opt '{' enum_name_list '}'
| K_enum K_bit unsigned_signed_opt range '{' enum_name_list '}'
{ enum_type_t*enum_type = new enum_type_t;
enum_type->names .reset($6);
enum_type->base_type = IVL_VT_BOOL;
enum_type->signed_flag = $4;
enum_type->range.reset( $3 );
enum_type->signed_flag = $3;
enum_type->range.reset( $4 );
$$ = enum_type;
}
;

View File

@ -2508,6 +2508,9 @@ void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list<perm_st
assert(enum_type->range.get() != 0);
assert(enum_type->range->size() == 2);
// Add the file and line information to the enumeration type.
FILE_NAME(&(enum_type->li), li);
// Attach the enumeration to the current scope.
pform_put_enum_type_in_scope(enum_type);

View File

@ -1,7 +1,7 @@
#ifndef __pform_types_H
#define __pform_types_H
/*
* Copyright (c) 2007-2008 Stephen Williams (steve@icarus.com)
* Copyright (c) 2007-2011 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -21,6 +21,7 @@
// This for the perm_string type.
# include "StringHeap.h"
# include "LineInfo.h"
# include "verinum.h"
# include "named.h"
# include "ivl_target.h"
@ -67,6 +68,7 @@ struct enum_type_t {
bool signed_flag;
std::auto_ptr< list<PExpr*> > range;
std::auto_ptr< list<named_pexpr_t> > names;
LineInfo li;
};

View File

@ -262,6 +262,24 @@ extern "C" unsigned ivl_enum_width(ivl_enumtype_t net)
return net->base_width();
}
extern "C" int ivl_enum_signed(ivl_enumtype_t net)
{
assert(net);
return net->has_sign();
}
extern "C" const char*ivl_enum_file(ivl_enumtype_t net)
{
assert(net);
return net->get_file().str();
}
extern "C" unsigned ivl_enum_lineno(ivl_enumtype_t net)
{
assert(net);
return net->get_lineno();
}
extern "C" const char* ivl_event_name(ivl_event_t net)
{
static char*name_buffer = 0;
@ -291,7 +309,6 @@ extern "C" const char* ivl_event_basename(ivl_event_t net)
return net->name;
}
extern "C" const char*ivl_event_file(ivl_event_t net)
{
assert(net);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2010-2011 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -23,13 +23,36 @@
# include <string.h>
# include <assert.h>
// HERE: This still needs work! Fall back to <width>'<signed>b format for
// very large constants. This should also be int64_t sized values.
// The run time still needs to be modified to work with signed values
// and we also need to pass the file and line information.
static void draw_enum2_value(ivl_enumtype_t enumtype, unsigned idx)
{
long val = 0;
long mask = 1;
long val, mask;
const char*bits = ivl_enum_bits(enumtype, idx);
const char*bit;
for (bit = bits, mask = 1 ; bit[0] != 0 ; bit += 1, mask <<= 1) {
unsigned len = strlen(bits);
/* Sign extend if needed. */
if (ivl_enum_signed(enumtype)) {
assert(len <= sizeof(long)*8);
if ((bits[len-1] == '1') && (len < sizeof(long)*8)) {
val = -1L & ~((1L << len) - 1L);
// HERE: Remove once vvp has been updated.
if (ivl_enum_signed(enumtype)) {
fprintf(stderr, "%s:%u: tgt-vvp sorry: signed "
"enumerations with negative values are not "
"currently supported by vvp.\n",
ivl_enum_file(enumtype),
ivl_enum_lineno(enumtype));
vvp_errors += 1;
}
} else val = 0;
} else {
assert(len < sizeof(long)*8);
val = 0;
}
for (bit = bits, mask = 1 ; *bit != 0 ; bit += 1, mask <<= 1) {
if (*bit == '1')
val |= mask;
}
@ -42,7 +65,8 @@ static void draw_enum4_value(ivl_enumtype_t enumtype, unsigned idx)
const char*bits = ivl_enum_bits(enumtype, idx);
const char*bit;
fprintf(vvp_out, "%u'b", ivl_enum_width(enumtype));
fprintf(vvp_out, "%u'%sb", ivl_enum_width(enumtype),
ivl_enum_signed(enumtype) ? "s" : "");
for (bit = bits+strlen(bits) ; bit > bits ; bit -= 1)
fputc(bit[-1], vvp_out);