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:
parent
9d2dd782c0
commit
396ffd1cdd
12
PGenerate.h
12
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.
|
||||
list<NetScope*>scope_list_;
|
||||
|
|
|
|||
|
|
@ -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() == "") {
|
||||
|
|
|
|||
12
elab_sig.cc
12
elab_sig.cc
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
14
elaborate.cc
14
elaborate.cc
|
|
@ -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
33
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
|
||||
|
|
|
|||
50
pform.cc
50
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;
|
||||
|
||||
|
|
|
|||
2
pform.h
2
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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue