Add check of begin/end labels for genblock
[yosys.git] / frontends / verilog / verilog_parser.y
index 678ce6c8759ae572dc5b7b0d5192b76aebc631b3..fb5846f7b58eb84d117096ea19acae015b8bc7db 100644 (file)
@@ -282,7 +282,7 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode)
 %token TOK_OR_ASSIGN TOK_XOR_ASSIGN TOK_AND_ASSIGN TOK_SUB_ASSIGN
 
 %type <ast> range range_or_multirange  non_opt_range non_opt_multirange range_or_signed_int
-%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
+%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type
 %type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id integral_number
 %type <string> type_name
 %type <ast> opt_enum_init enum_type struct_type non_wire_data_type
@@ -619,26 +619,19 @@ non_opt_delay:
 delay:
        non_opt_delay | %empty;
 
-wire_type:
-       {
-               astbuf3 = new AstNode(AST_WIRE);
-               current_wire_rand = false;
-               current_wire_const = false;
-       } wire_type_token_list {
-               $$ = astbuf3;
-               SET_RULE_LOC(@$, @2, @$);
-       };
+io_wire_type:
+       { astbuf3 = new AstNode(AST_WIRE); current_wire_rand = false; current_wire_const = false; }
+       wire_type_token_io wire_type_const_rand opt_wire_type_token wire_type_signedness
+       { $$ = astbuf3; SET_RULE_LOC(@$, @2, @$); };
 
-wire_type_token_list:
-       wire_type_token |
-       wire_type_token_list wire_type_token |
-       wire_type_token_io |
-       hierarchical_type_id {
-               astbuf3->is_custom_type = true;
-               astbuf3->children.push_back(new AstNode(AST_WIRETYPE));
-               astbuf3->children.back()->str = *$1;
-               delete $1;
-       };
+non_io_wire_type:
+       { astbuf3 = new AstNode(AST_WIRE); current_wire_rand = false; current_wire_const = false; }
+       wire_type_const_rand wire_type_token wire_type_signedness
+       { $$ = astbuf3; SET_RULE_LOC(@$, @2, @$); };
+
+wire_type:
+       io_wire_type  |
+       non_io_wire_type;
 
 wire_type_token_io:
        TOK_INPUT {
@@ -652,8 +645,32 @@ wire_type_token_io:
                astbuf3->is_output = true;
        };
 
+wire_type_signedness:
+       TOK_SIGNED   { astbuf3->is_signed = true;  } |
+       TOK_UNSIGNED { astbuf3->is_signed = false; } |
+       %empty;
+
+wire_type_const_rand:
+       TOK_RAND TOK_CONST {
+           current_wire_rand = true;
+           current_wire_const = true;
+       } |
+       TOK_CONST {
+           current_wire_const = true;
+       } |
+       TOK_RAND {
+           current_wire_rand = true;
+       } |
+       %empty;
+
+opt_wire_type_token:
+       wire_type_token | %empty;
+
 wire_type_token:
