diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 4a8172e45..0663758e8 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -35,6 +35,7 @@ #include #include #include +#include // For std::gcd in C++17 // #include @@ -4477,7 +4478,8 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file continue; } - auto value = VERILOG_FRONTEND::const2ast(stringf("%d'%c", mem_width, is_readmemh ? 'h' : 'b') + token); + VERILOG_FRONTEND::ConstParser p{mem_filename, std::nullopt}; + auto value = p.const2ast(stringf("%d'%c", mem_width, is_readmemh ? 'h' : 'b') + token); if (unconditional_init) { diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index 1f5f437ef..9c4a2e76c 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -42,18 +42,35 @@ YOSYS_NAMESPACE_BEGIN using namespace AST; +using namespace VERILOG_FRONTEND; -static int get_line_num() { - // TODO - return 999; +std::string ConstParser::fmt_maybe_loc(std::string msg) { + std::string s; + s += filename.value_or("INTERNAL"); + + if (loc) + s += stringf("%d", loc->first_line); + s += ": "; + + s += msg; + return s; } + +void ConstParser::log_maybe_loc_error(std::string msg) { + log_error("%s", fmt_maybe_loc(msg).c_str()); +} + +void ConstParser::log_maybe_loc_warn(std::string msg) { + log_warning("%s", fmt_maybe_loc(msg).c_str()); +} + // divide an arbitrary length decimal number by two and return the rest -static int my_decimal_div_by_two(std::vector &digits) +int ConstParser::my_decimal_div_by_two(std::vector &digits) { int carry = 0; for (size_t i = 0; i < digits.size(); i++) { if (digits[i] >= 10) - log_file_error(current_filename, get_line_num(), "Invalid use of [a-fxz?] in decimal constant.\n"); + log_maybe_loc_error("Invalid use of [a-fxz?] in decimal constant.\n"); digits[i] += carry * 10; carry = digits[i] % 2; digits[i] /= 2; @@ -64,7 +81,7 @@ static int my_decimal_div_by_two(std::vector &digits) } // find the number of significant bits in a binary number (not including the sign bit) -static int my_ilog2(int x) +int ConstParser::my_ilog2(int x) { int ret = 0; while (x != 0 && x != -1) { @@ -75,7 +92,7 @@ static int my_ilog2(int x) } // parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?') -static void my_strtobin(std::vector &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized) +void ConstParser::my_strtobin(std::vector &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized) { // all digits in string (MSB at index 0) std::vector digits; @@ -106,8 +123,8 @@ static void my_strtobin(std::vector &data, const char *str, int le int bits_per_digit = my_ilog2(base-1); for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) { if (*it > (base-1) && *it < 0xf0) - log_file_error(current_filename, get_line_num(), "Digit larger than %d used in in base-%d constant.\n", - base-1, base); + log_maybe_loc_error(stringf("Digit larger than %d used in in base-%d constant.\n", + base-1, base)); for (int i = 0; i < bits_per_digit; i++) { int bitmask = 1 << i; if (*it == 0xf0) @@ -130,7 +147,7 @@ static void my_strtobin(std::vector &data, const char *str, int le } if (is_unsized && (len > len_in_bits)) - log_file_error(current_filename, get_line_num(), "Unsized constant must have width of 1 bit, but have %d bits!\n", len); + log_maybe_loc_error(stringf("Unsized constant must have width of 1 bit, but have %d bits!\n", len)); for (len = len - 1; len >= 0; len--) if (data[len] == State::S1) @@ -144,21 +161,19 @@ static void my_strtobin(std::vector &data, const char *str, int le } if (len_in_bits == 0) - log_file_error(current_filename, get_line_num(), "Illegal integer constant size of zero (IEEE 1800-2012, 5.7).\n"); + log_maybe_loc_error("Illegal integer constant size of zero (IEEE 1800-2012, 5.7).\n"); 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()); + log_maybe_loc_warn(stringf("Literal has a width of %d bit, but value requires %d bit.\n", + len_in_bits, len)); } - // convert the Verilog code for a constant to an AST node -std::unique_ptr VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn_z) +std::unique_ptr ConstParser::const2ast(std::string code, char case_type, bool warn_z) { if (warn_z) { auto ret = const2ast(code, case_type); if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end()) - log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n", - current_filename.c_str(), get_line_num()); + log_maybe_loc_warn("Yosys has only limited support for tri-state logic at the moment.\n"); return ret; } @@ -249,4 +264,5 @@ std::unique_ptr VERILOG_FRONTEND::const2ast(std::string code, char case return NULL; } + YOSYS_NAMESPACE_END diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index 1b5c067b3..da908d3ae 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -45,8 +45,25 @@ YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { - // this function converts a Verilog constant to an AST_CONSTANT node - std::unique_ptr const2ast(std::string code, char case_type = 0, bool warn_z = false); + /* Ephemeral context class */ + struct ConstParser { + std::optional filename; + std::optional loc; + private: + std::string fmt_maybe_loc(std::string msg); + void log_maybe_loc_error(std::string msg); + void log_maybe_loc_warn(std::string msg); + // divide an arbitrary length decimal number by two and return the rest + int my_decimal_div_by_two(std::vector &digits); + // find the number of significant bits in a binary number (not including the sign bit) + int my_ilog2(int x); + // parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?') + void my_strtobin(std::vector &data, const char *str, int len_in_bits, int base, char case_type, bool is_unsized); + public: + // convert the Verilog code for a constant to an AST node + std::unique_ptr const2ast(std::string code, char case_type = 0, bool warn_z = false); + + }; extern void frontend_verilog_yyerror(char const *fmt, ...); }; diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index d2086e20b..575b652e8 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -140,11 +140,13 @@ return lexer->nextToken(); } - #define SET_AST_NODE_LOC(WHICH, BEGIN, END) \ - do { (WHICH)->location.first_line = (BEGIN).begin.line; \ - (WHICH)->location.first_column = (BEGIN).begin.column; \ - (WHICH)->location.last_line = (END).end.line; \ - (WHICH)->location.last_column = (END).end.column; } while(0) + #define SET_LOC(WHICH, BEGIN, END) \ + do { WHICH.first_line = (BEGIN).begin.line; \ + WHICH.first_column = (BEGIN).begin.column; \ + WHICH.last_line = (END).end.line; \ + WHICH.last_column = (END).end.column; } while(0) + + #define SET_AST_NODE_LOC(WHICH, BEGIN, END) SET_LOC((WHICH)->location, BEGIN, END) #define SET_RULE_LOC(LHS, BEGIN, END) \ do { (LHS).begin = BEGIN.begin; \ @@ -152,6 +154,13 @@ YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { + static ConstParser make_ConstParser_here(parser::location_type flex_loc) { + AstSrcLocType loc; + SET_LOC(loc, flex_loc, flex_loc); + std::optional filename = flex_loc.begin.filename ? std::make_optional(*(flex_loc.begin.filename)) : std::nullopt; + ConstParser p{filename, loc}; + return p; + } static void append_attr(AstNode *ast, dict> *al) { for (auto &it : *al) { @@ -3162,7 +3171,8 @@ basic_expr: TOK_LPAREN expr TOK_RPAREN integral_number { if ($4->compare(0, 1, "'") != 0) frontend_verilog_yyerror("Cast operation must be applied on sized constants e.g. () , while %s is not a sized constant.", $4->c_str()); - auto val = const2ast(*$4, extra->case_type_stack.size() == 0 ? 0 : extra->case_type_stack.back(), !mode->lib); + auto p = make_ConstParser_here(@4); + auto val = p.const2ast(*$4, extra->case_type_stack.size() == 0 ? 0 : extra->case_type_stack.back(), !mode->lib); if (val == nullptr) log_error("Value conversion failed: `%s'\n", $4->c_str()); $$ = std::make_unique(AST_TO_BITS, std::move($2), std::move(val)); @@ -3173,14 +3183,16 @@ basic_expr: auto bits = std::make_unique(AST_IDENTIFIER); bits->str = *$1; SET_AST_NODE_LOC(bits.get(), @1, @1); - auto val = const2ast(*$2, extra->case_type_stack.size() == 0 ? 0 : extra->case_type_stack.back(), !mode->lib); + auto p = make_ConstParser_here(@2); + auto val = p.const2ast(*$2, extra->case_type_stack.size() == 0 ? 0 : extra->case_type_stack.back(), !mode->lib); SET_AST_NODE_LOC(val.get(), @2, @2); if (val == nullptr) log_error("Value conversion failed: `%s'\n", $2->c_str()); $$ = std::make_unique(AST_TO_BITS, std::move(bits), std::move(val)); } | integral_number { - $$ = const2ast(*$1, extra->case_type_stack.size() == 0 ? 0 : extra->case_type_stack.back(), !mode->lib); + auto p = make_ConstParser_here(@1); + $$ = p.const2ast(*$1, extra->case_type_stack.size() == 0 ? 0 : extra->case_type_stack.back(), !mode->lib); SET_AST_NODE_LOC($$.get(), @1, @1); if ($$ == nullptr) log_error("Value conversion failed: `%s'\n", $1->c_str()); diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 23d0e0d36..a33008c3b 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5704,9 +5704,8 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri if (('0' <= netname[0] && netname[0] <= '9') || netname[0] == '\'') { cover("kernel.rtlil.sigspec.parse.const"); - // TODO fix - // AST::get_line_num = sigspec_parse_get_dummy_line_num; - auto ast = VERILOG_FRONTEND::const2ast(netname); + VERILOG_FRONTEND::ConstParser p; + auto ast = p.const2ast(netname); if (ast == nullptr) return false; sig.append(RTLIL::Const(ast->bits));