Test type correctness during elaboration.

Create a netenum_t class to carry the enumeration type in the
netlist.h structures, and use that type to check enumerations
with assignments.
This commit is contained in:
Stephen Williams 2010-11-02 20:16:42 -07:00
parent 94acc39b55
commit 5b5a6b05b7
13 changed files with 206 additions and 21 deletions

View File

@ -95,9 +95,9 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
elab_scope.o elab_sig.o elab_sig_analog.o emit.o eval.o eval_attrib.o \
eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \
load_module.o netlist.o netmisc.o net_analog.o net_assign.o net_design.o \
net_event.o net_expr.o net_func.o net_link.o net_modulo.o net_nex_input.o \
net_nex_output.o net_proc.o net_scope.o net_tran.o net_udp.o \
pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \
netenum.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \
net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \
net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \
pform_disciplines.o pform_dump.o pform_types.o set_width.o \
symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \
Attrib.o HName.o LineInfo.o Module.o PDelays.o PEvent.o PExpr.o PGate.o \

View File

@ -94,6 +94,9 @@ ostream& operator << (ostream&o, ivl_variable_type_t val)
case IVL_VT_LOGIC:
o << "logic";
break;
case IVL_VT_STRING:
o << "string";
break;
}
return o;
}
@ -1190,7 +1193,7 @@ void NetScope::dump(ostream&o) const
o << " enum sets {" << endl;
/* Dump the enumerations and enum names in this scope. */
for (list<enum_set_t>::const_iterator cur = enum_sets_.begin()
for (list<netenum_t*>::const_iterator cur = enum_sets_.begin()
; cur != enum_sets_.end() ; ++ cur) {
o << " " << *cur << endl;
}

View File

@ -104,6 +104,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
switch (data_type_lv) {
case IVL_VT_REAL:
case IVL_VT_STRING:
unsized_flag = true;
expr_wid = -2;
expr_wid_lv = -1;
@ -2782,7 +2783,15 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
tmp = stmp;
}
} else if (NetEConstEnum*etmp = dynamic_cast<NetEConstEnum*>(tmp)) {
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Elaborate parameter <" << path_
<< "> as enumeration constant." << endl;
tmp = etmp->dup_expr();
} else {
/* No bit or part select. Make the constant into a
NetEConstParam if possible. */
NetEConst*ctmp = dynamic_cast<NetEConst*>(tmp);

View File

@ -42,6 +42,7 @@
# include "Statement.h"
# include "AStatement.h"
# include "netlist.h"
# include "netenum.h"
# include "util.h"
# include <typeinfo>
# include <cassert>
@ -209,12 +210,15 @@ static void elaborate_scope_localparams_(Design*des, NetScope*scope,
static void elaborate_scope_enumeration(Design*des, NetScope*scope,
enum_set_t enum_set)
{
scope->add_enumeration_set(enum_set);
netenum_t*use_enum = new netenum_t(IVL_VT_BOOL, true, 31, 0);
scope->add_enumeration_set(use_enum);
for (map<perm_string,verinum>::const_iterator cur = enum_set->begin()
; cur != enum_set->end() ; ++ cur) {
bool rc = scope->add_enumeration_name(enum_set, cur->first);
bool rc = use_enum->insert_name(cur->first, cur->second);
rc &= scope->add_enumeration_name(use_enum, cur->first);
if (! rc) {
cerr << "<>:0: error: Duplicate enumeration name " << cur->first << endl;
des->errors += 1;

View File

@ -1098,6 +1098,15 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
? new NetNet(scope, name_, wtype, msb, lsb, array_s0, array_e0)
: new NetNet(scope, name_, wtype, msb, lsb);
// If this is an enumeration, then set the enumeration set for
// the new signal. This turns it into an enumeration.
if (enum_set_) {
ivl_assert(*this, enum_set_->size() > 0);
enum_set_m::const_iterator sample_name = enum_set_->begin();
netenum_t*use_enum = scope->enumeration_for_name(sample_name->first);
sig->set_enumeration(use_enum);
}
if (wtype == NetNet::WIRE) sig->devirtualize_pins();
ivl_variable_type_t use_data_type = data_type_;

View File

@ -2271,6 +2271,12 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
rv = cast_to_int2(rv);
}
if (lv->enumeration() && (lv->enumeration() != rv->enumeration())) {
cerr << get_fileline() << ": error: "
<< "Enumeration type mismatch in assignment." << endl;
des->errors += 1;
}
NetAssign*cur = new NetAssign(lv, rv);
cur->set_line(*this);

View File

@ -87,6 +87,25 @@ ivl_variable_type_t NetAssign_::expr_type() const
return sig_->data_type();
}
netenum_t*NetAssign_::enumeration() const
{
netenum_t*tmp = 0;
// If the base signal is not an enumeration, return nil.
if ( (tmp = sig_->enumeration()) == 0 )
return 0;
// Part select of an enumeration is not an enumeration.
if (base_ != 0)
return 0;
// Concatenation of enumerations is not an enumeration.
if (more != 0)
return 0;
return tmp;
}
perm_string NetAssign_::name() const
{
if (sig_) {

View File

@ -31,6 +31,11 @@ ivl_variable_type_t NetExpr::expr_type() const
return IVL_VT_LOGIC;
}
netenum_t*NetExpr::enumeration() const
{
return 0;
}
/*
* Create an add/sub node from the two operands. Make a best guess of
* the
@ -432,7 +437,7 @@ unsigned NetEConcat::repeat() const
return repeat_value_;
}
NetEConstEnum::NetEConstEnum(NetScope*s, perm_string n, enum_set_t eset, const verinum&v)
NetEConstEnum::NetEConstEnum(NetScope*s, perm_string n, netenum_t*eset, const verinum&v)
: NetEConst(v), scope_(s), enum_set_(eset)
{
}
@ -441,7 +446,7 @@ NetEConstEnum::~NetEConstEnum()
{
}
const enum_set_t NetEConstEnum::enumeration() const
netenum_t*NetEConstEnum::enumeration() const
{
return enum_set_;
}

View File

@ -21,6 +21,7 @@
# include "compiler.h"
# include "netlist.h"
# include "netenum.h"
# include <cstring>
# include <cstdlib>
# include <sstream>
@ -453,15 +454,15 @@ NetNet* NetScope::find_signal(perm_string key)
return 0;
}
void NetScope::add_enumeration_set(enum_set_t enum_set)
void NetScope::add_enumeration_set(netenum_t*enum_set)
{
enum_sets_.push_back(enum_set);
}
bool NetScope::add_enumeration_name(enum_set_t enum_set, perm_string name)
bool NetScope::add_enumeration_name(netenum_t*enum_set, perm_string name)
{
enum_set_m::const_iterator enum_val = enum_set->find(name);
assert(enum_val != enum_set->end());
enum_set_m::const_iterator enum_val = enum_set->find_name(name);
assert(enum_val != enum_set->end_name());
NetEConstEnum*val = new NetEConstEnum(this, name, enum_set, enum_val->second);
@ -472,6 +473,14 @@ bool NetScope::add_enumeration_name(enum_set_t enum_set, perm_string name)
return cur.second;
}
netenum_t*NetScope::enumeration_for_name(perm_string name)
{
NetEConstEnum*tmp = enum_names_[name];
assert(tmp != 0);
return tmp->enumeration();
}
/*
* This method locates a child scope by name. The name is the simple
* name of the child, no hierarchy is searched.

45
netenum.cc Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2010 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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "netenum.h"
netenum_t::netenum_t(ivl_variable_type_t base_type, bool signed_flag, long msb, long lsb)
: base_type_(base_type), signed_flag_(signed_flag), msb_(msb), lsb_(lsb)
{
}
netenum_t::~netenum_t()
{
}
bool netenum_t::insert_name(perm_string name, const verinum&val)
{
names_[name] = verinum(val, msb_-lsb_+1);
return true;
}
netenum_t::iterator netenum_t::find_name(perm_string name) const
{
return names_.find(name);
}
netenum_t::iterator netenum_t::end_name() const
{
return names_.end();
}

48
netenum.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef __netenum_H
#define __netenum_H
/*
* Copyright (c) 2010 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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "ivl_target.h"
# include "verinum.h"
# include "StringHeap.h"
# include <map>
class netenum_t {
public:
explicit netenum_t(ivl_variable_type_t base_type, bool signed_flag,
long msb, long lsb);
~netenum_t();
bool insert_name(perm_string name, const verinum&val);
typedef std::map<perm_string,verinum>::const_iterator iterator;
iterator find_name(perm_string name) const;
iterator end_name() const;
private:
ivl_variable_type_t base_type_;
bool signed_flag_;
long msb_, lsb_;
std::map<perm_string,verinum> names_;
};
#endif

View File

@ -450,7 +450,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
: NetObj(s, n, 1),
type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE),
signed_(false), isint_(false), is_scalar_(false), local_flag_(false),
discipline_(0), msb_(npins-1), lsb_(0), dimensions_(0),
enumeration_(0), discipline_(0), msb_(npins-1), lsb_(0), dimensions_(0),
s0_(0), e0_(0), eref_count_(0), lref_count_(0)
{
assert(s);
@ -495,7 +495,8 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
long ms, long ls)
: NetObj(s, n, 1), type_(t),
port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false),
isint_(false), is_scalar_(false), local_flag_(false), discipline_(0),
isint_(false), is_scalar_(false), local_flag_(false),
enumeration_(0), discipline_(0),
msb_(ms), lsb_(ls),
dimensions_(0), s0_(0), e0_(0),
eref_count_(0), lref_count_(0)
@ -543,7 +544,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
: NetObj(s, n, calculate_count(array_s, array_e)),
type_(t), port_type_(NOT_A_PORT),
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false),
is_scalar_(false), local_flag_(false), discipline_(0),
is_scalar_(false), local_flag_(false), enumeration_(0), discipline_(0),
msb_(ms), lsb_(ls),
dimensions_(1), s0_(array_s), e0_(array_e),
eref_count_(0), lref_count_(0)
@ -684,6 +685,17 @@ void NetNet::set_scalar(bool flag)
is_scalar_ = flag;
}
netenum_t*NetNet::enumeration(void) const
{
return enumeration_;
}
void NetNet::set_enumeration(netenum_t*es)
{
ivl_assert(*this, enumeration_ == 0);
enumeration_ = es;
}
ivl_discipline_t NetNet::get_discipline() const
{
return discipline_;

View File

@ -71,6 +71,7 @@ class NetRamDq;
class NetTaskDef;
class NetEvTrig;
class NetEvWait;
class netenum_t;
struct target;
struct functor_t;
@ -596,6 +597,9 @@ class NetNet : public NetObj {
bool get_scalar() const;
void set_scalar(bool);
void set_enumeration(netenum_t*enum_set);
netenum_t*enumeration(void) const;
/* Attach a discipline to the net. */
ivl_discipline_t get_discipline() const;
void set_discipline(ivl_discipline_t dis);
@ -668,6 +672,7 @@ class NetNet : public NetObj {
bool isint_ : 1; // original type of integer
bool is_scalar_ : 1;
bool local_flag_: 1;
netenum_t*enumeration_;
ivl_discipline_t discipline_;
long msb_, lsb_;
@ -749,8 +754,10 @@ class NetScope : public Attrib {
void rem_signal(NetNet*);
NetNet* find_signal(perm_string name);
void add_enumeration_set(enum_set_t enum_set);
bool add_enumeration_name(enum_set_t enum_set, perm_string);
void add_enumeration_set(netenum_t*enum_set);
bool add_enumeration_name(netenum_t*enum_set, perm_string enum_name);
netenum_t* enumeration_for_name(perm_string name);
/* The parent and child() methods allow users of NetScope
objects to locate nearby scopes. */
@ -931,7 +938,7 @@ class NetScope : public Attrib {
// enumerations present in this scope. The enum_names_ is a
// map of all the enumeration names back to the sets that
// contain them.
std::list<enum_set_t> enum_sets_;
std::list<netenum_t*> enum_sets_;
std::map<perm_string,NetEConstEnum*> enum_names_;
NetScope*up_;
@ -1633,6 +1640,11 @@ class NetExpr : public LineInfo {
// expressions to check validity.
virtual bool has_width() const;
// Return the enumeration set that defines this expressions
// enumeration type, or return nil if the expression is not
// part of the enumeration.
virtual netenum_t*enumeration() const;
// Expressions in parameter declarations may have encountered
// arguments that are themselves untyped parameters. These
// cannot be fully resolved for type when elaborated (they are
@ -1725,12 +1737,12 @@ class NetEConstEnum : public NetEConst {
public:
explicit NetEConstEnum(NetScope*scope, perm_string name,
enum_set_t enum_set, const verinum&val);
netenum_t*enum_set, const verinum&val);
~NetEConstEnum();
perm_string name() const;
const NetScope*scope() const;
const enum_set_t enumeration() const;
netenum_t*enumeration() const;
virtual bool set_width(unsigned w, bool last_chance =false);
virtual void expr_scan(struct expr_scan_t*) const;
@ -1740,7 +1752,7 @@ class NetEConstEnum : public NetEConst {
private:
NetScope*scope_;
enum_set_t enum_set_;
netenum_t*enum_set_;
perm_string name_;
};
@ -2289,6 +2301,10 @@ class NetAssign_ {
unsigned lwidth() const;
ivl_variable_type_t expr_type() const;
// Return the enumeration type of this l-value, or nil if it's
// not an enumeration.
netenum_t*enumeration() const;
// Get the name of the underlying object.
perm_string name() const;