diff options
author | Ahmed Irfan <irfan@levert.(none)> | 2015-04-03 16:38:07 +0200 |
---|---|---|
committer | Ahmed Irfan <irfan@levert.(none)> | 2015-04-03 16:38:07 +0200 |
commit | bdf6b2b19ab2206f5957ad5b2ec582c2730d45ee (patch) | |
tree | 1d02541701054a1c3b1cdb66478d0cbc31c2d38f /frontends/verilog | |
parent | 8acdd90bc918b780ad45cdac42b3baf84d2cc476 (diff) | |
parent | 4b4490761949e738dee54bdfc52e080e0a5c9067 (diff) | |
download | yosys-bdf6b2b19ab2206f5957ad5b2ec582c2730d45ee.tar.gz yosys-bdf6b2b19ab2206f5957ad5b2ec582c2730d45ee.tar.bz2 yosys-bdf6b2b19ab2206f5957ad5b2ec582c2730d45ee.zip |
Merge branch 'master' of https://github.com/cliffordwolf/yosys
Diffstat (limited to 'frontends/verilog')
-rw-r--r-- | frontends/verilog/.gitignore | 8 | ||||
-rw-r--r-- | frontends/verilog/Makefile.inc | 24 | ||||
-rw-r--r-- | frontends/verilog/const2ast.cc | 16 | ||||
-rw-r--r-- | frontends/verilog/preproc.cc | 9 | ||||
-rw-r--r-- | frontends/verilog/verilog_frontend.cc | 60 | ||||
-rw-r--r-- | frontends/verilog/verilog_frontend.h | 5 | ||||
-rw-r--r-- | frontends/verilog/verilog_lexer.l (renamed from frontends/verilog/lexer.l) | 51 | ||||
-rw-r--r-- | frontends/verilog/verilog_parser.y (renamed from frontends/verilog/parser.y) | 136 |
8 files changed, 220 insertions, 89 deletions
diff --git a/frontends/verilog/.gitignore b/frontends/verilog/.gitignore index 72b06b0bf..1d4ae9e5c 100644 --- a/frontends/verilog/.gitignore +++ b/frontends/verilog/.gitignore @@ -1,4 +1,4 @@ -lexer.cc -parser.output -parser.tab.cc -parser.tab.h +verilog_lexer.cc +verilog_parser.output +verilog_parser.tab.cc +verilog_parser.tab.h diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 49eb320ec..92cbd0b87 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -1,20 +1,20 @@ -GENFILES += frontends/verilog/parser.tab.cc -GENFILES += frontends/verilog/parser.tab.h -GENFILES += frontends/verilog/parser.output -GENFILES += frontends/verilog/lexer.cc +GENFILES += frontends/verilog/verilog_parser.tab.cc +GENFILES += frontends/verilog/verilog_parser.tab.h +GENFILES += frontends/verilog/verilog_parser.output +GENFILES += frontends/verilog/verilog_lexer.cc -frontends/verilog/parser.tab.cc: frontends/verilog/parser.y - $(P) bison -d -r all -b frontends/verilog/parser frontends/verilog/parser.y - $(Q) mv frontends/verilog/parser.tab.c frontends/verilog/parser.tab.cc +frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y + $(P) $(BISON) -d -r all -b frontends/verilog/verilog_parser frontends/verilog/verilog_parser.y + $(Q) mv frontends/verilog/verilog_parser.tab.c frontends/verilog/verilog_parser.tab.cc -frontends/verilog/parser.tab.h: frontends/verilog/parser.tab.cc +frontends/verilog/verilog_parser.tab.h: frontends/verilog/verilog_parser.tab.cc -frontends/verilog/lexer.cc: frontends/verilog/lexer.l - $(P) flex -o frontends/verilog/lexer.cc frontends/verilog/lexer.l +frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l + $(P) flex -o frontends/verilog/verilog_lexer.cc frontends/verilog/verilog_lexer.l -OBJS += frontends/verilog/parser.tab.o -OBJS += frontends/verilog/lexer.o +OBJS += frontends/verilog/verilog_parser.tab.o +OBJS += frontends/verilog/verilog_lexer.o OBJS += frontends/verilog/preproc.o OBJS += frontends/verilog/verilog_frontend.o OBJS += frontends/verilog/const2ast.o diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index a81e3010f..735bc5f99 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -132,8 +132,16 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le } // convert the verilog code for a constant to an AST node -AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type) +AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn_z) { + if (warn_z) { + AstNode *ret = const2ast(code, case_type); + if (std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end()) + log_warning("Yosys does not support tri-state logic at the moment. (%s:%d)\n", + current_filename.c_str(), frontend_verilog_yyget_lineno()); + return ret; + } + const char *str = code.c_str(); // Strings @@ -174,7 +182,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type) if (str == endptr) len_in_bits = -1; - // The "<bits>'s?[bodh]<digits>" syntax + // The "<bits>'s?[bodhBODH]<digits>" syntax if (*endptr == '\'') { std::vector<RTLIL::State> data; @@ -186,15 +194,19 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type) switch (*(endptr+1)) { case 'b': + case 'B': my_strtobin(data, endptr+2, len_in_bits, 2, case_type); break; case 'o': + case 'O': my_strtobin(data, endptr+2, len_in_bits, 8, case_type); break; case 'd': + case 'D': my_strtobin(data, endptr+2, len_in_bits, 10, case_type); break; case 'h': + case 'H': my_strtobin(data, endptr+2, len_in_bits, 16, case_type); break; default: diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index f83433219..e2118630e 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -201,8 +201,8 @@ static void input_file(std::istream &f, std::string filename) insert_input(""); auto it = input_buffer.begin(); - input_buffer.insert(it, "`file_push " + filename + "\n"); - while ((rc = f.readsome(buffer, sizeof(buffer)-1)) > 0) { + input_buffer.insert(it, "`file_push \"" + filename + "\"\n"); + while ((rc = readsome(f, buffer, sizeof(buffer)-1)) > 0) { buffer[rc] = 0; input_buffer.insert(it, buffer); } @@ -221,7 +221,8 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons input_buffer_charp = 0; input_file(f, filename); - defines_map["__YOSYS__"] = "1"; + defines_map["YOSYS"] = "1"; + defines_map["SYNTHESIS"] = "1"; while (!input_buffer.empty()) { @@ -422,7 +423,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons if (tok == "(" || tok == "{" || tok == "[") level++; } - for (size_t i = 0; i < args.size(); i++) + for (int i = 0; i < GetSize(args); i++) defines_map[stringf("macro_%s_arg%d", name.c_str(), i+1)] = args[i]; } else { insert_input(tok); diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index c6d4a0b79..635c9ce47 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -54,6 +54,10 @@ struct VerilogFrontend : public Frontend { log(" enable support for SystemVerilog features. (only a small subset\n"); log(" of SystemVerilog is supported)\n"); log("\n"); + log(" -formal\n"); + log(" enable support for assert() and assume() statements\n"); + log(" (assert support is also enabled with -sv)\n"); + log("\n"); log(" -dump_ast1\n"); log(" dump abstract syntax tree (before simplification)\n"); log("\n"); @@ -83,11 +87,20 @@ struct VerilogFrontend : public Frontend { log(" this can also be achieved by setting the 'nomem2reg'\n"); log(" attribute on the respective module or register.\n"); log("\n"); + log(" This is potentially dangerous. Usually the front-end has good\n"); + log(" reasons for converting an array to a list of registers.\n"); + log(" Prohibiting this step will likely result in incorrect synthesis\n"); + log(" results.\n"); + log("\n"); log(" -mem2reg\n"); log(" always convert memories to registers. this can also be\n"); log(" achieved by setting the 'mem2reg' attribute on the respective\n"); log(" module or register.\n"); log("\n"); + log(" -nomeminit\n"); + log(" do not infer $meminit cells and instead convert initialized\n"); + log(" memories to registers directly in the front-end.\n"); + log("\n"); log(" -ppdump\n"); log(" dump verilog code after pre-processor\n"); log("\n"); @@ -139,6 +152,7 @@ struct VerilogFrontend : public Frontend { bool flag_dump_ast2 = false; bool flag_dump_vlog = false; bool flag_nolatches = false; + bool flag_nomeminit = false; bool flag_nomem2reg = false; bool flag_mem2reg = false; bool flag_ppdump = false; @@ -154,6 +168,7 @@ struct VerilogFrontend : public Frontend { frontend_verilog_yydebug = false; sv_mode = false; + formal_mode = false; log_header("Executing Verilog-2005 frontend.\n"); @@ -166,6 +181,10 @@ struct VerilogFrontend : public Frontend { sv_mode = true; continue; } + if (arg == "-formal") { + formal_mode = true; + continue; + } if (arg == "-dump_ast1") { flag_dump_ast1 = true; continue; @@ -186,6 +205,10 @@ struct VerilogFrontend : public Frontend { flag_nolatches = true; continue; } + if (arg == "-nomeminit") { + flag_nomeminit = true; + continue; + } if (arg == "-nomem2reg") { flag_nomem2reg = true; continue; @@ -257,7 +280,8 @@ struct VerilogFrontend : public Frontend { } extra_args(f, filename, args, argidx); - log("Parsing Verilog input from `%s' to AST representation.\n", filename.c_str()); + log("Parsing %s%s input from `%s' to AST representation.\n", + formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str()); AST::current_filename = filename; AST::set_line_num = &frontend_verilog_yyset_lineno; @@ -288,7 +312,7 @@ struct VerilogFrontend : public Frontend { child->attributes[attr] = AST::AstNode::mkconst_int(1, false); } - AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire); + AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire); if (!flag_nopp) delete lexin; @@ -300,22 +324,6 @@ struct VerilogFrontend : public Frontend { } } VerilogFrontend; -// the yyerror function used by bison to report parser errors -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: ", - 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"); - log_error("%s", buffer); - exit(1); -} - struct VerilogDefaults : public Pass { VerilogDefaults() : Pass("verilog_defaults", "set default options for read_verilog") { } virtual void help() @@ -376,3 +384,19 @@ struct VerilogDefaults : public Pass { YOSYS_NAMESPACE_END +// the yyerror function used by bison to report parser errors +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); + exit(1); +} + diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index af6495f8f..5561f54cd 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -43,7 +43,7 @@ namespace VERILOG_FRONTEND extern struct AST::AstNode *current_ast; // this function converts a Verilog constant to an AST_CONSTANT node - AST::AstNode *const2ast(std::string code, char case_type = 0); + AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false); // state of `default_nettype extern bool default_nettype_wire; @@ -51,6 +51,9 @@ namespace VERILOG_FRONTEND // running in SystemVerilog mode extern bool sv_mode; + // running in -formal mode + extern bool formal_mode; + // lexer input stream extern std::istream *lexin; } diff --git a/frontends/verilog/lexer.l b/frontends/verilog/verilog_lexer.l index c9302aba8..8fbaa953d 100644 --- a/frontends/verilog/lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -42,7 +42,7 @@ #include "kernel/log.h" #include "verilog_frontend.h" #include "frontends/ast/ast.h" -#include "parser.tab.h" +#include "verilog_parser.tab.h" USING_YOSYS_NAMESPACE using namespace AST; @@ -64,7 +64,7 @@ YOSYS_NAMESPACE_END return TOK_ID; #define YY_INPUT(buf,result,max_size) \ - result = lexin->readsome(buf, max_size); + result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size) %} @@ -85,6 +85,10 @@ YOSYS_NAMESPACE_END fn_stack.push_back(current_filename); ln_stack.push_back(frontend_verilog_yyget_lineno()); current_filename = yytext+11; + if (!current_filename.empty() && current_filename.front() == '"') + current_filename = current_filename.substr(1); + if (!current_filename.empty() && current_filename.back() == '"') + current_filename = current_filename.substr(0, current_filename.size()-1); frontend_verilog_yyset_lineno(0); } @@ -112,6 +116,9 @@ YOSYS_NAMESPACE_END "`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */ +"`celldefine"[^\n]* /* ignore `celldefine */ +"`endcelldefine"[^\n]* /* ignore `endcelldefine */ + "`default_nettype"[ \t]+[^ \t\r\n/]+ { char *p = yytext; while (*p != 0 && *p != ' ' && *p != '\t') p++; @@ -162,8 +169,9 @@ YOSYS_NAMESPACE_END "always_ff" { SV_KEYWORD(TOK_ALWAYS); } "always_latch" { SV_KEYWORD(TOK_ALWAYS); } -"assert" { SV_KEYWORD(TOK_ASSERT); } -"property" { SV_KEYWORD(TOK_PROPERTY); } +"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); } +"assume" { if (formal_mode) return TOK_ASSUME; return TOK_ID; } +"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); } "logic" { SV_KEYWORD(TOK_REG); } "bit" { SV_KEYWORD(TOK_REG); } @@ -177,12 +185,12 @@ YOSYS_NAMESPACE_END "genvar" { return TOK_GENVAR; } "real" { return TOK_REAL; } -[0-9]+ { +[0-9][0-9_]* { frontend_verilog_yylval.string = new std::string(yytext); return TOK_CONST; } -[0-9]*[ \t]*\'s?[bodh][ \t\r\n]*[0-9a-fA-FzxZX?_]+ { +[0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ { frontend_verilog_yylval.string = new std::string(yytext); return TOK_CONST; } @@ -240,7 +248,7 @@ and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 { supply0 { return TOK_SUPPLY0; } supply1 { return TOK_SUPPLY1; } -"$"(display|time|stop|finish) { +"$"(display|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) { frontend_verilog_yylval.string = new std::string(yytext); return TOK_ID; } @@ -254,8 +262,12 @@ supply1 { return TOK_SUPPLY1; } } "/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" { - log("Warning: Found one of those horrible `(synopsys|synthesis) translate_off' comments.\n"); - log("It is strongly suggested to use `ifdef constructs instead!\n"); + static bool printed_warning = false; + if (!printed_warning) { + log_warning("Found one of those horrible `(synopsys|synthesis) translate_off' comments.\n" + "Yosys does support them but it is recommended to use `ifdef constructs instead!\n"); + printed_warning = true; + } BEGIN(SYNOPSYS_TRANSLATE_OFF); } <SYNOPSYS_TRANSLATE_OFF>. /* ignore synopsys translate_off body */ @@ -266,13 +278,21 @@ supply1 { return TOK_SUPPLY1; } BEGIN(SYNOPSYS_FLAGS); } <SYNOPSYS_FLAGS>full_case { - log("Warning: Found one of those horrible `(synopsys|synthesis) full_case' comments.\n"); - log("It is strongly suggested to use verilog x-values and default branches instead!\n"); + static bool printed_warning = false; + if (!printed_warning) { + log_warning("Found one of those horrible `(synopsys|synthesis) full_case' comments.\n" + "Yosys does support them but it is recommended to use verilog `full_case' attributes instead!\n"); + printed_warning = true; + } return TOK_SYNOPSYS_FULL_CASE; } <SYNOPSYS_FLAGS>parallel_case { - log("Warning: Found one of those horrible `(synopsys|synthesis) parallel_case' comments.\n"); - log("It is strongly suggested to use verilog `parallel_case' attributes instead!\n"); + static bool printed_warning = false; + if (!printed_warning) { + log_warning("Found one of those horrible `(synopsys|synthesis) parallel_case' comments.\n" + "Yosys does support them but it is recommended to use verilog `parallel_case' attributes instead!\n"); + printed_warning = true; + } return TOK_SYNOPSYS_PARALLEL_CASE; } <SYNOPSYS_FLAGS>. /* ignore everything else */ @@ -342,7 +362,10 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { [ \t\r\n] /* ignore whitespaces */ \\[\r\n] /* ignore continuation sequence */ "//"[^\r\n]* /* ignore one-line comments */ -"#"[$a-zA-Z_0-9\.]+ /* ignore simulation timings */ + +"#"\ *[0-9][0-9_]* /* ignore simulation timings */ +"#"\ *[0-9][0-9_]*\.[0-9][0-9_]* /* ignore simulation timings */ +"#"\ *[$a-zA-Z_\.][$a-zA-Z_0-9\.]* /* ignore simulation timings */ . { return *yytext; } diff --git a/frontends/verilog/parser.y b/frontends/verilog/verilog_parser.y index a9f69a49c..d935cab37 100644 --- a/frontends/verilog/parser.y +++ b/frontends/verilog/verilog_parser.y @@ -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 @@ -111,7 +111,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,10 +139,11 @@ 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(); - log_assert(SIZE(ast_stack) == 0); + log_assert(GetSize(ast_stack) == 0); for (auto &it : default_attr_list) delete it.second; default_attr_list.clear(); @@ -240,7 +241,7 @@ module: }; module_para_opt: - '#' '(' module_para_list ')' | /* empty */; + '#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | /* empty */; module_para_list: single_module_para | @@ -249,11 +250,10 @@ module_para_list: single_module_para: TOK_PARAMETER { + if (astbuf1) delete astbuf1; astbuf1 = new AstNode(AST_PARAMETER); astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - } param_signed param_integer param_range single_param_decl { - delete astbuf1; - }; + } param_signed param_integer param_range single_param_decl | single_param_decl; module_args_opt: '(' ')' | /* empty */ | '(' module_args optional_comma ')'; @@ -310,10 +310,17 @@ module_arg: do_not_require_port_stubs = true; }; +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; }; @@ -449,7 +456,7 @@ task_func_decl: } opt_dpi_function_args ';' { current_function_or_task = NULL; } | - attr TOK_TASK TOK_ID ';' { + attr TOK_TASK TOK_ID { current_function_or_task = new AstNode(AST_TASK); current_function_or_task->str = *$3; append_attr(current_function_or_task, $1); @@ -457,11 +464,11 @@ task_func_decl: ast_stack.push_back(current_function_or_task); current_function_or_task_port_id = 1; delete $3; - } task_func_body TOK_ENDTASK { + } task_func_args_opt ';' task_func_body TOK_ENDTASK { current_function_or_task = NULL; ast_stack.pop_back(); } | - attr TOK_FUNCTION opt_signed range_or_signed_int TOK_ID ';' { + attr TOK_FUNCTION opt_signed range_or_signed_int TOK_ID { current_function_or_task = new AstNode(AST_FUNCTION); current_function_or_task->str = *$5; append_attr(current_function_or_task, $1); @@ -478,7 +485,7 @@ task_func_decl: current_function_or_task->children.push_back(outreg); current_function_or_task_port_id = 1; delete $5; - } task_func_body TOK_ENDFUNCTION { + } task_func_args_opt ';' task_func_body TOK_ENDFUNCTION { current_function_or_task = NULL; ast_stack.pop_back(); }; @@ -512,6 +519,45 @@ opt_signed: $$ = false; }; +task_func_args_opt: + '(' ')' | /* empty */ | '(' { + albuf = nullptr; + astbuf1 = nullptr; + astbuf2 = nullptr; + } task_func_args optional_comma { + delete astbuf1; + if (astbuf2 != NULL) + delete astbuf2; + free_attr(albuf); + } ')'; + +task_func_args: + task_func_port | task_func_args ',' task_func_port; + +task_func_port: + attr wire_type range { + if (albuf) { + delete astbuf1; + if (astbuf2 != NULL) + delete astbuf2; + free_attr(albuf); + } + albuf = $1; + astbuf1 = $2; + astbuf2 = $3; + if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) { + if (astbuf2) { + frontend_verilog_yyerror("Syntax error."); + } else { + astbuf2 = new AstNode(AST_RANGE); + astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true)); + astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_right, true)); + } + } + if (astbuf2 && astbuf2->children.size() != 2) + frontend_verilog_yyerror("Syntax error."); + } wire_name | wire_name; + task_func_body: task_func_body behavioral_stmt | /* empty */; @@ -568,6 +614,8 @@ param_decl_list: single_param_decl: TOK_ID '=' expr { + if (astbuf1 == nullptr) + frontend_verilog_yyerror("syntax error"); AstNode *node = astbuf1->clone(); node->str = *$1; delete node->children[0]; @@ -609,27 +657,39 @@ wire_decl: } if (astbuf2 && astbuf2->children.size() != 2) frontend_verilog_yyerror("Syntax error."); - } wire_name_list ';' { + } wire_name_list { delete astbuf1; if (astbuf2 != NULL) delete astbuf2; free_attr(albuf); - } | - attr TOK_SUPPLY0 TOK_ID ';' { + } ';' | + attr TOK_SUPPLY0 TOK_ID { ast_stack.back()->children.push_back(new AstNode(AST_WIRE)); ast_stack.back()->children.back()->str = *$3; append_attr(ast_stack.back()->children.back(), $1); ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1))); ast_stack.back()->children.back()->children[0]->str = *$3; delete $3; - } | - attr TOK_SUPPLY1 TOK_ID ';' { + } opt_supply_wires ';' | + attr TOK_SUPPLY1 TOK_ID { ast_stack.back()->children.push_back(new AstNode(AST_WIRE)); ast_stack.back()->children.back()->str = *$3; append_attr(ast_stack.back()->children.back(), $1); ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(1, false, 1))); ast_stack.back()->children.back()->children[0]->str = *$3; delete $3; + } opt_supply_wires ';'; + +opt_supply_wires: + /* empty */ | + opt_supply_wires ',' TOK_ID { + AstNode *wire_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-2)->clone(); + AstNode *assign_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-1)->clone(); + wire_node->str = *$3; + assign_node->children[0]->str = *$3; + ast_stack.back()->children.push_back(wire_node); + ast_stack.back()->children.push_back(assign_node); + delete $3; }; wire_name_list: @@ -689,7 +749,7 @@ 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; @@ -709,7 +769,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); @@ -874,27 +934,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 ';' | + non_opt_delay behavioral_stmt | + simple_behavioral_stmt ';' | ';' | hierarchical_id attr { AstNode *node = new AstNode(AST_TCALL); node->str = *$1; @@ -1008,10 +1075,6 @@ opt_synopsys_attr: } | /* empty */; -behavioral_stmt_opt: - behavioral_stmt | - ';' ; - behavioral_stmt_list: behavioral_stmt_list behavioral_stmt | /* empty */; @@ -1040,7 +1103,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(); @@ -1211,7 +1274,7 @@ basic_expr: if ($4->substr(0, 1) != "'") frontend_verilog_yyerror("Syntax error."); AstNode *bits = $2; - AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back()); + AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true); if (val == NULL) log_error("Value conversion failed: `%s'\n", $4->c_str()); $$ = new AstNode(AST_TO_BITS, bits, val); @@ -1222,7 +1285,7 @@ basic_expr: frontend_verilog_yyerror("Syntax error."); AstNode *bits = new AstNode(AST_IDENTIFIER); bits->str = *$1; - AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back()); + AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true); if (val == NULL) log_error("Value conversion failed: `%s'\n", $2->c_str()); $$ = new AstNode(AST_TO_BITS, bits, val); @@ -1230,14 +1293,14 @@ basic_expr: delete $2; } | TOK_CONST TOK_CONST { - $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back()); + $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true); if ($$ == NULL || (*$2)[0] != '\'') log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str()); delete $1; delete $2; } | TOK_CONST { - $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back()); + $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true); if ($$ == NULL) log_error("Value conversion failed: `%s'\n", $1->c_str()); delete $1; @@ -1278,10 +1341,15 @@ basic_expr: '(' expr ')' { $$ = $2; } | + '(' expr ':' expr ':' expr ')' { + delete $2; + $$ = $4; + delete $6; + } | '{' concat_list '}' { $$ = $2; } | - '{' expr '{' expr '}' '}' { + '{' expr '{' concat_list '}' '}' { $$ = new AstNode(AST_REPLICATE, $2, $4); } | '~' attr basic_expr %prec UNARY_OPS { |