Also add support for labels on sva module items, fixes #699
authorClifford Wolf <clifford@clifford.at>
Sat, 9 Mar 2019 06:53:58 +0000 (22:53 -0800)
committerClifford Wolf <clifford@clifford.at>
Sat, 9 Mar 2019 06:55:09 +0000 (22:55 -0800)
Signed-off-by: Clifford Wolf <clifford@clifford.at>
frontends/verilog/verilog_lexer.l
frontends/verilog/verilog_parser.y

index 1b1873e242da2292063ccc60274b21f602bbd21e..e51a12f767cae99c601c90c1a0668966961c5ef8 100644 (file)
@@ -189,10 +189,57 @@ YOSYS_NAMESPACE_END
 "always_ff"    { SV_KEYWORD(TOK_ALWAYS); }
 "always_latch" { SV_KEYWORD(TOK_ALWAYS); }
 
-"assert"     { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
-"assume"     { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
-"cover"      { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
-"restrict"   { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); }
+ /* parse labels on assert, assume, cover, and restrict right here because it's insanley complex
+    to do it in the parser (because we force the parser too early to reduce when parsing cells..) */
+([a-zA-Z_$][a-zA-Z0-9_$]*[ \t\r\n]*:[ \t\r\n]*)?(assert|assume|cover|restrict)/[^a-zA-Z0-9_$\.] {
+       frontend_verilog_yylval.string = new std::string(yytext);
+       auto &str = *frontend_verilog_yylval.string;
+       std::string keyword;
+       int cursor = 0;
+
+       while (1) {
+               if (cursor == GetSize(str)) {
+                       keyword = str;
+                       delete frontend_verilog_yylval.string;
+                       frontend_verilog_yylval.string = nullptr;
+                       goto sva_without_label;
+               }
+               char c = str[cursor];
+               if (c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != ':') {
+                       cursor++;
+                       continue;
+               }
+
+               keyword = str.substr(cursor);
+               str = "\\" + str.substr(0, cursor);
+               break;
+       }
+
+       cursor = 0;
+       while (1) {
+               log_assert(cursor < GetSize(keyword));
+               char c = keyword[cursor];
+               if (c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != ':') {
+                       keyword = keyword.substr(cursor);
+                       break;
+               }
+               cursor++;
+       }
+
+       if      (keyword == "assert")     { return TOK_ASSERT;   }
+       else if (keyword == "assume")     { return TOK_ASSUME;   }
+       else if (keyword == "cover")      { return TOK_COVER;    }
+       else if (keyword == "restrict")   { return TOK_RESTRICT; }
+       else log_abort();
+
+sva_without_label:
+       if      (keyword == "assert")     { if (formal_mode) return TOK_ASSERT;   SV_KEYWORD(TOK_ASSERT);   }
+       else if (keyword == "assume")     { if (formal_mode) return TOK_ASSUME;   SV_KEYWORD(TOK_ASSUME);   }
+       else if (keyword == "cover")      { if (formal_mode) return TOK_COVER;    SV_KEYWORD(TOK_COVER);    }
+       else if (keyword == "restrict")   { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); }
+       else log_abort();
+}
+
 "property"   { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
 "rand"       { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); }
 "const"      { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
@@ -303,7 +350,7 @@ supply1 { return TOK_SUPPLY1; }
 
 [a-zA-Z_$][a-zA-Z0-9_$\.]* {
        frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
-    return TOK_ID;
+       return TOK_ID;
 }
 
 "/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
index 2258f3f6f8b3f8e497f777be8b268931914fd987..649dd384f48c8fad9279186e7485be8f9cf53eb7 100644 (file)
@@ -106,6 +106,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
 }
 
 %token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
+%token <string> TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER
 %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
 %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
 %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
@@ -119,14 +120,13 @@ static void free_attr(std::map<std::string, AstNode*> *al)
 %token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
 %token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
 %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
-%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME
-%token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
+%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
 %token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
 %token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY
 
 %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 <string> opt_label opt_stmt_label tok_prim_wrapper hierarchical_id
+%type <string> opt_label tok_prim_wrapper hierarchical_id
 %type <boolean> opt_signed opt_property unique_case_attr
 %type <al> attr case_attr
 
@@ -1337,14 +1337,6 @@ opt_property:
                $$ = false;
        };
 
-opt_stmt_label:
-       TOK_ID ':' {
-               $$ = $1;
-       } |
-       /* empty */ {
-               $$ = NULL;
-       };
-
 modport_stmt:
     TOK_MODPORT TOK_ID {
         AstNode *modport = new AstNode(AST_MODPORT);
@@ -1381,11 +1373,11 @@ modport_type_token:
     TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;}
 
 assert:
-       opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' {
+       TOK_ASSERT opt_property '(' expr ')' ';' {
                if (noassert_mode) {
-                       delete $5;
+                       delete $4;
                } else {
-                       AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5);
+                       AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4);
                        if ($1 != nullptr)
                                node->str = *$1;
                        ast_stack.back()->children.push_back(node);
