diff options
Diffstat (limited to 'frontends/verilog/verilog_parser.y')
-rw-r--r-- | frontends/verilog/verilog_parser.y | 131 |
1 files changed, 104 insertions, 27 deletions
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 863fee59..c730ce5b 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -57,7 +57,8 @@ namespace VERILOG_FRONTEND { std::vector<char> case_type_stack; bool do_not_require_port_stubs; bool default_nettype_wire; - bool sv_mode, formal_mode; + bool sv_mode, formal_mode, lib_mode; + bool norestrict_mode, assume_asserts_mode; std::istream *lexin; } YOSYS_NAMESPACE_END @@ -102,6 +103,7 @@ static void free_attr(std::map<std::string, AstNode*> *al) %token <string> TOK_STRING TOK_ID TOK_CONST TOK_REALVAL TOK_PRIMITIVE %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 %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT @@ -111,7 +113,8 @@ 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 TOK_PROPERTY +%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME +%token TOK_RESTRICT TOK_PROPERTY %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 @@ -133,6 +136,9 @@ static void free_attr(std::map<std::string, AstNode*> *al) %left OP_POW %right UNARY_OPS +%define parse.error verbose +%define parse.lac full + %expect 2 %debug @@ -155,6 +161,7 @@ design: task_func_decl design | param_decl design | localparam_decl design | + package design | /* empty */; attr: @@ -212,6 +219,14 @@ hierarchical_id: TOK_ID { $$ = $1; } | + hierarchical_id TOK_PACKAGESEP TOK_ID { + if ($3->substr(0, 1) == "\\") + *$1 += "::" + $3->substr(1); + else + *$1 += "::" + *$3; + delete $3; + $$ = $1; + } | hierarchical_id '.' TOK_ID { if ($3->substr(0, 1) == "\\") *$1 += "." + $3->substr(1); @@ -246,11 +261,10 @@ module_para_opt: '#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | /* empty */; module_para_list: - single_module_para | - single_module_para ',' module_para_list | - /* empty */; + single_module_para | module_para_list ',' single_module_para; single_module_para: + /* empty */ | TOK_PARAMETER { if (astbuf1) delete astbuf1; astbuf1 = new AstNode(AST_PARAMETER); @@ -302,7 +316,7 @@ module_arg: node->children.push_back($3); if (!node->is_input && !node->is_output) frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $4->c_str()); - if (node->is_reg && node->is_input && !node->is_output) + if (node->is_reg && node->is_input && !node->is_output && !sv_mode) frontend_verilog_yyerror("Input port `%s' is declared as register.", $4->c_str()); ast_stack.back()->children.push_back(node); append_attr(node, $1); @@ -312,6 +326,25 @@ module_arg: do_not_require_port_stubs = true; }; +package: + attr TOK_PACKAGE TOK_ID { + AstNode *mod = new AstNode(AST_PACKAGE); + ast_stack.back()->children.push_back(mod); + ast_stack.push_back(mod); + current_ast_mod = mod; + mod->str = *$3; + append_attr(mod, $1); + } ';' package_body TOK_ENDPACKAGE { + ast_stack.pop_back(); + current_ast_mod = NULL; + }; + +package_body: + package_body package_body_stmt |; + +package_body_stmt: + localparam_decl; + non_opt_delay: '#' '(' expr ')' { delete $3; } | '#' '(' expr ':' expr ':' expr ')' { delete $3; delete $5; delete $7; }; @@ -736,7 +769,7 @@ wire_name: if (port_stubs.count(*$1) != 0) { if (!node->is_input && !node->is_output) frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $1->c_str()); - if (node->is_reg && node->is_input && !node->is_output) + if (node->is_reg && node->is_input && !node->is_output && !sv_mode) frontend_verilog_yyerror("Input port `%s' is declared as register.", $1->c_str()); node->port_id = port_stubs[*$1]; port_stubs.erase(*$1); @@ -825,10 +858,10 @@ cell_parameter_list_opt: '#' '(' cell_parameter_list ')' | /* empty */; cell_parameter_list: - /* empty */ | cell_parameter | - cell_parameter ',' cell_parameter_list; + cell_parameter | cell_parameter_list ',' cell_parameter; cell_parameter: + /* empty */ | expr { AstNode *node = new AstNode(AST_PARASET); astbuf1->children.push_back(node); @@ -843,14 +876,40 @@ cell_parameter: }; cell_port_list: - /* empty */ | cell_port | - cell_port ',' cell_port_list | - /* empty */ ',' { - AstNode *node = new AstNode(AST_ARGUMENT); - astbuf2->children.push_back(node); - } cell_port_list; + cell_port_list_rules { + // remove empty args from end of list + while (!astbuf2->children.empty()) { + AstNode *node = astbuf2->children.back(); + if (node->type != AST_ARGUMENT) break; + if (!node->children.empty()) break; + if (!node->str.empty()) break; + astbuf2->children.pop_back(); + delete node; + } + + // check port types + bool has_positional_args = false; + bool has_named_args = false; + for (auto node : astbuf2->children) { + if (node->type != AST_ARGUMENT) continue; + if (node->str.empty()) + has_positional_args = true; + else + has_named_args = true; + } + + if (has_positional_args && has_named_args) + frontend_verilog_yyerror("Mix of positional and named cell ports."); + }; + +cell_port_list_rules: + cell_port | cell_port_list_rules ',' cell_port; cell_port: + /* empty */ { + AstNode *node = new AstNode(AST_ARGUMENT); + astbuf2->children.push_back(node); + } | expr { AstNode *node = new AstNode(AST_ARGUMENT); astbuf2->children.push_back(node); @@ -937,18 +996,30 @@ opt_label: assert: TOK_ASSERT '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $3)); + ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $3)); } | TOK_ASSUME '(' expr ')' ';' { ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3)); + } | + TOK_RESTRICT '(' expr ')' ';' { + if (norestrict_mode) + delete $3; + else + ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3)); }; assert_property: TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $4)); + ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4)); } | TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); + } | + TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' { + if (norestrict_mode) + delete $4; + else + ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); }; simple_behavioral_stmt: @@ -1099,7 +1170,9 @@ case_body: case_item: { - AstNode *node = new AstNode(AST_COND); + AstNode *node = new AstNode( + case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX : + case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND); ast_stack.back()->children.push_back(node); ast_stack.push_back(node); } case_select { @@ -1119,7 +1192,9 @@ gen_case_body: gen_case_item: { - AstNode *node = new AstNode(AST_COND); + AstNode *node = new AstNode( + case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX : + case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND); ast_stack.back()->children.push_back(node); ast_stack.push_back(node); } case_select { @@ -1154,6 +1229,8 @@ rvalue: $$ = new AstNode(AST_IDENTIFIER, $2); $$->str = *$1; delete $1; + if ($2 == nullptr && formal_mode && ($$->str == "\\$initstate" || $$->str == "\\$anyconst")) + $$->type = AST_FCALL; } | hierarchical_id non_opt_multirange { $$ = new AstNode(AST_IDENTIFIER, $2); @@ -1278,7 +1355,7 @@ basic_expr: if ($4->substr(0, 1) != "'") frontend_verilog_yyerror("Syntax error."); AstNode *bits = $2; - AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true); + AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if (val == NULL) log_error("Value conversion failed: `%s'\n", $4->c_str()); $$ = new AstNode(AST_TO_BITS, bits, val); @@ -1289,7 +1366,7 @@ basic_expr: frontend_verilog_yyerror("Syntax error."); AstNode *bits = new AstNode(AST_IDENTIFIER); bits->str = *$1; - AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true); + AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if (val == NULL) log_error("Value conversion failed: `%s'\n", $2->c_str()); $$ = new AstNode(AST_TO_BITS, bits, val); @@ -1297,24 +1374,24 @@ basic_expr: delete $2; } | TOK_CONST TOK_CONST { - $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true); + $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if ($$ == NULL || (*$2)[0] != '\'') log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str()); delete $1; delete $2; } | TOK_CONST { - $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true); + $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if ($$ == NULL) log_error("Value conversion failed: `%s'\n", $1->c_str()); delete $1; } | TOK_REALVAL { $$ = new AstNode(AST_REALVALUE); - char *p = strdup($1->c_str()), *q; - for (int i = 0, j = 0; !p[j]; j++) - if (p[j] != '_') - p[i++] = p[j], p[i] = 0; + char *p = (char*)malloc(GetSize(*$1) + 1), *q; + for (int i = 0, j = 0; j < GetSize(*$1); j++) + if ((*$1)[j] != '_') + p[i++] = (*$1)[j], p[i] = 0; $$->realvalue = strtod(p, &q); log_assert(*q == 0); delete $1; |