diff options
-rw-r--r-- | frontends/ast/ast.cc | 10 | ||||
-rw-r--r-- | frontends/ast/ast.h | 2 | ||||
-rw-r--r-- | frontends/ast/genrtlil.cc | 1 | ||||
-rw-r--r-- | frontends/ast/simplify.cc | 80 | ||||
-rw-r--r-- | frontends/verilog/Makefile.inc | 4 | ||||
-rw-r--r-- | frontends/verilog/parser.y | 44 | ||||
-rw-r--r-- | tests/simple/generate.v | 27 |
7 files changed, 161 insertions, 7 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index ccadc2069..10c7fc85b 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 f90fe9b7b..ab1b9bec5 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 7ebc4b719..269752df5 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 0a32e9506..ae2f0caae 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 6693f2d1b..5586b4cc2 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 5a45a7761..01c9a0095 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 { diff --git a/tests/simple/generate.v b/tests/simple/generate.v index d458c076d..39e573a73 100644 --- a/tests/simple/generate.v +++ b/tests/simple/generate.v @@ -65,3 +65,30 @@ end endmodule +// ------------------------------------------ + +module test3(a, b, sel, y, z); + +input [3:0] a, b; +input sel; +output [3:0] y, z; + +genvar i; +generate + for (i=0; i < 2; i=i+1) + assign y[i] = sel ? a[i] : b[i], z[i] = sel ? b[i] : a[i]; + for (i=0; i < 2; i=i+1) begin + if (i == 0) + assign y[2] = sel ? a[2] : b[2]; + else + assign z[2] = sel ? a[2] : b[2]; + case (i) + default: + assign z[3] = sel ? a[3] : b[3]; + 0: + assign y[3] = sel ? a[3] : b[3]; + endcase + end +endgenerate + +endmodule |