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:
parent
90bfebd578
commit
bd754b24f4
74
PGenerate.cc
74
PGenerate.cc
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
17
PGenerate.h
17
PGenerate.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
31
elab_sig.cc
31
elab_sig.cc
|
|
@ -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
|
||||
|
|
|
|||
29
elaborate.cc
29
elaborate.cc
|
|
@ -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);
|
||||
|
|
|
|||
2
parse.y
2
parse.y
|
|
@ -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(); }
|
||||
|
|
|
|||
10
pform.cc
10
pform.cc
|
|
@ -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)
|
||||
|
|
|
|||
2
pform.h
2
pform.h
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue