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 \ 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 \ 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 \ 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 \ netenum.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \
net_nex_output.o net_proc.o net_scope.o net_tran.o net_udp.o \ net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \
pad_to_width.o parse.o parse_misc.o pform.o pform_analog.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 \ 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 \ 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 \ 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: case IVL_VT_LOGIC:
o << "logic"; o << "logic";
break; break;
case IVL_VT_STRING:
o << "string";
break;
} }
return o; return o;
} }
@ -1190,7 +1193,7 @@ void NetScope::dump(ostream&o) const
o << " enum sets {" << endl; o << " enum sets {" << endl;
/* Dump the enumerations and enum names in this scope. */ /* 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) { ; cur != enum_sets_.end() ; ++ cur) {
o << " " << *cur << endl; o << " " << *cur << endl;
} }

View File

@ -104,6 +104,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
switch (data_type_lv) { switch (data_type_lv) {
case IVL_VT_REAL: case IVL_VT_REAL:
case IVL_VT_STRING:
unsized_flag = true; unsized_flag = true;
expr_wid = -2; expr_wid = -2;
expr_wid_lv = -1; expr_wid_lv = -1;
@ -2782,7 +2783,15 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
tmp = stmp; 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 { } else {
/* No bit or part select. Make the constant into a /* No bit or part select. Make the constant into a
NetEConstParam if possible. */ NetEConstParam if possible. */
NetEConst*ctmp = dynamic_cast<NetEConst*>(tmp); NetEConst*ctmp = dynamic_cast<NetEConst*>(tmp);

View File

@ -42,6 +42,7 @@
# include "Statement.h" # include "Statement.h"
# include "AStatement.h" # include "AStatement.h"
# include "netlist.h" # include "netlist.h"
# include "netenum.h"
# include "util.h" # include "util.h"
# include <typeinfo> # include <typeinfo>
# include <cassert> # include <cassert>
@ -209,12 +210,15 @@ static void elaborate_scope_localparams_(Design*des, NetScope*scope,
static void elaborate_scope_enumeration(Design*des, NetScope*scope, static void elaborate_scope_enumeration(Design*des, NetScope*scope,
enum_set_t enum_set) 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() for (map<perm_string,verinum>::const_iterator cur = enum_set->begin()
; cur != enum_set->end() ; ++ cur) { ; 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) { if (! rc) {
cerr << "<>:0: error: Duplicate enumeration name " << cur->first << endl; cerr << "<>:0: error: Duplicate enumeration name " << cur->first << endl;
des->errors += 1; 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, array_s0, array_e0)
: new NetNet(scope, name_, wtype, msb, lsb); : 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(); if (wtype == NetNet::WIRE) sig->devirtualize_pins();
ivl_variable_type_t use_data_type = data_type_; 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); 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); NetAssign*cur = new NetAssign(lv, rv);
cur->set_line(*this); cur->set_line(*this);

View File

@ -87,6 +87,25 @@ ivl_variable_type_t NetAssign_::expr_type() const
return sig_->data_type(); 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 perm_string NetAssign_::name() const
{ {
if (sig_) { if (sig_) {

View File

@ -31,6 +31,11 @@ ivl_variable_type_t NetExpr::expr_type() const
return IVL_VT_LOGIC; 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 * Create an add/sub node from the two operands. Make a best guess of
* the * the
@ -432,7 +437,7 @@ unsigned NetEConcat::repeat() const
return repeat_value_; 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) : 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_; return enum_set_;
} }

View File

@ -21,6 +21,7 @@
# include "compiler.h" # include "compiler.h"
# include "netlist.h" # include "netlist.h"
# include "netenum.h"
# include <cstring> # include <cstring>
# include <cstdlib> # include <cstdlib>
# include <sstream> # include <sstream>
@ -453,15 +454,15 @@ NetNet* NetScope::find_signal(perm_string key)
return 0; 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); 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); enum_set_m::const_iterator enum_val = enum_set->find_name(name);
assert(enum_val != enum_set->end()); assert(enum_val != enum_set->end_name());
NetEConstEnum*val = new NetEConstEnum(this, name, enum_set, enum_val->second); 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; 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 * This method locates a child scope by name. The name is the simple
* name of the child, no hierarchy is searched. * 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), : NetObj(s, n, 1),
type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE),
signed_(false), isint_(false), is_scalar_(false), local_flag_(false), 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) s0_(0), e0_(0), eref_count_(0), lref_count_(0)
{ {
assert(s); assert(s);
@ -495,7 +495,8 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
long ms, long ls) long ms, long ls)
: NetObj(s, n, 1), type_(t), : NetObj(s, n, 1), type_(t),
port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), 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), msb_(ms), lsb_(ls),
dimensions_(0), s0_(0), e0_(0), dimensions_(0), s0_(0), e0_(0),
eref_count_(0), lref_count_(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)), : NetObj(s, n, calculate_count(array_s, array_e)),
type_(t), port_type_(NOT_A_PORT), type_(t), port_type_(NOT_A_PORT),
data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), 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), msb_(ms), lsb_(ls),
dimensions_(1), s0_(array_s), e0_(array_e), dimensions_(1), s0_(array_s), e0_(array_e),
eref_count_(0), lref_count_(0) eref_count_(0), lref_count_(0)
@ -684,6 +685,17 @@ void NetNet::set_scalar(bool flag)
is_scalar_ = 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 ivl_discipline_t NetNet::get_discipline() const
{ {
return discipline_; return discipline_;

View File

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