Support direct nesting of conditional generate schemes.

Verilog generate schemes support a special case where conditional
generate schemes that contain only a nested conditional generate
scheme do not create a new scope. Instead, it relies on the nested
generate scheme to generate the scope.
This commit is contained in:
Stephen Williams 2008-11-27 19:45:22 -08:00
parent 90bfebd578
commit bd754b24f4
8 changed files with 207 additions and 17 deletions

View File

@ -22,10 +22,12 @@
# include "PGenerate.h"
# include "PWire.h"
# include "ivl_assert.h"
PGenerate::PGenerate(unsigned id)
: id_number(id)
{
direct_nested_ = false;
parent = 0;
lexical_scope = 0;
}
@ -38,3 +40,75 @@ void PGenerate::add_gate(PGate*gate)
{
gates.push_back(gate);
}
void PGenerate::probe_for_direct_nesting_(void)
{
direct_nested_ = false;
ivl_assert(*this, scheme_type==GS_CASE_ITEM || scheme_type==GS_CONDIT || scheme_type==GS_ELSE);
// If this scheme has received an explicit name, then it
// cannot be direct nested.
if (scope_name[0] != '$') return;
if (tasks.size() > 0) return;
if (funcs.size() > 0) return;
if (gates.size() > 0) return;
if (parameters.size() > 0) return;
if (localparams.size() > 0) return;
if (events.size() > 0) return;
if (wires.size() > 0) return;
if (behaviors.size() > 0) return;
if (analog_behaviors.size() > 0) return;
if (generate_schemes.size() == 0) return;
switch (generate_schemes.size()) {
case 1: {
PGenerate*child = generate_schemes.front();
if (child->scheme_type == GS_CONDIT)
direct_nested_ = true;
if (child->scheme_type == GS_CASE)
direct_nested_ = true;
break;
}
case 2: {
PGenerate*child1 = generate_schemes.front();
PGenerate*child2 = generate_schemes.back();
if (child1->scheme_type==GS_CONDIT && child2->scheme_type==GS_ELSE)
direct_nested_ = true;
if (child2->scheme_type==GS_CONDIT && child1->scheme_type==GS_ELSE)
direct_nested_ = true;
break;
}
}
}
ostream& operator << (ostream&out, PGenerate::scheme_t type)
{
switch (type) {
case PGenerate::GS_NONE:
out << "GS_NONE";
break;
case PGenerate::GS_LOOP:
out << "GS_LOOP";
break;
case PGenerate::GS_CONDIT:
out << "GS_CONDIT";
break;
case PGenerate::GS_ELSE:
out << "GS_ELSE";
break;
case PGenerate::GS_CASE:
out << "GS_CASE";
break;
case PGenerate::GS_CASE_ITEM:
out << "GS_CASE_ITEM";
break;
case PGenerate::GS_NBLOCK:
out << "GS_NBLOCK";
break;
}
return out;
}

View File

