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;
|
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_;
|
||||||
|
|
|
||||||
|
|
@ -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() == "") {
|
||||||
|
|
|
||||||
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;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
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;
|
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;
|
||||||
|
|
|
||||||
15
parse.y
15
parse.y
|
|
@ -1906,10 +1906,16 @@ module_item
|
||||||
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
|
||||||
|
|
|
||||||
50
pform.cc
50
pform.cc
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
2
pform.h
2
pform.h
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue