diff options
Diffstat (limited to 'frontends/verilog')
-rw-r--r-- | frontends/verilog/Makefile.inc | 2 | ||||
-rw-r--r-- | frontends/verilog/verilog_frontend.cc | 22 | ||||
-rw-r--r-- | frontends/verilog/verilog_frontend.h | 7 | ||||
-rw-r--r-- | frontends/verilog/verilog_lexer.l | 131 | ||||
-rw-r--r-- | frontends/verilog/verilog_parser.y | 481 |
5 files changed, 539 insertions, 104 deletions
diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 6a8462b41..cf9b9531e 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -10,7 +10,7 @@ frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc -frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l +frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l frontends/verilog/verilog_parser.tab.cc $(Q) mkdir -p $(dir $@) $(P) flex -o frontends/verilog/verilog_lexer.cc $< diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 058d750c3..f2c1c227f 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -42,11 +42,27 @@ 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_file_error(node->filename, node->linenum, "Found DPI function %s.\n", node->str.c_str()); + log_file_error(node->filename, node->location.first_line, "Found DPI function %s.\n", node->str.c_str()); for (auto child : node->children) error_on_dpi_function(child); } +static void add_package_types(std::map<std::string, AST::AstNode *> &user_types, std::vector<AST::AstNode *> &package_list) +{ + // prime the parser's user type lookup table with the package qualified names + // of typedefed names in the packages seen so far. + user_types.clear(); + for (const auto &pkg : package_list) { + log_assert(pkg->type==AST::AST_PACKAGE); + for (const auto &node: pkg->children) { + if (node->type == AST::AST_TYPEDEF) { + std::string s = pkg->str + "::" + node->str.substr(1); + user_types[s] = node; + } + } + } +} + struct VerilogFrontend : public Frontend { VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { } void help() YS_OVERRIDE @@ -450,6 +466,9 @@ struct VerilogFrontend : public Frontend { lexin = new std::istringstream(code_after_preproc); } + // make package typedefs available to parser + add_package_types(pkg_user_types, design->verilog_packages); + frontend_verilog_yyset_lineno(1); frontend_verilog_yyrestart(NULL); frontend_verilog_yyparse(); @@ -468,6 +487,7 @@ struct VerilogFrontend : public Frontend { 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, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); + if (!flag_nopp) delete lexin; diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index a7c9b2fe6..73ea51e6c 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -45,6 +45,12 @@ namespace VERILOG_FRONTEND // this function converts a Verilog constant to an AST_CONSTANT node AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false); + // names of locally typedef'ed types + extern std::map<std::string, AST::AstNode*> user_types; + + // names of package typedef'ed types + extern std::map<std::string, AST::AstNode*> pkg_user_types; + // state of `default_nettype extern bool default_nettype_wire; @@ -87,7 +93,6 @@ YOSYS_NAMESPACE_END // the usual bison/flex stuff extern int frontend_verilog_yydebug; -int frontend_verilog_yylex(void); void frontend_verilog_yyerror(char const *fmt, ...); void frontend_verilog_yyrestart(FILE *f); int frontend_verilog_yyparse(void); diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 9b43c250e..74e8dce7f 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -55,29 +55,57 @@ namespace VERILOG_FRONTEND { } YOSYS_NAMESPACE_END +#define YYSTYPE FRONTEND_VERILOG_YYSTYPE +#define YYLTYPE FRONTEND_VERILOG_YYLTYPE + #define SV_KEYWORD(_tok) \ if (sv_mode) return _tok; \ log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\ "recognized unless read_verilog is called with -sv!\n", yytext, \ AST::current_filename.c_str(), frontend_verilog_yyget_lineno()); \ - frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); \ + yylval->string = new std::string(std::string("\\") + yytext); \ return TOK_ID; #define NON_KEYWORD() \ - frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); \ + yylval->string = new std::string(std::string("\\") + yytext); \ return TOK_ID; #define YY_INPUT(buf,result,max_size) \ result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size) +YYLTYPE real_location; +YYLTYPE old_location; + +#define YY_USER_ACTION \ + old_location = real_location; \ + real_location.first_line = real_location.last_line; \ + real_location.first_column = real_location.last_column; \ + for(int i = 0; yytext[i] != '\0'; ++i){ \ + if(yytext[i] == '\n') { \ + real_location.last_line++; \ + real_location.last_column = 1; \ + } \ + else { \ + real_location.last_column++; \ + } \ + } \ + (*yylloc) = real_location; + +#define YY_BREAK \ + (*yylloc) = old_location; \ + break; + #undef YY_BUF_SIZE #define YY_BUF_SIZE 65536 +extern int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param); %} %option yylineno %option noyywrap %option nounput +%option bison-locations +%option bison-bridge %option prefix="frontend_verilog_yy" %x COMMENT @@ -85,8 +113,10 @@ YOSYS_NAMESPACE_END %x SYNOPSYS_TRANSLATE_OFF %x SYNOPSYS_FLAGS %x IMPORT_DPI +%x BASED_CONST %% + int comment_caller; <INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_push "[^\n]* { fn_stack.push_back(current_filename); @@ -97,12 +127,16 @@ YOSYS_NAMESPACE_END if (!current_filename.empty() && current_filename.back() == '"') current_filename = current_filename.substr(0, current_filename.size()-1); frontend_verilog_yyset_lineno(0); + yylloc->first_line = yylloc->last_line = 0; + real_location.first_line = real_location.last_line = 0; } <INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_pop"[^\n]*\n { current_filename = fn_stack.back(); fn_stack.pop_back(); frontend_verilog_yyset_lineno(ln_stack.back()); + yylloc->first_line = yylloc->last_line = ln_stack.back(); + real_location.first_line = real_location.last_line = ln_stack.back(); ln_stack.pop_back(); } @@ -110,6 +144,8 @@ YOSYS_NAMESPACE_END char *p = yytext + 5; while (*p == ' ' || *p == '\t') p++; frontend_verilog_yyset_lineno(atoi(p)); + yylloc->first_line = yylloc->last_line = atoi(p); + real_location.first_line = real_location.last_line = atoi(p); while (*p && *p != ' ' && *p != '\t') p++; while (*p == ' ' || *p == '\t') p++; char *q = *p ? p + 1 : p; @@ -198,7 +234,7 @@ YOSYS_NAMESPACE_END [a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] { if (!strcmp(yytext, "default")) return TOK_DEFAULT; - frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); + yylval->string = new std::string(std::string("\\") + yytext); return TOK_SVA_LABEL; } @@ -235,27 +271,39 @@ YOSYS_NAMESPACE_END "typedef" { SV_KEYWORD(TOK_TYPEDEF); } [0-9][0-9_]* { - frontend_verilog_yylval.string = new std::string(yytext); + yylval->string = new std::string(yytext); return TOK_CONSTVAL; } -[0-9]*[ \t]*\'[sS]?[bodhBODH]?[ \t\r\n]*[0-9a-fA-FzxZX?_]+ { - frontend_verilog_yylval.string = new std::string(yytext); - return TOK_CONSTVAL; +\'[01zxZX] { + yylval->string = new std::string(yytext); + return TOK_UNBASED_UNSIZED_CONSTVAL; +} + +\'[sS]?[bodhBODH] { + BEGIN(BASED_CONST); + yylval->string = new std::string(yytext); + return TOK_BASE; +} + +<BASED_CONST>[0-9a-fA-FzxZX?][0-9a-fA-FzxZX?_]* { + BEGIN(0); + yylval->string = new std::string(yytext); + return TOK_BASED_CONSTVAL; } [0-9][0-9_]*\.[0-9][0-9_]*([eE][-+]?[0-9_]+)? { - frontend_verilog_yylval.string = new std::string(yytext); + yylval->string = new std::string(yytext); return TOK_REALVAL; } [0-9][0-9_]*[eE][-+]?[0-9_]+ { - frontend_verilog_yylval.string = new std::string(yytext); + yylval->string = new std::string(yytext); return TOK_REALVAL; } \" { BEGIN(STRING); } -<STRING>\\. { yymore(); } +<STRING>\\. { yymore(); real_location = old_location; } <STRING>\" { BEGIN(0); char *yystr = strdup(yytext); @@ -291,14 +339,14 @@ YOSYS_NAMESPACE_END yystr[j++] = yystr[i++]; } yystr[j] = 0; - frontend_verilog_yylval.string = new std::string(yystr, j); + yylval->string = new std::string(yystr, j); free(yystr); return TOK_STRING; } -<STRING>. { yymore(); } +<STRING>. { yymore(); real_location = old_location; } and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 { - frontend_verilog_yylval.string = new std::string(yytext); + yylval->string = new std::string(yytext); return TOK_PRIMITIVE; } @@ -306,31 +354,55 @@ supply0 { return TOK_SUPPLY0; } supply1 { return TOK_SUPPLY1; } "$"(display|write|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) { - frontend_verilog_yylval.string = new std::string(yytext); + yylval->string = new std::string(yytext); return TOK_ID; } "$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) { if (!specify_mode) REJECT; - frontend_verilog_yylval.string = new std::string(yytext); + yylval->string = new std::string(yytext); return TOK_ID; } "$"(info|warning|error|fatal) { - frontend_verilog_yylval.string = new std::string(yytext); + yylval->string = new std::string(yytext); return TOK_MSG_TASKS; } "$signed" { return TOK_TO_SIGNED; } "$unsigned" { return TOK_TO_UNSIGNED; } +[a-zA-Z_][a-zA-Z0-9_]*::[a-zA-Z_$][a-zA-Z0-9_$]* { + // package qualifier + auto s = std::string("\\") + yytext; + if (pkg_user_types.count(s) > 0) { + // found it + yylval->string = new std::string(s); + return TOK_USER_TYPE; + } + else { + // backup before :: just return first part + size_t len = strchr(yytext, ':') - yytext; + yyless(len); + yylval->string = new std::string(std::string("\\") + yytext); + return TOK_ID; + } +} + [a-zA-Z_$][a-zA-Z0-9_$]* { - frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); - return TOK_ID; + auto s = std::string("\\") + yytext; + if (user_types.count(s) > 0) { + yylval->string = new std::string(s); + return TOK_USER_TYPE; + } + else { + yylval->string = new std::string(std::string("\\") + yytext); + return TOK_ID; + } } [a-zA-Z_$][a-zA-Z0-9_$\.]* { - frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); + yylval->string = new std::string(std::string("\\") + yytext); return TOK_ID; } @@ -377,7 +449,7 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { } <IMPORT_DPI>[a-zA-Z_$][a-zA-Z0-9_$]* { - frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); + yylval->string = new std::string(std::string("\\") + yytext); return TOK_ID; } @@ -393,7 +465,7 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { } "\\"[^ \t\r\n]+ { - frontend_verilog_yylval.string = new std::string(yytext); + yylval->string = new std::string(yytext); return TOK_ID; } @@ -435,25 +507,26 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { [-+]?[=*]> { if (!specify_mode) REJECT; - frontend_verilog_yylval.string = new std::string(yytext); + yylval->string = new std::string(yytext); return TOK_SPECIFY_OPER; } "&&&" { - if (!specify_mode) REJECT; + if (!specify_mode) return TOK_IGNORED_SPECIFY_AND; return TOK_SPECIFY_AND; } -"/*" { BEGIN(COMMENT); } +<INITIAL,BASED_CONST>"/*" { comment_caller=YY_START; BEGIN(COMMENT); } <COMMENT>. /* ignore comment body */ <COMMENT>\n /* ignore comment body */ -<COMMENT>"*/" { BEGIN(0); } +<COMMENT>"*/" { BEGIN(comment_caller); } -[ \t\r\n] /* ignore whitespaces */ -\\[\r\n] /* ignore continuation sequence */ -"//"[^\r\n]* /* ignore one-line comments */ +<INITIAL,BASED_CONST>[ \t\r\n] /* ignore whitespaces */ +<INITIAL,BASED_CONST>\\[\r\n] /* ignore continuation sequence */ +<INITIAL,BASED_CONST>"//"[^\r\n]* /* ignore one-line comments */ -. { return *yytext; } +<INITIAL>. { return *yytext; } +<*>. { BEGIN(0); return *yytext; } %% diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 2c7304cc4..f7e3afd13 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -38,8 +38,11 @@ #include <stack> #include <string.h> #include "frontends/verilog/verilog_frontend.h" +#include "frontends/verilog/verilog_parser.tab.hh" #include "kernel/log.h" +#define YYLEX_PARAM &yylval, &yylloc + USING_YOSYS_NAMESPACE using namespace AST; using namespace VERILOG_FRONTEND; @@ -51,6 +54,8 @@ namespace VERILOG_FRONTEND { 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::map<std::string, AstNode*> user_types; + std::map<std::string, AstNode*> pkg_user_types; std::vector<AstNode*> ast_stack; struct AstNode *astbuf1, *astbuf2, *astbuf3; struct AstNode *current_function_or_task; @@ -68,6 +73,20 @@ namespace VERILOG_FRONTEND { } YOSYS_NAMESPACE_END +#define SET_AST_NODE_LOC(WHICH, BEGIN, END) \ + do { (WHICH)->location.first_line = (BEGIN).first_line; \ + (WHICH)->location.first_column = (BEGIN).first_column; \ + (WHICH)->location.last_line = (END).last_line; \ + (WHICH)->location.last_column = (END).last_column; } while(0) + +#define SET_RULE_LOC(LHS, BEGIN, END) \ + do { (LHS).first_line = (BEGIN).first_line; \ + (LHS).first_column = (BEGIN).first_column; \ + (LHS).last_line = (END).last_line; \ + (LHS).last_column = (END).last_column; } while(0) + +int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param); + static void append_attr(AstNode *ast, std::map<std::string, AstNode*> *al) { for (auto &it : *al) { @@ -108,9 +127,44 @@ struct specify_rise_fall { specify_triple fall; }; +static void addTypedefNode(std::string *name, AstNode *node) +{ + log_assert(node); + // seems to be support for local scoped typedefs in simplify() + // and tests redefine types. + //if (user_types.count(*name) > 0) { + // frontend_verilog_yyerror("Type already defined."); + //} + auto *tnode = new AstNode(AST_TYPEDEF, node); + tnode->str = *name; + user_types[*name] = tnode; + if (current_ast_mod && current_ast_mod->type == AST_PACKAGE) { + // typedef inside a package so we need the qualified name + auto qname = current_ast_mod->str + "::" + (*name).substr(1); + pkg_user_types[qname] = tnode; + } + delete name; + ast_stack.back()->children.push_back(tnode); +} + +static AstNode *makeRange(int msb = 31, int lsb = 0, bool isSigned = true) +{ + auto range = new AstNode(AST_RANGE); + range->children.push_back(AstNode::mkconst_int(msb, true)); + range->children.push_back(AstNode::mkconst_int(lsb, true)); + range->is_signed = isSigned; + return range; +} + +static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = true) +{ + auto range = makeRange(msb, lsb, isSigned); + parent->children.push_back(range); +} %} %define api.prefix {frontend_verilog_yy} +%define api.pure /* The union is defined in the header, so we need to provide all the * includes it requires @@ -134,6 +188,8 @@ struct specify_rise_fall { %token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE %token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS +%token <string> TOK_BASE TOK_BASED_CONSTVAL TOK_UNBASED_UNSIZED_CONSTVAL +%token <string> TOK_USER_TYPE %token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM @@ -146,7 +202,7 @@ struct specify_rise_fall { %token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC %token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT %token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY -%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND +%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND TOK_IGNORED_SPECIFY_AND %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 @@ -156,14 +212,16 @@ struct specify_rise_fall { %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_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id +%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 %type <boolean> opt_signed opt_property unique_case_attr always_comb_or_latch always_or_always_ff %type <al> attr case_attr %type <specify_target_ptr> specify_target -%type <specify_triple_ptr> specify_triple +%type <specify_triple_ptr> specify_triple specify_opt_triple %type <specify_rise_fall_ptr> specify_rise_fall -%type <ast> specify_if specify_condition specify_opt_arg +%type <ast> specify_if specify_condition %type <ch> specify_edge // operator precedence from low to high @@ -187,6 +245,7 @@ struct specify_rise_fall { %nonassoc TOK_ELSE %debug +%locations %% @@ -229,7 +288,9 @@ attr: }; attr_opt: - attr_opt ATTR_BEGIN opt_attr_list ATTR_END | + attr_opt ATTR_BEGIN opt_attr_list ATTR_END { + SET_RULE_LOC(@$, @2, @$); + }| /* empty */; defattr: @@ -293,7 +354,9 @@ hierarchical_id: }; hierarchical_type_id: - '(' hierarchical_id ')' { $$ = $2; }; + TOK_USER_TYPE + | '(' TOK_USER_TYPE ')' { $$ = $2; } // non-standard grammar + ; module: attr TOK_MODULE TOK_ID { @@ -311,9 +374,11 @@ module: if (port_stubs.size() != 0) frontend_verilog_yyerror("Missing details for module port `%s'.", port_stubs.begin()->first.c_str()); + SET_AST_NODE_LOC(ast_stack.back(), @2, @$); ast_stack.pop_back(); log_assert(ast_stack.size() == 1); current_ast_mod = NULL; + user_types.clear(); }; module_para_opt: @@ -374,6 +439,7 @@ module_arg: node->str = *$1; node->port_id = ++port_counter; ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @1, @1); } else { if (port_stubs.count(*$1) != 0) frontend_verilog_yyerror("Duplicate module port `%s'.", $1->c_str()); @@ -399,6 +465,7 @@ module_arg: attr wire_type range TOK_ID { AstNode *node = $2; node->str = *$4; + SET_AST_NODE_LOC(node, @4, @4); node->port_id = ++port_counter; if ($3 != NULL) node->children.push_back($3); @@ -425,10 +492,13 @@ package: } ';' package_body TOK_ENDPACKAGE { ast_stack.pop_back(); current_ast_mod = NULL; + user_types.clear(); }; package_body: - package_body package_body_stmt |; + package_body package_body_stmt + | // optional + ; package_body_stmt: typedef_decl | @@ -452,6 +522,7 @@ interface: ast_stack.pop_back(); log_assert(ast_stack.size() == 1); current_ast_mod = NULL; + user_types.clear(); }; interface_body: @@ -476,8 +547,9 @@ wire_type: astbuf3 = new AstNode(AST_WIRE); current_wire_rand = false; current_wire_const = false; - } wire_type_token_list delay { + } wire_type_token_list { $$ = astbuf3; + SET_RULE_LOC(@$, @2, @$); }; wire_type_token_list: @@ -551,13 +623,15 @@ non_opt_range: } | '[' expr TOK_POS_INDEXED expr ']' { $$ = new AstNode(AST_RANGE); - $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, $2->clone(), $4), AstNode::mkconst_int(1, true))); - $$->children.push_back(new AstNode(AST_ADD, $2, AstNode::mkconst_int(0, true))); + AstNode *expr = new AstNode(AST_CONCAT, $2); + $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), $4), AstNode::mkconst_int(1, true))); + $$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); } | '[' expr TOK_NEG_INDEXED expr ']' { $$ = new AstNode(AST_RANGE); - $$->children.push_back(new AstNode(AST_ADD, $2, AstNode::mkconst_int(0, true))); - $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, $2->clone(), AstNode::mkconst_int(1, true)), $4)); + AstNode *expr = new AstNode(AST_CONCAT, $2); + $$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); + $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), AstNode::mkconst_int(1, true)), $4)); } | '[' expr ']' { $$ = new AstNode(AST_RANGE); @@ -604,6 +678,7 @@ module_body: module_body_stmt: task_func_decl | specify_block | param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | + enum_decl | always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block; checker_decl: @@ -855,7 +930,7 @@ specify_item: delete target; delete timing; } | - TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr specify_opt_arg ')' ';' { + TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' specify_triple specify_opt_triple ')' ';' { if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" && *$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange") frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str()); @@ -868,8 +943,8 @@ specify_item: AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1); AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1); - AstNode *limit = $11; - AstNode *limit2 = $12; + specify_triple *limit = $11; + specify_triple *limit2 = $12; AstNode *cell = new AstNode(AST_CELL); ast_stack.back()->children.push_back(cell); @@ -880,11 +955,23 @@ specify_item: cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1))); cell->children.back()->str = "\\TYPE"; - cell->children.push_back(new AstNode(AST_PARASET, limit)); - cell->children.back()->str = "\\T_LIMIT"; + cell->children.push_back(new AstNode(AST_PARASET, limit->t_min)); + cell->children.back()->str = "\\T_LIMIT_MIN"; + + cell->children.push_back(new AstNode(AST_PARASET, limit->t_avg)); + cell->children.back()->str = "\\T_LIMIT_TYP"; - cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2 : AstNode::mkconst_int(0, true))); - cell->children.back()->str = "\\T_LIMIT2"; + cell->children.push_back(new AstNode(AST_PARASET, limit->t_max)); + cell->children.back()->str = "\\T_LIMIT_MAX"; + + cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_min : AstNode::mkconst_int(0, true))); + cell->children.back()->str = "\\T_LIMIT2_MIN"; + + cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_avg : AstNode::mkconst_int(0, true))); + cell->children.back()->str = "\\T_LIMIT2_TYP"; + + cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_max : AstNode::mkconst_int(0, true))); + cell->children.back()->str = "\\T_LIMIT2_MAX"; cell->children.push_back(new AstNode(AST_PARASET, src_pen)); cell->children.back()->str = "\\SRC_PEN"; @@ -913,8 +1000,8 @@ specify_item: delete $1; }; -specify_opt_arg: - ',' expr { +specify_opt_triple: + ',' specify_triple { $$ = $2; } | /* empty */ { @@ -983,7 +1070,46 @@ specify_rise_fall: $$->fall = *$4; delete $2; delete $4; - }; + } | + '(' specify_triple ',' specify_triple ',' specify_triple ')' { + $$ = new specify_rise_fall; + $$->rise = *$2; + $$->fall = *$4; + delete $2; + delete $4; + delete $6; + log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + } | + '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' { + $$ = new specify_rise_fall; + $$->rise = *$2; + $$->fall = *$4; + delete $2; + delete $4; + delete $6; + delete $8; + delete $10; + delete $12; + log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + } | + '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' { + $$ = new specify_rise_fall; + $$->rise = *$2; + $$->fall = *$4; + delete $2; + delete $4; + delete $6; + delete $8; + delete $10; + delete $12; + delete $14; + delete $16; + delete $18; + delete $20; + delete $22; + delete $24; + log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + } specify_triple: expr { @@ -1031,7 +1157,7 @@ list_of_specparam_assignments: specparam_assignment | list_of_specparam_assignments ',' specparam_assignment; specparam_assignment: - ignspec_id '=' constant_mintypmax_expression ; + ignspec_id '=' ignspec_expr ; ignspec_opt_cond: TOK_IF '(' ignspec_expr ')' | /* empty */; @@ -1048,13 +1174,15 @@ simple_path_declaration : ; path_delay_value : - '(' path_delay_expression list_of_path_delay_extra_expressions ')' - | path_delay_expression - | path_delay_expression list_of_path_delay_extra_expressions + '(' ignspec_expr list_of_path_delay_extra_expressions ')' + | ignspec_expr + | ignspec_expr list_of_path_delay_extra_expressions ; list_of_path_delay_extra_expressions : - ',' path_delay_expression | ',' path_delay_expression list_of_path_delay_extra_expressions; + ',' ignspec_expr + | ',' ignspec_expr list_of_path_delay_extra_expressions + ; specify_edge_identifier : TOK_POSEDGE | TOK_NEGEDGE ; @@ -1105,16 +1233,9 @@ system_timing_arg : system_timing_args : system_timing_arg | + system_timing_args TOK_IGNORED_SPECIFY_AND system_timing_arg | system_timing_args ',' system_timing_arg ; -path_delay_expression : - ignspec_constant_expression; - -constant_mintypmax_expression : - ignspec_constant_expression - | ignspec_constant_expression ':' ignspec_constant_expression ':' ignspec_constant_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' @@ -1123,10 +1244,16 @@ ignspec_constant_expression: expr { delete $1; }; ignspec_expr: - expr { delete $1; }; + expr { delete $1; } | + expr ':' expr ':' expr { + delete $1; + delete $3; + delete $5; + }; ignspec_id: - TOK_ID { delete $1; }; + TOK_ID { delete $1; } + range_or_multirange { delete $3; }; /**********************************************************************/ @@ -1224,6 +1351,85 @@ single_defparam_decl: ast_stack.back()->children.push_back(node); }; +enum_type: TOK_ENUM { + static int enum_count; + // create parent node for the enum + astbuf2 = new AstNode(AST_ENUM); + ast_stack.back()->children.push_back(astbuf2); + astbuf2->str = std::string("$enum"); + astbuf2->str += std::to_string(enum_count++); + // create the template for the names + astbuf1 = new AstNode(AST_ENUM_ITEM); + astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + } param_signed enum_base_type '{' enum_name_list '}' { // create template for the enum vars + auto tnode = astbuf1->clone(); + delete astbuf1; + astbuf1 = tnode; + tnode->type = AST_WIRE; + tnode->attributes["\\enum_type"] = AstNode::mkconst_str(astbuf2->str); + // drop constant but keep any range + delete tnode->children[0]; + tnode->children.erase(tnode->children.begin()); } + ; + +enum_base_type: int_vec param_range + | int_atom + | /* nothing */ {astbuf1->is_reg = true; addRange(astbuf1); } + ; + +int_atom: TOK_INTEGER {astbuf1->is_reg=true; addRange(astbuf1); } // probably should do byte, range [7:0] here + ; + +int_vec: TOK_REG {astbuf1->is_reg = true;} + | TOK_LOGIC {astbuf1->is_logic = true;} + ; + +enum_name_list: + enum_name_decl + | enum_name_list ',' enum_name_decl + ; + +enum_name_decl: + TOK_ID opt_enum_init { + // put in fn + log_assert(astbuf1); + log_assert(astbuf2); + auto node = astbuf1->clone(); + node->str = *$1; + delete $1; + delete node->children[0]; + node->children[0] = $2 ?: new AstNode(AST_NONE); + astbuf2->children.push_back(node); + } + ; + +opt_enum_init: + '=' basic_expr { $$ = $2; } // TODO: restrict this + | /* optional */ { $$ = NULL; } + ; + +enum_var_list: + enum_var + | enum_var_list ',' enum_var + ; + +enum_var: TOK_ID { + log_assert(astbuf1); + log_assert(astbuf2); + auto node = astbuf1->clone(); + ast_stack.back()->children.push_back(node); + node->str = *$1; + delete $1; + node->is_enum = true; + } + ; + +enum_decl: enum_type enum_var_list ';' { + //enum_type creates astbuf1 for use by typedef only + delete astbuf1; + } + ; + wire_decl: attr wire_type range { albuf = $1; @@ -1240,7 +1446,7 @@ wire_decl: } if (astbuf2 && astbuf2->children.size() != 2) frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]"); - } wire_name_list { + } delay wire_name_list { delete astbuf1; if (astbuf2 != NULL) delete astbuf2; @@ -1328,11 +1534,24 @@ wire_name_and_opt_assign: if (astbuf1->attributes.count("\\defaultvalue")) delete astbuf1->attributes.at("\\defaultvalue"); astbuf1->attributes["\\defaultvalue"] = $3; - } else - if (astbuf1->is_reg || astbuf1->is_logic) - ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $3)))); - else - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $3)); + } + else if (astbuf1->is_reg || astbuf1->is_logic){ + AstNode *assign = new AstNode(AST_ASSIGN_LE, wire, $3); + AstNode *block = new AstNode(AST_BLOCK, assign); + AstNode *init = new AstNode(AST_INITIAL, block); + + SET_AST_NODE_LOC(assign, @1, @3); + SET_AST_NODE_LOC(block, @1, @3); + SET_AST_NODE_LOC(init, @1, @3); + + ast_stack.back()->children.push_back(init); + } + else { + AstNode *assign = new AstNode(AST_ASSIGN, wire, $3); + SET_AST_NODE_LOC(assign, @1, @3); + ast_stack.back()->children.push_back(assign); + } + }; wire_name: @@ -1381,6 +1600,8 @@ wire_name: if (node->is_input || node->is_output) node->port_id = current_function_or_task_port_id++; } + //FIXME: for some reason, TOK_ID has a location which always points to one column *after* the real last column... + SET_AST_NODE_LOC(node, @1, @1); ast_stack.back()->children.push_back(node); delete $1; @@ -1394,11 +1615,17 @@ assign_expr_list: assign_expr: lvalue '=' expr { - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, $1, $3)); + AstNode *node = new AstNode(AST_ASSIGN, $1, $3); + SET_AST_NODE_LOC(node, @$, @$); + ast_stack.back()->children.push_back(node); }; +type_name: TOK_ID // first time seen + | TOK_USER_TYPE // redefinition + ; + typedef_decl: - TOK_TYPEDEF wire_type range TOK_ID range_or_multirange ';' { + TOK_TYPEDEF wire_type range type_name range_or_multirange ';' { astbuf1 = $2; astbuf2 = $3; if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) { @@ -1431,10 +1658,12 @@ typedef_decl: } astbuf1->children.push_back(rangeNode); } - - ast_stack.back()->children.push_back(new AstNode(AST_TYPEDEF, astbuf1)); - ast_stack.back()->children.back()->str = *$4; - }; + addTypedefNode($4, astbuf1); + } | + TOK_TYPEDEF enum_type type_name ';' { + addTypedefNode($3, astbuf1); + } + ; cell_stmt: attr TOK_ID { @@ -1474,14 +1703,19 @@ single_cell: astbuf2->str = *$1; delete $1; ast_stack.back()->children.push_back(astbuf2); - } '(' cell_port_list ')' | + } '(' cell_port_list ')' { + SET_AST_NODE_LOC(astbuf2, @1, @$); + } | TOK_ID non_opt_range { astbuf2 = astbuf1->clone(); if (astbuf2->type != AST_PRIMITIVE) astbuf2->str = *$1; delete $1; ast_stack.back()->children.push_back(new AstNode(AST_CELLARRAY, $2, astbuf2)); - } '(' cell_port_list ')'; + } '(' cell_port_list ')'{ + SET_AST_NODE_LOC(astbuf2, @1, @$); + SET_AST_NODE_LOC(astbuf3, @1, @$); + }; prim_list: single_prim | @@ -1616,8 +1850,13 @@ always_stmt: ast_stack.back()->children.push_back(block); ast_stack.push_back(block); } behavioral_stmt { + SET_AST_NODE_LOC(ast_stack.back(), @6, @6); ast_stack.pop_back(); + + SET_AST_NODE_LOC(ast_stack.back(), @2, @$); ast_stack.pop_back(); + + SET_RULE_LOC(@$, @2, @$); } | attr always_comb_or_latch { AstNode *node = new AstNode(AST_ALWAYS); @@ -1746,6 +1985,7 @@ assert: delete $5; } else { AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5); + SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); @@ -1758,6 +1998,7 @@ assert: delete $5; } else { AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5); + SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); @@ -1770,6 +2011,7 @@ assert: delete $6; } else { AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6); + SET_AST_NODE_LOC(node, @1, @7); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); @@ -1782,6 +2024,7 @@ assert: delete $6; } else { AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6); + SET_AST_NODE_LOC(node, @1, @7); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); @@ -1791,6 +2034,7 @@ assert: } | opt_sva_label TOK_COVER opt_property '(' expr ')' ';' { AstNode *node = new AstNode(AST_COVER, $5); + SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) { node->str = *$1; delete $1; @@ -1799,6 +2043,7 @@ assert: } | opt_sva_label TOK_COVER opt_property '(' ')' ';' { AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); + SET_AST_NODE_LOC(node, @1, @5); if ($1 != nullptr) { node->str = *$1; delete $1; @@ -1807,6 +2052,7 @@ assert: } | opt_sva_label TOK_COVER ';' { AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); + SET_AST_NODE_LOC(node, @1, @2); if ($1 != nullptr) { node->str = *$1; delete $1; @@ -1818,6 +2064,7 @@ assert: delete $5; } else { AstNode *node = new AstNode(AST_ASSUME, $5); + SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); @@ -1832,6 +2079,7 @@ assert: delete $6; } else { AstNode *node = new AstNode(AST_FAIR, $6); + SET_AST_NODE_LOC(node, @1, @7); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); @@ -1844,35 +2092,45 @@ assert: assert_property: opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5)); + AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5); + SET_AST_NODE_LOC(node, @1, @6); + ast_stack.back()->children.push_back(node); if ($1 != nullptr) { ast_stack.back()->children.back()->str = *$1; delete $1; } } | opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); + AstNode *node = new AstNode(AST_ASSUME, $5); + SET_AST_NODE_LOC(node, @1, @6); + ast_stack.back()->children.push_back(node); if ($1 != nullptr) { ast_stack.back()->children.back()->str = *$1; delete $1; } } | 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)); + AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6); + SET_AST_NODE_LOC(node, @1, @7); + ast_stack.back()->children.push_back(node); if ($1 != nullptr) { ast_stack.back()->children.back()->str = *$1; delete $1; } } | opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + AstNode *node = new AstNode(AST_FAIR, $6); + SET_AST_NODE_LOC(node, @1, @7); + ast_stack.back()->children.push_back(node); if ($1 != nullptr) { ast_stack.back()->children.back()->str = *$1; delete $1; } } | opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5)); + AstNode *node = new AstNode(AST_COVER, $5); + SET_AST_NODE_LOC(node, @1, @6); + ast_stack.back()->children.push_back(node); if ($1 != nullptr) { ast_stack.back()->children.back()->str = *$1; delete $1; @@ -1882,7 +2140,9 @@ assert_property: if (norestrict_mode) { delete $5; } else { - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); + AstNode *node = new AstNode(AST_ASSUME, $5); + SET_AST_NODE_LOC(node, @1, @6); + ast_stack.back()->children.push_back(node); if ($1 != nullptr) { ast_stack.back()->children.back()->str = *$1; delete $1; @@ -1893,7 +2153,9 @@ assert_property: if (norestrict_mode) { delete $6; } else { - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + AstNode *node = new AstNode(AST_FAIR, $6); + SET_AST_NODE_LOC(node, @1, @7); + ast_stack.back()->children.push_back(node); if ($1 != nullptr) { ast_stack.back()->children.back()->str = *$1; delete $1; @@ -1905,18 +2167,22 @@ simple_behavioral_stmt: lvalue '=' delay expr { AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $4); ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @1, @4); } | lvalue TOK_INCREMENT { AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, new AstNode(AST_ADD, $1->clone(), AstNode::mkconst_int(1, true))); ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @1, @2); } | lvalue TOK_DECREMENT { AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, new AstNode(AST_SUB, $1->clone(), AstNode::mkconst_int(1, true))); ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @1, @2); } | lvalue OP_LE delay expr { AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $4); ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @1, @4); }; // this production creates the obligatory if-else shift/reduce conflict @@ -1972,7 +2238,9 @@ behavioral_stmt: ast_stack.back()->children.push_back(block); ast_stack.push_back(block); } behavioral_stmt { + SET_AST_NODE_LOC(ast_stack.back(), @13, @13); ast_stack.pop_back(); + SET_AST_NODE_LOC(ast_stack.back(), @2, @13); ast_stack.pop_back(); } | attr TOK_WHILE '(' expr ')' { @@ -1985,6 +2253,7 @@ behavioral_stmt: ast_stack.back()->children.push_back(block); ast_stack.push_back(block); } behavioral_stmt { + SET_AST_NODE_LOC(ast_stack.back(), @7, @7); ast_stack.pop_back(); ast_stack.pop_back(); } | @@ -1998,6 +2267,7 @@ behavioral_stmt: ast_stack.back()->children.push_back(block); ast_stack.push_back(block); } behavioral_stmt { + SET_AST_NODE_LOC(ast_stack.back(), @7, @7); ast_stack.pop_back(); ast_stack.pop_back(); } | @@ -2005,14 +2275,18 @@ behavioral_stmt: AstNode *node = new AstNode(AST_CASE); AstNode *block = new AstNode(AST_BLOCK); AstNode *cond = new AstNode(AST_COND, AstNode::mkconst_int(1, false, 1), block); + SET_AST_NODE_LOC(cond, @4, @4); ast_stack.back()->children.push_back(node); node->children.push_back(new AstNode(AST_REDUCE_BOOL, $4)); node->children.push_back(cond); ast_stack.push_back(node); ast_stack.push_back(block); append_attr(node, $1); - } behavioral_stmt optional_else { + } behavioral_stmt { + SET_AST_NODE_LOC(ast_stack.back(), @7, @7); + } optional_else { ast_stack.pop_back(); + SET_AST_NODE_LOC(ast_stack.back(), @2, @9); ast_stack.pop_back(); } | case_attr case_type '(' expr ')' { @@ -2020,7 +2294,9 @@ behavioral_stmt: ast_stack.back()->children.push_back(node); ast_stack.push_back(node); append_attr(node, $1); + SET_AST_NODE_LOC(ast_stack.back(), @4, @4); } opt_synopsys_attr case_body TOK_ENDCASE { + SET_AST_NODE_LOC(ast_stack.back(), @2, @9); case_type_stack.pop_back(); ast_stack.pop_back(); }; @@ -2072,10 +2348,14 @@ optional_else: TOK_ELSE { AstNode *block = new AstNode(AST_BLOCK); AstNode *cond = new AstNode(AST_COND, new AstNode(AST_DEFAULT), block); + SET_AST_NODE_LOC(cond, @1, @1); + ast_stack.pop_back(); ast_stack.back()->children.push_back(cond); ast_stack.push_back(block); - } behavioral_stmt | + } behavioral_stmt { + SET_AST_NODE_LOC(ast_stack.back(), @3, @3); + } | /* empty */ %prec FAKE_THEN; case_body: @@ -2096,6 +2376,7 @@ case_item: case_type_stack.push_back(0); } behavioral_stmt { case_type_stack.pop_back(); + SET_AST_NODE_LOC(ast_stack.back(), @4, @4); ast_stack.pop_back(); ast_stack.pop_back(); }; @@ -2113,6 +2394,7 @@ gen_case_item: ast_stack.push_back(node); } case_select { case_type_stack.push_back(0); + SET_AST_NODE_LOC(ast_stack.back(), @2, @2); } gen_stmt_or_null { case_type_stack.pop_back(); ast_stack.pop_back(); @@ -2124,10 +2406,14 @@ case_select: case_expr_list: TOK_DEFAULT { - ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT)); + AstNode *node = new AstNode(AST_DEFAULT); + SET_AST_NODE_LOC(node, @1, @1); + ast_stack.back()->children.push_back(node); } | TOK_SVA_LABEL { - ast_stack.back()->children.push_back(new AstNode(AST_IDENTIFIER)); + AstNode *node = new AstNode(AST_IDENTIFIER); + SET_AST_NODE_LOC(node, @1, @1); + ast_stack.back()->children.push_back(node); ast_stack.back()->children.back()->str = *$1; delete $1; } | @@ -2147,6 +2433,7 @@ rvalue: hierarchical_id range { $$ = new AstNode(AST_IDENTIFIER, $2); $$->str = *$1; + SET_AST_NODE_LOC($$, @1, @1); delete $1; if ($2 == nullptr && ($$->str == "\\$initstate" || $$->str == "\\$anyconst" || $$->str == "\\$anyseq" || @@ -2156,6 +2443,7 @@ rvalue: hierarchical_id non_opt_multirange { $$ = new AstNode(AST_IDENTIFIER, $2); $$->str = *$1; + SET_AST_NODE_LOC($$, @1, @1); delete $1; }; @@ -2274,6 +2562,7 @@ expr: $$->children.push_back($1); $$->children.push_back($4); $$->children.push_back($6); + SET_AST_NODE_LOC($$, @1, @$); append_attr($$, $3); }; @@ -2281,7 +2570,7 @@ basic_expr: rvalue { $$ = $1; } | - '(' expr ')' TOK_CONSTVAL { + '(' expr ')' integral_number { if ($4->compare(0, 1, "'") != 0) 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; @@ -2291,11 +2580,12 @@ basic_expr: $$ = new AstNode(AST_TO_BITS, bits, val); delete $4; } | - hierarchical_id TOK_CONSTVAL { + hierarchical_id integral_number { if ($2->compare(0, 1, "'") != 0) 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; + SET_AST_NODE_LOC(bits, @1, @1); 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()); @@ -2303,14 +2593,7 @@ basic_expr: delete $1; delete $2; } | - TOK_CONSTVAL TOK_CONSTVAL { - $$ = 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_CONSTVAL { + integral_number { $$ = 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()); @@ -2323,6 +2606,7 @@ basic_expr: if ((*$1)[j] != '_') p[i++] = (*$1)[j], p[i] = 0; $$->realvalue = strtod(p, &q); + SET_AST_NODE_LOC($$, @1, @1); log_assert(*q == 0); delete $1; free(p); @@ -2336,6 +2620,7 @@ basic_expr: node->str = *$1; delete $1; ast_stack.push_back(node); + SET_AST_NODE_LOC(node, @1, @1); append_attr(node, $2); } '(' arg_list optional_comma ')' { $$ = ast_stack.back(); @@ -2365,148 +2650,185 @@ basic_expr: } | '~' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_BIT_NOT, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); } | basic_expr '&' attr basic_expr { $$ = new AstNode(AST_BIT_AND, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_NAND attr basic_expr { $$ = new AstNode(AST_BIT_NOT, new AstNode(AST_BIT_AND, $1, $4)); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '|' attr basic_expr { $$ = new AstNode(AST_BIT_OR, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_NOR attr basic_expr { $$ = new AstNode(AST_BIT_NOT, new AstNode(AST_BIT_OR, $1, $4)); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '^' attr basic_expr { $$ = new AstNode(AST_BIT_XOR, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_XNOR attr basic_expr { $$ = new AstNode(AST_BIT_XNOR, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | '&' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_AND, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); } | OP_NAND attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_AND, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); $$ = new AstNode(AST_LOGIC_NOT, $$); } | '|' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_OR, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); } | OP_NOR attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_OR, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); $$ = new AstNode(AST_LOGIC_NOT, $$); + SET_AST_NODE_LOC($$, @1, @3); } | '^' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_XOR, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); } | OP_XNOR attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_REDUCE_XNOR, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); } | basic_expr OP_SHL attr basic_expr { $$ = new AstNode(AST_SHIFT_LEFT, $1, new AstNode(AST_TO_UNSIGNED, $4)); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_SHR attr basic_expr { $$ = new AstNode(AST_SHIFT_RIGHT, $1, new AstNode(AST_TO_UNSIGNED, $4)); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_SSHL attr basic_expr { $$ = new AstNode(AST_SHIFT_SLEFT, $1, new AstNode(AST_TO_UNSIGNED, $4)); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_SSHR attr basic_expr { $$ = new AstNode(AST_SHIFT_SRIGHT, $1, new AstNode(AST_TO_UNSIGNED, $4)); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '<' attr basic_expr { $$ = new AstNode(AST_LT, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_LE attr basic_expr { $$ = new AstNode(AST_LE, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_EQ attr basic_expr { $$ = new AstNode(AST_EQ, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_NE attr basic_expr { $$ = new AstNode(AST_NE, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_EQX attr basic_expr { $$ = new AstNode(AST_EQX, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_NEX attr basic_expr { $$ = new AstNode(AST_NEX, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_GE attr basic_expr { $$ = new AstNode(AST_GE, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '>' attr basic_expr { $$ = new AstNode(AST_GT, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '+' attr basic_expr { $$ = new AstNode(AST_ADD, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '-' attr basic_expr { $$ = new AstNode(AST_SUB, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '*' attr basic_expr { $$ = new AstNode(AST_MUL, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '/' attr basic_expr { $$ = new AstNode(AST_DIV, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr '%' attr basic_expr { $$ = new AstNode(AST_MOD, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_POW attr basic_expr { $$ = new AstNode(AST_POW, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | '+' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_POS, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); } | '-' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_NEG, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); } | basic_expr OP_LAND attr basic_expr { $$ = new AstNode(AST_LOGIC_AND, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | basic_expr OP_LOR attr basic_expr { $$ = new AstNode(AST_LOGIC_OR, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); append_attr($$, $3); } | '!' attr basic_expr %prec UNARY_OPS { $$ = new AstNode(AST_LOGIC_NOT, $3); + SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); }; @@ -2518,3 +2840,18 @@ concat_list: $$ = $3; $$->children.push_back($1); }; + +integral_number: + TOK_CONSTVAL { $$ = $1; } | + TOK_UNBASED_UNSIZED_CONSTVAL { $$ = $1; } | + TOK_BASE TOK_BASED_CONSTVAL { + $1->append(*$2); + $$ = $1; + delete $2; + } | + TOK_CONSTVAL TOK_BASE TOK_BASED_CONSTVAL { + $1->append(*$2).append(*$3); + $$ = $1; + delete $2; + delete $3; + }; |