-       TOK_WIRE {
+       hierarchical_type_id {
+               astbuf3->is_custom_type = true;
+               astbuf3->children.push_back(new AstNode(AST_WIRETYPE));
+               astbuf3->children.back()->str = *$1;
        } |
        TOK_WOR {
                astbuf3->is_wor = true;
@@ -661,20 +678,27 @@ wire_type_token:
        TOK_WAND {
                astbuf3->is_wand = true;
        } |
+       // wires
+       TOK_WIRE {
+       } |
+       TOK_WIRE logic_type {
+       } |
+       // regs
        TOK_REG {
                astbuf3->is_reg = true;
        } |
-       TOK_LOGIC {
-               astbuf3->is_logic = true;
+       TOK_VAR TOK_REG {
+               astbuf3->is_reg = true;
        } |
+       // logics
        TOK_VAR {
                astbuf3->is_logic = true;
        } |
-       TOK_INTEGER {
-               astbuf3->is_reg = true;
-               astbuf3->range_left = 31;
-               astbuf3->range_right = 0;
-               astbuf3->is_signed = true;
+       TOK_VAR logic_type {
+               astbuf3->is_logic = true;
+       } |
+       logic_type {
+               astbuf3->is_logic = true;
        } |
        TOK_GENVAR {
                astbuf3->type = AST_GENVAR;
@@ -682,15 +706,15 @@ wire_type_token:
                astbuf3->is_signed = true;
                astbuf3->range_left = 31;
                astbuf3->range_right = 0;
+       };
+
+logic_type:
+       TOK_LOGIC {
        } |
-       TOK_SIGNED {
+       TOK_INTEGER {
+               astbuf3->range_left = 31;
+               astbuf3->range_right = 0;
                astbuf3->is_signed = true;
-       } |
-       TOK_RAND {
-               current_wire_rand = true;
-       } |
-       TOK_CONST {
-               current_wire_const = true;
        };
 
 non_opt_range:
@@ -746,6 +770,7 @@ module_body:
        module_body module_body_stmt |
        /* the following line makes the generate..endgenrate keywords optional */
        module_body gen_stmt |
+       module_body gen_block |
        module_body ';' |
        %empty;
 
@@ -884,7 +909,11 @@ task_func_args:
 
 task_func_port:
        attr wire_type range {
+               bool prev_was_input = true;
+               bool prev_was_output = false;
                if (albuf) {
+                       prev_was_input = astbuf1->is_input;
+                       prev_was_output = astbuf1->is_output;
                        delete astbuf1;
                        if (astbuf2 != NULL)
                                delete astbuf2;
@@ -893,6 +922,12 @@ task_func_port:
                albuf = $1;
                astbuf1 = $2;
                astbuf2 = checkRange(astbuf1, $3);
+               if (!astbuf1->is_input && !astbuf1->is_output) {
+                       if (!sv_mode)
+                               frontend_verilog_yyerror("task/function argument direction missing");
+                       astbuf1->is_input = prev_was_input;
+                       astbuf1->is_output = prev_was_output;
+               }
        } wire_name |
        {
                if (!astbuf1) {
@@ -1793,7 +1828,7 @@ type_name: TOK_ID         // first time seen
         ;
 
 typedef_decl:
-       TOK_TYPEDEF wire_type range type_name range_or_multirange ';' {
+       TOK_TYPEDEF non_io_wire_type range type_name range_or_multirange ';' {
                astbuf1 = $2;
                astbuf2 = checkRange(astbuf1, $3);
                if (astbuf2)
@@ -2425,6 +2460,16 @@ behavioral_stmt:
                exitTypeScope();
                if ($4 != NULL && $8 != NULL && *$4 != *$8)
                        frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $4->c_str()+1, $8->c_str()+1);
+               AstNode *node = ast_stack.back();
+               // In SystemVerilog, unnamed blocks with block item declarations
+               // create an implicit hierarchy scope
+               if (sv_mode && node->str.empty())
+                   for (const AstNode* child : node->children)
+                       if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER
+                               || child->type == AST_LOCALPARAM || child->type == AST_TYPEDEF) {
+                           node->str = "$unnamed_block$" + std::to_string(autoidx++);
+                           break;
+                       }
                SET_AST_NODE_LOC(ast_stack.back(), @2, @8);
                delete $4;
                delete $8;
@@ -2439,6 +2484,7 @@ behavioral_stmt:
                ast_stack.back()->children.push_back($7);
        } ';' simple_behavioral_stmt ')' {
                AstNode *block = new AstNode(AST_BLOCK);
+               block->str = "$for_loop$" + std::to_string(autoidx++);
                ast_stack.back()->children.push_back(block);
                ast_stack.push_back(block);
        } behavioral_stmt {
@@ -2688,6 +2734,7 @@ single_arg:
 
 module_gen_body:
        module_gen_body gen_stmt_or_module_body_stmt |
+       module_gen_body gen_block |
        %empty;
 
 gen_stmt_or_module_body_stmt:
@@ -2713,12 +2760,7 @@ gen_stmt:
                ast_stack.back()->children.push_back(node);
                ast_stack.push_back(node);
                ast_stack.back()->children.push_back($3);
-               AstNode *block = new AstNode(AST_GENBLOCK);
-               ast_stack.back()->children.push_back(block);
-               ast_stack.push_back(block);
-       } gen_stmt_block {
-               ast_stack.pop_back();
-       } opt_gen_else {
+       } gen_stmt_block opt_gen_else {
                SET_AST_NODE_LOC(ast_stack.back(), @1, @7);
                ast_stack.pop_back();
        } |
@@ -2731,6 +2773,18 @@ gen_stmt:
                SET_AST_NODE_LOC(ast_stack.back(), @1, @7);
                ast_stack.pop_back();
        } |
+       TOK_MSG_TASKS {
+               AstNode *node = new AstNode(AST_TECALL);
+               node->str = *$1;
+               delete $1;
+               ast_stack.back()->children.push_back(node);
+               ast_stack.push_back(node);
+       } opt_arg_list ';'{
+               SET_AST_NODE_LOC(ast_stack.back(), @1, @3);
+               ast_stack.pop_back();
+       };
+
+gen_block:
        TOK_BEGIN {
                enterTypeScope();
        } opt_label {
@@ -2740,22 +2794,15 @@ gen_stmt:
                ast_stack.push_back(node);
        } module_gen_body TOK_END opt_label {
                exitTypeScope();
+               if ($3 != NULL && $7 != NULL && *$3 != *$7)
+                       frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $3->c_str()+1, $7->c_str()+1);
                delete $3;
                delete $7;
                SET_AST_NODE_LOC(ast_stack.back(), @1, @7);
                ast_stack.pop_back();
-       } |
-       TOK_MSG_TASKS {
-               AstNode *node = new AstNode(AST_TECALL);
-               node->str = *$1;
-               delete $1;
-               ast_stack.back()->children.push_back(node);
-               ast_stack.push_back(node);
-       } opt_arg_list ';'{
-               SET_AST_NODE_LOC(ast_stack.back(), @1, @3);
-               ast_stack.pop_back();
        };
 
+// result is wrapped in a genblock only if necessary
 gen_stmt_block:
        {
                AstNode *node = new AstNode(AST_GENBLOCK);
@@ -2764,7 +2811,7 @@ gen_stmt_block:
        } gen_stmt_or_module_body_stmt {
                SET_AST_NODE_LOC(ast_stack.back(), @2, @2);
                ast_stack.pop_back();
-       };
+       } | gen_block;
 
 opt_gen_else:
        TOK_ELSE gen_stmt_block | %empty %prec FAKE_THEN;