diff options
Diffstat (limited to 'frontends/verilog')
-rw-r--r-- | frontends/verilog/.gitignore | 2 | ||||
-rw-r--r-- | frontends/verilog/Makefile.inc | 7 | ||||
-rw-r--r-- | frontends/verilog/const2ast.cc | 8 | ||||
-rw-r--r-- | frontends/verilog/verilog_frontend.cc | 80 | ||||
-rw-r--r-- | frontends/verilog/verilog_frontend.h | 9 | ||||
-rw-r--r-- | frontends/verilog/verilog_lexer.l | 25 | ||||
-rw-r--r-- | frontends/verilog/verilog_parser.y | 454 |
7 files changed, 448 insertions, 137 deletions
diff --git a/frontends/verilog/.gitignore b/frontends/verilog/.gitignore index 1d4ae9e5c..aadbcdcdd 100644 --- a/frontends/verilog/.gitignore +++ b/frontends/verilog/.gitignore @@ -1,4 +1,4 @@ verilog_lexer.cc verilog_parser.output verilog_parser.tab.cc -verilog_parser.tab.h +verilog_parser.tab.hh diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index a06c1d5ab..dbaace585 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -1,15 +1,14 @@ GENFILES += frontends/verilog/verilog_parser.tab.cc -GENFILES += frontends/verilog/verilog_parser.tab.h +GENFILES += frontends/verilog/verilog_parser.tab.hh GENFILES += frontends/verilog/verilog_parser.output GENFILES += frontends/verilog/verilog_lexer.cc frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y $(Q) mkdir -p $(dir $@) - $(P) $(BISON) -d -r all -b frontends/verilog/verilog_parser $< - $(Q) mv frontends/verilog/verilog_parser.tab.c frontends/verilog/verilog_parser.tab.cc + $(P) $(BISON) -o $@ -d -r all -b frontends/verilog/verilog_parser $< -frontends/verilog/verilog_parser.tab.h: frontends/verilog/verilog_parser.tab.cc +frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l $(Q) mkdir -p $(dir $@) diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index 4a58357bf..7848c626d 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -49,8 +49,7 @@ static int my_decimal_div_by_two(std::vector<uint8_t> &digits) int carry = 0; for (size_t i = 0; i < digits.size(); i++) { if (digits[i] >= 10) - log_error("Invalid use of [a-fxz?] in decimal constant at %s:%d.\n", - current_filename.c_str(), get_line_num()); + log_file_error(current_filename, get_line_num(), "Invalid use of [a-fxz?] in decimal constant.\n"); digits[i] += carry * 10; carry = digits[i] % 2; digits[i] /= 2; @@ -105,8 +104,8 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le int bits_per_digit = my_ilog2(base-1); for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) { if (*it > (base-1) && *it < 0xf0) - log_error("Digit larger than %d used in in base-%d constant at %s:%d.\n", - base-1, base, current_filename.c_str(), get_line_num()); + log_file_error(current_filename, get_line_num(), "Digit larger than %d used in in base-%d constant.\n", + base-1, base); for (int i = 0; i < bits_per_digit; i++) { int bitmask = 1 << i; if (*it == 0xf0) @@ -238,4 +237,3 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn } YOSYS_NAMESPACE_END - diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 505c94619..504f8b3f3 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -42,14 +42,14 @@ static std::list<std::vector<std::string>> verilog_defaults_stack; static void error_on_dpi_function(AST::AstNode *node) { if (node->type == AST::AST_DPI_FUNCTION) - log_error("Found DPI function %s at %s:%d.\n", node->str.c_str(), node->filename.c_str(), node->linenum); + log_file_error(node->filename, node->linenum, "Found DPI function %s.\n", node->str.c_str()); for (auto child : node->children) error_on_dpi_function(child); } struct VerilogFrontend : public Frontend { VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -66,19 +66,37 @@ struct VerilogFrontend : public Frontend { log(" enable support for SystemVerilog assertions and some Yosys extensions\n"); log(" replace the implicit -D SYNTHESIS with -D FORMAL\n"); log("\n"); + log(" -noassert\n"); + log(" ignore assert() statements\n"); + log("\n"); + log(" -noassume\n"); + log(" ignore assume() statements\n"); + log("\n"); log(" -norestrict\n"); - log(" ignore restrict() assertions\n"); + log(" ignore restrict() statements\n"); log("\n"); log(" -assume-asserts\n"); log(" treat all assert() statements like assume() statements\n"); log("\n"); + log(" -assert-assumes\n"); + log(" treat all assume() statements like assert() statements\n"); + log("\n"); + log(" -debug\n"); + log(" alias for -dump_ast1 -dump_ast2 -dump_vlog1 -dump_vlog2 -yydebug\n"); + log("\n"); log(" -dump_ast1\n"); log(" dump abstract syntax tree (before simplification)\n"); log("\n"); log(" -dump_ast2\n"); log(" dump abstract syntax tree (after simplification)\n"); log("\n"); - log(" -dump_vlog\n"); + log(" -no_dump_ptr\n"); + log(" do not include hex memory addresses in dump (easier to diff dumps)\n"); + log("\n"); + log(" -dump_vlog1\n"); + log(" dump ast as Verilog code (before simplification)\n"); + log("\n"); + log(" -dump_vlog2\n"); log(" dump ast as Verilog code (after simplification)\n"); log("\n"); log(" -dump_rtlil\n"); @@ -180,11 +198,13 @@ struct VerilogFrontend : public Frontend { log("supported by the Yosys Verilog front-end.\n"); log("\n"); } - virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool flag_dump_ast1 = false; bool flag_dump_ast2 = false; - bool flag_dump_vlog = false; + bool flag_no_dump_ptr = false; + bool flag_dump_vlog1 = false; + bool flag_dump_vlog2 = false; bool flag_dump_rtlil = false; bool flag_nolatches = false; bool flag_nomeminit = false; @@ -225,6 +245,14 @@ struct VerilogFrontend : public Frontend { formal_mode = true; continue; } + if (arg == "-noassert") { + noassert_mode = true; + continue; + } + if (arg == "-noassume") { + noassume_mode = true; + continue; + } if (arg == "-norestrict") { norestrict_mode = true; continue; @@ -233,6 +261,18 @@ struct VerilogFrontend : public Frontend { assume_asserts_mode = true; continue; } + if (arg == "-assert-assumes") { + assert_assumes_mode = true; + continue; + } + if (arg == "-debug") { + flag_dump_ast1 = true; + flag_dump_ast2 = true; + flag_dump_vlog1 = true; + flag_dump_vlog2 = true; + frontend_verilog_yydebug = true; + continue; + } if (arg == "-dump_ast1") { flag_dump_ast1 = true; continue; @@ -241,8 +281,16 @@ struct VerilogFrontend : public Frontend { flag_dump_ast2 = true; continue; } - if (arg == "-dump_vlog") { - flag_dump_vlog = true; + if (arg == "-no_dump_ptr") { + flag_no_dump_ptr = true; + continue; + } + if (arg == "-dump_vlog1") { + flag_dump_vlog1 = true; + continue; + } + if (arg == "-dump_vlog2") { + flag_dump_vlog2 = true; continue; } if (arg == "-dump_rtlil") { @@ -381,7 +429,7 @@ struct VerilogFrontend : public Frontend { if (flag_nodpi) error_on_dpi_function(current_ast); - AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); + AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); if (!flag_nopp) delete lexin; @@ -395,7 +443,7 @@ struct VerilogFrontend : public Frontend { struct VerilogDefaults : public Pass { VerilogDefaults() : Pass("verilog_defaults", "set default options for read_verilog") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -416,7 +464,7 @@ struct VerilogDefaults : public Pass { log("not imply -clear.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design*) + void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE { if (args.size() < 2) cmd_error(args, 1, "Missing argument."); @@ -453,7 +501,7 @@ struct VerilogDefaults : public Pass { struct VerilogDefines : public Pass { VerilogDefines() : Pass("verilog_defines", "define and undefine verilog defines") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -469,7 +517,7 @@ struct VerilogDefines : public Pass { log(" undefine the preprocessor symbol 'name'\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -519,13 +567,11 @@ void frontend_verilog_yyerror(char const *fmt, ...) va_list ap; char buffer[1024]; char *p = buffer; - p += snprintf(p, buffer + sizeof(buffer) - p, "Parser error in line %s:%d: ", - YOSYS_NAMESPACE_PREFIX AST::current_filename.c_str(), frontend_verilog_yyget_lineno()); va_start(ap, fmt); p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap); va_end(ap); p += snprintf(p, buffer + sizeof(buffer) - p, "\n"); - YOSYS_NAMESPACE_PREFIX log_error("%s", buffer); + YOSYS_NAMESPACE_PREFIX log_file_error(YOSYS_NAMESPACE_PREFIX AST::current_filename, frontend_verilog_yyget_lineno(), + "%s", buffer); exit(1); } - diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index 16edc7985..523bbc897 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -54,12 +54,21 @@ namespace VERILOG_FRONTEND // running in -formal mode extern bool formal_mode; + // running in -noassert mode + extern bool noassert_mode; + + // running in -noassume mode + extern bool noassume_mode; + // running in -norestrict mode extern bool norestrict_mode; // running in -assume-asserts mode extern bool assume_asserts_mode; + // running in -assert-assumes mode + extern bool assert_assumes_mode; + // running in -lib mode extern bool lib_mode; diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index d12c9ee4e..6ef38252a 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -42,7 +42,7 @@ #include "kernel/log.h" #include "frontends/verilog/verilog_frontend.h" #include "frontends/ast/ast.h" -#include "verilog_parser.tab.h" +#include "verilog_parser.tab.hh" USING_YOSYS_NAMESPACE using namespace AST; @@ -135,6 +135,9 @@ YOSYS_NAMESPACE_END frontend_verilog_yyerror("Unsupported default nettype: %s", p); } +"`protect"[^\n]* /* ignore `protect*/ +"`endprotect"[^\n]* /* ignore `endprotect*/ + "`"[a-zA-Z_$][a-zA-Z0-9_$]* { frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext); } @@ -150,6 +153,9 @@ YOSYS_NAMESPACE_END "specparam" { return TOK_SPECPARAM; } "package" { SV_KEYWORD(TOK_PACKAGE); } "endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); } +"interface" { SV_KEYWORD(TOK_INTERFACE); } +"endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); } +"modport" { SV_KEYWORD(TOK_MODPORT); } "parameter" { return TOK_PARAMETER; } "localparam" { return TOK_LOCALPARAM; } "defparam" { return TOK_DEFPARAM; } @@ -183,6 +189,14 @@ YOSYS_NAMESPACE_END "always_ff" { SV_KEYWORD(TOK_ALWAYS); } "always_latch" { SV_KEYWORD(TOK_ALWAYS); } + /* use special token for labels on assert, assume, cover, and restrict because it's insanley complex + to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some + global state.. its a mess) */ +[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(std::string("\\") + yytext); + return TOK_SVA_LABEL; +} + "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); } @@ -192,7 +206,7 @@ YOSYS_NAMESPACE_END "const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } "checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } "endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } -"logic" { SV_KEYWORD(TOK_REG); } +"logic" { SV_KEYWORD(TOK_LOGIC); } "bit" { SV_KEYWORD(TOK_REG); } "eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } @@ -268,7 +282,7 @@ YOSYS_NAMESPACE_END yystr[j++] = yystr[i++]; } yystr[j] = 0; - frontend_verilog_yylval.string = new std::string(yystr); + frontend_verilog_yylval.string = new std::string(yystr, j); free(yystr); return TOK_STRING; } @@ -295,6 +309,11 @@ supply1 { return TOK_SUPPLY1; } return TOK_ID; } +[a-zA-Z_$][a-zA-Z0-9_$\.]* { + frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); + return TOK_ID; +} + "/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" { static bool printed_warning = false; if (!printed_warning) { diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index e803d8072..52685f637 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -35,6 +35,7 @@ %{ #include <list> +#include <stack> #include <string.h> #include "frontends/verilog/verilog_frontend.h" #include "kernel/log.h" @@ -47,7 +48,8 @@ YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { int port_counter; std::map<std::string, int> port_stubs; - std::map<std::string, AstNode*> attr_list, default_attr_list; + std::map<std::string, AstNode*> *attr_list, default_attr_list; + std::stack<std::map<std::string, AstNode*> *> attr_list_stack; std::map<std::string, AstNode*> *albuf; std::vector<AstNode*> ast_stack; struct AstNode *astbuf1, *astbuf2, *astbuf3; @@ -58,8 +60,10 @@ namespace VERILOG_FRONTEND { bool do_not_require_port_stubs; bool default_nettype_wire; bool sv_mode, formal_mode, lib_mode; - bool norestrict_mode, assume_asserts_mode; + bool noassert_mode, noassume_mode, norestrict_mode; + bool assume_asserts_mode, assert_assumes_mode; bool current_wire_rand, current_wire_const; + bool current_modport_input, current_modport_output; std::istream *lexin; } YOSYS_NAMESPACE_END @@ -101,11 +105,13 @@ static void free_attr(std::map<std::string, AstNode*> *al) bool boolean; } -%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE +%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL +%token 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 -%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG +%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT +%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC %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 %token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC @@ -114,15 +120,14 @@ 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 tok_prim_wrapper hierarchical_id -%type <boolean> opt_signed unique_case_attr +%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id +%type <boolean> opt_signed opt_property unique_case_attr %type <al> attr case_attr // operator precedence from low to high @@ -167,19 +172,23 @@ design: param_decl design | localparam_decl design | package design | + interface design | /* empty */; attr: { - for (auto &it : attr_list) - delete it.second; - attr_list.clear(); + if (attr_list != nullptr) + attr_list_stack.push(attr_list); + attr_list = new std::map<std::string, AstNode*>; for (auto &it : default_attr_list) - attr_list[it.first] = it.second->clone(); + (*attr_list)[it.first] = it.second->clone(); } attr_opt { - std::map<std::string, AstNode*> *al = new std::map<std::string, AstNode*>; - al->swap(attr_list); - $$ = al; + $$ = attr_list; + if (!attr_list_stack.empty()) { + attr_list = attr_list_stack.top(); + attr_list_stack.pop(); + } else + attr_list = nullptr; }; attr_opt: @@ -188,15 +197,20 @@ attr_opt: defattr: DEFATTR_BEGIN { + if (attr_list != nullptr) + attr_list_stack.push(attr_list); + attr_list = new std::map<std::string, AstNode*>; for (auto &it : default_attr_list) delete it.second; default_attr_list.clear(); - for (auto &it : attr_list) - delete it.second; - attr_list.clear(); } opt_attr_list { - default_attr_list = attr_list; - attr_list.clear(); + attr_list->swap(default_attr_list); + delete attr_list; + if (!attr_list_stack.empty()) { + attr_list = attr_list_stack.top(); + attr_list_stack.pop(); + } else + attr_list = nullptr; } DEFATTR_END; opt_attr_list: @@ -208,15 +222,15 @@ attr_list: attr_assign: hierarchical_id { - if (attr_list.count(*$1) != 0) - delete attr_list[*$1]; - attr_list[*$1] = AstNode::mkconst_int(1, false); + if (attr_list->count(*$1) != 0) + delete (*attr_list)[*$1]; + (*attr_list)[*$1] = AstNode::mkconst_int(1, false); delete $1; } | hierarchical_id '=' expr { - if (attr_list.count(*$1) != 0) - delete attr_list[*$1]; - attr_list[*$1] = $3; + if (attr_list->count(*$1) != 0) + delete (*attr_list)[*$1]; + (*attr_list)[*$1] = $3; delete $1; }; @@ -301,7 +315,7 @@ module_arg_opt_assignment: else ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2)); } else - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("SystemVerilog interface in module port list cannot have a default value."); } | /* empty */; @@ -319,6 +333,21 @@ module_arg: } delete $1; } module_arg_opt_assignment | + TOK_ID { + astbuf1 = new AstNode(AST_INTERFACEPORT); + astbuf1->children.push_back(new AstNode(AST_INTERFACEPORTTYPE)); + astbuf1->children[0]->str = *$1; + delete $1; + } TOK_ID { /* SV interfaces */ + if (!sv_mode) + frontend_verilog_yyerror("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str()); + astbuf2 = astbuf1->clone(); // really only needed if multiple instances of same type. + astbuf2->str = *$3; + delete $3; + astbuf2->port_id = ++port_counter; + ast_stack.back()->children.push_back(astbuf2); + delete astbuf1; // really only needed if multiple instances of same type. + } module_arg_opt_assignment | attr wire_type range TOK_ID { AstNode *node = $2; node->str = *$4; @@ -356,6 +385,33 @@ package_body: package_body_stmt: localparam_decl; +interface: + TOK_INTERFACE TOK_ID { + do_not_require_port_stubs = false; + AstNode *intf = new AstNode(AST_INTERFACE); + ast_stack.back()->children.push_back(intf); + ast_stack.push_back(intf); + current_ast_mod = intf; + port_stubs.clear(); + port_counter = 0; + intf->str = *$2; + delete $2; + } module_para_opt module_args_opt ';' interface_body TOK_ENDINTERFACE { + if (port_stubs.size() != 0) + frontend_verilog_yyerror("Missing details for module port `%s'.", + port_stubs.begin()->first.c_str()); + ast_stack.pop_back(); + log_assert(ast_stack.size() == 1); + current_ast_mod = NULL; + }; + +interface_body: + interface_body interface_body_stmt |; + +interface_body_stmt: + param_decl | localparam_decl | defparam_decl | wire_decl | always_stmt | assign_stmt | + modport_stmt; + non_opt_delay: '#' TOK_ID { delete $2; } | '#' TOK_CONSTVAL { delete $2; } | @@ -376,9 +432,10 @@ wire_type: }; wire_type_token_list: - wire_type_token | wire_type_token_list wire_type_token; + wire_type_token | wire_type_token_list wire_type_token | + wire_type_token_io ; -wire_type_token: +wire_type_token_io: TOK_INPUT { astbuf3->is_input = true; } | @@ -388,12 +445,17 @@ wire_type_token: TOK_INOUT { astbuf3->is_input = true; astbuf3->is_output = true; - } | + }; + +wire_type_token: TOK_WIRE { } | TOK_REG { astbuf3->is_reg = true; } | + TOK_LOGIC { + astbuf3->is_logic = true; + } | TOK_INTEGER { astbuf3->is_reg = true; astbuf3->range_left = 31; @@ -545,6 +607,7 @@ task_func_decl: AstNode *outreg = new AstNode(AST_WIRE); outreg->str = *$6; outreg->is_signed = $4; + outreg->is_reg = true; if ($5 != NULL) { outreg->children.push_back($5); outreg->is_signed = $4 || $5->is_signed; @@ -619,7 +682,7 @@ task_func_port: astbuf2 = $3; if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) { if (astbuf2) { - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions (task/function arguments)"); } else { astbuf2 = new AstNode(AST_RANGE); astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true)); @@ -627,7 +690,7 @@ task_func_port: } } if (astbuf2 && astbuf2->children.size() != 2) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("task/function argument range must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]"); } wire_name | wire_name; task_func_body: @@ -647,7 +710,7 @@ specify_item: // | pulsestyle_declaration // | showcancelled_declaration | path_declaration - // | system_timing_declaration + | system_timing_declaration ; specparam_declaration: @@ -675,22 +738,23 @@ showcancelled_declaration : */ path_declaration : - simple_path_declaration + simple_path_declaration ';' // | edge_sensitive_path_declaration // | state_dependent_path_declaration ; simple_path_declaration : - parallel_path_description '=' path_delay_value ';' - // | full_path_description '=' path_delay_value ';' + parallel_path_description '=' path_delay_value | + full_path_description '=' path_delay_value ; path_delay_value : - //list_of_path_delay_expressions - '(' list_of_path_delay_expressions ')' + '(' path_delay_expression list_of_path_delay_extra_expressions ')' + | path_delay_expression + | path_delay_expression list_of_path_delay_extra_expressions ; -list_of_path_delay_expressions : +list_of_path_delay_extra_expressions : /* t_path_delay_expression | trise_path_delay_expression ',' tfall_path_delay_expression @@ -702,12 +766,11 @@ list_of_path_delay_expressions : t0x_path_delay_expression ',' tx1_path_delay_expression ',' t1x_path_delay_expression ',' tx0_path_delay_expression ',' txz_path_delay_expression ',' tzx_path_delay_expression */ - path_delay_expression - | path_delay_expression ',' path_delay_expression - | path_delay_expression ',' path_delay_expression ',' path_delay_expression - | path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' + ',' path_delay_expression + | ',' path_delay_expression ',' path_delay_expression + | ',' path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' path_delay_expression - | path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' + | ',' path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' path_delay_expression @@ -716,6 +779,22 @@ list_of_path_delay_expressions : parallel_path_description : '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' ; +full_path_description : + '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' ; + +// This was broken into 2 rules to solve shift/reduce conflicts +list_of_path_inputs : + specify_input_terminal_descriptor opt_polarity_operator | + specify_input_terminal_descriptor more_path_inputs opt_polarity_operator ; + +more_path_inputs : + ',' specify_input_terminal_descriptor | + more_path_inputs ',' specify_input_terminal_descriptor ; + +list_of_path_outputs : + specify_output_terminal_descriptor | + list_of_path_outputs ',' specify_output_terminal_descriptor ; + opt_polarity_operator : '+' | '-' @@ -729,10 +808,17 @@ specify_input_terminal_descriptor : specify_output_terminal_descriptor : TOK_ID ; -/* system_timing_declaration : - ; -*/ + TOK_ID '(' system_timing_args ')' ';' ; + +system_timing_arg : + TOK_POSEDGE TOK_ID | + TOK_NEGEDGE TOK_ID | + expr ; + +system_timing_args : + system_timing_arg | + system_timing_args ',' system_timing_arg ; /* t_path_delay_expression : @@ -785,7 +871,7 @@ tzx_path_delay_expression : */ path_delay_expression : - constant_mintypmax_expression; + constant_expression; constant_mintypmax_expression : constant_expression @@ -795,7 +881,7 @@ constant_mintypmax_expression : // for the time being this is OK, but we may write our own expr here. // as I'm not sure it is legal to use a full expr here (probably not) // On the other hand, other rules requiring constant expressions also use 'expr' -// (such as param assignment), so we may leave this as-is, perhaps assing runtime checks for constant-ness +// (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness constant_expression: expr ; @@ -807,7 +893,7 @@ param_signed: param_integer: TOK_INTEGER { if (astbuf1->children.size() != 1) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("Internal error in param_integer - should not happen?"); astbuf1->children.push_back(new AstNode(AST_RANGE)); astbuf1->children.back()->children.push_back(AstNode::mkconst_int(31, true)); astbuf1->children.back()->children.push_back(AstNode::mkconst_int(0, true)); @@ -817,7 +903,7 @@ param_integer: param_real: TOK_REAL { if (astbuf1->children.size() != 1) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("Parameter already declared as integer, cannot set to real."); astbuf1->children.push_back(new AstNode(AST_REALVALUE)); } | /* empty */; @@ -825,7 +911,7 @@ param_range: range { if ($1 != NULL) { if (astbuf1->children.size() != 1) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("integer/real parameters should not have a range."); astbuf1->children.push_back($1); } }; @@ -851,9 +937,15 @@ param_decl_list: single_param_decl: TOK_ID '=' expr { - if (astbuf1 == nullptr) - frontend_verilog_yyerror("syntax error"); - AstNode *node = astbuf1->clone(); + AstNode *node; + if (astbuf1 == nullptr) { + if (!sv_mode) + frontend_verilog_yyerror("In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword"); + node = new AstNode(AST_PARAMETER); + node->children.push_back(AstNode::mkconst_int(0, true)); + } else { + node = astbuf1->clone(); + } node->str = *$1; delete node->children[0]; node->children[0] = $3; @@ -884,7 +976,7 @@ wire_decl: astbuf2 = $3; if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) { if (astbuf2) { - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions."); } else { astbuf2 = new AstNode(AST_RANGE); astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true)); @@ -892,7 +984,7 @@ wire_decl: } } if (astbuf2 && astbuf2->children.size() != 2) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]"); } wire_name_list { delete astbuf1; if (astbuf2 != NULL) @@ -986,7 +1078,7 @@ wire_name_and_opt_assign: wire_name: TOK_ID range_or_multirange { if (astbuf1 == nullptr) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("Internal error - should not happen - no AST_WIRE node."); AstNode *node = astbuf1->clone(); node->str = *$1; append_attr_clone(node, albuf); @@ -994,7 +1086,7 @@ wire_name: node->children.push_back(astbuf2->clone()); if ($2 != NULL) { if (node->is_input || node->is_output) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("input/output/inout ports cannot have unpacked dimensions."); if (!astbuf2) { AstNode *rng = new AstNode(AST_RANGE); rng->children.push_back(AstNode::mkconst_int(0, true)); @@ -1024,6 +1116,7 @@ wire_name: node->port_id = current_function_or_task_port_id++; } ast_stack.back()->children.push_back(node); + delete $1; }; @@ -1236,74 +1329,216 @@ opt_label: $$ = NULL; }; +opt_sva_label: + TOK_SVA_LABEL ':' { + $$ = $1; + } | + /* empty */ { + $$ = NULL; + }; + opt_property: - TOK_PROPERTY | /* empty */; + TOK_PROPERTY { + $$ = true; + } | + /* empty */ { + $$ = false; + }; -opt_stmt_label: - TOK_ID ':' | /* empty */; +modport_stmt: + TOK_MODPORT TOK_ID { + AstNode *modport = new AstNode(AST_MODPORT); + ast_stack.back()->children.push_back(modport); + ast_stack.push_back(modport); + modport->str = *$2; + delete $2; + } modport_args_opt { + ast_stack.pop_back(); + log_assert(ast_stack.size() == 2); + } ';' + +modport_args_opt: + '(' ')' | '(' modport_args optional_comma ')'; + +modport_args: + modport_arg | modport_args ',' modport_arg; + +modport_arg: + modport_type_token modport_member | + modport_member + +modport_member: + TOK_ID { + AstNode *modport_member = new AstNode(AST_MODPORTMEMBER); + ast_stack.back()->children.push_back(modport_member); + modport_member->str = *$1; + modport_member->is_input = current_modport_input; + modport_member->is_output = current_modport_output; + delete $1; + } + +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 ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5)); + opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' { + if (noassert_mode) { + delete $5; + } else { + AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if ($1 != nullptr) + delete $1; } | - opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); + opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' { + if (noassume_mode) { + delete $5; + } else { + AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if ($1 != nullptr) + delete $1; } | - opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6)); + opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { + if (noassert_mode) { + delete $6; + } else { + AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if ($1 != nullptr) + delete $1; } | - opt_stmt_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + opt_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' { + if (noassume_mode) { + delete $6; + } else { + AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if ($1 != nullptr) + delete $1; } | - opt_stmt_label TOK_COVER opt_property '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5)); + opt_sva_label TOK_COVER opt_property '(' expr ')' ';' { + AstNode *node = new AstNode(AST_COVER, $5); + if ($1 != nullptr) { + node->str = *$1; + delete $1; + } + ast_stack.back()->children.push_back(node); } | - opt_stmt_label TOK_COVER opt_property '(' ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false))); + opt_sva_label TOK_COVER opt_property '(' ')' ';' { + AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); + if ($1 != nullptr) { + node->str = *$1; + delete $1; + } + ast_stack.back()->children.push_back(node); } | - opt_stmt_label TOK_COVER ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false))); + opt_sva_label TOK_COVER ';' { + AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); + if ($1 != nullptr) { + node->str = *$1; + delete $1; + } + ast_stack.back()->children.push_back(node); } | - opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' { - if (norestrict_mode) + opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' { + if (norestrict_mode) { delete $5; - else - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); + } else { + AstNode *node = new AstNode(AST_ASSUME, $5); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if (!$3) + 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 ')' ';' { - if (norestrict_mode) + opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' { + if (norestrict_mode) { delete $6; - else - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + } else { + AstNode *node = new AstNode(AST_FAIR, $6); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if (!$3) + log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); + if ($1 != nullptr) + delete $1; }; assert_property: - TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { - 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)); + opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5)); + 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)); + opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $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)); + opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6)); + 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)); + opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | - TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' { - if (norestrict_mode) - delete $4; - else - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); + opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | - TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - if (norestrict_mode) + opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' { + if (norestrict_mode) { delete $5; - else - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5)); + } else { + ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } + } + } | + opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { + if (norestrict_mode) { + delete $6; + } else { + ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } + } }; simple_behavioral_stmt: @@ -1348,7 +1583,7 @@ behavioral_stmt: node->str = *$3; } behavioral_stmt_list TOK_END opt_label { if ($3 != NULL && $7 != NULL && *$3 != *$7) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $3->c_str()+1, $7->c_str()+1); if ($3 != NULL) delete $3; if ($7 != NULL) @@ -1521,6 +1756,11 @@ case_expr_list: TOK_DEFAULT { ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT)); } | + TOK_SVA_LABEL { + ast_stack.back()->children.push_back(new AstNode(AST_IDENTIFIER)); + ast_stack.back()->children.back()->str = *$1; + delete $1; + } | expr { ast_stack.back()->children.push_back($1); } | @@ -1664,7 +1904,7 @@ basic_expr: } | '(' expr ')' TOK_CONSTVAL { if ($4->substr(0, 1) != "'") - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("Cast operation must be applied on sized constants e.g. (<expr>)<constval> , while %s is not a sized constant.", $4->c_str()); AstNode *bits = $2; AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if (val == NULL) @@ -1674,7 +1914,7 @@ basic_expr: } | hierarchical_id TOK_CONSTVAL { if ($2->substr(0, 1) != "'") - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("Cast operation must be applied on sized constants, e.g. <ID>\'d0, while %s is not a sized constant.", $2->c_str()); AstNode *bits = new AstNode(AST_IDENTIFIER); bits->str = *$1; AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); |