Various improvements in support for generate statements
authorClifford Wolf <clifford@clifford.at>
Wed, 4 Dec 2013 20:06:54 +0000 (21:06 +0100)
committerClifford Wolf <clifford@clifford.at>
Wed, 4 Dec 2013 20:06:54 +0000 (21:06 +0100)
frontends/ast/ast.cc
frontends/ast/ast.h
frontends/ast/genrtlil.cc
frontends/ast/simplify.cc
frontends/verilog/Makefile.inc
frontends/verilog/parser.y
tests/simple/generate.v

index ccadc20694ec99c4e92a367631bb03a9bffd7933..10c7fc85bf8212809885240b1cfe5ba22825dd30 100644 (file)
@@ -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)
 {
index f90fe9b7b1fbbfd65e9c84bf99dee745f5c19372..ab1b9bec54b63e8fb131bd425c2fef6343fb3485 100644 (file)
@@ -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
index 7ebc4b7192a4c1b1c31699bf76ef57129bc59293..269752df53dccf94e0350d668cfcfa4081a568ee 100644 (file)
@@ -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
index 0a32e950656859547bc2b6e856beb828bd6d1026..ae2f0caaec1f6ff14ebd9152398ab65981862360 100644 (file)
@@ -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)
        {
index 6693f2d1b15de36ec0b7044fd63ffe5cf206d88e..5586b4cc2b29c1a040f889faf7726409c838f5e9 100644 (file)
@@ -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
 
index 5a45a776166aed9a1c2d2a6f1a8d4222fa534587..01c9a0095952b5705957dfde9598354fa0043722 100644 (file)
@@ -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 {
index d458c076d8152ce90b7a06d571b15a887869cff2..39e573a737d294e6cf806cb8e6bbb207678fdeab 100644 (file)
@@ -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