@@ -1393,11 +1385,11 @@ assert:
                if ($1 != nullptr)
                        delete $1;
        } |
-       opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' {
+       TOK_ASSUME opt_property '(' expr ')' ';' {
                if (noassume_mode) {
-                       delete $5;
+                       delete $4;
                } else {
-                       AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5);
+                       AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $4);
                        if ($1 != nullptr)
                                node->str = *$1;
                        ast_stack.back()->children.push_back(node);
@@ -1405,11 +1397,11 @@ assert:
                if ($1 != nullptr)
                        delete $1;
        } |
-       opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
+       TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
                if (noassert_mode) {
-                       delete $6;
+                       delete $5;
                } else {
-                       AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6);
+                       AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5);
                        if ($1 != nullptr)
                                node->str = *$1;
                        ast_stack.back()->children.push_back(node);
@@ -1417,11 +1409,11 @@ assert:
                if ($1 != nullptr)
                        delete $1;
        } |
-       opt_stmt_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
+       TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
                if (noassume_mode) {
-                       delete $6;
+                       delete $5;
                } else {
-                       AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6);
+                       AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $5);
                        if ($1 != nullptr)
                                node->str = *$1;
                        ast_stack.back()->children.push_back(node);
@@ -1429,15 +1421,15 @@ assert:
                if ($1 != nullptr)
                        delete $1;
        } |
-       opt_stmt_label TOK_COVER opt_property '(' expr ')' ';' {
-               AstNode *node = new AstNode(AST_COVER, $5);
+       TOK_COVER opt_property '(' expr ')' ';' {
+               AstNode *node = new AstNode(AST_COVER, $4);
                if ($1 != nullptr) {
                        node->str = *$1;
                        delete $1;
                }
                ast_stack.back()->children.push_back(node);
        } |
-       opt_stmt_label TOK_COVER opt_property '(' ')' ';' {
+       TOK_COVER opt_property '(' ')' ';' {
                AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
                if ($1 != nullptr) {
                        node->str = *$1;
@@ -1445,7 +1437,7 @@ assert:
                }
                ast_stack.back()->children.push_back(node);
        } |
-       opt_stmt_label TOK_COVER ';' {
+       TOK_COVER ';' {
                AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
                if ($1 != nullptr) {
                        node->str = *$1;
@@ -1453,30 +1445,30 @@ assert:
                }
                ast_stack.back()->children.push_back(node);
        } |
-       opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' {
+       TOK_RESTRICT opt_property '(' expr ')' ';' {
                if (norestrict_mode) {
-                       delete $5;
+                       delete $4;
                } else {
-                       AstNode *node = new AstNode(AST_ASSUME, $5);
+                       AstNode *node = new AstNode(AST_ASSUME, $4);
                        if ($1 != nullptr)
                                node->str = *$1;
                        ast_stack.back()->children.push_back(node);
                }
-               if (!$3)
+               if (!$2)
                        log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
                if ($1 != nullptr)
                        delete $1;
        } |
-       opt_stmt_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
+       TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
                if (norestrict_mode) {
-                       delete $6;
+                       delete $5;
                } else {
-                       AstNode *node = new AstNode(AST_FAIR, $6);
+                       AstNode *node = new AstNode(AST_FAIR, $5);
                        if ($1 != nullptr)
                                node->str = *$1;
                        ast_stack.back()->children.push_back(node);
                }
-               if (!$3)
+               if (!$2)
                        log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
                if ($1 != nullptr)
                        delete $1;
@@ -1485,30 +1477,60 @@ assert:
 assert_property:
        TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
                ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4));
+               if ($1 != nullptr) {
+                       ast_stack.back()->children.back()->str = *$1;
+                       delete $1;
+               }
        } |
        TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
                ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
+               if ($1 != nullptr) {
+                       ast_stack.back()->children.back()->str = *$1;
+                       delete $1;
+               }
        } |
        TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
                ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5));
+               if ($1 != nullptr) {
+                       ast_stack.back()->children.back()->str = *$1;
+                       delete $1;
+               }
        } |
        TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
                ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
+               if ($1 != nullptr) {
+                       ast_stack.back()->children.back()->str = *$1;
+                       delete $1;
+               }
        } |
        TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
                ast_stack.back()->children.push_back(new AstNode(AST_COVER, $4));
+               if ($1 != nullptr) {
+                       ast_stack.back()->children.back()->str = *$1;
+                       delete $1;
+               }
        } |
        TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
-               if (norestrict_mode)
+               if (norestrict_mode) {
                        delete $4;
-               else
+               } else {
                        ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
+                       if ($1 != nullptr) {
+                               ast_stack.back()->children.back()->str = *$1;
+                               delete $1;
+                       }
+               }
        } |
        TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
-               if (norestrict_mode)
+               if (norestrict_mode) {
                        delete $5;
-               else
+               } else {
                        ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
+                       if ($1 != nullptr) {
+                               ast_stack.back()->children.back()->str = *$1;
+                               delete $1;
+                       }
+               }
        };
 
 simple_behavioral_stmt: