diff options
Diffstat (limited to 'frontends/verilog/verilog_parser.y')
-rw-r--r-- | frontends/verilog/verilog_parser.y | 124 |
1 files changed, 86 insertions, 38 deletions
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 621b6cc18..e7c3578c7 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2,11 +2,11 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * + * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -36,7 +36,7 @@ %{ #include <list> #include <string.h> -#include "verilog_frontend.h" +#include "frontends/verilog/verilog_frontend.h" #include "kernel/log.h" USING_YOSYS_NAMESPACE @@ -57,7 +57,7 @@ namespace VERILOG_FRONTEND { std::vector<char> case_type_stack; bool do_not_require_port_stubs; bool default_nettype_wire; - bool sv_mode; + bool sv_mode, formal_mode; std::istream *lexin; } YOSYS_NAMESPACE_END @@ -102,6 +102,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 +112,7 @@ 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_PROPERTY +%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME 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 @@ -139,6 +140,7 @@ static void free_attr(std::map<std::string, AstNode*> *al) %% input: { + ast_stack.clear(); ast_stack.push_back(current_ast); } design { ast_stack.pop_back(); @@ -152,6 +154,9 @@ design: module design | defattr design | task_func_decl design | + param_decl design | + localparam_decl design | + package design | /* empty */; attr: @@ -209,6 +214,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); @@ -243,11 +256,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); @@ -299,7 +311,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); @@ -309,10 +321,36 @@ 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; }; + +delay: + non_opt_delay | /* empty */; + wire_type: { astbuf3 = new AstNode(AST_WIRE); - } wire_type_token_list { + } wire_type_token_list delay { $$ = astbuf3; }; @@ -700,6 +738,8 @@ wire_name_and_opt_assign: wire_name: TOK_ID range_or_multirange { + if (astbuf1 == nullptr) + frontend_verilog_yyerror("Syntax error."); AstNode *node = astbuf1->clone(); node->str = *$1; append_attr_clone(node, albuf); @@ -724,7 +764,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); @@ -741,13 +781,13 @@ wire_name: }; assign_stmt: - TOK_ASSIGN assign_expr_list ';'; + TOK_ASSIGN delay assign_expr_list ';'; assign_expr_list: assign_expr | assign_expr_list ',' assign_expr; assign_expr: - expr '=' expr { + lvalue '=' expr { ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, $1, $3)); }; @@ -761,7 +801,7 @@ cell_stmt: } cell_parameter_list_opt cell_list ';' { delete astbuf1; } | - attr tok_prim_wrapper { + attr tok_prim_wrapper delay { astbuf1 = new AstNode(AST_PRIMITIVE); astbuf1->str = *$2; append_attr(astbuf1, $1); @@ -813,10 +853,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); @@ -831,14 +871,10 @@ 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 | cell_port_list ',' cell_port; cell_port: + /* empty */ | expr { AstNode *node = new AstNode(AST_ARGUMENT); astbuf2->children.push_back(node); @@ -926,27 +962,34 @@ opt_label: assert: TOK_ASSERT '(' expr ')' ';' { ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $3)); + } | + TOK_ASSUME '(' expr ')' ';' { + 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)); + } | + TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); }; simple_behavioral_stmt: - lvalue '=' expr { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3); + lvalue '=' delay expr { + AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $4); ast_stack.back()->children.push_back(node); } | - lvalue OP_LE expr { - AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $3); + lvalue OP_LE delay expr { + AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $4); ast_stack.back()->children.push_back(node); }; // this production creates the obligatory if-else shift/reduce conflict behavioral_stmt: - defattr | assert | wire_decl | - simple_behavioral_stmt ';' | + defattr | assert | wire_decl | param_decl | localparam_decl | + non_opt_delay behavioral_stmt | + simple_behavioral_stmt ';' | ';' | hierarchical_id attr { AstNode *node = new AstNode(AST_TCALL); node->str = *$1; @@ -1039,13 +1082,13 @@ behavioral_stmt: }; case_type: - TOK_CASE { + TOK_CASE { case_type_stack.push_back(0); } | - TOK_CASEX { + TOK_CASEX { case_type_stack.push_back('x'); } | - TOK_CASEZ { + TOK_CASEZ { case_type_stack.push_back('z'); }; @@ -1060,10 +1103,6 @@ opt_synopsys_attr: } | /* empty */; -behavioral_stmt_opt: - behavioral_stmt | - ';' ; - behavioral_stmt_list: behavioral_stmt_list behavioral_stmt | /* empty */; @@ -1084,7 +1123,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 { @@ -1092,7 +1133,7 @@ case_item: ast_stack.back()->children.push_back(block); ast_stack.push_back(block); case_type_stack.push_back(0); - } behavioral_stmt_opt { + } behavioral_stmt { case_type_stack.pop_back(); ast_stack.pop_back(); ast_stack.pop_back(); @@ -1104,7 +1145,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 { @@ -1330,6 +1373,11 @@ basic_expr: '(' expr ')' { $$ = $2; } | + '(' expr ':' expr ':' expr ')' { + delete $2; + $$ = $4; + delete $6; + } | '{' concat_list '}' { $$ = $2; } | |