@ -25,6 +25,7 @@
# include "PScope.h"
# include <list>
# include <map>
# include <valarray>
# include "pform_types.h"
class Design;
@ -74,6 +75,10 @@ class PGenerate : public LineInfo, public LexicalScope {
PExpr*loop_init;
PExpr*loop_test;
PExpr*loop_step;
// Case items may have multiple guard expression values. It is
// enough for any on of the guards to match the case statement
// test value.
std::valarray<PExpr*> item_test;
list<PGate*> gates;
void add_gate(PGate*);
@ -104,18 +109,30 @@ class PGenerate : public LineInfo, public LexicalScope {
bool generate_scope_case_(Design*des, NetScope*container);
bool generate_scope_nblock_(Design*des, NetScope*container);
// Call probe during elaborate_scope to calulate the
// directed_nested_ flag. It is OK to store the direct_nested_
// information here because "direct nested" is a property of
// the lexical generate code.
void probe_for_direct_nesting_(void);
bool direct_nested_;
// Elaborate_scope within a generated scope.
void elaborate_subscope_(Design*des, NetScope*scope);
void elaborate_subscope_direct_(Design*des, NetScope*scope);
// These are the scopes created by generate_scope.
list<NetScope*>scope_list_;
// internal function called on each scope generated by this scheme.
bool elaborate_sig_(Design*des, NetScope*scope) const;
bool elaborate_sig_direct_(Design*des, NetScope*scope) const;
bool elaborate_(Design*des, NetScope*scope) const;
bool elaborate_direct_(Design*des, NetScope*scope) const;
private: // not implemented
PGenerate(const PGenerate&);
PGenerate& operator= (const PGenerate&);
};
extern std::ostream& operator << (std::ostream&, PGenerate::scheme_t);
#endif

View File

@ -636,14 +636,26 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
des->errors += 1;
return false;
}
if (debug_scopes)
cerr << get_fileline() << ": debug: Generate condition "
<< (else_flag? "(else)" : "(if)")
<< " value=" << test->value() << ": Generate scope="
<< use_name << endl;
NetScope*scope = new NetScope(container, use_name,
NetScope::GENBLOCK);
probe_for_direct_nesting_();
if (direct_nested_) {
if (debug_scopes)
cerr << get_fileline() << ": debug: Generate condition "
<< (else_flag? "(else)" : "(if)")
<< " detected direct nesting." << endl;
elaborate_subscope_direct_(des, container);
return true;
}
// If this is not directly nested, then generate a scope
// for myself. That is what I will pass to the subscope.
NetScope*scope = new NetScope(container, use_name, NetScope::GENBLOCK);
scope->set_line(get_file(), get_lineno());
elaborate_subscope_(des, scope);
@ -675,24 +687,27 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
assert( item->scheme_type == PGenerate::GS_CASE_ITEM );
// Detect that the item is a default.
if (item->loop_test == 0) {
if (item->item_test.size() == 0) {
default_item = item;
cur ++;
continue;
}
NetExpr*item_value_ex = elab_and_eval(des, container, item->loop_test, -1);
NetEConst*item_value_co = dynamic_cast<NetEConst*>(item_value_ex);
assert(item_value_co);
bool match_flag = false;
for (unsigned idx = 0 ; idx < item->item_test.size() && !match_flag ; idx +=1 ) {
NetExpr*item_value_ex = elab_and_eval(des, container, item->item_test[idx], -1);
NetEConst*item_value_co = dynamic_cast<NetEConst*>(item_value_ex);
assert(item_value_co);
// If we stumble on the item that matches, then break
// out now.
if (case_value_co->value() == item_value_co->value()) {
if (case_value_co->value() == item_value_co->value())
match_flag = true;
delete item_value_co;
break;
}
delete item_value_co;
// If we stumble on the item that matches, then break out now.
if (match_flag)
break;
cur ++;
}
@ -714,6 +729,15 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
// The name of the scope to generate, whatever that item is.
hname_t use_name (item->scope_name);
item->probe_for_direct_nesting_();
if (item->direct_nested_) {
if (debug_scopes)
cerr << get_fileline() << ": debug: Generate case item " << scope_name
<< " detected direct nesting." << endl;
item->elaborate_subscope_direct_(des, container);
return true;
}
NetScope*scope = new NetScope(container, use_name,
NetScope::GENBLOCK);
scope->set_line(get_file(), get_lineno());
@ -745,6 +769,15 @@ bool PGenerate::generate_scope_nblock_(Design*des, NetScope*container)
return true;
}
void PGenerate::elaborate_subscope_direct_(Design*des, NetScope*scope)
{
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++ ) {
(*cur) -> generate_scope(des, scope);
}
}
void PGenerate::elaborate_subscope_(Design*des, NetScope*scope)
{
// Scan the generated scope for nested generate schemes,
@ -787,6 +820,10 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope)
// Scan through all the named events in this scope.
elaborate_scope_events_(des, scope, events);
if (debug_scopes)
cerr << get_fileline() << ": debug: Generated scope " << scope_path(scope)
<< " by generate block " << scope_name << endl;
// Save the scope that we created, for future use.
scope_list_.push_back(scope);
}

View File

