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;
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.
list<NetScope*>scope_list_;

View File

@ -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<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);
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<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
{
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;
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;
}

View File

@ -3227,7 +3227,7 @@ bool Module::elaborate(Design*des, NetScope*scope) const
typedef list<PGenerate*>::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;

33
parse.y
View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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;
}