From 360be597a86b6f50709aedc03b51cd446504a3f5 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 21 Jun 2008 18:36:46 -0700 Subject: [PATCH] Minor cleanup and comments. The initial elaboration needs better comments/documentation. --- elaborate.cc | 39 +++++++++++++++++++------- netmisc.cc | 76 +++++++++++++++++++++++++++++++++++---------------- netmisc.h | 10 +++++++ pform_types.h | 26 +++++++++++++++++- 4 files changed, 116 insertions(+), 35 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index a0d8d73a0..cc8bbf90c 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3775,6 +3775,12 @@ struct root_elem { NetScope *scope; }; +/* + * This function is the root of all elaboration. The input is the list + * of root module names. The function locates the Module definitions + * for each root, does the whole elaboration sequence, and fills in + * the resulting Design. + */ Design* elaborate(listroots) { svector root_elems(roots.size()); @@ -3785,7 +3791,7 @@ Design* elaborate(listroots) // module and elaborate what I find. Design*des = new Design; - // Scan the root modules, and elaborate their scopes. + // Scan the root modules by name, and elaborate their scopes. for (list::const_iterator root = roots.begin() ; root != roots.end() ; root++) { @@ -3804,29 +3810,42 @@ Design* elaborate(listroots) // Get the module definition for this root instance. Module *rmod = (*mod).second; - // Make the root scope. + // Make the root scope. This makes a NetScoep object and + // pushes it into the list of root scopes in the Design. NetScope*scope = des->make_root_scope(*root); + + // Collect some basic properties of this scope from the + // Module definition. scope->set_line(rmod); scope->time_unit(rmod->time_unit); scope->time_precision(rmod->time_precision); scope->default_nettype(rmod->default_nettype); des->set_precision(rmod->time_precision); - Module::replace_t stub; - - // Recursively elaborate from this root scope down. This - // does a lot of the grunt work of creating sub-scopes, etc. - if (! rmod->elaborate_scope(des, scope, stub)) { - delete des; - return 0; - } + // Save this scope, along with its defintion, in the + // "root_elems" list for later passes. struct root_elem *r = new struct root_elem; r->mod = rmod; r->scope = scope; root_elems[i++] = r; } + // Elaborate the instances of the root modules into the root + // scopes that we created. The elaborate_scope for each will + // recurse down the design, furtner elaborating sub-scope all + // the way down to the leaves. + for (i = 0; i < root_elems.count(); i += 1) { + Module*rmod = root_elems[i]->mod; + NetScope*scope = root_elems[i]->scope; + + Module::replace_t stub; + if (! rmod->elaborate_scope(des, scope, stub)) { + delete des; + return 0; + } + } + // Errors already? Probably missing root modules. Just give up // now and return nothing. if (des->errors > 0) diff --git a/netmisc.cc b/netmisc.cc index 2cab1dc8d..e6e6e5659 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -244,6 +244,57 @@ bool eval_as_double(double&value, NetExpr*expr) return false; } +/* + * At the parser level, a name component it a name with a collection + * of expressions. For example foo[N] is the name "foo" and the index + * expression "N". This function takes as input the name component and + * returns the path component name. It will evaulate the index + * expression if it is present. + */ +hname_t eval_path_component(Design*des, NetScope*scope, + const name_component_t&comp) +{ + // No index exression, so the path component is an undecorated + // name, for example "foo". + 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); + + const index_component_t&index = comp.index.front(); + + // 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; + } + + // Darn, the expression doesn't evaluate to a constant. That's + // and 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; + + delete tmp; + return hname_t (comp.name, 0); +} + std::list eval_scope_path(Design*des, NetScope*scope, const pform_name_t&path) { @@ -253,30 +304,7 @@ std::list eval_scope_path(Design*des, NetScope*scope, for (pform_path_it cur = path.begin() ; cur != path.end(); cur++) { const name_component_t&comp = *cur; - if (comp.index.empty()) { - res.push_back(hname_t(comp.name)); - continue; - } - - assert(comp.index.size() == 1); - const index_component_t&index = comp.index.front(); - assert(index.sel == index_component_t::SEL_BIT); - - NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1); - ivl_assert(*index.msb, tmp); - - if (NetEConst*ctmp = dynamic_cast(tmp)) { - res.push_back(hname_t(comp.name, ctmp->value().as_long())); - delete ctmp; - continue; - } else { - cerr << index.msb->get_fileline() << ": error: " - << "Scope index expression is not constant: " - << *index.msb << endl; - des->errors += 1; - } - - return res; + res.push_back( eval_path_component(des,scope,comp) ); } return res; diff --git a/netmisc.h b/netmisc.h index 20efe2d98..7d1b42a90 100644 --- a/netmisc.h +++ b/netmisc.h @@ -152,6 +152,16 @@ void eval_expr(NetExpr*&expr, int prune_width =-1); bool eval_as_long(long&value, NetExpr*expr); bool eval_as_double(double&value, NetExpr*expr); +/* + * Evaluate the component of a scope path to get an hname_t value. Do + * the evaluation in the context of the given scope. + */ +extern hname_t eval_path_component(Design*des, NetScope*scope, + const name_component_t&comp); + +/* + * Evaluate an entire scope path in the context of the given scope. + */ extern std::list eval_scope_path(Design*des, NetScope*scope, const pform_name_t&path); diff --git a/pform_types.h b/pform_types.h index 25c3324a2..35f0039e8 100644 --- a/pform_types.h +++ b/pform_types.h @@ -53,10 +53,34 @@ struct name_component_t { extern bool operator < (const name_component_t&lef, const name_component_t&rig); /* - * The pform_name_t is the general form for a hierarchical identifier. + * The pform_name_t is the general form for a hierarchical + * identifier. It is an ordered list of name components. Each name + * component is an identifier and an optional list of bit/part + * selects. The simplest name component is a simple identifier: + * + * foo + * + * The bit/part selects come from the source and are made part of the + * name component. A bit select is a single number that may be a bit + * select of a vector or a word select of an array: + * + * foo[5] -- a bit select/word index + * foo[6:4] -- a part select + * + * The index components of a name component are collected into an + * ordered list, so there may be many, for example: + * + * foo[5][6:4] -- a part select of an array word + * + * The pform_name_t, then, is an ordered list of these name + * components. The list of names comes from a hierarchical name in the + * source, like this: + * + * foo[5].bar[6:4] -- a part select of a vector in sub-scope foo[5]. */ typedef std::list pform_name_t; + inline perm_string peek_head_name(const pform_name_t&that) { return that.front().name;