summaryrefslogtreecommitdiff
path: root/frontends
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2013-12-04 21:06:54 +0100
committerClifford Wolf <clifford@clifford.at>2013-12-04 21:06:54 +0100
commit4a4a3fc3377243d85100b829a0f6b785376cce9f (patch)
tree689dda333df9ac7012ce460e8f7e801b631c0882 /frontends
parentf4b46ed31e5f5c41bbd4ee1fdf996ecdc2010174 (diff)
Various improvements in support for generate statements
Diffstat (limited to 'frontends')
-rw-r--r--frontends/ast/ast.cc10
-rw-r--r--frontends/ast/ast.h2
-rw-r--r--frontends/ast/genrtlil.cc1
-rw-r--r--frontends/ast/simplify.cc80
-rw-r--r--frontends/verilog/Makefile.inc4
-rw-r--r--frontends/verilog/parser.y44
6 files changed, 134 insertions, 7 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index ccadc206..10c7fc85 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -135,6 +135,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_GENVAR)
X(AST_GENFOR)
X(AST_GENIF)
+ X(AST_GENCASE)
X(AST_GENBLOCK)
X(AST_POSEDGE)
X(AST_NEGEDGE)
@@ -700,6 +701,15 @@ RTLIL::Const AstNode::asParaConst()
return val;
}
+bool AstNode::asBool()
+{
+ log_assert(type == AST_CONSTANT);
+ for (auto &bit : bits)
+ if (bit == RTLIL::State::S1)
+ return true;
+ return false;
+}
+
// create a new AstModule from an AST_MODULE AST node
static AstModule* process_module(AstNode *ast)
{
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index f90fe9b7..ab1b9bec 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -116,6 +116,7 @@ namespace AST
AST_GENVAR,
AST_GENFOR,
AST_GENIF,
+ AST_GENCASE,
AST_GENBLOCK,
AST_POSEDGE,
@@ -218,6 +219,7 @@ namespace AST
RTLIL::Const bitsAsConst(int width = -1);
RTLIL::Const asAttrConst();
RTLIL::Const asParaConst();
+ bool asBool();
};
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 7ebc4b71..269752df 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -812,6 +812,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_GENFOR:
case AST_GENBLOCK:
case AST_GENIF:
+ case AST_GENCASE:
break;
// remember the parameter, needed for example in techmap
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 0a32e950..ae2f0caa 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -346,7 +346,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
bool did_something_here = true;
if ((type == AST_GENFOR || type == AST_FOR) && i >= 3)
break;
- if (type == AST_GENIF && i >= 1)
+ if ((type == AST_GENIF || type == AST_GENCASE) && i >= 1)
break;
if (type == AST_GENBLOCK)
break;
@@ -726,7 +726,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// dumpAst(f, "verilog-ast> ");
log_error("Condition for generate if at %s:%d is not constant!\n", filename.c_str(), linenum);
}
- if (buf->integer != 0) {
+ if (buf->asBool() != 0) {
delete buf;
buf = children[1]->clone();
} else {
@@ -757,6 +757,82 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
did_something = true;
}
+ // simplify generate-case blocks
+ if (type == AST_GENCASE && children.size() != 0)
+ {
+ AstNode *buf = children[0]->clone();
+ while (buf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
+ if (buf->type != AST_CONSTANT) {
+ // for (auto f : log_files)
+ // dumpAst(f, "verilog-ast> ");
+ log_error("Condition for generate case at %s:%d is not constant!\n", filename.c_str(), linenum);
+ }
+
+ bool ref_signed = buf->is_signed;
+ RTLIL::Const ref_value = buf->bitsAsConst();
+ delete buf;
+
+ AstNode *selected_case = NULL;
+ for (size_t i = 1; i < children.size(); i++)
+ {
+ log_assert(children.at(i)->type == AST_COND);
+
+ AstNode *this_genblock = NULL;
+ for (auto child : children.at(i)->children) {
+ log_assert(this_genblock == NULL);
+ if (child->type == AST_GENBLOCK)
+ this_genblock = child;
+ }
+
+ for (auto child : children.at(i)->children)
+ {
+ if (child->type == AST_DEFAULT) {
+ if (selected_case == NULL)
+ selected_case = this_genblock;
+ continue;
+ }
+ if (child->type == AST_GENBLOCK)
+ continue;
+
+ buf = child->clone();
+ while (buf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
+ if (buf->type != AST_CONSTANT) {
+ // for (auto f : log_files)
+ // dumpAst(f, "verilog-ast> ");
+ log_error("Expression in generate case at %s:%d is not constant!\n", filename.c_str(), linenum);
+ }
+
+ if (RTLIL::const_eq(ref_value, buf->bitsAsConst(), ref_signed && buf->is_signed, ref_signed && buf->is_signed, 1).as_bool()) {
+ selected_case = this_genblock;
+ i = children.size();
+ break;
+ }
+ }
+ }
+
+ if (selected_case != NULL)
+ {
+ log_assert(selected_case->type == AST_GENBLOCK);
+ buf = selected_case->clone();
+
+ if (!buf->str.empty()) {
+ std::map<std::string, std::string> name_map;
+ buf->expand_genblock(std::string(), buf->str + ".", name_map);
+ }
+
+ for (size_t i = 0; i < buf->children.size(); i++) {
+ buf->children[i]->simplify(false, false, false, stage, -1, false);
+ current_ast_mod->children.push_back(buf->children[i]);
+ }
+
+ buf->children.clear();
+ delete buf;
+ }
+
+ delete_children();
+ did_something = true;
+ }
+
// replace primitives with assignmens
if (type == AST_PRIMITIVE)
{
diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc
index 6693f2d1..5586b4cc 100644
--- a/frontends/verilog/Makefile.inc
+++ b/frontends/verilog/Makefile.inc
@@ -4,10 +4,12 @@ GENFILES += frontends/verilog/parser.tab.h
GENFILES += frontends/verilog/parser.output
GENFILES += frontends/verilog/lexer.cc
-frontends/verilog/parser.tab.cc frontends/verilog/parser.tab.h: frontends/verilog/parser.y
+frontends/verilog/parser.tab.cc: frontends/verilog/parser.y
bison -d -r all -b frontends/verilog/parser frontends/verilog/parser.y
mv frontends/verilog/parser.tab.c frontends/verilog/parser.tab.cc
+frontends/verilog/parser.tab.h: frontends/verilog/parser.tab.cc
+
frontends/verilog/lexer.cc: frontends/verilog/lexer.l
flex -o frontends/verilog/lexer.cc frontends/verilog/lexer.l
diff --git a/frontends/verilog/parser.y b/frontends/verilog/parser.y
index 5a45a776..01c9a009 100644
--- a/frontends/verilog/parser.y
+++ b/frontends/verilog/parser.y
@@ -887,6 +887,22 @@ case_item:
ast_stack.pop_back();
};
+gen_case_body:
+ gen_case_body gen_case_item |
+ /* empty */;
+
+gen_case_item:
+ {
+ AstNode *node = new AstNode(AST_COND);
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ } case_select {
+ case_type_stack.push_back(0);
+ } gen_stmt_or_null {
+ case_type_stack.pop_back();
+ ast_stack.pop_back();
+ };
+
case_select:
case_expr_list ':' |
TOK_DEFAULT;
@@ -956,7 +972,6 @@ single_arg:
module_gen_body:
module_gen_body gen_stmt |
- module_gen_body module_body_stmt |
/* empty */;
// this production creates the obligatory if-else shift/reduce conflict
@@ -967,7 +982,7 @@ gen_stmt:
ast_stack.push_back(node);
} simple_behavioral_stmt ';' expr {
ast_stack.back()->children.push_back($6);
- } ';' simple_behavioral_stmt ')' gen_stmt {
+ } ';' simple_behavioral_stmt ')' gen_stmt_block {
ast_stack.pop_back();
} |
TOK_IF '(' expr ')' {
@@ -975,7 +990,15 @@ gen_stmt:
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
ast_stack.back()->children.push_back($3);
- } gen_stmt opt_gen_else {
+ } gen_stmt_block opt_gen_else {
+ ast_stack.pop_back();
+ } |
+ case_type '(' expr ')' {
+ AstNode *node = new AstNode(AST_GENCASE, $3);
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ } gen_case_body TOK_ENDCASE {
+ case_type_stack.pop_back();
ast_stack.pop_back();
} |
TOK_BEGIN opt_label {
@@ -989,10 +1012,23 @@ gen_stmt:
if ($6 != NULL)
delete $6;
ast_stack.pop_back();
+ } |
+ module_body_stmt;
+
+gen_stmt_block:
+ {
+ AstNode *node = new AstNode(AST_GENBLOCK);
+ ast_stack.back()->children.push_back(node);
+ ast_stack.push_back(node);
+ } gen_stmt {
+ ast_stack.pop_back();
};
+gen_stmt_or_null:
+ gen_stmt_block | ';';
+
opt_gen_else:
- TOK_ELSE gen_stmt | /* empty */;
+ TOK_ELSE gen_stmt_or_null | /* empty */;
expr:
basic_expr {