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.
This commit is contained in:
parent
e2bad56a5c
commit
2e2317b7c7
68
HName.cc
68
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 <iostream>
|
||||
# include <cstring>
|
||||
# include <cstdlib>
|
||||
# include <climits>
|
||||
|
||||
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<int>&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;
|
||||
}
|
||||
|
|
|
|||
34
HName.h
34
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 <iostream>
|
||||
# include <list>
|
||||
# include <vector>
|
||||
# include "StringHeap.h"
|
||||
# include <climits>
|
||||
#ifdef __GNUC__
|
||||
#if __GNUC__ > 2
|
||||
using namespace std;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
# include <cassert>
|
||||
|
||||
/*
|
||||
* 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<int>&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<int> 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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
15
net_scope.cc
15
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<hname_t,NetScope*>::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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
70
netmisc.cc
70
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<int> index_values;
|
||||
|
||||
const index_component_t&index = comp.index.front();
|
||||
for (list<index_component_t>::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<NetEConst*>(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<NetEConst*>(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<hname_t> eval_scope_path(Design*des, NetScope*scope,
|
||||
|
|
|
|||
15
t-dll.cc
15
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue