Add support for generate case

Generate case is a complex generate scheme where the items are
sub-schemes of the case generate itself. The parser handles them
something like nested generate statements, but storing the case
guards as the test expression. Then the elaborator notes the
case scheme and reaches into the case item schemes inside to make
up tests, select the generate item, and elaborate.
This commit is contained in:
Stephen Williams 2008-02-09 22:19:42 -08:00
parent 0ac36dc5af
commit bc1d3eb7cd
7 changed files with 196 additions and 11 deletions

View File

@ -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);

View File

@ -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<NetEConst*>(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<NetEConst*>(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<PGenerate*>::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<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()) {
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,

View File

@ -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<PGenerate*>::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<NetScope*>::const_iterator scope_list_it_t;
for (scope_list_it_t cur = scope_list_.begin()
; cur != scope_list_.end() ; cur ++ ) {

18
parse.y
View File

@ -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

View File

@ -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)

View File

@ -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();

View File

@ -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