From 396ffd1cdd29bb1dc6e16e394f171a66cb3bd354 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 21 Jun 2007 19:04:48 -0700 Subject: [PATCH] Add support for conditional generate. In the process, fix bugs related to generate used multiple times by multiple scopes causing spurious generation results. Signed-off-by: Stephen Williams --- PGenerate.h | 12 ++++++--- elab_scope.cc | 70 ++++++++++++++++++++++++++++++++++++++++++++------- elab_sig.cc | 12 ++++++--- elaborate.cc | 14 ++++++++--- parse.y | 33 ++++++++++++++---------- pform.cc | 50 ++++++++++++++++++++++++++++++++++++ pform.h | 2 ++ pform_dump.cc | 4 +++ 8 files changed, 165 insertions(+), 32 deletions(-) diff --git a/PGenerate.h b/PGenerate.h index 010c3793a..39be19f47 100644 --- a/PGenerate.h +++ b/PGenerate.h @@ -50,7 +50,7 @@ class PGenerate : public LineInfo { const unsigned id_number; perm_string scope_name; - enum scheme_t {GS_NONE, GS_LOOP, GS_CONDIT}; + enum scheme_t {GS_NONE, GS_LOOP, GS_CONDIT, GS_ELSE}; scheme_t scheme_type; // generate loops have an index variable and three @@ -78,13 +78,19 @@ class PGenerate : public LineInfo { // contain the generated scope. bool generate_scope(Design*des, NetScope*container); - bool elaborate_sig(Design*des) const; - bool elaborate(Design*des) const; + // Elaborate signals within any of the generated scopes that + // were made by this generate block within the given container scope. + bool elaborate_sig(Design*des, NetScope*container) const; + bool elaborate(Design*des, NetScope*container) const; void dump(ostream&out, unsigned indent) const; private: bool generate_scope_loop_(Design*des, NetScope*container); + bool generate_scope_condit_(Design*des, NetScope*container, bool else_flag); + + // Elaborate_scope within a generated scope. + void elaborate_subscope_(Design*des, NetScope*scope); // These are the scopes created by generate_scope. listscope_list_; diff --git a/elab_scope.cc b/elab_scope.cc index 6288e6028..059e715ef 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -146,6 +146,12 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, ; cur != replacements.end() ; cur ++) { NetExpr*val = (*cur).second; + if (val == 0) { + cerr << get_line() << ": internal error: " + << "Missing expression in parameter replacement for " + << (*cur).first; + } + assert(val); if (debug_scopes) { cerr << get_line() << ": debug: " << "Replace " << (*cur).first @@ -309,6 +315,12 @@ bool PGenerate::generate_scope(Design*des, NetScope*container) case GS_LOOP: return generate_scope_loop_(des, container); + case GS_CONDIT: + return generate_scope_condit_(des, container, false); + + case GS_ELSE: + return generate_scope_condit_(des, container, true); + default: cerr << get_line() << ": sorry: Generate of this sort" << " is not supported yet!" << endl; @@ -379,15 +391,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) << loop_index << " = " << genvar_verinum << endl; } - // Scan the generated scope for gates that may create - // their own scopes. - typedef list::const_iterator pgate_list_it_t; - for (pgate_list_it_t cur = gates.begin() - ; cur != gates.end() ; cur ++) { - (*cur) ->elaborate_scope(des, scope); - } - - scope_list_.push_back(scope); + elaborate_subscope_(des, scope); // Calculate the step for the loop variable. NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1); @@ -413,6 +417,54 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) return true; } +bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else_flag) +{ + NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1); + NetEConst*test = dynamic_cast (test_ex); + assert(test); + + // If the condition evaluates as false, then do not create the + // scope. + if (test->value().as_long() == 0 && !else_flag + || test->value().as_long() != 0 && else_flag) { + if (debug_elaborate) + cerr << get_line() << ": debug: Generate condition " + << (else_flag? "(else)" : "(if)") + << " value=" << test->value() << ": skip generation" + << endl; + delete test_ex; + return true; + } + + hname_t use_name (scope_name); + if (debug_elaborate) + cerr << get_line() << ": debug: Generate condition " + << (else_flag? "(else)" : "(if)") + << " value=" << test->value() << ": Generate scope=" + << use_name << endl; + + NetScope*scope = new NetScope(container, use_name, + NetScope::GENBLOCK); + + elaborate_subscope_(des, scope); + + return true; +} + +void PGenerate::elaborate_subscope_(Design*des, NetScope*scope) +{ + // Scan the generated scope for gates that may create + // their own scopes. + typedef list::const_iterator pgate_list_it_t; + for (pgate_list_it_t cur = gates.begin() + ; cur != gates.end() ; cur ++) { + (*cur) ->elaborate_scope(des, scope); + } + + // Save the scope that we created, for future use. + scope_list_.push_back(scope); +} + void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const { if (get_name() == "") { diff --git a/elab_sig.cc b/elab_sig.cc index 1d85de367..13c8bb617 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -186,7 +186,7 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const typedef list::const_iterator generate_it_t; for (generate_it_t cur = generate_schemes.begin() ; cur != generate_schemes.end() ; cur ++ ) { - (*cur) -> elaborate_sig(des); + (*cur) -> elaborate_sig(des, scope); } // Get all the gates of the module and elaborate them by @@ -269,7 +269,7 @@ bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope, return flag; } -bool PGenerate::elaborate_sig(Design*des) const +bool PGenerate::elaborate_sig(Design*des, NetScope*container) const { bool flag = true; @@ -277,9 +277,15 @@ bool PGenerate::elaborate_sig(Design*des) const for (scope_list_it_t cur = scope_list_.begin() ; cur != scope_list_.end() ; cur ++ ) { + NetScope*scope = *cur; + + if (scope->parent() != container) + continue; + if (debug_elaborate) cerr << get_line() << ": debug: Elaborate nets in " - << "scope " << scope_path(*cur) << endl; + << "scope " << scope_path(*cur) + << " in generate " << id_number << endl; flag = elaborate_sig_(des, *cur) & flag; } diff --git a/elaborate.cc b/elaborate.cc index 3bb05da07..e54cade9d 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3227,7 +3227,7 @@ bool Module::elaborate(Design*des, NetScope*scope) const typedef list::const_iterator generate_it_t; for (generate_it_t cur = generate_schemes.begin() ; cur != generate_schemes.end() ; cur ++ ) { - (*cur)->elaborate(des); + (*cur)->elaborate(des, scope); } // Elaborate functions. @@ -3288,7 +3288,7 @@ bool Module::elaborate(Design*des, NetScope*scope) const return result_flag; } -bool PGenerate::elaborate(Design*des) const +bool PGenerate::elaborate(Design*des, NetScope*container) const { bool flag = true; @@ -3296,11 +3296,17 @@ bool PGenerate::elaborate(Design*des) const for (scope_list_it_t cur = scope_list_.begin() ; cur != scope_list_.end() ; cur ++ ) { + NetScope*scope = *cur; + // Check that this scope is one that is contained in the + // container that the caller passed in. + if (scope->parent() != container) + continue; + if (debug_elaborate) cerr << get_line() << ": debug: Elaborate in " - << "scope " << scope_path(*cur) << endl; + << "scope " << scope_path(scope) << endl; - flag = elaborate_(des, *cur) & flag; + flag = elaborate_(des, scope) & flag; } return flag; diff --git a/parse.y b/parse.y index 507fa5f87..a20b40146 100644 --- a/parse.y +++ b/parse.y @@ -1894,22 +1894,28 @@ module_item is supposed to be limited to certain kinds of module items, but the semantic tests will check that for us. */ - | K_generate module_item_list_opt K_endgenerate + | K_generate module_item_list_opt K_endgenerate - | K_genvar list_of_identifiers ';' - { pform_genvars($2); } + | K_genvar list_of_identifiers ';' + { pform_genvars($2); } - | K_for '(' IDENTIFIER '=' expression ';' - expression ';' - IDENTIFIER '=' expression ')' - { pform_start_generate_for(@1, $3, $5, $7, $9, $11); } - generate_block - { pform_endgenerate(); } + | K_for '(' IDENTIFIER '=' expression ';' + expression ';' + IDENTIFIER '=' expression ')' + { pform_start_generate_for(@1, $3, $5, $7, $9, $11); } + generate_block + { pform_endgenerate(); } - | K_if '(' expression ')' generate_block_opt K_else generate_block - { yyerror(@1, "sorry: Condition generate not supported yet."); - } + | generate_if + generate_block_opt + K_else + { pform_start_generate_else(@1); } + generate_block + { pform_endgenerate(); } + | generate_if + generate_block_opt %prec less_than_K_else + { pform_endgenerate(); } /* specify blocks are parsed but ignored. */ @@ -1966,6 +1972,7 @@ module_item { yyerror(@1, "error: Malformed $attribute parameter list."); } ; +generate_if : K_if '(' expression ')' { pform_start_generate_if(@1, $3); } module_item_list : module_item_list module_item @@ -1990,7 +1997,7 @@ generate_block { pform_generate_block_name($3); } ; -generate_block_opt : generate_block | ; +generate_block_opt : generate_block | ';' ; /* A net declaration assignment allows the programmer to combine the diff --git a/pform.cc b/pform.cc index 801f866a1..1f14597a0 100644 --- a/pform.cc +++ b/pform.cc @@ -362,6 +362,48 @@ void pform_start_generate_for(const struct vlltype&li, delete[]ident2; } +void pform_start_generate_if(const struct vlltype&li, PExpr*test) +{ + PGenerate*gen = new PGenerate(scope_generate_counter++); + + gen->set_file(li.text); + gen->set_lineno(li.first_line); + + // For now, assume that generates do not nest. + gen->parent = pform_cur_generate; + pform_cur_generate = gen; + + pform_cur_generate->scheme_type = PGenerate::GS_CONDIT; + + pform_cur_generate->loop_init = 0; + pform_cur_generate->loop_test = test; + pform_cur_generate->loop_step = 0; +} + +void pform_start_generate_else(const struct vlltype&li) +{ + assert(pform_cur_generate); + assert(pform_cur_generate->scheme_type == PGenerate::GS_CONDIT); + + PGenerate*cur = pform_cur_generate; + pform_endgenerate(); + + PGenerate*gen = new PGenerate(scope_generate_counter++); + + gen->set_file(li.text); + gen->set_lineno(li.first_line); + + // For now, assume that generates do not nest. + gen->parent = pform_cur_generate; + pform_cur_generate = gen; + + pform_cur_generate->scheme_type = PGenerate::GS_ELSE; + + pform_cur_generate->loop_init = 0; + pform_cur_generate->loop_test = cur->loop_test; + pform_cur_generate->loop_step = 0; +} + void pform_generate_block_name(char*name) { assert(pform_cur_generate != 0); @@ -375,6 +417,14 @@ void pform_endgenerate() assert(pform_cur_generate != 0); assert(pform_cur_module); + // If there is no explicit block name, then use a default + // internal name. + if (pform_cur_generate->scope_name == 0) { + char tmp[16]; + snprintf(tmp, sizeof tmp, "$gen%d", pform_cur_generate->id_number); + pform_cur_generate->scope_name = lex_strings.make(tmp); + } + PGenerate*cur = pform_cur_generate; pform_cur_generate = cur->parent; diff --git a/pform.h b/pform.h index 0f3f0a52e..8899b16e9 100644 --- a/pform.h +++ b/pform.h @@ -186,6 +186,8 @@ extern void pform_start_generate_for(const struct vlltype&li, PExpr*test, char*ident2, PExpr*next); +extern void pform_start_generate_if(const struct vlltype&li, PExpr*test); +extern void pform_start_generate_else(const struct vlltype&li); extern void pform_generate_block_name(char*name); extern void pform_endgenerate(); diff --git a/pform_dump.cc b/pform_dump.cc index 8f97a3485..da02a1b28 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -839,6 +839,10 @@ void PGenerate::dump(ostream&out, unsigned indent) const << "=" << *loop_step << ")"; break; case GS_CONDIT: + out << " if (" << *loop_test << ")"; + break; + case GS_ELSE: + out << " else !(" << *loop_test << ")"; break; }