diff --git a/PGenerate.h b/PGenerate.h index 39be19f47..b29c60b25 100644 --- a/PGenerate.h +++ b/PGenerate.h @@ -37,7 +37,17 @@ class PGate; class PWire; /* - * This represents a generate scheme. + * This represents a generate scheme. The interpretation of the + * members depends on the scheme_type. + * + * GS_LOOP + * + * GS_CASE + * loop_test is the expression to be compared. + * generates contains only GS_CASE_ITEM schemes. + * GS_CASE_ITEM + * The parent points to the GS_CASE that contains this item. + * the loop_test is compared with the parent->loop_test expression. */ class PGenerate : public LineInfo { @@ -50,7 +60,8 @@ class PGenerate : public LineInfo { const unsigned id_number; perm_string scope_name; - enum scheme_t {GS_NONE, GS_LOOP, GS_CONDIT, GS_ELSE}; + enum scheme_t {GS_NONE, GS_LOOP, GS_CONDIT, GS_ELSE, + GS_CASE, GS_CASE_ITEM}; scheme_t scheme_type; // generate loops have an index variable and three @@ -88,6 +99,7 @@ class PGenerate : public LineInfo { private: bool generate_scope_loop_(Design*des, NetScope*container); bool generate_scope_condit_(Design*des, NetScope*container, bool else_flag); + bool generate_scope_case_(Design*des, NetScope*container); // Elaborate_scope within a generated scope. void elaborate_subscope_(Design*des, NetScope*scope); diff --git a/elab_scope.cc b/elab_scope.cc index 7cc2eeddd..c954da025 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -315,6 +315,15 @@ bool PGenerate::generate_scope(Design*des, NetScope*container) case GS_ELSE: return generate_scope_condit_(des, container, true); + case GS_CASE: + return generate_scope_case_(des, container); + return true; + + case GS_CASE_ITEM: + cerr << get_fileline() << ": internal error: " + << "Case item outside of a case generate scheme?" << endl; + return false; + default: cerr << get_fileline() << ": sorry: Generate of this sort" << " is not supported yet!" << endl; @@ -345,7 +354,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) genvar = init->value().as_long(); delete init_ex; - if (debug_elaborate) + if (debug_scopes) cerr << get_fileline() << ": debug: genvar init = " << genvar << endl; container->genvar_tmp = loop_index; @@ -367,7 +376,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) des->errors += 1; return false; } - if (debug_elaborate) + if (debug_scopes) cerr << get_fileline() << ": debug: " << "Create generated scope " << use_name << endl; @@ -386,7 +395,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) genvar_verinum); scope->set_localparam(loop_index, gp); - if (debug_elaborate) + if (debug_scopes) cerr << get_fileline() << ": debug: " << "Create implicit localparam " << loop_index << " = " << genvar_verinum << endl; @@ -398,7 +407,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1); NetEConst*step = dynamic_cast(step_ex); assert(step); - if (debug_elaborate) + if (debug_scopes) cerr << get_fileline() << ": debug: genvar step from " << genvar << " to " << step->value().as_long() << endl; @@ -428,7 +437,7 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else // scope. if ( (test->value().as_long() == 0 && !else_flag) || (test->value().as_long() != 0 && else_flag) ) { - if (debug_elaborate) + if (debug_scopes) cerr << get_fileline() << ": debug: Generate condition " << (else_flag? "(else)" : "(if)") << " value=" << test->value() << ": skip generation" @@ -445,7 +454,7 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else des->errors += 1; return false; } - if (debug_elaborate) + if (debug_scopes) cerr << get_fileline() << ": debug: Generate condition " << (else_flag? "(else)" : "(if)") << " value=" << test->value() << ": Generate scope=" @@ -459,6 +468,71 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else return true; } +bool PGenerate::generate_scope_case_(Design*des, NetScope*container) +{ + NetExpr*case_value_ex = elab_and_eval(des, container, loop_test, -1); + NetEConst*case_value_co = dynamic_cast(case_value_ex); + assert(case_value_co); + + // The name of the scope to generate, whatever that item is. + hname_t use_name (scope_name); + + if (debug_scopes) + cerr << get_fileline() << ": debug: Generate case " + << "switch value=" << case_value_co->value() << endl; + + PGenerate*default_item = 0; + + typedef list::const_iterator generator_it_t; + generator_it_t cur = generates.begin(); + while (cur != generates.end()) { + PGenerate*item = *cur; + assert( item->scheme_type == PGenerate::GS_CASE_ITEM ); + + // Detect that the item is a default. + if (item->loop_test == 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); + + // If we stumble on the item that matches, then break + // out now. + if (case_value_co->value() == item_value_co->value()) { + delete item_value_co; + break; + } + + delete item_value_co; + cur ++; + } + + delete case_value_co; + case_value_co = 0; + + PGenerate*item = (cur == generates.end())? default_item : *cur; + if (item == 0) { + cerr << get_fileline() << ": debug: " + << "No generate items found" << endl; + return true; + } + + if (debug_scopes) + cerr << get_fileline() << ": debug: " + << "Generate case matches item at " + << item->get_fileline() << endl; + + NetScope*scope = new NetScope(container, use_name, + NetScope::GENBLOCK); + item->elaborate_subscope_(des, scope); + + return true; +} + void PGenerate::elaborate_subscope_(Design*des, NetScope*scope) { // Scan the generated scope for nested generate schemes, diff --git a/elaborate.cc b/elaborate.cc index 0845329e5..50481b044 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3554,6 +3554,27 @@ bool PGenerate::elaborate(Design*des, NetScope*container) const { bool flag = true; + // Handle the special case that this is a CASE scheme. In this + // case the PGenerate itself does not have the generated + // item. Look instead for the case ITEM that has a scope + // generated for it. + if (scheme_type == PGenerate::GS_CASE) { + if (debug_elaborate) + cerr << get_fileline() << ": debug: generate case" + << " elaborating in scope " + << scope_path(container) << "." << endl; + + typedef list::const_iterator generate_it_t; + for (generate_it_t cur = generates.begin() + ; cur != generates.end() ; cur ++) { + PGenerate*item = *cur; + if (! item->scope_list_.empty()) { + flag &= item->elaborate(des, container); + } + } + return flag; + } + typedef list::const_iterator scope_list_it_t; for (scope_list_it_t cur = scope_list_.begin() ; cur != scope_list_.end() ; cur ++ ) { diff --git a/parse.y b/parse.y index a5d0679fc..818372c7c 100644 --- a/parse.y +++ b/parse.y @@ -1920,6 +1920,12 @@ module_item generate_block_opt %prec less_than_K_else { pform_endgenerate(); } + | K_case '(' expression ')' + { pform_start_generate_case(@1, $3); } + generate_case_items + K_endcase + { pform_endgenerate(); } + /* specify blocks are parsed but ignored. */ | K_specify K_endspecify @@ -1984,6 +1990,18 @@ module_item generate_if : K_if '(' expression ')' { pform_start_generate_if(@1, $3); } +generate_case_items + : generate_case_items generate_case_item + | generate_case_item + ; + +generate_case_item + : expression ':' { pform_generate_case_item(@1, $1); } generate_block + { pform_endgenerate(); } + | K_default ':' { pform_generate_case_item(@1, 0); } generate_block + { pform_endgenerate(); } + ; + module_item_list : module_item_list module_item | module_item diff --git a/pform.cc b/pform.cc index 3da43e8e4..425a2162e 100644 --- a/pform.cc +++ b/pform.cc @@ -412,6 +412,51 @@ void pform_start_generate_else(const struct vlltype&li) pform_cur_generate->loop_step = 0; } +/* + * The GS_CASE version of the PGenerate contains only case items. The + * items in turn contain the generated items themselves. + */ +void pform_start_generate_case(const struct vlltype&li, PExpr*expr) +{ + PGenerate*gen = new PGenerate(scope_generate_counter++); + + FILE_NAME(gen, li); + + gen->parent = pform_cur_generate; + pform_cur_generate = gen; + + pform_cur_generate->scheme_type = PGenerate::GS_CASE; + + pform_cur_generate->loop_init = 0; + pform_cur_generate->loop_test = expr; + pform_cur_generate->loop_step = 0; +} + +/* + * The generate case item is a special case schema that takes its id + * from the case schema that it is a part of. The idea is that the + * 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) +{ + assert(pform_cur_generate); + assert(pform_cur_generate->scheme_type == PGenerate::GS_CASE); + + PGenerate*gen = new PGenerate(pform_cur_generate->id_number); + + FILE_NAME(gen, li); + + gen->parent = pform_cur_generate; + pform_cur_generate = gen; + + 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_step = 0; +} + void pform_generate_block_name(char*name) { assert(pform_cur_generate != 0); @@ -439,10 +484,14 @@ void pform_endgenerate() PGenerate*cur = pform_cur_generate; pform_cur_generate = cur->parent; - if (pform_cur_generate != 0) + if (pform_cur_generate != 0) { + assert(cur->scheme_type == PGenerate::GS_CASE_ITEM + || pform_cur_generate->scheme_type != PGenerate::GS_CASE); pform_cur_generate->generates.push_back(cur); - else + } else { + assert(cur->scheme_type != PGenerate::GS_CASE_ITEM); pform_cur_module->generate_schemes.push_back(cur); + } } bool pform_expression_is_constant(const PExpr*ex) diff --git a/pform.h b/pform.h index 2ae8d0c57..5dc556f30 100644 --- a/pform.h +++ b/pform.h @@ -188,6 +188,8 @@ extern void pform_start_generate_for(const struct vlltype&li, 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_start_generate_case(const struct vlltype&lp, PExpr*test); +extern void pform_generate_case_item(const struct vlltype&lp, PExpr*test); extern void pform_generate_block_name(char*name); extern void pform_endgenerate(); diff --git a/pform_dump.cc b/pform_dump.cc index 6db7ccce1..addc8932c 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -854,6 +854,15 @@ void PGenerate::dump(ostream&out, unsigned indent) const case GS_ELSE: out << " else !(" << *loop_test << ")"; break; + case GS_CASE: + out << " case (" << *loop_test << ")"; + break; + case GS_CASE_ITEM: + if (loop_test) + out << " (" << *loop_test << ") == (" << *parent->loop_test << ")"; + else + out << " default:"; + break; } if (scope_name) @@ -882,7 +891,7 @@ void PGenerate::dump(ostream&out, unsigned indent) const (*idx)->dump(out, indent+2); } - out << " endgenerate" << endl; + out << setw(indent) << "" << "endgenerate" << endl; } void Module::dump(ostream&out) const