@ -412,6 +412,9 @@ bool PGModule::elaborate_sig_udp_(Design*des, NetScope*scope, PUdp*udp) const
bool PGenerate::elaborate_sig(Design*des, NetScope*container) const
{
if (direct_nested_)
return elaborate_sig_direct_(des, container);
bool flag = true;
// Handle the special case that this is a CASE scheme. In this
@ -428,7 +431,7 @@ bool PGenerate::elaborate_sig(Design*des, NetScope*container) const
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++) {
PGenerate*item = *cur;
if (! item->scope_list_.empty()) {
if (item->direct_nested_ || !item->scope_list_.empty()) {
flag &= item->elaborate_sig(des, container);
}
}
@ -454,6 +457,32 @@ bool PGenerate::elaborate_sig(Design*des, NetScope*container) const
return flag;
}
bool PGenerate::elaborate_sig_direct_(Design*des, NetScope*container) const
{
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Direct nesting " << scope_name
<< " (scheme_type=" << scheme_type << ")"
<< " elaborate_sig in scope "
<< scope_path(container) << "." << endl;
// Elaborate_sig for a direct nested generated scheme knows
// that there are only sub_schemes to be elaborated. There
// should be exactly 1 active generate scheme, search for it
// using this loop.
bool flag = true;
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++) {
PGenerate*item = *cur;
if (item->direct_nested_ || !item->scope_list_.empty()) {
// Found the item, and it is direct nested.
flag &= item->elaborate_sig(des, container);
}
}
return flag;
}
bool PGenerate::elaborate_sig_(Design*des, NetScope*scope) const
{
// Scan the declared PWires to elaborate the obvious signals

View File

@ -3972,6 +3972,9 @@ bool Module::elaborate(Design*des, NetScope*scope) const
bool PGenerate::elaborate(Design*des, NetScope*container) const
{
if (direct_nested_)
return elaborate_direct_(des, container);
bool flag = true;
// Handle the special case that this is a CASE scheme. In this
@ -3988,7 +3991,7 @@ bool PGenerate::elaborate(Design*des, NetScope*container) const
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++) {
PGenerate*item = *cur;
if (! item->scope_list_.empty()) {
if (item->direct_nested_ || !item->scope_list_.empty()) {
flag &= item->elaborate(des, container);
}
}
@ -4026,6 +4029,30 @@ bool PGenerate::elaborate(Design*des, NetScope*container) const
return flag;
}
bool PGenerate::elaborate_direct_(Design*des, NetScope*container) const
{
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Direct nesting elaborate in scope "
<< scope_path(container) << "." << endl;
// Elaborate for a direct nested generated scheme knows
// that there are only sub_schemes to be elaborated. There
// should be exactly 1 active generate scheme, search for it
// using this loop.
bool flag = true;
typedef list<PGenerate*>::const_iterator generate_it_t;
for (generate_it_t cur = generate_schemes.begin()
; cur != generate_schemes.end() ; cur ++) {
PGenerate*item = *cur;
if (item->direct_nested_ || !item->scope_list_.empty()) {
// Found the item, and it is direct nested.
flag &= item->elaborate(des, container);
}
}
return flag;
}
bool PGenerate::elaborate_(Design*des, NetScope*scope) const
{
elaborate_functions(des, scope, funcs);

View File

@ -2321,7 +2321,7 @@ generate_case_items
;
generate_case_item
: expression ':' { pform_generate_case_item(@1, $1); } generate_block_opt
: expression_list_proper ':' { pform_generate_case_item(@1, $1); } generate_block_opt
{ pform_endgenerate(); }
| K_default ':' { pform_generate_case_item(@1, 0); } generate_block_opt
{ pform_endgenerate(); }

View File

@ -558,7 +558,7 @@ void pform_start_generate_nblock(const struct vlltype&li, char*name)
* case schema can only instantiate exactly one item, so the items
* need not have a unique number.
*/
void pform_generate_case_item(const struct vlltype&li, PExpr*expr)
void pform_generate_case_item(const struct vlltype&li, svector<PExpr*>*expr_list)
{
assert(pform_cur_generate);
assert(pform_cur_generate->scheme_type == PGenerate::GS_CASE);
@ -573,8 +573,14 @@ void pform_generate_case_item(const struct vlltype&li, PExpr*expr)
pform_cur_generate->scheme_type = PGenerate::GS_CASE_ITEM;
pform_cur_generate->loop_init = 0;
pform_cur_generate->loop_test = expr;
pform_cur_generate->loop_test = 0;
pform_cur_generate->loop_step = 0;
if (expr_list != 0) {
pform_cur_generate->item_test.resize(expr_list->count());
for (unsigned idx = 0 ; idx < expr_list->count() ; idx += 1)
pform_cur_generate->item_test[idx] = expr_list[0][idx];
}
}
void pform_generate_block_name(char*name)

View File

@ -205,7 +205,7 @@ 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_start_generate_case(const struct vlltype&lp, PExpr*test);
extern void pform_start_generate_nblock(const struct vlltype&lp, char*name);
extern void pform_generate_case_item(const struct vlltype&lp, PExpr*test);
extern void pform_generate_case_item(const struct vlltype&lp, svector<PExpr*>*test);
extern void pform_generate_block_name(char*name);
extern void pform_endgenerate();