From 2e2317b7c7f4d97ae18d94e05794f71e49542bd4 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 30 Mar 2014 17:20:42 -0700 Subject: [PATCH] Generalize the hname_t to handle n-dimensional scope arrays. ... Not that they actually exist yet. But this fixes some symbol search issues and makes room for this support in the future. --- HName.cc | 68 ++++++++++++++++++++++++++++++++++-------------- HName.h | 34 ++++++++++++------------ design_dump.cc | 4 +-- elab_scope.cc | 6 +++-- elab_sig.cc | 2 +- net_scope.cc | 15 +++++++++++ netlist.h | 6 +++++ netmisc.cc | 70 ++++++++++++++++++++++++-------------------------- t-dll.cc | 15 ++++++++--- 9 files changed, 140 insertions(+), 80 deletions(-) diff --git a/HName.cc b/HName.cc index 709528489..c783d57bb 100644 --- a/HName.cc +++ b/HName.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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,22 +22,26 @@ # include # include # include -# include +using namespace std; hname_t::hname_t() { - number_ = INT_MIN; } hname_t::hname_t(perm_string text) : name_(text) { - number_ = INT_MIN; } hname_t::hname_t(perm_string text, int num) -: name_(text), number_(num) +: name_(text), number_(1) +{ + number_[0] = num; +} + +hname_t::hname_t(perm_string text, vector&nums) +: name_(text), number_(nums) { } @@ -53,24 +57,50 @@ hname_t& hname_t::operator = (const hname_t&that) return *this; } -bool operator < (const hname_t&l, const hname_t&r) +bool hname_t::operator < (const hname_t&r) const { - int cmp = strcmp(l.peek_name(), r.peek_name()); + int cmp = strcmp(name_, r.name_); if (cmp < 0) return true; if (cmp > 0) return false; - if (l.has_number() && r.has_number()) - return l.peek_number() < r.peek_number(); - else - return false; + + // The text parts are equal, so compare then number + // parts. Finish as soon as we find one to be less or more + // than the other. + size_t idx = 0; + while (number_.size() > idx || r.number_.size() > idx) { + + // Ran out of l numbers, so less. + if (number_.size() <= idx) + return true; + + // Ran out of r numbers, so greater. + if (r.number_.size() <= idx) + return false; + + if (number_[idx] < r.number_[idx]) + return true; + + if (number_[idx] > r.number_[idx]) + return false; + + idx += 1; + } + + // Fall-through means that we are equal, including all the + // number parts, so not less. + return false; } -bool operator == (const hname_t&l, const hname_t&r) +bool hname_t::operator == (const hname_t&r) const { - if (l.peek_name() == r.peek_name()) { - if (l.has_number() && r.has_number()) - return l.peek_number() == r.peek_number(); - else - return true; + if (name_ == r.name_) { + if (number_.size() != r.number_.size()) + return false; + + for (size_t idx = 0 ; idx < number_.size() ; idx += 1) + if (number_[idx] != r.number_[idx]) return false; + + return true; } return false; @@ -84,8 +114,8 @@ ostream& operator<< (ostream&out, const hname_t&that) } out << that.peek_name(); - if (that.has_number()) - out << "[" << that.peek_number() << "]"; + for (size_t idx = 0 ; idx < that.number_.size() ; idx += 1) + out << "[" << that.number_[idx] << "]"; return out; } diff --git a/HName.h b/HName.h index ce561f8f0..6d1f3ccb7 100644 --- a/HName.h +++ b/HName.h @@ -1,7 +1,7 @@ #ifndef __HName_H #define __HName_H /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2014 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,13 +21,10 @@ # include # include +# include # include "StringHeap.h" -# include -#ifdef __GNUC__ -#if __GNUC__ > 2 -using namespace std; -#endif -#endif + +# include /* * This class represents a component of a Verilog hierarchical name. A @@ -39,27 +36,33 @@ using namespace std; class hname_t { + friend ostream& operator<< (ostream&out, const hname_t&that); + public: hname_t (); explicit hname_t (perm_string text); explicit hname_t (perm_string text, int num); + explicit hname_t (perm_string text, std::vector&nums); hname_t (const hname_t&that); ~hname_t(); hname_t& operator= (const hname_t&); + bool operator == (const hname_t&that) const; + bool operator < (const hname_t&that) const; + // Return the string part of the hname_t. perm_string peek_name(void) const; - bool has_number() const; - int peek_number() const; + size_t has_numbers() const; + int peek_number(size_t idx) const; private: perm_string name_; // If the number is anything other than INT_MIN, then this is // the numeric part of the name. Otherwise, it is not part of // the name at all. - int number_; + std::vector number_; private: // not implemented }; @@ -73,18 +76,17 @@ inline perm_string hname_t::peek_name(void) const return name_; } -inline int hname_t::peek_number() const +inline int hname_t::peek_number(size_t idx) const { - return number_; + assert(number_.size() > idx); + return number_[idx]; } -inline bool hname_t::has_number() const +inline size_t hname_t::has_numbers() const { - return number_ != INT_MIN; + return number_.size(); } -extern bool operator < (const hname_t&, const hname_t&); -extern bool operator == (const hname_t&, const hname_t&); extern ostream& operator<< (ostream&, const hname_t&); inline bool operator != (const hname_t&l, const hname_t&r) diff --git a/design_dump.cc b/design_dump.cc index 52627302f..9a8a256d7 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -200,9 +200,7 @@ static inline void dump_scope_path(ostream&o, const NetScope*scope) o << "."; } const hname_t name = scope->fullname(); - o << name.peek_name(); - if (name.has_number()) - o << "[" << name.peek_number() << "]"; + o << name; } ostream& operator <<(ostream&o, struct __ScopePathManip marg) diff --git a/elab_scope.cc b/elab_scope.cc index 1b78ac894..2d70d938b 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -883,8 +883,10 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) // Check the generate block name. - // A generate "loop" can not have the same name as another scope object. - const NetScope *child = container->child(hname_t(scope_name)); + // A generate "loop" can not have the same name as another + // scope object. Find any scope with this name, not just an + // exact match scope. + const NetScope *child = container->child_byname(scope_name); if (child) { cerr << get_fileline() << ": error: generate \"loop\" and "; child->print_type(cerr); diff --git a/elab_sig.cc b/elab_sig.cc index 4b8b0ec36..2d6fdcf9b 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -949,7 +949,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const des->errors += error_cnt_; // A signal can not have the same name as a scope object. - const NetScope *child = scope->child(hname_t(name_)); + const NetScope *child = scope->child_byname(name_); if (child) { cerr << get_fileline() << ": error: signal and "; child->print_type(cerr); diff --git a/net_scope.cc b/net_scope.cc index e72a31133..ba9782a56 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -668,6 +668,21 @@ const NetScope* NetScope::child(const hname_t&name) const return cur->second; } +const NetScope* NetScope::child_byname(perm_string name) const +{ + hname_t hname (name); + map::const_iterator cur = children_.lower_bound(hname); + + if (cur == children_.end()) + return 0; + + if (cur->first.peek_name() == name) + return cur->second; + + return 0; +} + + perm_string NetScope::local_symbol() { ostringstream res; diff --git a/netlist.h b/netlist.h index 58d2e5d7f..4f49bf9b2 100644 --- a/netlist.h +++ b/netlist.h @@ -966,6 +966,12 @@ class NetScope : public Definitions, public Attrib { const NetScope* parent() const { return up_; } const NetScope* child(const hname_t&name) const; + // Look for a child scope by name. This ignores the number + // part of the child scope name, so there may be multiple + // matches. Only return one. This function is only really + // useful for some elaboration error checking. + const NetScope* child_byname(perm_string name) const; + // Nested modules have slightly different scope search rules. inline bool nested_module() const { return nested_module_; } // Program blocks have elaboration constraints. diff --git a/netmisc.cc b/netmisc.cc index 4271720a7..ec08cffdf 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -950,50 +950,48 @@ hname_t eval_path_component(Design*des, NetScope*scope, if (comp.index.empty()) return hname_t(comp.name); - // The parser will assure that path components will have only - // one index. For example, foo[N] is one index, foo[n][m] is two. - assert(comp.index.size() == 1); + vector index_values; - const index_component_t&index = comp.index.front(); + for (list::const_iterator cur = comp.index.begin() + ; cur != comp.index.end() ; ++cur) { + const index_component_t&index = *cur; - if (index.sel != index_component_t::SEL_BIT) { - cerr << index.msb->get_fileline() << ": error: " - << "Part select is not valid for this kind of object." << endl; - des->errors += 1; - return hname_t(comp.name, 0); - } + if (index.sel != index_component_t::SEL_BIT) { + cerr << index.msb->get_fileline() << ": error: " + << "Part select is not valid for this kind of object." << endl; + des->errors += 1; + return hname_t(comp.name, 0); + } - // The parser will assure that path components will have only - // bit select index expressions. For example, "foo[n]" is OK, - // but "foo[n:m]" is not. - assert(index.sel == index_component_t::SEL_BIT); + // The parser will assure that path components will have only + // bit select index expressions. For example, "foo[n]" is OK, + // but "foo[n:m]" is not. + assert(index.sel == index_component_t::SEL_BIT); - // Evaluate the bit select to get a number. - NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1); - ivl_assert(*index.msb, tmp); - - // Now we should have a constant value for the bit select - // expression, and we can use it to make the final hname_t - // value, for example "foo[5]". - if (NetEConst*ctmp = dynamic_cast(tmp)) { - hname_t res(comp.name, ctmp->value().as_long()); - delete ctmp; - return res; - } + // Evaluate the bit select to get a number. + NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1); + ivl_assert(*index.msb, tmp); + if (NetEConst*ctmp = dynamic_cast(tmp)) { + index_values.push_back(ctmp->value().as_long()); + delete ctmp; + continue; + } #if 1 - // Darn, the expression doesn't evaluate to a constant. That's - // an error to be reported. And make up a fake index value to - // return to the caller. - cerr << index.msb->get_fileline() << ": error: " - << "Scope index expression is not constant: " - << *index.msb << endl; - des->errors += 1; + // Darn, the expression doesn't evaluate to a constant. That's + // an error to be reported. And make up a fake index value to + // return to the caller. + cerr << index.msb->get_fileline() << ": error: " + << "Scope index expression is not constant: " + << *index.msb << endl; + des->errors += 1; #endif - error_flag = true; + error_flag = true; - delete tmp; - return hname_t (comp.name, 0); + delete tmp; + } + + return hname_t(comp.name, index_values); } std::list eval_scope_path(Design*des, NetScope*scope, diff --git a/t-dll.cc b/t-dll.cc index d28d44c48..a068bb59b 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -160,12 +160,21 @@ inline static const char *basename(ivl_scope_t scope, const char *inst) static perm_string make_scope_name(const hname_t&name) { - if (! name.has_number()) + if (! name.has_numbers()) return name.peek_name(); char buf[1024]; - snprintf(buf, sizeof buf, "%s[%d]", - name.peek_name().str(), name.peek_number()); + snprintf(buf, sizeof buf, "%s", name.peek_name().str()); + + char*cp = buf + strlen(buf); + size_t ncp = sizeof buf - (cp-buf); + + for (size_t idx = 0 ; idx < name.has_numbers() ; idx += 1) { + int len = snprintf(cp, ncp, "[%d]", name.peek_number(idx)); + cp += len; + ncp -= len; + } + return lex_strings.make(buf); }