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 <steve@icarus.com>
This commit is contained in:
Stephen Williams 2007-06-21 19:04:48 -07:00
parent 9d2dd782c0
commit 396ffd1cdd
8 changed files with 165 additions and 32 deletions

View File

@ -50,7 +50,7 @@ class PGenerate : public LineInfo {
const unsigned id_number; const unsigned id_number;
perm_string scope_name; 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; scheme_t scheme_type;
// generate loops have an index variable and three // generate loops have an index variable and three
@ -78,13 +78,19 @@ class PGenerate : public LineInfo {
// contain the generated scope. // contain the generated scope.
bool generate_scope(Design*des, NetScope*container); bool generate_scope(Design*des, NetScope*container);
bool elaborate_sig(Design*des) const; // Elaborate signals within any of the generated scopes that
bool elaborate(Design*des) const; // 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; void dump(ostream&out, unsigned indent) const;
private: private:
bool generate_scope_loop_(Design*des, NetScope*container); 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. // These are the scopes created by generate_scope.
list<NetScope*>scope_list_; list<NetScope*>scope_list_;

View File

@ -146,6 +146,12 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
; cur != replacements.end() ; cur ++) { ; cur != replacements.end() ; cur ++) {
NetExpr*val = (*cur).second; 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) { if (debug_scopes) {
cerr << get_line() << ": debug: " cerr << get_line() << ": debug: "
<< "Replace " << (*cur).first << "Replace " << (*cur).first
@ -309,6 +315,12 @@ bool PGenerate::generate_scope(Design*des, NetScope*container)
case GS_LOOP: case GS_LOOP:
return generate_scope_loop_(des, container); 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: default:
cerr << get_line() << ": sorry: Generate of this sort" cerr << get_line() << ": sorry: Generate of this sort"
<< " is not supported yet!" << endl; << " is not supported yet!" << endl;
@ -379,15 +391,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
<< loop_index << " = " << genvar_verinum << endl; << loop_index << " = " << genvar_verinum << endl;
} }
// Scan the generated scope for gates that may create elaborate_subscope_(des, scope);
// their own scopes.
typedef list<PGate*>::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);
// Calculate the step for the loop variable. // Calculate the step for the loop variable.
NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1); 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; 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<NetEConst*> (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<PGate*>::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 void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
{ {
if (get_name() == "") { if (get_name() == "") {

View File

@ -186,7 +186,7 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
typedef list<PGenerate*>::const_iterator generate_it_t; typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generate_schemes.begin() for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++ ) { ; 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 // 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; return flag;
} }
bool PGenerate::elaborate_sig(Design*des) const bool PGenerate::elaborate_sig(Design*des, NetScope*container) const
{ {
bool flag = true; bool flag = true;
@ -277,9 +277,15 @@ bool PGenerate::elaborate_sig(Design*des) const
for (scope_list_it_t cur = scope_list_.begin() for (scope_list_it_t cur = scope_list_.begin()
; cur != scope_list_.end() ; cur ++ ) { ; cur != scope_list_.end() ; cur ++ ) {
NetScope*scope = *cur;
if (scope->parent() != container)
continue;
if (debug_elaborate) if (debug_elaborate)
cerr << get_line() << ": debug: Elaborate nets in " 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; flag = elaborate_sig_(des, *cur) & flag;
} }

View File

@ -3227,7 +3227,7 @@ bool Module::elaborate(Design*des, NetScope*scope) const
typedef list<PGenerate*>::const_iterator generate_it_t; typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generate_schemes.begin() for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++ ) { ; cur != generate_schemes.end() ; cur ++ ) {
(*cur)->elaborate(des); (*cur)->elaborate(des, scope);
} }
// Elaborate functions. // Elaborate functions.
@ -3288,7 +3288,7 @@ bool Module::elaborate(Design*des, NetScope*scope) const
return result_flag; return result_flag;
} }
bool PGenerate::elaborate(Design*des) const bool PGenerate::elaborate(Design*des, NetScope*container) const
{ {
bool flag = true; bool flag = true;
@ -3296,11 +3296,17 @@ bool PGenerate::elaborate(Design*des) const
for (scope_list_it_t cur = scope_list_.begin() for (scope_list_it_t cur = scope_list_.begin()
; cur != scope_list_.end() ; cur ++ ) { ; 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) if (debug_elaborate)
cerr << get_line() << ": debug: Elaborate in " 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; return flag;

33
parse.y
View File

@ -1894,22 +1894,28 @@ module_item
is supposed to be limited to certain kinds of module items, but is supposed to be limited to certain kinds of module items, but
the semantic tests will check that for us. */ 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 ';' | K_genvar list_of_identifiers ';'
{ pform_genvars($2); } { pform_genvars($2); }
| K_for '(' IDENTIFIER '=' expression ';' | K_for '(' IDENTIFIER '=' expression ';'
expression ';' expression ';'
IDENTIFIER '=' expression ')' IDENTIFIER '=' expression ')'
{ pform_start_generate_for(@1, $3, $5, $7, $9, $11); } { pform_start_generate_for(@1, $3, $5, $7, $9, $11); }
generate_block generate_block
{ pform_endgenerate(); } { pform_endgenerate(); }
| K_if '(' expression ')' generate_block_opt K_else generate_block | generate_if
{ yyerror(@1, "sorry: Condition generate not supported yet."); 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. */ /* specify blocks are parsed but ignored. */
@ -1966,6 +1972,7 @@ module_item
{ yyerror(@1, "error: Malformed $attribute parameter list."); } { 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_list module_item : module_item_list module_item
@ -1990,7 +1997,7 @@ generate_block
{ pform_generate_block_name($3); } { 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 /* A net declaration assignment allows the programmer to combine the

View File

@ -362,6 +362,48 @@ void pform_start_generate_for(const struct vlltype&li,
delete[]ident2; 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) void pform_generate_block_name(char*name)
{ {
assert(pform_cur_generate != 0); assert(pform_cur_generate != 0);
@ -375,6 +417,14 @@ void pform_endgenerate()
assert(pform_cur_generate != 0); assert(pform_cur_generate != 0);
assert(pform_cur_module); 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; PGenerate*cur = pform_cur_generate;
pform_cur_generate = cur->parent; pform_cur_generate = cur->parent;

View File

@ -186,6 +186,8 @@ extern void pform_start_generate_for(const struct vlltype&li,
PExpr*test, PExpr*test,
char*ident2, char*ident2,
PExpr*next); 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_generate_block_name(char*name);
extern void pform_endgenerate(); extern void pform_endgenerate();

View File

@ -839,6 +839,10 @@ void PGenerate::dump(ostream&out, unsigned indent) const
<< "=" << *loop_step << ")"; << "=" << *loop_step << ")";
break; break;
case GS_CONDIT: case GS_CONDIT:
out << " if (" << *loop_test << ")";
break;
case GS_ELSE:
out << " else !(" << *loop_test << ")";
break; break;
} }