diff options
Diffstat (limited to 'frontends/verilog')
-rw-r--r-- | frontends/verilog/Makefile.inc | 6 | ||||
-rw-r--r-- | frontends/verilog/const2ast.cc | 93 | ||||
-rw-r--r-- | frontends/verilog/preproc.cc | 11 | ||||
-rw-r--r-- | frontends/verilog/verilog_frontend.cc | 88 | ||||
-rw-r--r-- | frontends/verilog/verilog_frontend.h | 7 | ||||
-rw-r--r-- | frontends/verilog/verilog_lexer.l | 28 | ||||
-rw-r--r-- | frontends/verilog/verilog_parser.y | 124 |
7 files changed, 245 insertions, 112 deletions
diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 92cbd0b87..a06c1d5ab 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -5,13 +5,15 @@ GENFILES += frontends/verilog/verilog_parser.output GENFILES += frontends/verilog/verilog_lexer.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) 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 frontends/verilog/verilog_parser.tab.h: frontends/verilog/verilog_parser.tab.cc frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l - $(P) flex -o frontends/verilog/verilog_lexer.cc frontends/verilog/verilog_lexer.l + $(Q) mkdir -p $(dir $@) + $(P) flex -o frontends/verilog/verilog_lexer.cc $< OBJS += frontends/verilog/verilog_parser.tab.o OBJS += frontends/verilog/verilog_lexer.o diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index 735bc5f99..4a58357bf 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -2,11 +2,11 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * + * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -48,7 +48,9 @@ static int my_decimal_div_by_two(std::vector<uint8_t> &digits) { int carry = 0; for (size_t i = 0; i < digits.size(); i++) { - log_assert(digits[i] < 10); + 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()); digits[i] += carry * 10; carry = digits[i] % 2; digits[i] /= 2; @@ -91,54 +93,67 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le str++; } + if (base == 10 && GetSize(digits) == 1 && digits.front() >= 0xf0) + base = 2; + + data.clear(); + if (base == 10) { - data.clear(); - if (len_in_bits < 0) { - while (!digits.empty()) - data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0); - while (data.size() < 32) - data.push_back(RTLIL::S0); - } else { - for (int i = 0; i < len_in_bits; i++) - data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0); + while (!digits.empty()) + data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0); + } else { + 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()); + for (int i = 0; i < bits_per_digit; i++) { + int bitmask = 1 << i; + if (*it == 0xf0) + data.push_back(case_type == 'x' ? RTLIL::Sa : RTLIL::Sx); + else if (*it == 0xf1) + data.push_back(case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz); + else if (*it == 0xf2) + data.push_back(RTLIL::Sa); + else + data.push_back((*it & bitmask) ? RTLIL::S1 : RTLIL::S0); + } } - return; } - int bits_per_digit = my_ilog2(base-1); - if (len_in_bits < 0) - len_in_bits = std::max<int>(digits.size() * bits_per_digit, 32); + int len = GetSize(data); + RTLIL::State msb = data.empty() ? RTLIL::S0 : data.back(); - data.clear(); - data.resize(len_in_bits); - - for (int i = 0; i < len_in_bits; i++) { - int bitmask = 1 << (i % bits_per_digit); - int digitidx = digits.size() - (i / bits_per_digit) - 1; - if (digitidx < 0) { - if (i > 0 && (data[i-1] == RTLIL::Sz || data[i-1] == RTLIL::Sx || data[i-1] == RTLIL::Sa)) - data[i] = data[i-1]; - else - data[i] = RTLIL::S0; - } else if (digits[digitidx] == 0xf0) - data[i] = case_type == 'x' ? RTLIL::Sa : RTLIL::Sx; - else if (digits[digitidx] == 0xf1) - data[i] = case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz; - else if (digits[digitidx] == 0xf2) - data[i] = RTLIL::Sa; - else - data[i] = (digits[digitidx] & bitmask) ? RTLIL::S1 : RTLIL::S0; + if (len_in_bits < 0) { + if (len < 32) + data.resize(32, msb == RTLIL::S0 || msb == RTLIL::S1 ? RTLIL::S0 : msb); + return; + } + + for (len = len - 1; len >= 0; len--) + if (data[len] == RTLIL::S1) + break; + if (msb == RTLIL::S0 || msb == RTLIL::S1) { + len += 1; + data.resize(len_in_bits, RTLIL::S0); + } else { + len += 2; + data.resize(len_in_bits, msb); } + + if (len > len_in_bits) + log_warning("Literal has a width of %d bit, but value requires %d bit. (%s:%d)\n", + len_in_bits, len, current_filename.c_str(), get_line_num()); } -// convert the verilog code for a constant to an AST node +// convert the Verilog code for a constant to an AST node 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()); + log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n", + current_filename.c_str(), get_line_num()); return ret; } @@ -215,8 +230,6 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn if (len_in_bits < 0) { if (is_signed && data.back() == RTLIL::S1) data.push_back(RTLIL::S0); - while (data.size() < 32) - data.push_back(RTLIL::S0); } return AstNode::mkconst_bits(data, is_signed); } diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index 4e5d16599..997920b89 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -2,11 +2,11 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * + * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -39,6 +39,7 @@ #include <string.h> YOSYS_NAMESPACE_BEGIN +using namespace VERILOG_FRONTEND; static std::list<std::string> output_code; static std::list<std::string> input_buffer; @@ -109,7 +110,7 @@ static std::string next_token(bool pass_newline = false) } return token; } - + if (ch == ' ' || ch == '\t') { while ((ch = next_char()) != 0) { @@ -201,7 +202,7 @@ 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"); + 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); @@ -222,7 +223,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons input_file(f, filename); defines_map["YOSYS"] = "1"; - defines_map["SYNTHESIS"] = "1"; + defines_map[formal_mode ? "FORMAL" : "SYNTHESIS"] = "1"; while (!input_buffer.empty()) { diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 23d35f682..576f068b3 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -2,11 +2,11 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * + * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -39,21 +39,33 @@ using namespace VERILOG_FRONTEND; static std::vector<std::string> verilog_defaults; 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); + for (auto child : node->children) + error_on_dpi_function(child); +} + struct VerilogFrontend : public Frontend { - VerilogFrontend() : Frontend("verilog", "read modules from verilog file") { } + VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { } virtual void help() { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" read_verilog [options] [filename]\n"); log("\n"); - log("Load modules from a verilog file to the current design. A large subset of\n"); + log("Load modules from a Verilog file to the current design. A large subset of\n"); log("Verilog-2005 is supported.\n"); log("\n"); log(" -sv\n"); 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() from SystemVerilog\n"); + log(" replace the implicit -D SYNTHESIS with -D FORMAL\n"); + log("\n"); log(" -dump_ast1\n"); log(" dump abstract syntax tree (before simplification)\n"); log("\n"); @@ -61,7 +73,7 @@ struct VerilogFrontend : public Frontend { log(" dump abstract syntax tree (after simplification)\n"); log("\n"); log(" -dump_vlog\n"); - log(" dump ast as verilog code (after simplification)\n"); + log(" dump ast as Verilog code (after simplification)\n"); log("\n"); log(" -yydebug\n"); log(" enable parser debug output\n"); @@ -83,19 +95,31 @@ 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(" dump Verilog code after pre-processor\n"); log("\n"); log(" -nopp\n"); log(" do not run the pre-processor\n"); log("\n"); + log(" -nodpi\n"); + log(" disable DPI-C support\n"); + log("\n"); log(" -lib\n"); - log(" only create empty blackbox modules\n"); + log(" only create empty blackbox modules. This implies -DBLACKBOX.\n"); log("\n"); log(" -noopt\n"); log(" don't perform basic optimizations (such as const folding) in the\n"); @@ -113,6 +137,9 @@ struct VerilogFrontend : public Frontend { log(" to a later 'hierarchy' command. Useful in cases where the default\n"); log(" parameters of modules yield invalid or not synthesizable code.\n"); log("\n"); + log(" -noautowire\n"); + log(" make the default of `default_nettype be \"none\" instead of \"wire\".\n"); + log("\n"); log(" -setattr <attribute_name>\n"); log(" set the specified attribute (to the value 1) on all loaded modules\n"); log("\n"); @@ -129,9 +156,12 @@ struct VerilogFrontend : public Frontend { log("\n"); log("Note that the Verilog frontend does a pretty good job of processing valid\n"); log("verilog input, but has not very good error reporting. It generally is\n"); - log("recommended to use a simulator (for example icarus verilog) for checking\n"); + log("recommended to use a simulator (for example Icarus Verilog) for checking\n"); log("the syntax of the code, rather than to rely on read_verilog for that.\n"); log("\n"); + log("See the Yosys README file for a list of non-standard Verilog features\n"); + 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) { @@ -139,10 +169,12 @@ 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; bool flag_nopp = false; + bool flag_nodpi = false; bool flag_lib = false; bool flag_noopt = false; bool flag_icells = false; @@ -154,8 +186,10 @@ struct VerilogFrontend : public Frontend { frontend_verilog_yydebug = false; sv_mode = false; + formal_mode = false; + default_nettype_wire = true; - log_header("Executing Verilog-2005 frontend.\n"); + log_header(design, "Executing Verilog-2005 frontend.\n"); args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end()); @@ -166,6 +200,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 +224,10 @@ struct VerilogFrontend : public Frontend { flag_nolatches = true; continue; } + if (arg == "-nomeminit") { + flag_nomeminit = true; + continue; + } if (arg == "-nomem2reg") { flag_nomem2reg = true; continue; @@ -202,8 +244,13 @@ struct VerilogFrontend : public Frontend { flag_nopp = true; continue; } + if (arg == "-nodpi") { + flag_nodpi = true; + continue; + } if (arg == "-lib") { flag_lib = true; + defines_map["BLACKBOX"] = string(); continue; } if (arg == "-noopt") { @@ -222,6 +269,10 @@ struct VerilogFrontend : public Frontend { flag_defer = true; continue; } + if (arg == "-noautowire") { + default_nettype_wire = false; + continue; + } if (arg == "-setattr" && argidx+1 < args.size()) { attributes.push_back(RTLIL::escape_id(args[++argidx])); continue; @@ -257,14 +308,14 @@ struct VerilogFrontend : public Frontend { } extra_args(f, filename, args, argidx); - log("Parsing %s input from `%s' to AST representation.\n", sv_mode ? "SystemVerilog" : "Verilog", 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; AST::get_line_num = &frontend_verilog_yyget_lineno; current_ast = new AST::AstNode(AST::AST_DESIGN); - default_nettype_wire = true; lexin = f; std::string code_after_preproc; @@ -288,7 +339,10 @@ 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); + if (flag_nodpi) + error_on_dpi_function(current_ast); + + 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; @@ -308,16 +362,16 @@ struct VerilogDefaults : public Pass { log("\n"); log(" verilog_defaults -add [options]\n"); log("\n"); - log("Add the sepcified options to the list of default options to read_verilog.\n"); + log("Add the specified options to the list of default options to read_verilog.\n"); log("\n"); log("\n"); - log(" verilog_defaults -clear"); + log(" verilog_defaults -clear\n"); log("\n"); - log("Clear the list of verilog default options.\n"); + log("Clear the list of Verilog default options.\n"); log("\n"); log("\n"); - log(" verilog_defaults -push"); - log(" verilog_defaults -pop"); + log(" verilog_defaults -push\n"); + log(" verilog_defaults -pop\n"); log("\n"); log("Push or pop the list of default options to a stack. Note that -push does\n"); log("not imply -clear.\n"); diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index e277f3e3c..fb98f4afb 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -2,11 +2,11 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * + * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -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/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index cb8fafcb2..107a2dfdd 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -2,11 +2,11 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * + * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -40,7 +40,7 @@ #endif #include "kernel/log.h" -#include "verilog_frontend.h" +#include "frontends/verilog/verilog_frontend.h" #include "frontends/ast/ast.h" #include "verilog_parser.tab.h" @@ -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++; @@ -134,6 +141,8 @@ YOSYS_NAMESPACE_END "endfunction" { return TOK_ENDFUNCTION; } "task" { return TOK_TASK; } "endtask" { return TOK_ENDTASK; } +"package" { SV_KEYWORD(TOK_PACKAGE); } +"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); } "parameter" { return TOK_PARAMETER; } "localparam" { return TOK_LOCALPARAM; } "defparam" { return TOK_DEFPARAM; } @@ -162,8 +171,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; SV_KEYWORD(TOK_ASSUME); } +"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); } "logic" { SV_KEYWORD(TOK_REG); } "bit" { SV_KEYWORD(TOK_REG); } @@ -240,7 +250,7 @@ and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 { supply0 { return TOK_SUPPLY0; } supply1 { return TOK_SUPPLY1; } -"$"(display|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) { +"$"(display|write|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) { frontend_verilog_yylval.string = new std::string(yytext); return TOK_ID; } @@ -273,7 +283,7 @@ supply1 { return TOK_SUPPLY1; } 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"); + "Yosys does support them but it is recommended to use Verilog `full_case' attributes instead!\n"); printed_warning = true; } return TOK_SYNOPSYS_FULL_CASE; @@ -282,7 +292,7 @@ supply1 { return TOK_SUPPLY1; } 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"); + "Yosys does support them but it is recommended to use Verilog `parallel_case' attributes instead!\n"); printed_warning = true; } return TOK_SYNOPSYS_PARALLEL_CASE; @@ -343,6 +353,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { "<<<" { return OP_SSHL; } ">>>" { return OP_SSHR; } +"::" { SV_KEYWORD(TOK_PACKAGESEP); } + "+:" { return TOK_POS_INDEXED; } "-:" { return TOK_NEG_INDEXED; } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 621b6cc18..e7c3578c7 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2,11 +2,11 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * + * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. - * + * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -36,7 +36,7 @@ %{ #include <list> #include <string.h> -#include "verilog_frontend.h" +#include "frontends/verilog/verilog_frontend.h" #include "kernel/log.h" USING_YOSYS_NAMESPACE @@ -57,7 +57,7 @@ namespace VERILOG_FRONTEND { std::vector<char> case_type_stack; bool do_not_require_port_stubs; bool default_nettype_wire; - bool sv_mode; + bool sv_mode, formal_mode; std::istream *lexin; } YOSYS_NAMESPACE_END @@ -102,6 +102,7 @@ static void free_attr(std::map<std::string, AstNode*> *al) %token <string> TOK_STRING TOK_ID TOK_CONST TOK_REALVAL TOK_PRIMITIVE %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM +%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT @@ -111,7 +112,7 @@ static void free_attr(std::map<std::string, AstNode*> *al) %token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL %token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED -%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_PROPERTY +%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME TOK_PROPERTY %type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int %type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list @@ -139,6 +140,7 @@ static void free_attr(std::map<std::string, AstNode*> *al) %% input: { + ast_stack.clear(); ast_stack.push_back(current_ast); } design { ast_stack.pop_back(); @@ -152,6 +154,9 @@ design: module design | defattr design | task_func_decl design | + param_decl design | + localparam_decl design | + package design | /* empty */; attr: @@ -209,6 +214,14 @@ hierarchical_id: TOK_ID { $$ = $1; } | + hierarchical_id TOK_PACKAGESEP TOK_ID { + if ($3->substr(0, 1) == "\\") + *$1 += "::" + $3->substr(1); + else + *$1 += "::" + *$3; + delete $3; + $$ = $1; + } | hierarchical_id '.' TOK_ID { if ($3->substr(0, 1) == "\\") *$1 += "." + $3->substr(1); @@ -243,11 +256,10 @@ module_para_opt: '#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | /* empty */; module_para_list: - single_module_para | - single_module_para ',' module_para_list | - /* empty */; + single_module_para | module_para_list ',' single_module_para; single_module_para: + /* empty */ | TOK_PARAMETER { if (astbuf1) delete astbuf1; astbuf1 = new AstNode(AST_PARAMETER); @@ -299,7 +311,7 @@ module_arg: node->children.push_back($3); if (!node->is_input && !node->is_output) frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $4->c_str()); - if (node->is_reg && node->is_input && !node->is_output) + if (node->is_reg && node->is_input && !node->is_output && !sv_mode) frontend_verilog_yyerror("Input port `%s' is declared as register.", $4->c_str()); ast_stack.back()->children.push_back(node); append_attr(node, $1); @@ -309,10 +321,36 @@ module_arg: do_not_require_port_stubs = true; }; +package: + attr TOK_PACKAGE TOK_ID { + AstNode *mod = new AstNode(AST_PACKAGE); + ast_stack.back()->children.push_back(mod); + ast_stack.push_back(mod); + current_ast_mod = mod; + mod->str = *$3; + append_attr(mod, $1); + } ';' package_body TOK_ENDPACKAGE { + ast_stack.pop_back(); + current_ast_mod = NULL; + }; + +package_body: + package_body package_body_stmt |; + +package_body_stmt: + localparam_decl; + +non_opt_delay: + '#' '(' expr ')' { delete $3; } | + '#' '(' expr ':' expr ':' expr ')' { delete $3; delete $5; delete $7; }; + +delay: + non_opt_delay | /* empty */; + wire_type: { astbuf3 = new AstNode(AST_WIRE); - } wire_type_token_list { + } wire_type_token_list delay { $$ = astbuf3; }; @@ -700,6 +738,8 @@ wire_name_and_opt_assign: wire_name: TOK_ID range_or_multirange { + if (astbuf1 == nullptr) + frontend_verilog_yyerror("Syntax error."); AstNode *node = astbuf1->clone(); node->str = *$1; append_attr_clone(node, albuf); @@ -724,7 +764,7 @@ wire_name: if (port_stubs.count(*$1) != 0) { if (!node->is_input && !node->is_output) frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $1->c_str()); - if (node->is_reg && node->is_input && !node->is_output) + if (node->is_reg && node->is_input && !node->is_output && !sv_mode) frontend_verilog_yyerror("Input port `%s' is declared as register.", $1->c_str()); node->port_id = port_stubs[*$1]; port_stubs.erase(*$1); @@ -741,13 +781,13 @@ wire_name: }; assign_stmt: - TOK_ASSIGN assign_expr_list ';'; + TOK_ASSIGN delay assign_expr_list ';'; assign_expr_list: assign_expr | assign_expr_list ',' assign_expr; assign_expr: - expr '=' expr { + lvalue '=' expr { ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, $1, $3)); }; @@ -761,7 +801,7 @@ cell_stmt: } cell_parameter_list_opt cell_list ';' { delete astbuf1; } | - attr tok_prim_wrapper { + attr tok_prim_wrapper delay { astbuf1 = new AstNode(AST_PRIMITIVE); astbuf1->str = *$2; append_attr(astbuf1, $1); @@ -813,10 +853,10 @@ cell_parameter_list_opt: '#' '(' cell_parameter_list ')' | /* empty */; cell_parameter_list: - /* empty */ | cell_parameter | - cell_parameter ',' cell_parameter_list; + cell_parameter | cell_parameter_list ',' cell_parameter; cell_parameter: + /* empty */ | expr { AstNode *node = new AstNode(AST_PARASET); astbuf1->children.push_back(node); @@ -831,14 +871,10 @@ cell_parameter: }; cell_port_list: - /* empty */ | cell_port | - cell_port ',' cell_port_list | - /* empty */ ',' { - AstNode *node = new AstNode(AST_ARGUMENT); - astbuf2->children.push_back(node); - } cell_port_list; + cell_port | cell_port_list ',' cell_port; cell_port: + /* empty */ | expr { AstNode *node = new AstNode(AST_ARGUMENT); astbuf2->children.push_back(node); @@ -926,27 +962,34 @@ opt_label: assert: TOK_ASSERT '(' expr ')' ';' { ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $3)); + } | + TOK_ASSUME '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3)); }; assert_property: TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $4)); + } | + TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); }; simple_behavioral_stmt: - lvalue '=' expr { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3); + lvalue '=' delay expr { + AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $4); ast_stack.back()->children.push_back(node); } | - lvalue OP_LE expr { - AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $3); + lvalue OP_LE delay expr { + AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $4); ast_stack.back()->children.push_back(node); }; // this production creates the obligatory if-else shift/reduce conflict behavioral_stmt: - defattr | assert | wire_decl | - simple_behavioral_stmt ';' | + defattr | assert | wire_decl | param_decl | localparam_decl | + non_opt_delay behavioral_stmt | + simple_behavioral_stmt ';' | ';' | hierarchical_id attr { AstNode *node = new AstNode(AST_TCALL); node->str = *$1; @@ -1039,13 +1082,13 @@ behavioral_stmt: }; case_type: - TOK_CASE { + TOK_CASE { case_type_stack.push_back(0); } | - TOK_CASEX { + TOK_CASEX { case_type_stack.push_back('x'); } | - TOK_CASEZ { + TOK_CASEZ { case_type_stack.push_back('z'); }; @@ -1060,10 +1103,6 @@ opt_synopsys_attr: } | /* empty */; -behavioral_stmt_opt: - behavioral_stmt | - ';' ; - behavioral_stmt_list: behavioral_stmt_list behavioral_stmt | /* empty */; @@ -1084,7 +1123,9 @@ case_body: case_item: { - AstNode *node = new AstNode(AST_COND); + AstNode *node = new AstNode( + case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX : + case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND); ast_stack.back()->children.push_back(node); ast_stack.push_back(node); } case_select { @@ -1092,7 +1133,7 @@ case_item: ast_stack.back()->children.push_back(block); ast_stack.push_back(block); case_type_stack.push_back(0); - } behavioral_stmt_opt { + } behavioral_stmt { case_type_stack.pop_back(); ast_stack.pop_back(); ast_stack.pop_back(); @@ -1104,7 +1145,9 @@ gen_case_body: gen_case_item: { - AstNode *node = new AstNode(AST_COND); + AstNode *node = new AstNode( + case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX : + case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND); ast_stack.back()->children.push_back(node); ast_stack.push_back(node); } case_select { @@ -1330,6 +1373,11 @@ basic_expr: '(' expr ')' { $$ = $2; } | + '(' expr ':' expr ':' expr ')' { + delete $2; + $$ = $4; + delete $6; + } | '{' concat_list '}' { $$ = $2; } | |