diff --git a/elab_scope.cc b/elab_scope.cc index eb0028ee8..3c9c166c1 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -48,6 +48,7 @@ # include "netlist.h" # include "netclass.h" # include "netenum.h" +# include "parse_api.h" # include "util.h" # include # include @@ -156,6 +157,10 @@ static void collect_scope_specparams_(Design*des, NetScope*scope, } } +/* + * Elaborate the enumeration into the given scope. If scope==0, then + * the enumeration goes into $root instead of a scope. + */ static void elaborate_scope_enumeration(Design*des, NetScope*scope, enum_type_t*enum_type) { @@ -176,7 +181,10 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, msb, lsb, enum_type->names->size()); use_enum->set_line(enum_type->li); - scope->add_enumeration_set(use_enum); + if (scope) + scope->add_enumeration_set(use_enum); + else + des->add_enumeration_set(use_enum); ivl_assert(*enum_type, enum_type->net_type == 0); enum_type->net_type = use_enum; @@ -270,7 +278,11 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, 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 (scope) + rc_flag &= scope->add_enumeration_name(use_enum, cur->name); + else + rc_flag &= des->add_enumeration_name(use_enum, cur->name); + if (! rc_flag) { cerr << use_enum->get_fileline() << ": error: Duplicate enumeration name " @@ -297,6 +309,15 @@ static void elaborate_scope_enumerations(Design*des, NetScope*scope, } } +void elaborate_rootscope_enumerations(Design*des) +{ + for (set::const_iterator cur = pform_enum_sets.begin() + ; cur != pform_enum_sets.end() ; ++ cur) { + enum_type_t*curp = *cur; + elaborate_scope_enumeration(des, 0, curp); + } +} + /* * If the pclass includes an implicit and explicit constructor, then * merge the implicit constructor into the explicit constructor as diff --git a/elab_sig.cc b/elab_sig.cc index 7f2c8780a..d60e2a1f5 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -965,7 +965,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const << "'." << endl; des->errors += 1; } - // A signal can not have the same name as a parameter. + // A signal can not have the same name as a parameter. Note + // that we treat enumeration literals similar to parameters, + // so if the name matches an enumeration literal, it will be + // caught here. const NetExpr *ex_msb, *ex_lsb; const NetExpr *parm = scope->get_parameter(des, name_, ex_msb, ex_lsb); if (parm) { diff --git a/elaborate.cc b/elaborate.cc index 4aa898d5c..1fa4d19be 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -5663,6 +5663,9 @@ Design* elaborate(listroots) // module and elaborate what I find. Design*des = new Design; + // Elaborate enum sets in $root scope. + elaborate_rootscope_enumerations(des); + // Elaborate the packages. Package elaboration is simpler // because there are fewer sub-scopes involved. i = 0; diff --git a/net_expr.cc b/net_expr.cc index 6ff935185..c0e92ed4d 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -260,7 +260,7 @@ void NetEConcat::set(unsigned idx, NetExpr*e) expr_width( expr_width() + repeat_ * e->expr_width() ); } -NetEConstEnum::NetEConstEnum(NetScope*s, perm_string n, const netenum_t*eset, const verinum&v) +NetEConstEnum::NetEConstEnum(Definitions*s, perm_string n, const netenum_t*eset, const verinum&v) : NetEConst(v), scope_(s), enum_set_(eset), name_(n) { assert(has_width()); diff --git a/net_scope.cc b/net_scope.cc index 64667c50e..410d1b16b 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -30,6 +30,59 @@ class PExpr; +Definitions::Definitions() +{ +} + +Definitions::~Definitions() +{ +} + +void Definitions::add_enumeration_set(netenum_t*enum_set) +{ + enum_sets_.push_back(enum_set); +} + +bool Definitions::add_enumeration_name(netenum_t*enum_set, perm_string name) +{ + netenum_t::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); + + pair::iterator, bool> cur; + cur = enum_names_.insert(make_pair(name,val)); + + // Return TRUE if the name is added (i.e. is NOT a duplicate.) + return cur.second; +} + +/* + * This locates the enumeration TYPE for the given enumeration literal. + */ +const netenum_t*Definitions::enumeration_for_name(perm_string name) +{ + NetEConstEnum*tmp = enum_names_[name]; + assert(tmp != 0); + + return tmp->enumeration(); +} + +/* + * This locates the VALUE for the given enumeration literal. + */ +const NetExpr* Definitions::enumeration_expr(perm_string key) +{ + map::const_iterator eidx; + + eidx = enum_names_.find(key); + if (eidx != enum_names_.end()) { + return eidx->second; + } else { + return 0; + } +} + /* * The NetScope class keeps a scope tree organized. Each node of the * scope tree points to its parent, its right sibling and its leftmost @@ -265,14 +318,13 @@ const NetExpr* NetScope::get_parameter(Design*des, return idx->second.val; } - map::const_iterator eidx; + msb = 0; + lsb = 0; + const NetExpr*tmp = enumeration_expr(key); + if (tmp) return tmp; - eidx = enum_names_.find(key); - if (eidx != enum_names_.end()) { - msb = 0; - lsb = 0; - return eidx->second; - } + tmp = des->enumeration_expr(key); + if (tmp) return tmp; return 0; } @@ -551,33 +603,6 @@ NetNet* NetScope::find_signal(perm_string key) return 0; } -void NetScope::add_enumeration_set(netenum_t*enum_set) -{ - enum_sets_.push_back(enum_set); -} - -bool NetScope::add_enumeration_name(netenum_t*enum_set, perm_string name) -{ - netenum_t::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); - - pair::iterator, bool> cur; - cur = enum_names_.insert(make_pair(name,val)); - - // Return TRUE if the name is added (i.e. is NOT a duplicate.) - return cur.second; -} - -const netenum_t*NetScope::enumeration_for_name(perm_string name) -{ - NetEConstEnum*tmp = enum_names_[name]; - assert(tmp != 0); - - return tmp->enumeration(); -} - void NetScope::add_class(netclass_t*net_class) { classes_[net_class->get_name()] = net_class; diff --git a/netlist.h b/netlist.h index 1f2a3ddbe..237019ce5 100644 --- a/netlist.h +++ b/netlist.h @@ -819,12 +819,44 @@ class NetBaseDef { NetProc*proc_; }; +/* + * Some definitions (and methods to manipulate them) are common to a + * couple of types. Keep them here. + */ +class Definitions { + + public: + Definitions(); + ~Definitions(); + + void add_enumeration_set(netenum_t*enum_set); + bool add_enumeration_name(netenum_t*enum_set, perm_string enum_name); + + // Look up the enumeration literal in this scope. if the name + // is present, then return the enumeration type that declares it. + const netenum_t* enumeration_for_name(perm_string name); + + // Look up an enumeration literal in this scope. If the + // literal is present, return the expression that defines its + // value. + const NetExpr* enumeration_expr(perm_string key); + + protected: + // Enumerations. The enum_sets_ is a list of all the + // 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_sets_; + std::map enum_names_; + +}; + /* * This object type is used to contain a logical scope within a * design. The scope doesn't represent any executable hardware, but is * just a handle that netlist processors can use to grab at the design. */ -class NetScope : public Attrib { +class NetScope : public Definitions, public Attrib { public: enum TYPE { MODULE, CLASS, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK, PACKAGE }; @@ -897,11 +929,6 @@ class NetScope : public Attrib { void rem_signal(NetNet*); NetNet* find_signal(perm_string name); - void add_enumeration_set(netenum_t*enum_set); - bool add_enumeration_name(netenum_t*enum_set, perm_string enum_name); - - const netenum_t* enumeration_for_name(perm_string name); - void add_class(netclass_t*class_type); netclass_t* find_class(perm_string name); @@ -1153,13 +1180,6 @@ class NetScope : public Attrib { const PFunction*func_pform_; unsigned elab_stage_; - // Enumerations. The enum_sets_ is a list of all the - // 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_sets_; - std::map enum_names_; - std::map classes_; NetScope*up_; @@ -1973,12 +1993,11 @@ class NetEConst : public NetExpr { class NetEConstEnum : public NetEConst { public: - explicit NetEConstEnum(NetScope*scope, perm_string name, + explicit NetEConstEnum(Definitions*scope, perm_string name, const netenum_t*enum_set, const verinum&val); ~NetEConstEnum(); perm_string name() const; - const NetScope*scope() const; const netenum_t*enumeration() const; virtual void expr_scan(struct expr_scan_t*) const; @@ -1987,7 +2006,7 @@ class NetEConstEnum : public NetEConst { virtual NetEConstEnum* dup_expr() const; private: - NetScope*scope_; + Definitions*scope_; const netenum_t*enum_set_; perm_string name_; }; @@ -4499,7 +4518,7 @@ struct elaborator_work_item_t { * This class contains an entire design. It includes processes and a * netlist, and can be passed around from function to function. */ -class Design { +class Design : public Definitions { public: Design(); diff --git a/parse_api.h b/parse_api.h index e334c0443..8101e4295 100644 --- a/parse_api.h +++ b/parse_api.h @@ -24,11 +24,14 @@ # include # include # include +# include +class Design; class Module; class PPackage; class PUdp; class data_type_t; +class enum_type_t; /* * These are maps of the modules and primitives parsed from the @@ -38,10 +41,13 @@ class data_type_t; extern std::map pform_modules; extern std::map pform_primitives; extern std::map pform_typedefs; +extern std::set pform_enum_sets; extern std::map pform_packages; extern void pform_dump(std::ostream&out, const PPackage*pac); +extern void elaborate_rootscope_enumerations(Design*des); + /* * This code actually invokes the parser to make modules. The first * parameter is the name of the file that is to be parsed. The diff --git a/pform.cc b/pform.cc index e67417ec5..9a72eceab 100644 --- a/pform.cc +++ b/pform.cc @@ -55,6 +55,7 @@ map pform_primitives; * typedefs in the $root scope go here. */ mappform_typedefs; +setpform_enum_sets; std::string vlltype::get_fileline() const { @@ -487,7 +488,12 @@ static void pform_put_wire_in_scope(perm_string name, PWire*net) static void pform_put_enum_type_in_scope(enum_type_t*enum_set) { - lexical_scope->enum_sets.insert(enum_set); + if (lexical_scope) { + ivl_assert(*enum_set, lexical_scope); + lexical_scope->enum_sets.insert(enum_set); + } else { + pform_enum_sets.insert(enum_set); + } } PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type)