From bd754b24f42c0c6450d59be54cb1d8403b282f42 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 27 Nov 2008 19:45:22 -0800 Subject: [PATCH] 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. --- PGenerate.cc | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++ PGenerate.h | 17 ++++++++++++ elab_scope.cc | 59 ++++++++++++++++++++++++++++++++-------- elab_sig.cc | 31 ++++++++++++++++++++- elaborate.cc | 29 +++++++++++++++++++- parse.y | 2 +- pform.cc | 10 +++++-- pform.h | 2 +- 8 files changed, 207 insertions(+), 17 deletions(-) diff --git a/PGenerate.cc b/PGenerate.cc index a769501e7..360344df8 100644 --- a/PGenerate.cc +++ b/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; +} diff --git a/PGenerate.h b/PGenerate.h index 74082a27a..7f8cecefc 100644 --- a/PGenerate.h +++ b/PGenerate.h @@ -25,6 +25,7 @@ # include "PScope.h" # include # include +# include # 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 item_test; list 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. listscope_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 diff --git a/elab_scope.cc b/elab_scope.cc index d7ca9853c..3c1fb760c 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -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(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(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::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); } diff --git a/elab_sig.cc b/elab_sig.cc index 618911fa4..176b6abff 100644 --- a/elab_sig.cc +++ b/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::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 diff --git a/elaborate.cc b/elaborate.cc index 222fd7555..5a604ca7c 100644 --- a/elaborate.cc +++ b/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::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); diff --git a/parse.y b/parse.y index 1a0f29bd6..32d281b12 100644 --- a/parse.y +++ b/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(); } diff --git a/pform.cc b/pform.cc index a737a33b4..2737b0ea0 100644 --- a/pform.cc +++ b/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*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) diff --git a/pform.h b/pform.h index 27330573b..aec95e4dc 100644 --- a/pform.h +++ b/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*test); extern void pform_generate_block_name(char*name); extern void pform_endgenerate();