From 40b387a70b2e3757bd8c8612758b0333761473a1 Mon Sep 17 00:00:00 2001 From: George Rennie Date: Wed, 3 Jul 2024 22:12:06 +0100 Subject: [PATCH 001/176] smtbmc: Support skipping steps in cover mode --- backends/smt2/smtbmc.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index c3bdcebbe..1dcedc8ca 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -1866,6 +1866,11 @@ elif covermode: smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, step-1, step)) smt_assert_antecedent("(not (|%s_is| s%d))" % (topmod, step)) + if step < skip_steps: + print_msg("Skipping step %d.." % (step)) + step += 1 + continue + while "1" in cover_mask: print_msg("Checking cover reachability in step %d.." % (step)) smt_push() From 9047290683467fe981684462abf0d3d89191d148 Mon Sep 17 00:00:00 2001 From: George Rennie Date: Wed, 6 Nov 2024 19:49:09 +0100 Subject: [PATCH 002/176] write_btor: support $buf * treated the same as $pos --- backends/btor/btor.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index c3637bc8f..2def5eaba 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -508,7 +508,7 @@ struct BtorWorker goto okay; } - if (cell->type.in(ID($not), ID($neg), ID($_NOT_), ID($pos))) + if (cell->type.in(ID($not), ID($neg), ID($_NOT_), ID($pos), ID($buf))) { string btor_op; if (cell->type.in(ID($not), ID($_NOT_))) btor_op = "not"; @@ -520,9 +520,9 @@ struct BtorWorker int nid_a = get_sig_nid(cell->getPort(ID::A), width, a_signed); SigSpec sig = sigmap(cell->getPort(ID::Y)); - // the $pos cell just passes through, all other cells need an actual operation applied + // the $pos/$buf cells just pass through, all other cells need an actual operation applied int nid = nid_a; - if (cell->type != ID($pos)) + if (!cell->type.in(ID($pos), ID($buf))) { log_assert(!btor_op.empty()); int sid = get_bv_sid(width); From d7c66889052854a40d577e8d216c328256cd869a Mon Sep 17 00:00:00 2001 From: George Rennie Date: Fri, 15 Nov 2024 11:47:09 +0100 Subject: [PATCH 003/176] write_btor: support $_BUF_ --- backends/btor/btor.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 2def5eaba..ad8f4b680 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -508,7 +508,7 @@ struct BtorWorker goto okay; } - if (cell->type.in(ID($not), ID($neg), ID($_NOT_), ID($pos), ID($buf))) + if (cell->type.in(ID($not), ID($neg), ID($_NOT_), ID($pos), ID($buf), ID($_BUF_))) { string btor_op; if (cell->type.in(ID($not), ID($_NOT_))) btor_op = "not"; @@ -522,7 +522,7 @@ struct BtorWorker // the $pos/$buf cells just pass through, all other cells need an actual operation applied int nid = nid_a; - if (!cell->type.in(ID($pos), ID($buf))) + if (!cell->type.in(ID($pos), ID($buf), ID($_BUF_))) { log_assert(!btor_op.empty()); int sid = get_bv_sid(width); From af8e85b7d27558bfc11ee95e11d4d9f141aef5e6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 21 Apr 2025 11:39:33 -0700 Subject: [PATCH 004/176] techlibs/lattice: add missing clock muxes to ECP5 block ram blackboxes prjtrellis documentation shows that EBR clock inputs have optional inverters. The bram techmap outputs those parameters, and nextpnr consumes them. But for whatever reason, Diamond doesn't include those parameters in its blackbox models. This makes synth_lattice fail when targeting ECP5 with a design that maps block RAMs if you include any pass that needs cells_bb_ecp5.v's definitions. This change fixes up the ECP5 bram blackbox models at generation time, by adding the missing parameters back in. Signed-off-by: David Anderson --- techlibs/lattice/cells_bb_ecp5.v | 4 ++++ techlibs/lattice/cells_xtra.py | 21 ++++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/techlibs/lattice/cells_bb_ecp5.v b/techlibs/lattice/cells_bb_ecp5.v index fc22495e2..20a8134c3 100644 --- a/techlibs/lattice/cells_bb_ecp5.v +++ b/techlibs/lattice/cells_bb_ecp5.v @@ -19,6 +19,8 @@ endmodule (* blackbox *) module DP16KD (...); + parameter CLKAMUX = "CLKA"; + parameter CLKBMUX = "CLKB"; parameter DATA_WIDTH_A = 18; parameter DATA_WIDTH_B = 18; parameter REGMODE_A = "NOREG"; @@ -215,6 +217,8 @@ endmodule (* blackbox *) module PDPW16KD (...); + parameter CLKRMUX = "CLKR"; + parameter CLKWMUX = "CLKW"; parameter DATA_WIDTH_W = 36; parameter DATA_WIDTH_R = 36; parameter GSR = "ENABLED"; diff --git a/techlibs/lattice/cells_xtra.py b/techlibs/lattice/cells_xtra.py index c17281cc7..5531fd2b2 100644 --- a/techlibs/lattice/cells_xtra.py +++ b/techlibs/lattice/cells_xtra.py @@ -11,10 +11,11 @@ import re class Cell: - def __init__(self, name, keep=False, port_attrs={}): + def __init__(self, name, keep=False, port_attrs={}, extra_params={}): self.name = name self.keep = keep self.port_attrs = port_attrs + self.extra_params = extra_params self.found = False class State(Enum): @@ -120,8 +121,18 @@ devices = [ #Cell("XOR3"), #Cell("XOR4"), #Cell("XOR5"), - Cell("DP16KD"), - Cell("PDPW16KD"), + Cell("DP16KD", extra_params={ + # Optional clock inverters, present in prjtrellis data but + # not in Diamond bb models. + "CLKAMUX": "CLKA", + "CLKBMUX": "CLKB", + }), + Cell("PDPW16KD", extra_params={ + # Optional clock inverters, present in prjtrellis data but + # not in Diamond bb models. + "CLKWMUX": "CLKW", + "CLKRMUX": "CLKR", + }), #Cell("DPR16X4C"), #Cell("SPR16X4C"), #Cell("LVDSOB"), @@ -795,6 +806,10 @@ def xtract_cells_decl(device, cells, dirs, outf): rng = None module_ports.append((kind, rng, port)) elif l.startswith('parameter ') and state == State.IN_MODULE: + if cell.extra_params: + for name, default in sorted(cell.extra_params.items()): + outf.write(' parameter {} = "{}";\n'.format(name, default)) + cell.extra_params = None l = l.strip() if l.endswith((';', ',')): l = l[:-1] From 41107e5473f117d9314dca6b0bfb140612c130fb Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 16 Jun 2025 21:26:08 +0200 Subject: [PATCH 005/176] log: add -expect types prefix-log, prefix-warning, prefix-error --- kernel/log.cc | 81 ++++++++++++++++++++++++++----------------- kernel/log.h | 1 + passes/cmds/logger.cc | 17 ++++++--- 3 files changed, 63 insertions(+), 36 deletions(-) diff --git a/kernel/log.cc b/kernel/log.cc index fabbe09fd..49b2e29cd 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -44,6 +44,7 @@ std::vector log_scratchpads; std::map> log_hdump; std::vector log_warn_regexes, log_nowarn_regexes, log_werror_regexes; dict log_expect_log, log_expect_warning, log_expect_error; +dict log_expect_prefix_log, log_expect_prefix_warning, log_expect_prefix_error; std::set log_warnings, log_experimentals, log_experimentals_ignored; int log_warnings_count = 0; int log_warnings_count_noexpect = 0; @@ -178,7 +179,7 @@ void logv(const char *format, va_list ap) { log_warn_regex_recusion_guard = true; - if (log_warn_regexes.empty() && log_expect_log.empty()) + if (log_warn_regexes.empty() && log_expect_log.empty() && log_expect_prefix_log.empty()) { linebuffer.clear(); } @@ -191,9 +192,9 @@ void logv(const char *format, va_list ap) if (std::regex_search(linebuffer, re)) log_warning("Found log message matching -W regex:\n%s", str.c_str()); - for (auto &item : log_expect_log) - if (std::regex_search(linebuffer, item.second.pattern)) - item.second.current_count++; + for (auto &[_, item] : log_expect_log) + if (std::regex_search(linebuffer, item.pattern)) + item.current_count++; linebuffer.clear(); } @@ -266,9 +267,15 @@ static void logv_warning_with_prefix(const char *prefix, log_error("%s", message.c_str()); bool warning_match = false; - for (auto &item : log_expect_warning) - if (std::regex_search(message, item.second.pattern)) { - item.second.current_count++; + for (auto &[_, item] : log_expect_warning) + if (std::regex_search(message, item.pattern)) { + item.current_count++; + warning_match = true; + } + + for (auto &[_, item] : log_expect_prefix_warning) + if (std::regex_search(string(prefix) + message, item.pattern)) { + item.current_count++; warning_match = true; } @@ -355,9 +362,13 @@ static void logv_error_with_prefix(const char *prefix, log_make_debug = bak_log_make_debug; - for (auto &item : log_expect_error) - if (std::regex_search(log_last_error, item.second.pattern)) - item.second.current_count++; + for (auto &[_, item] : log_expect_error) + if (std::regex_search(log_last_error, item.pattern)) + item.current_count++; + + for (auto &[_, item] : log_expect_prefix_error) + if (std::regex_search(string(prefix) + string(log_last_error), item.pattern)) + item.current_count++; log_check_expected(); @@ -711,38 +722,39 @@ void log_check_expected() // copy out all of the expected logs so that they cannot be re-checked // or match against themselves dict expect_log, expect_warning, expect_error; + dict expect_prefix_log, expect_prefix_warning, expect_prefix_error; std::swap(expect_warning, log_expect_warning); std::swap(expect_log, log_expect_log); std::swap(expect_error, log_expect_error); + std::swap(expect_prefix_warning, log_expect_prefix_warning); + std::swap(expect_prefix_log, log_expect_prefix_log); + std::swap(expect_prefix_error, log_expect_prefix_error); - for (auto &item : expect_warning) { - if (item.second.current_count == 0) { + auto check = [&](const std::string kind, std::string pattern, LogExpectedItem item) { + if (item.current_count == 0) { log_warn_regexes.clear(); - log_error("Expected warning pattern '%s' not found !\n", item.first.c_str()); + log_error("Expected %s pattern '%s' not found !\n", kind.c_str(), pattern.c_str()); } - if (item.second.current_count != item.second.expected_count) { + if (item.current_count != item.expected_count) { log_warn_regexes.clear(); - log_error("Expected warning pattern '%s' found %d time(s), instead of %d time(s) !\n", - item.first.c_str(), item.second.current_count, item.second.expected_count); + log_error("Expected %s pattern '%s' found %d time(s), instead of %d time(s) !\n", + kind.c_str(), pattern.c_str(), item.current_count, item.expected_count); } - } + }; - for (auto &item : expect_log) { - if (item.second.current_count == 0) { - log_warn_regexes.clear(); - log_error("Expected log pattern '%s' not found !\n", item.first.c_str()); - } - if (item.second.current_count != item.second.expected_count) { - log_warn_regexes.clear(); - log_error("Expected log pattern '%s' found %d time(s), instead of %d time(s) !\n", - item.first.c_str(), item.second.current_count, item.second.expected_count); - } - } + for (auto &[pattern, item] : expect_warning) + check("warning", pattern, item); + for (auto &[pattern, item] : expect_prefix_warning) + check("prefixed warning", pattern, item); + for (auto &[pattern, item] : expect_log) + check("log", pattern, item); + for (auto &[pattern, item] : expect_prefix_log) + check("prefixed log", pattern, item); - for (auto &item : expect_error) - if (item.second.current_count == item.second.expected_count) { + auto check_err = [&](const std::string kind, std::string pattern, LogExpectedItem item) { + if (item.current_count == item.expected_count) { log_warn_regexes.clear(); - log("Expected error pattern '%s' found !!!\n", item.first.c_str()); + log("Expected %s pattern '%s' found !!!\n", kind.c_str(), pattern.c_str()); yosys_shutdown(); #ifdef EMSCRIPTEN throw 0; @@ -753,8 +765,13 @@ void log_check_expected() #endif } else { log_warn_regexes.clear(); - log_error("Expected error pattern '%s' not found !\n", item.first.c_str()); + log_error("Expected %s pattern '%s' not found !\n", kind.c_str(), pattern.c_str()); } + }; + for (auto &[pattern, item] : expect_error) + check_err("error", pattern, item); + for (auto &[pattern, item] : expect_prefix_error) + check_err("prefixed error", pattern, item); } // --------------------------------------------------- diff --git a/kernel/log.h b/kernel/log.h index e26ef072c..48997d250 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -201,6 +201,7 @@ struct LogExpectedItem }; extern dict log_expect_log, log_expect_warning, log_expect_error; +extern dict log_expect_prefix_log, log_expect_prefix_warning, log_expect_prefix_error; void log_check_expected(); const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true); diff --git a/passes/cmds/logger.cc b/passes/cmds/logger.cc index 241a8799f..9b7ab1183 100644 --- a/passes/cmds/logger.cc +++ b/passes/cmds/logger.cc @@ -60,6 +60,8 @@ struct LoggerPass : public Pass { log(" -expect \n"); log(" expect log, warning or error to appear. matched errors will terminate\n"); log(" with exit code 0.\n"); + log(" Types prefix-log, prefix-warning and prefix-error match the entire\n"); + log(" logged string, including filename if present.\n"); log("\n"); log(" -expect-no-warnings\n"); log(" gives error in case there is at least one warning that is not expected.\n"); @@ -151,26 +153,33 @@ struct LoggerPass : public Pass { } if (args[argidx] == "-expect" && argidx+3 < args.size()) { std::string type = args[++argidx]; - if (type!="error" && type!="warning" && type!="log") + if (type!="error" && type!="warning" && type!="log" + && type!="prefix-error" && type!="prefix-warning" && type!="prefix-log") log_cmd_error("Expect command require type to be 'log', 'warning' or 'error' !\n"); - if (type=="error" && log_expect_error.size()>0) + if ((type=="error" || type=="prefix-error") && log_expect_error.size()>0) log_cmd_error("Only single error message can be expected !\n"); std::string pattern = args[++argidx]; - if (pattern.front() == '\"' && pattern.back() == '\"') pattern = pattern.substr(1, pattern.size() - 2); + if (pattern.front() == '\"' && pattern.back() == '\"') pattern = pattern.substr(1, pattern.size() - 2); int count = atoi(args[++argidx].c_str()); if (count<=0) log_cmd_error("Number of expected messages must be higher then 0 !\n"); - if (type=="error" && count!=1) + if ((type=="error" || type=="prefix-error") && count!=1) log_cmd_error("Expected error message occurrences must be 1 !\n"); log("Added regex '%s' to expected %s messages list.\n", pattern.c_str(), type.c_str()); try { if (type == "error") log_expect_error[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); + else if (type == "prefix-error") + log_expect_prefix_error[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); else if (type == "warning") log_expect_warning[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); + else if (type == "prefix-warning") + log_expect_prefix_warning[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); else if (type == "log") log_expect_log[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); + else if (type == "prefix-log") + log_expect_prefix_log[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); else log_abort(); } catch (const std::regex_error& e) { From 49cd3887a76ab40c5595460c6f162f07085de321 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 16 Jun 2025 21:48:12 +0200 Subject: [PATCH 006/176] const2ast: add diagnostics tests --- tests/verilog/constparser_f.ys | 6 ++++++ tests/verilog/constparser_f_file.sv | 3 +++ tests/verilog/constparser_f_file.ys | 2 ++ tests/verilog/constparser_g.ys | 6 ++++++ 4 files changed, 17 insertions(+) create mode 100644 tests/verilog/constparser_f.ys create mode 100644 tests/verilog/constparser_f_file.sv create mode 100644 tests/verilog/constparser_f_file.ys create mode 100644 tests/verilog/constparser_g.ys diff --git a/tests/verilog/constparser_f.ys b/tests/verilog/constparser_f.ys new file mode 100644 index 000000000..3dd3f1323 --- /dev/null +++ b/tests/verilog/constparser_f.ys @@ -0,0 +1,6 @@ +read_verilog < Date: Mon, 16 Jun 2025 22:50:31 +0200 Subject: [PATCH 007/176] fixup! const2ast: add diagnostics tests --- tests/verilog/constparser_f.ys | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/verilog/constparser_f.ys b/tests/verilog/constparser_f.ys index 3dd3f1323..4c5eff46f 100644 --- a/tests/verilog/constparser_f.ys +++ b/tests/verilog/constparser_f.ys @@ -1,6 +1,7 @@ +logger -expect prefix-error "< Date: Thu, 19 Jun 2025 18:47:48 +0200 Subject: [PATCH 008/176] Makefile: remove hardcoded -soname for libyosys.so --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b452105b1..ac999417e 100644 --- a/Makefile +++ b/Makefile @@ -747,7 +747,7 @@ libyosys.so: $(filter-out kernel/driver.o,$(OBJS)) ifeq ($(OS), Darwin) $(P) $(CXX) -o libyosys.so -shared -undefined dynamic_lookup -Wl,-install_name,$(LIBDIR)/libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC) else - $(P) $(CXX) -o libyosys.so -shared -Wl,-soname,$(LIBDIR)/libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC) + $(P) $(CXX) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC) endif %.o: %.cc From a57c593c415c07a7849278e5809eeb9ace3c191b Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 16 Jul 2025 15:32:47 +1200 Subject: [PATCH 009/176] tests: Add equiv_assume.ys --- tests/various/equiv_assume.ys | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/various/equiv_assume.ys diff --git a/tests/various/equiv_assume.ys b/tests/various/equiv_assume.ys new file mode 100644 index 000000000..cb7731c29 --- /dev/null +++ b/tests/various/equiv_assume.ys @@ -0,0 +1,26 @@ +read_verilog -sv < Date: Wed, 16 Jul 2025 21:04:41 +1200 Subject: [PATCH 010/176] equiv_simple: Add -set-assumes option Based on existing code for input cone and the `sat` handling of `-set-assumes`. Update `equiv_assume.ys` to use `-set-assumes` option. --- passes/equiv/equiv_simple.cc | 79 ++++++++++++++++++++++++++++++++--- tests/various/equiv_assume.ys | 4 +- 2 files changed, 77 insertions(+), 6 deletions(-) diff --git a/passes/equiv/equiv_simple.cc b/passes/equiv/equiv_simple.cc index 59974a1e6..bdb39172b 100644 --- a/passes/equiv/equiv_simple.cc +++ b/passes/equiv/equiv_simple.cc @@ -27,6 +27,7 @@ struct EquivSimpleWorker { Module *module; const vector &equiv_cells; + const vector &assume_cells; Cell *equiv_cell; SigMap &sigmap; @@ -37,12 +38,13 @@ struct EquivSimpleWorker int max_seq; bool short_cones; bool verbose; + bool set_assumes; pool> imported_cells_cache; - EquivSimpleWorker(const vector &equiv_cells, SigMap &sigmap, dict &bit2driver, int max_seq, bool short_cones, bool verbose, bool model_undef) : - module(equiv_cells.front()->module), equiv_cells(equiv_cells), equiv_cell(nullptr), - sigmap(sigmap), bit2driver(bit2driver), satgen(ez.get(), &sigmap), max_seq(max_seq), short_cones(short_cones), verbose(verbose) + EquivSimpleWorker(const vector &equiv_cells, const vector &assume_cells, SigMap &sigmap, dict &bit2driver, int max_seq, bool short_cones, bool verbose, bool model_undef, bool set_assumes) : + module(equiv_cells.front()->module), equiv_cells(equiv_cells), assume_cells(assume_cells), equiv_cell(nullptr), + sigmap(sigmap), bit2driver(bit2driver), satgen(ez.get(), &sigmap), max_seq(max_seq), short_cones(short_cones), verbose(verbose), set_assumes(set_assumes) { satgen.model_undef = model_undef; } @@ -182,6 +184,53 @@ struct EquivSimpleWorker #endif } + if (set_assumes) { + pool extra_problem_cells; + for (auto assume : assume_cells) { + pool assume_seed, next_assume_seed; + assume_seed.insert(sigmap(assume->getPort(ID::A)).as_bit()); + assume_seed.insert(sigmap(assume->getPort(ID::EN)).as_bit()); + pool assume_cells_cone; + pool assume_bits_cone; + pool overlap_bits; + for (auto bit_x : assume_seed) { + find_input_cone(next_assume_seed, assume_cells_cone, assume_bits_cone, short_cells_cone_a, short_bits_cone_a, &overlap_bits, bit_x); + } + if (GetSize(overlap_bits)) { + extra_problem_cells.insert(assume); + extra_problem_cells.insert(assume_cells_cone.begin(), assume_cells_cone.end()); + overlap_bits.clear(); + } + assume_cells_cone.clear(); + assume_bits_cone.clear(); + for (auto bit_x : assume_seed) { + find_input_cone(next_assume_seed, assume_cells_cone, assume_bits_cone, short_cells_cone_b, short_bits_cone_b, &overlap_bits, bit_x); + } + if (GetSize(overlap_bits)) { + extra_problem_cells.insert(assume); + extra_problem_cells.insert(assume_cells_cone.begin(), assume_cells_cone.end()); + overlap_bits.clear(); + } + assume_cells_cone.clear(); + assume_bits_cone.clear(); + next_assume_seed.clear(); + } + + if (GetSize(extra_problem_cells)) { + auto old_size = GetSize(problem_cells); + problem_cells.insert(extra_problem_cells.begin(), extra_problem_cells.end()); + if (verbose) { + log(" Adding %d new cells to check assumptions (and reusing %d).\n", + GetSize(problem_cells) - old_size, + old_size - (GetSize(problem_cells) - GetSize(extra_problem_cells))); + #if 0 + for (auto cell : extra_problem_cells) + log(" cell: %s\n", log_id(cell)); + #endif + } + } + } + for (auto cell : problem_cells) { auto key = pair(cell, step+1); if (!imported_cells_cache.count(key) && !satgen.importCell(cell, step+1)) { @@ -193,6 +242,14 @@ struct EquivSimpleWorker imported_cells_cache.insert(key); } + if (set_assumes) { + RTLIL::SigSpec assumes_a, assumes_en; + satgen.getAssumes(assumes_a, assumes_en, step+1); + for (int i = 0; i < GetSize(assumes_a); i++) + log("Import constraint from assume cell: %s when %s.\n", log_signal(assumes_a[i]), log_signal(assumes_en[i])); + ez->assume(satgen.importAssumes(step+1)); + } + if (satgen.model_undef) { for (auto bit : input_bits) ez->assume(ez->NOT(satgen.importUndefSigBit(bit, step+1))); @@ -301,10 +358,14 @@ struct EquivSimplePass : public Pass { log(" -seq \n"); log(" the max. number of time steps to be considered (default = 1)\n"); log("\n"); + log(" -set-assumes\n"); + log(" set all assumptions provided via $assume cells\n"); + log("\n"); } void execute(std::vector args, Design *design) override { bool verbose = false, short_cones = false, model_undef = false, nogroup = false; + bool set_assumes = false; int success_counter = 0; int max_seq = 1; @@ -332,6 +393,10 @@ struct EquivSimplePass : public Pass { max_seq = atoi(args[++argidx].c_str()); continue; } + if (args[argidx] == "-set-assumes") { + set_assumes = true; + continue; + } break; } extra_args(args, argidx, design); @@ -347,9 +412,10 @@ struct EquivSimplePass : public Pass { SigMap sigmap(module); dict bit2driver; dict> unproven_equiv_cells; + vector assumes; int unproven_cells_counter = 0; - for (auto cell : module->selected_cells()) + for (auto cell : module->selected_cells()) { if (cell->type == ID($equiv) && cell->getPort(ID::A) != cell->getPort(ID::B)) { auto bit = sigmap(cell->getPort(ID::Y).as_bit()); auto bit_group = bit; @@ -357,7 +423,10 @@ struct EquivSimplePass : public Pass { bit_group.offset = 0; unproven_equiv_cells[bit_group][bit] = cell; unproven_cells_counter++; + } else if (cell->type == ID($assume)) { + assumes.push_back(cell); } + } if (unproven_equiv_cells.empty()) continue; @@ -383,7 +452,7 @@ struct EquivSimplePass : public Pass { for (auto it2 : it.second) cells.push_back(it2.second); - EquivSimpleWorker worker(cells, sigmap, bit2driver, max_seq, short_cones, verbose, model_undef); + EquivSimpleWorker worker(cells, assumes, sigmap, bit2driver, max_seq, short_cones, verbose, model_undef, set_assumes); success_counter += worker.run(); } } diff --git a/tests/various/equiv_assume.ys b/tests/various/equiv_assume.ys index cb7731c29..0033ac95c 100644 --- a/tests/various/equiv_assume.ys +++ b/tests/various/equiv_assume.ys @@ -18,9 +18,11 @@ design -load input equiv_make -make_assert gold gate equiv prep -top equiv sat -set-assumes -prove-asserts -verify +# this fails +# sat -prove-asserts -verify # so should $equiv design -load input equiv_make gold gate equiv -equiv_simple equiv +equiv_simple -set-assumes equiv equiv_status -assert equiv From 5ec189a2f5023f72f897f7fa3842fd8cc2a94f25 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 16 Jul 2025 21:05:03 +1200 Subject: [PATCH 011/176] Tests: Extra equiv_assume tests --- tests/various/equiv_assume.ys | 88 +++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/tests/various/equiv_assume.ys b/tests/various/equiv_assume.ys index 0033ac95c..7264e5a29 100644 --- a/tests/various/equiv_assume.ys +++ b/tests/various/equiv_assume.ys @@ -26,3 +26,91 @@ design -load input equiv_make gold gate equiv equiv_simple -set-assumes equiv equiv_status -assert equiv + +# and it works through cells +design -reset +read_verilog -sv < Date: Sun, 3 Aug 2025 23:31:54 -0400 Subject: [PATCH 012/176] implement package import --- frontends/ast/ast.cc | 1 + frontends/ast/ast.h | 1 + frontends/ast/genrtlil.cc | 1 + frontends/ast/simplify.cc | 36 ++++++++++++++++++++++++++++++ frontends/verilog/verilog_lexer.l | 1 + frontends/verilog/verilog_parser.y | 11 +++++++++ 6 files changed, 51 insertions(+) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 431f7b4f8..04f749845 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -174,6 +174,7 @@ std::string AST::type2str(AstNodeType type) X(AST_MODPORT) X(AST_MODPORTMEMBER) X(AST_PACKAGE) + X(AST_IMPORT) X(AST_WIRETYPE) X(AST_TYPEDEF) X(AST_STRUCT) diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 2c2d408ce..776b5c833 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -153,6 +153,7 @@ namespace AST AST_MODPORT, AST_MODPORTMEMBER, AST_PACKAGE, + AST_IMPORT, AST_WIRETYPE, AST_TYPEDEF, diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 26ed0e3e4..79e543376 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1361,6 +1361,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_GENIF: case AST_GENCASE: case AST_PACKAGE: + case AST_IMPORT: case AST_ENUM: case AST_MODPORT: case AST_MODPORTMEMBER: diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 4d8c57ced..b524fadfd 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1103,6 +1103,42 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin int counter = 0; label_genblks(existing, counter); std::map this_wire_scope; + + // Process package imports after clearing the scope but before processing module declarations + for (auto &child : children) { + if (child->type == AST_IMPORT) { + // Find the package in the design + AstNode *package_node = nullptr; + for (auto &design_child : current_ast->children) { + if (design_child->type == AST_PACKAGE && design_child->str == child->str) { + package_node = design_child; + break; + } + } + + if (package_node) { + // Import all names from the package into current scope + for (auto &pkg_child : package_node->children) { + if (pkg_child->type == AST_PARAMETER || pkg_child->type == AST_LOCALPARAM || + pkg_child->type == AST_TYPEDEF || pkg_child->type == AST_FUNCTION || + pkg_child->type == AST_TASK || pkg_child->type == AST_ENUM) { + current_scope[pkg_child->str] = pkg_child; + } + if (pkg_child->type == AST_ENUM) { + for (auto enode : pkg_child->children) { + log_assert(enode->type==AST_ENUM_ITEM); + if (current_scope.count(enode->str) == 0) + current_scope[enode->str] = enode; + else + input_error("enum item %s already exists in current scope\n", enode->str.c_str()); + } + } + } + } else { + input_error("Package `%s' not found for import\n", child->str.c_str()); + } + } + } for (size_t i = 0; i < children.size(); i++) { AstNode *node = children[i]; diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index e2d7a2cd9..19c0774af 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -334,6 +334,7 @@ TIME_SCALE_SUFFIX [munpf]?s "specparam" { return TOK_SPECPARAM; } "package" { SV_KEYWORD(TOK_PACKAGE); } "endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); } +"import" { SV_KEYWORD(TOK_IMPORT); } "interface" { SV_KEYWORD(TOK_INTERFACE); } "endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); } "modport" { SV_KEYWORD(TOK_MODPORT); } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 17edc357d..bd9f47034 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -418,6 +418,7 @@ static const AstNode *addAsgnBinopStmt(dict *attr, AstNode * %token TOK_SUB_ASSIGN TOK_DIV_ASSIGN TOK_MOD_ASSIGN TOK_MUL_ASSIGN %token TOK_SHL_ASSIGN TOK_SHR_ASSIGN TOK_SSHL_ASSIGN TOK_SSHR_ASSIGN %token TOK_BIND TOK_TIME_SCALE +%token TOK_IMPORT %type range range_or_multirange non_opt_range non_opt_multirange %type wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type @@ -484,6 +485,7 @@ design: localparam_decl design | typedef_decl design | package design | + import_stmt design | interface design | bind_directive design | %empty; @@ -730,6 +732,15 @@ package_body: package_body_stmt: typedef_decl | localparam_decl | param_decl | task_func_decl; +import_stmt: + TOK_IMPORT hierarchical_id TOK_PACKAGESEP '*' ';' { + // Create an import node to track package imports + AstNode *import_node = new AstNode(AST_IMPORT); + import_node->str = *$2; + ast_stack.back()->children.push_back(import_node); + delete $2; + }; + interface: TOK_INTERFACE { enterTypeScope(); From 761015b23e1ce68b08b703f6a19f12362860d451 Mon Sep 17 00:00:00 2001 From: Rahul Bhagwat Date: Sun, 3 Aug 2025 23:48:33 -0400 Subject: [PATCH 013/176] add separate module test --- frontends/ast/simplify.cc | 20 ++++++++++++++++--- tests/verilog/package_import_separate.sv | 13 ++++++++++++ tests/verilog/package_import_separate.ys | 5 +++++ .../verilog/package_import_separate_module.sv | 19 ++++++++++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 tests/verilog/package_import_separate.sv create mode 100644 tests/verilog/package_import_separate.ys create mode 100644 tests/verilog/package_import_separate_module.sv diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index b524fadfd..8bb40cb6b 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1109,10 +1109,24 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (child->type == AST_IMPORT) { // Find the package in the design AstNode *package_node = nullptr; + + // First look in current_ast->children (for packages in same file) for (auto &design_child : current_ast->children) { - if (design_child->type == AST_PACKAGE && design_child->str == child->str) { - package_node = design_child; - break; + if (design_child->type == AST_PACKAGE) { + if (design_child->str == child->str) { + package_node = design_child; + break; + } + } + } + + // If not found, look in design->verilog_packages (for packages from other files) + if (!package_node && simplify_design_context != nullptr) { + for (auto &design_package : simplify_design_context->verilog_packages) { + if (design_package->str == child->str) { + package_node = design_package; + break; + } } } diff --git a/tests/verilog/package_import_separate.sv b/tests/verilog/package_import_separate.sv new file mode 100644 index 000000000..b2e5bb803 --- /dev/null +++ b/tests/verilog/package_import_separate.sv @@ -0,0 +1,13 @@ +package config_pkg; + localparam integer + DATA_WIDTH = 8, + ADDR_WIDTH = 4; + + localparam logic [2:0] + IDLE = 3'b000, + START = 3'b001, + DATA = 3'b010, + ODD_PARITY = 3'b011, + STOP = 3'b100, + DONE = 3'b101; +endpackage \ No newline at end of file diff --git a/tests/verilog/package_import_separate.ys b/tests/verilog/package_import_separate.ys new file mode 100644 index 000000000..0dff75897 --- /dev/null +++ b/tests/verilog/package_import_separate.ys @@ -0,0 +1,5 @@ +read_verilog -sv package_import_separate.sv +read_verilog -sv package_import_separate_module.sv +hierarchy -check +proc +opt -full \ No newline at end of file diff --git a/tests/verilog/package_import_separate_module.sv b/tests/verilog/package_import_separate_module.sv new file mode 100644 index 000000000..f940553b3 --- /dev/null +++ b/tests/verilog/package_import_separate_module.sv @@ -0,0 +1,19 @@ +import config_pkg::*; + +module top; + logic [DATA_WIDTH-1:0] data; + logic [ADDR_WIDTH-1:0] addr; + logic [2:0] state; + + always_comb begin + case (state) + IDLE: data = 8'h00; + START: data = 8'h01; + DATA: data = 8'h02; + ODD_PARITY: data = 8'h03; + STOP: data = 8'h04; + DONE: data = 8'h05; + default: data = 8'hFF; + endcase + end +endmodule \ No newline at end of file From fe59b6d3db1f13252b5a7cc308039558a8e41fdc Mon Sep 17 00:00:00 2001 From: Rahul Bhagwat Date: Mon, 4 Aug 2025 20:57:43 -0400 Subject: [PATCH 014/176] add safety checks and better name matching --- frontends/ast/simplify.cc | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 8bb40cb6b..693e8098a 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1105,25 +1105,35 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin std::map this_wire_scope; // Process package imports after clearing the scope but before processing module declarations - for (auto &child : children) { + for (size_t i = 0; i < children.size(); i++) { + AstNode *child = children[i]; if (child->type == AST_IMPORT) { + log_debug("Processing import for package: %s\n", child->str.c_str()); // Find the package in the design AstNode *package_node = nullptr; // First look in current_ast->children (for packages in same file) - for (auto &design_child : current_ast->children) { - if (design_child->type == AST_PACKAGE) { - if (design_child->str == child->str) { - package_node = design_child; - break; + if (current_ast != nullptr) { + for (auto &design_child : current_ast->children) { + if (design_child->type == AST_PACKAGE) { + if (design_child->str == child->str) { + package_node = design_child; + break; + } } } } // If not found, look in design->verilog_packages (for packages from other files) if (!package_node && simplify_design_context != nullptr) { + log_debug("Looking for package in design context, found %zu packages\n", simplify_design_context->verilog_packages.size()); for (auto &design_package : simplify_design_context->verilog_packages) { - if (design_package->str == child->str) { + // Handle both with and without leading backslash + std::string package_name = design_package->str; + if (package_name[0] == '\\') { + package_name = package_name.substr(1); + } + if (package_name == child->str || design_package->str == child->str) { package_node = design_package; break; } @@ -1148,8 +1158,16 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } } } + // Remove the import node since it's been processed + delete child; + children.erase(children.begin() + i); + i--; // Adjust index since we removed an element } else { - input_error("Package `%s' not found for import\n", child->str.c_str()); + // If we can't find the package, just remove the import node to avoid errors later + log_warning("Package `%s' not found for import, removing import statement\n", child->str.c_str()); + delete child; + children.erase(children.begin() + i); + i--; // Adjust index since we removed an element } } } From 93b39ad9b3bf16d96268a7fb6cc9e9765f0a2d0e Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 6 Aug 2025 15:12:48 +1200 Subject: [PATCH 015/176] equiv_induct: Add -set-assumes option Uses mostly the same code as equiv_simple, but the assumes are already being imported so long as they're in the selection, so it's even easier. --- passes/equiv/equiv_induct.cc | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/passes/equiv/equiv_induct.cc b/passes/equiv/equiv_induct.cc index 8d882ae83..b39d7a785 100644 --- a/passes/equiv/equiv_induct.cc +++ b/passes/equiv/equiv_induct.cc @@ -37,14 +37,15 @@ struct EquivInductWorker int max_seq; int success_counter; + bool set_assumes; dict ez_step_is_consistent; pool cell_warn_cache; SigPool undriven_signals; - EquivInductWorker(Module *module, const pool &unproven_equiv_cells, bool model_undef, int max_seq) : module(module), sigmap(module), + EquivInductWorker(Module *module, const pool &unproven_equiv_cells, bool model_undef, int max_seq, bool set_assumes) : module(module), sigmap(module), cells(module->selected_cells()), workset(unproven_equiv_cells), - satgen(ez.get(), &sigmap), max_seq(max_seq), success_counter(0) + satgen(ez.get(), &sigmap), max_seq(max_seq), success_counter(0), set_assumes(set_assumes) { satgen.model_undef = model_undef; } @@ -77,6 +78,14 @@ struct EquivInductWorker } } + if (set_assumes) { + RTLIL::SigSpec assumes_a, assumes_en; + satgen.getAssumes(assumes_a, assumes_en, step); + for (int i = 0; i < GetSize(assumes_a); i++) + log("Import constraint from assume cell: %s when %s.\n", log_signal(assumes_a[i]), log_signal(assumes_en[i])); + ez->assume(satgen.importAssumes(step)); + } + if (satgen.model_undef) { for (auto bit : undriven_signals.export_all()) ez->assume(ez->NOT(satgen.importUndefSigBit(bit, step))); @@ -184,6 +193,9 @@ struct EquivInductPass : public Pass { log(" -seq \n"); log(" the max. number of time steps to be considered (default = 4)\n"); log("\n"); + log(" -set-assumes\n"); + log(" set all assumptions provided via $assume cells\n"); + log("\n"); log("This command is very effective in proving complex sequential circuits, when\n"); log("the internal state of the circuit quickly propagates to $equiv cells.\n"); log("\n"); @@ -200,7 +212,7 @@ struct EquivInductPass : public Pass { void execute(std::vector args, Design *design) override { int success_counter = 0; - bool model_undef = false; + bool model_undef = false, set_assumes = false; int max_seq = 4; log_header(design, "Executing EQUIV_INDUCT pass.\n"); @@ -215,6 +227,10 @@ struct EquivInductPass : public Pass { max_seq = atoi(args[++argidx].c_str()); continue; } + if (args[argidx] == "-set-assumes") { + set_assumes = true; + continue; + } break; } extra_args(args, argidx, design); @@ -222,6 +238,7 @@ struct EquivInductPass : public Pass { for (auto module : design->selected_modules()) { pool unproven_equiv_cells; + vector assume_cells; for (auto cell : module->selected_cells()) if (cell->type == ID($equiv)) { @@ -234,7 +251,7 @@ struct EquivInductPass : public Pass { continue; } - EquivInductWorker worker(module, unproven_equiv_cells, model_undef, max_seq); + EquivInductWorker worker(module, unproven_equiv_cells, model_undef, max_seq, set_assumes); worker.run(); success_counter += worker.success_counter; } From f9e8127e2b90b0607d85e6dd6aea1bffd8dd251a Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 6 Aug 2025 15:13:04 +1200 Subject: [PATCH 016/176] tests: Add equiv_induct to equiv_assume.ys --- tests/various/equiv_assume.ys | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/various/equiv_assume.ys b/tests/various/equiv_assume.ys index 7264e5a29..7ca572c8c 100644 --- a/tests/various/equiv_assume.ys +++ b/tests/various/equiv_assume.ys @@ -22,11 +22,18 @@ sat -set-assumes -prove-asserts -verify # sat -prove-asserts -verify # so should $equiv +## in equiv_simple design -load input equiv_make gold gate equiv equiv_simple -set-assumes equiv equiv_status -assert equiv +## and equiv_induct +delete equiv +equiv_make gold gate equiv +equiv_induct -set-assumes equiv +equiv_status -assert equiv + # and it works through cells design -reset read_verilog -sv < Date: Wed, 6 Aug 2025 15:21:10 +1200 Subject: [PATCH 017/176] Less verbose equiv assumes both only print on the first step, and equiv_simple only prints if also verbose --- passes/equiv/equiv_induct.cc | 10 ++++++---- passes/equiv/equiv_simple.cc | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/passes/equiv/equiv_induct.cc b/passes/equiv/equiv_induct.cc index b39d7a785..1995be3cd 100644 --- a/passes/equiv/equiv_induct.cc +++ b/passes/equiv/equiv_induct.cc @@ -79,10 +79,12 @@ struct EquivInductWorker } if (set_assumes) { - RTLIL::SigSpec assumes_a, assumes_en; - satgen.getAssumes(assumes_a, assumes_en, step); - for (int i = 0; i < GetSize(assumes_a); i++) - log("Import constraint from assume cell: %s when %s.\n", log_signal(assumes_a[i]), log_signal(assumes_en[i])); + if (step == 1) { + RTLIL::SigSpec assumes_a, assumes_en; + satgen.getAssumes(assumes_a, assumes_en, step); + for (int i = 0; i < GetSize(assumes_a); i++) + log("Import constraint from assume cell: %s when %s.\n", log_signal(assumes_a[i]), log_signal(assumes_en[i])); + } ez->assume(satgen.importAssumes(step)); } diff --git a/passes/equiv/equiv_simple.cc b/passes/equiv/equiv_simple.cc index bdb39172b..1bebf5454 100644 --- a/passes/equiv/equiv_simple.cc +++ b/passes/equiv/equiv_simple.cc @@ -243,10 +243,12 @@ struct EquivSimpleWorker } if (set_assumes) { - RTLIL::SigSpec assumes_a, assumes_en; - satgen.getAssumes(assumes_a, assumes_en, step+1); - for (int i = 0; i < GetSize(assumes_a); i++) - log("Import constraint from assume cell: %s when %s.\n", log_signal(assumes_a[i]), log_signal(assumes_en[i])); + if (verbose && step == max_seq) { + RTLIL::SigSpec assumes_a, assumes_en; + satgen.getAssumes(assumes_a, assumes_en, step+1); + for (int i = 0; i < GetSize(assumes_a); i++) + log(" Import constraint from assume cell: %s when %s (%d).\n", log_signal(assumes_a[i]), log_signal(assumes_en[i]), step); + } ez->assume(satgen.importAssumes(step+1)); } From 7e0157ba2bee52f194af93f669aadff5fb67b59b Mon Sep 17 00:00:00 2001 From: Rahul Bhagwat Date: Wed, 6 Aug 2025 15:32:36 -0400 Subject: [PATCH 018/176] fix whitespace issues --- frontends/ast/simplify.cc | 12 ++++++------ tests/verilog/package_import_separate.sv | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 693e8098a..9c0abc327 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1103,7 +1103,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin int counter = 0; label_genblks(existing, counter); std::map this_wire_scope; - + // Process package imports after clearing the scope but before processing module declarations for (size_t i = 0; i < children.size(); i++) { AstNode *child = children[i]; @@ -1111,7 +1111,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin log_debug("Processing import for package: %s\n", child->str.c_str()); // Find the package in the design AstNode *package_node = nullptr; - + // First look in current_ast->children (for packages in same file) if (current_ast != nullptr) { for (auto &design_child : current_ast->children) { @@ -1123,7 +1123,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } } } - + // If not found, look in design->verilog_packages (for packages from other files) if (!package_node && simplify_design_context != nullptr) { log_debug("Looking for package in design context, found %zu packages\n", simplify_design_context->verilog_packages.size()); @@ -1139,12 +1139,12 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } } } - + if (package_node) { // Import all names from the package into current scope for (auto &pkg_child : package_node->children) { - if (pkg_child->type == AST_PARAMETER || pkg_child->type == AST_LOCALPARAM || - pkg_child->type == AST_TYPEDEF || pkg_child->type == AST_FUNCTION || + if (pkg_child->type == AST_PARAMETER || pkg_child->type == AST_LOCALPARAM || + pkg_child->type == AST_TYPEDEF || pkg_child->type == AST_FUNCTION || pkg_child->type == AST_TASK || pkg_child->type == AST_ENUM) { current_scope[pkg_child->str] = pkg_child; } diff --git a/tests/verilog/package_import_separate.sv b/tests/verilog/package_import_separate.sv index b2e5bb803..eddde709b 100644 --- a/tests/verilog/package_import_separate.sv +++ b/tests/verilog/package_import_separate.sv @@ -2,7 +2,7 @@ package config_pkg; localparam integer DATA_WIDTH = 8, ADDR_WIDTH = 4; - + localparam logic [2:0] IDLE = 3'b000, START = 3'b001, @@ -10,4 +10,4 @@ package config_pkg; ODD_PARITY = 3'b011, STOP = 3'b100, DONE = 3'b101; -endpackage \ No newline at end of file +endpackage From d3c8e6c14c5249fe0de59be176a7bc8b76caaf7f Mon Sep 17 00:00:00 2001 From: Rahul Bhagwat Date: Wed, 6 Aug 2025 15:39:30 -0400 Subject: [PATCH 019/176] use more standard naming conventions --- tests/verilog/package_import_separate.sv | 17 +++++++++-------- tests/verilog/package_import_separate_module.sv | 14 +++++++------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/tests/verilog/package_import_separate.sv b/tests/verilog/package_import_separate.sv index eddde709b..2337e4bce 100644 --- a/tests/verilog/package_import_separate.sv +++ b/tests/verilog/package_import_separate.sv @@ -1,13 +1,14 @@ -package config_pkg; +package package_import_separate; + localparam integer - DATA_WIDTH = 8, - ADDR_WIDTH = 4; + DATAWIDTH = 8, + ADDRWIDTH = 4; localparam logic [2:0] - IDLE = 3'b000, + IDLE = 3'b000, START = 3'b001, - DATA = 3'b010, - ODD_PARITY = 3'b011, - STOP = 3'b100, - DONE = 3'b101; + DATA = 3'b010, + STOP = 3'b100, + DONE = 3'b101; + endpackage diff --git a/tests/verilog/package_import_separate_module.sv b/tests/verilog/package_import_separate_module.sv index f940553b3..b58d3b814 100644 --- a/tests/verilog/package_import_separate_module.sv +++ b/tests/verilog/package_import_separate_module.sv @@ -1,19 +1,19 @@ -import config_pkg::*; +import package_import_separate::*; -module top; - logic [DATA_WIDTH-1:0] data; - logic [ADDR_WIDTH-1:0] addr; +module package_import_separate_module; + logic [DATAWIDTH-1:0] data; + logic [ADDRWIDTH-1:0] addr; logic [2:0] state; - + always_comb begin case (state) IDLE: data = 8'h00; START: data = 8'h01; DATA: data = 8'h02; - ODD_PARITY: data = 8'h03; STOP: data = 8'h04; DONE: data = 8'h05; default: data = 8'hFF; endcase end -endmodule \ No newline at end of file + +endmodule From f12055d3e0bdac503ce01db8a35ea07d2c52ace9 Mon Sep 17 00:00:00 2001 From: Rahul Bhagwat Date: Wed, 6 Aug 2025 15:39:36 -0400 Subject: [PATCH 020/176] rm debug logs --- frontends/ast/simplify.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 9c0abc327..05cc57ba1 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1108,7 +1108,6 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (size_t i = 0; i < children.size(); i++) { AstNode *child = children[i]; if (child->type == AST_IMPORT) { - log_debug("Processing import for package: %s\n", child->str.c_str()); // Find the package in the design AstNode *package_node = nullptr; @@ -1126,7 +1125,6 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // If not found, look in design->verilog_packages (for packages from other files) if (!package_node && simplify_design_context != nullptr) { - log_debug("Looking for package in design context, found %zu packages\n", simplify_design_context->verilog_packages.size()); for (auto &design_package : simplify_design_context->verilog_packages) { // Handle both with and without leading backslash std::string package_name = design_package->str; From 5cc1365b32df363c410ecd3890cd4d9445620d75 Mon Sep 17 00:00:00 2001 From: Rahul Bhagwat Date: Wed, 6 Aug 2025 19:00:11 -0400 Subject: [PATCH 021/176] add newline - whitespace --- tests/verilog/package_import_separate.ys | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/verilog/package_import_separate.ys b/tests/verilog/package_import_separate.ys index 0dff75897..cbfcaa898 100644 --- a/tests/verilog/package_import_separate.ys +++ b/tests/verilog/package_import_separate.ys @@ -2,4 +2,4 @@ read_verilog -sv package_import_separate.sv read_verilog -sv package_import_separate_module.sv hierarchy -check proc -opt -full \ No newline at end of file +opt -full From 3cbbb9456d57943495a67bcb79a3ab1b8c9e18ea Mon Sep 17 00:00:00 2001 From: Hongce Zhang Date: Thu, 7 Aug 2025 11:37:23 +0800 Subject: [PATCH 022/176] reorder verilog backend port wires --- backends/verilog/verilog_backend.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 070df1543..b49927513 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -2358,12 +2358,16 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) dump_attributes(f, indent, module->attributes, "\n", /*modattr=*/true); f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str()); int cnt = 0; + + std::vector port_ordered; + for (auto port : module->ports) { Wire *wire = module->wire(port); if (wire) { if (port != module->ports[0]) f << stringf(", "); f << stringf("%s", id(wire->name).c_str()); + port_ordered.push_back(wire); if (cnt==20) { f << stringf("\n"); cnt = 0; } else cnt++; continue; } @@ -2374,8 +2378,16 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) f << indent + " " << "reg " << id(initial_id) << " = 0;\n"; } - for (auto w : module->wires()) + // first dump input / output according to port_ordered; + for (auto w : port_ordered) dump_wire(f, indent + " ", w); + + for (auto w : module->wires()) { + // avoid duplication + if (std::find(port_ordered.begin(), port_ordered.end(), w) != port_ordered.end()) + continue; + dump_wire(f, indent + " ", w); + } for (auto &mem : Mem::get_all_memories(module)) dump_memory(f, indent + " ", mem); From fcd9f982459f353b8b0b2250111886e32252c664 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 7 Aug 2025 23:18:57 +0200 Subject: [PATCH 023/176] equiv_simple: refactor --- kernel/satgen.h | 6 +- passes/equiv/equiv_simple.cc | 469 ++++++++++++++++++++--------------- 2 files changed, 272 insertions(+), 203 deletions(-) diff --git a/kernel/satgen.h b/kernel/satgen.h index 2c8cbda13..996eaf9fb 100644 --- a/kernel/satgen.h +++ b/kernel/satgen.h @@ -64,7 +64,7 @@ struct ezSatPtr : public std::unique_ptr { struct SatGen { ezSAT *ez; - SigMap *sigmap; + const SigMap *sigmap; std::string prefix; SigPool initial_state; std::map asserts_a, asserts_en; @@ -75,12 +75,12 @@ struct SatGen bool model_undef; bool def_formal = false; - SatGen(ezSAT *ez, SigMap *sigmap, std::string prefix = std::string()) : + SatGen(ezSAT *ez, const SigMap *sigmap, std::string prefix = std::string()) : ez(ez), sigmap(sigmap), prefix(prefix), ignore_div_by_zero(false), model_undef(false) { } - void setContext(SigMap *sigmap, std::string prefix = std::string()) + void setContext(const SigMap *sigmap, std::string prefix = std::string()) { this->sigmap = sigmap; this->prefix = prefix; diff --git a/passes/equiv/equiv_simple.cc b/passes/equiv/equiv_simple.cc index 1bebf5454..f0c1b517c 100644 --- a/passes/equiv/equiv_simple.cc +++ b/passes/equiv/equiv_simple.cc @@ -28,273 +28,344 @@ struct EquivSimpleWorker Module *module; const vector &equiv_cells; const vector &assume_cells; - Cell *equiv_cell; + struct Cone { + pool cells; + pool bits; + void clear() { + cells.clear(); + bits.clear(); + } + }; - SigMap &sigmap; - dict &bit2driver; + struct DesignModel { + const SigMap &sigmap; + dict &bit2driver; + }; + DesignModel model; ezSatPtr ez; SatGen satgen; - int max_seq; - bool short_cones; - bool verbose; - bool set_assumes; + + struct Config { + bool verbose = false; + bool short_cones = false; + bool model_undef = false; + bool nogroup = false; + bool set_assumes = false; + int max_seq = 1; + }; + Config cfg; pool> imported_cells_cache; - EquivSimpleWorker(const vector &equiv_cells, const vector &assume_cells, SigMap &sigmap, dict &bit2driver, int max_seq, bool short_cones, bool verbose, bool model_undef, bool set_assumes) : - module(equiv_cells.front()->module), equiv_cells(equiv_cells), assume_cells(assume_cells), equiv_cell(nullptr), - sigmap(sigmap), bit2driver(bit2driver), satgen(ez.get(), &sigmap), max_seq(max_seq), short_cones(short_cones), verbose(verbose), set_assumes(set_assumes) + EquivSimpleWorker(const vector &equiv_cells, const vector &assume_cells, DesignModel model, Config cfg) : + module(equiv_cells.front()->module), equiv_cells(equiv_cells), assume_cells(assume_cells), + model(model), satgen(ez.get(), &model.sigmap), cfg(cfg) { - satgen.model_undef = model_undef; + satgen.model_undef = cfg.model_undef; } - bool find_input_cone(pool &next_seed, pool &cells_cone, pool &bits_cone, const pool &cells_stop, const pool &bits_stop, pool *input_bits, Cell *cell) - { - if (cells_cone.count(cell)) + struct ConeFinder { + DesignModel model; + // Bits we should also analyze in a later iteration (flop inputs) + pool &next_seed; + // Cells and bits we've seen so far while traversing + Cone& cone; + // We're not allowed to traverse past cells and bits in `stop` + const Cone& stop; + // Input bits are bits that no longer can be traversed + // Tracking these is optional + pool* input_bits; + + // Recursively traverses backwards from a cell to find all cells in its input cone + // Adds cell to cone.cells, stops at cells in 'stop' set + // Returns true if stopped on a stop cell + bool find_input_cone(Cell *cell) + { + if (cone.cells.count(cell)) + return false; + + cone.cells.insert(cell); + + if (stop.cells.count(cell)) + return true; + + for (auto &conn : cell->connections()) + if (yosys_celltypes.cell_input(cell->type, conn.first)) + for (auto bit : model.sigmap(conn.second)) { + if (RTLIL::builtin_ff_cell_types().count(cell->type)) { + if (!conn.first.in(ID::CLK, ID::C)) + next_seed.insert(bit); + } else + find_input_cone(bit); + } return false; + } + void find_input_cone(SigBit bit) + { + if (cone.bits.count(bit)) + return; - cells_cone.insert(cell); + cone.bits.insert(bit); - if (cells_stop.count(cell)) - return true; + if (stop.bits.count(bit)) { + if (input_bits != nullptr) input_bits->insert(bit); + return; + } - for (auto &conn : cell->connections()) - if (yosys_celltypes.cell_input(cell->type, conn.first)) - for (auto bit : sigmap(conn.second)) { - if (RTLIL::builtin_ff_cell_types().count(cell->type)) { - if (!conn.first.in(ID::CLK, ID::C)) - next_seed.insert(bit); - } else - find_input_cone(next_seed, cells_cone, bits_cone, cells_stop, bits_stop, input_bits, bit); - } - return false; - } + if (!model.bit2driver.count(bit)) + return; - void find_input_cone(pool &next_seed, pool &cells_cone, pool &bits_cone, const pool &cells_stop, const pool &bits_stop, pool *input_bits, SigBit bit) + // If the input cone of the driver cell reaches a stop bit, + // then `bit` is an "input bit" + if (find_input_cone(model.bit2driver.at(bit))) + if (input_bits != nullptr) input_bits->insert(bit); + } + void find_input_cone(pool bits) + { + for (auto bit : bits) + find_input_cone(bit); + } + }; + + // Builds (full or short) input cones from the seeds + // Creates full cones (no stops) and optionally short cones (stop at other side's cone) + // Updates seed_a/seed_b with next iteration's FF inputs + // Returns input bits and cone structures for SAT problem construction + std::tuple, Cone, Cone> init_iter(pool& seed_a, pool& seed_b) const { - if (bits_cone.count(bit)) - return; + // Empty, never inserted to, to traverse full cones + const Cone no_stop; + Cone full_cone_a, full_cone_b; - bits_cone.insert(bit); + // Values of seed_* for the next iteration + pool next_seed_a, next_seed_b; - if (bits_stop.count(bit)) { - if (input_bits != nullptr) input_bits->insert(bit); - return; + { + ConeFinder finder_a {model, next_seed_a, full_cone_a, no_stop, nullptr}; + finder_a.find_input_cone(seed_a); + + ConeFinder finder_b {model, next_seed_b, full_cone_b, no_stop, nullptr}; + finder_b.find_input_cone(seed_b); } - if (!bit2driver.count(bit)) - return; + Cone short_cone_a, short_cone_b; + pool input_bits; - if (find_input_cone(next_seed, cells_cone, bits_cone, cells_stop, bits_stop, input_bits, bit2driver.at(bit))) - if (input_bits != nullptr) input_bits->insert(bit); + if (cfg.short_cones) + { + // Rebuild cones with the knowledge of the full cones. + // Avoids stuffing overlaps in input cones into the solver + // e.g. for A by using the full B cone as stops + next_seed_a.clear(); + ConeFinder short_finder_a = {model, next_seed_a, short_cone_a, short_cone_b, &input_bits}; + short_finder_a.find_input_cone(seed_a); + next_seed_a.swap(seed_a); + + next_seed_b.clear(); + ConeFinder short_finder_b = {model, next_seed_b, short_cone_b, short_cone_a, &input_bits}; + short_finder_b.find_input_cone(seed_b); + next_seed_b.swap(seed_b); + } + else + { + short_cone_a = full_cone_a; + next_seed_a.swap(seed_a); + + short_cone_b = full_cone_b; + next_seed_b.swap(seed_b); + } + return std::make_tuple(input_bits, short_cone_a, short_cone_b); } - bool run_cell() + void report_new_cells(const pool& cells, const Cone& cone_a, const Cone& cone_b) const { - SigBit bit_a = sigmap(equiv_cell->getPort(ID::A)).as_bit(); - SigBit bit_b = sigmap(equiv_cell->getPort(ID::B)).as_bit(); - int ez_context = ez->frozen_literal(); + log(" Adding %d new cells to the problem (%d A, %d B, %d shared).\n", + GetSize(cells), GetSize(cone_a.cells), GetSize(cone_b.cells), + (GetSize(cone_a.cells) + GetSize(cone_b.cells)) - GetSize(cells)); + #if 0 + for (auto cell : short_cells_cone_a) + log(" A-side cell: %s\n", log_id(cell)); + for (auto cell : short_cells_cone_b) + log(" B-side cell: %s\n", log_id(cell)); + #endif + } + void report_new_assume_cells(const pool& extra_problem_cells, int old_size, const pool& problem_cells) const + { + if (cfg.verbose) { + log(" Adding %d new cells to check assumptions (and reusing %d).\n", + GetSize(problem_cells) - old_size, + old_size - (GetSize(problem_cells) - GetSize(extra_problem_cells))); + #if 0 + for (auto cell : extra_problem_cells) + log(" cell: %s\n", log_id(cell)); + #endif + } + } + + // Ensure the input cones of $assume cells get modelled by the problem + pool add_assumes_to_problem(const Cone& cone_a, const Cone& cone_b) const + { + pool extra_problem_cells; + for (auto assume : assume_cells) { + pool assume_seed, dummy_next_seed, overlap_bits; + assume_seed.insert(model.sigmap(assume->getPort(ID::A)).as_bit()); + assume_seed.insert(model.sigmap(assume->getPort(ID::EN)).as_bit()); + + for (auto& cone : std::array{cone_a, cone_b}) { + Cone assume_cone; + ConeFinder{model, dummy_next_seed, assume_cone, cone, &overlap_bits} + .find_input_cone(assume_seed); + if (GetSize(overlap_bits)) { + extra_problem_cells.insert(assume); + extra_problem_cells.insert(assume_cone.cells.begin(), assume_cone.cells.end()); + overlap_bits.clear(); + } + assume_cone.clear(); + dummy_next_seed.clear(); + } + } + return extra_problem_cells; + } + + static void report_missing_model(Cell* cell) + { + if (RTLIL::builtin_ff_cell_types().count(cell->type)) + log_cmd_error("No SAT model available for async FF cell %s (%s). Consider running `async2sync` or `clk2fflogic` first.\n", log_id(cell), log_id(cell->type)); + else + log_cmd_error("No SAT model available for cell %s (%s).\n", log_id(cell), log_id(cell->type)); + } + + void prepare_ezsat(int ez_context, SigBit bit_a, SigBit bit_b) + { if (satgen.model_undef) { - int ez_a = satgen.importSigBit(bit_a, max_seq+1); - int ez_b = satgen.importDefSigBit(bit_b, max_seq+1); - int ez_undef_a = satgen.importUndefSigBit(bit_a, max_seq+1); + int ez_a = satgen.importSigBit(bit_a, cfg.max_seq+1); + int ez_b = satgen.importDefSigBit(bit_b, cfg.max_seq+1); + int ez_undef_a = satgen.importUndefSigBit(bit_a, cfg.max_seq+1); ez->assume(ez->XOR(ez_a, ez_b), ez_context); ez->assume(ez->NOT(ez_undef_a), ez_context); } else { - int ez_a = satgen.importSigBit(bit_a, max_seq+1); - int ez_b = satgen.importSigBit(bit_b, max_seq+1); + int ez_a = satgen.importSigBit(bit_a, cfg.max_seq+1); + int ez_b = satgen.importSigBit(bit_b, cfg.max_seq+1); ez->assume(ez->XOR(ez_a, ez_b), ez_context); } + } + void construct_ezsat(const pool& input_bits, int step) + { + if (cfg.set_assumes) { + if (cfg.verbose && step == cfg.max_seq) { + RTLIL::SigSpec assumes_a, assumes_en; + satgen.getAssumes(assumes_a, assumes_en, step+1); + for (int i = 0; i < GetSize(assumes_a); i++) + log(" Import constraint from assume cell: %s when %s (%d).\n", log_signal(assumes_a[i]), log_signal(assumes_en[i]), step); + } + ez->assume(satgen.importAssumes(step+1)); + } + if (satgen.model_undef) { + for (auto bit : input_bits) + ez->assume(ez->NOT(satgen.importUndefSigBit(bit, step+1))); + } + + if (cfg.verbose) + log(" Problem size at t=%d: %d literals, %d clauses\n", step, ez->numCnfVariables(), ez->numCnfClauses()); + } + + bool prove_equiv_cell(Cell* cell) + { + SigBit bit_a = model.sigmap(cell->getPort(ID::A)).as_bit(); + SigBit bit_b = model.sigmap(cell->getPort(ID::B)).as_bit(); + int ez_context = ez->frozen_literal(); + + prepare_ezsat(ez_context, bit_a, bit_b); + + // Two bits, bit_a, and bit_b, have been marked equivalent in the design + // We will be traversing the input cones for each of them + // In the first iteration, we will using those as starting points pool seed_a = { bit_a }; pool seed_b = { bit_b }; - if (verbose) { - log(" Trying to prove $equiv cell %s:\n", log_id(equiv_cell)); - log(" A = %s, B = %s, Y = %s\n", log_signal(bit_a), log_signal(bit_b), log_signal(equiv_cell->getPort(ID::Y))); + if (cfg.verbose) { + log(" Trying to prove $equiv cell %s:\n", log_id(cell)); + log(" A = %s, B = %s, Y = %s\n", log_signal(bit_a), log_signal(bit_b), log_signal(cell->getPort(ID::Y))); } else { - log(" Trying to prove $equiv for %s:", log_signal(equiv_cell->getPort(ID::Y))); + log(" Trying to prove $equiv for %s:", log_signal(cell->getPort(ID::Y))); } - int step = max_seq; + int step = cfg.max_seq; while (1) { - pool no_stop_cells; - pool no_stop_bits; - - pool full_cells_cone_a, full_cells_cone_b; - pool full_bits_cone_a, full_bits_cone_b; - - pool next_seed_a, next_seed_b; - - for (auto bit_a : seed_a) - find_input_cone(next_seed_a, full_cells_cone_a, full_bits_cone_a, no_stop_cells, no_stop_bits, nullptr, bit_a); - - for (auto bit_b : seed_b) - find_input_cone(next_seed_b, full_cells_cone_b, full_bits_cone_b, no_stop_cells, no_stop_bits, nullptr, bit_b); - - pool short_cells_cone_a, short_cells_cone_b; - pool short_bits_cone_a, short_bits_cone_b; - pool input_bits; - - if (short_cones) - { - next_seed_a.clear(); - for (auto bit_a : seed_a) - find_input_cone(next_seed_a, short_cells_cone_a, short_bits_cone_a, full_cells_cone_b, full_bits_cone_b, &input_bits, bit_a); - next_seed_a.swap(seed_a); - - next_seed_b.clear(); - for (auto bit_b : seed_b) - find_input_cone(next_seed_b, short_cells_cone_b, short_bits_cone_b, full_cells_cone_a, full_bits_cone_a, &input_bits, bit_b); - next_seed_b.swap(seed_b); - } - else - { - short_cells_cone_a = full_cells_cone_a; - short_bits_cone_a = full_bits_cone_a; - next_seed_a.swap(seed_a); - - short_cells_cone_b = full_cells_cone_b; - short_bits_cone_b = full_bits_cone_b; - next_seed_b.swap(seed_b); - } + // Traverse input cones of seed_a and seed_b, potentially finding new seeds + auto [input_bits, cone_a, cone_b] = init_iter(seed_a, seed_b); + // Cells to model in SAT solver pool problem_cells; - problem_cells.insert(short_cells_cone_a.begin(), short_cells_cone_a.end()); - problem_cells.insert(short_cells_cone_b.begin(), short_cells_cone_b.end()); + problem_cells.insert(cone_a.cells.begin(), cone_a.cells.end()); + problem_cells.insert(cone_b.cells.begin(), cone_b.cells.end()); - if (verbose) - { - log(" Adding %d new cells to the problem (%d A, %d B, %d shared).\n", - GetSize(problem_cells), GetSize(short_cells_cone_a), GetSize(short_cells_cone_b), - (GetSize(short_cells_cone_a) + GetSize(short_cells_cone_b)) - GetSize(problem_cells)); - #if 0 - for (auto cell : short_cells_cone_a) - log(" A-side cell: %s\n", log_id(cell)); + if (cfg.verbose) + report_new_cells(problem_cells, cone_a, cone_b); - for (auto cell : short_cells_cone_b) - log(" B-side cell: %s\n", log_id(cell)); - #endif - } - - if (set_assumes) { - pool extra_problem_cells; - for (auto assume : assume_cells) { - pool assume_seed, next_assume_seed; - assume_seed.insert(sigmap(assume->getPort(ID::A)).as_bit()); - assume_seed.insert(sigmap(assume->getPort(ID::EN)).as_bit()); - pool assume_cells_cone; - pool assume_bits_cone; - pool overlap_bits; - for (auto bit_x : assume_seed) { - find_input_cone(next_assume_seed, assume_cells_cone, assume_bits_cone, short_cells_cone_a, short_bits_cone_a, &overlap_bits, bit_x); - } - if (GetSize(overlap_bits)) { - extra_problem_cells.insert(assume); - extra_problem_cells.insert(assume_cells_cone.begin(), assume_cells_cone.end()); - overlap_bits.clear(); - } - assume_cells_cone.clear(); - assume_bits_cone.clear(); - for (auto bit_x : assume_seed) { - find_input_cone(next_assume_seed, assume_cells_cone, assume_bits_cone, short_cells_cone_b, short_bits_cone_b, &overlap_bits, bit_x); - } - if (GetSize(overlap_bits)) { - extra_problem_cells.insert(assume); - extra_problem_cells.insert(assume_cells_cone.begin(), assume_cells_cone.end()); - overlap_bits.clear(); - } - assume_cells_cone.clear(); - assume_bits_cone.clear(); - next_assume_seed.clear(); - } - - if (GetSize(extra_problem_cells)) { + if (cfg.set_assumes) { + auto extras = add_assumes_to_problem(cone_a, cone_b); + if (GetSize(extras)) { auto old_size = GetSize(problem_cells); - problem_cells.insert(extra_problem_cells.begin(), extra_problem_cells.end()); - if (verbose) { - log(" Adding %d new cells to check assumptions (and reusing %d).\n", - GetSize(problem_cells) - old_size, - old_size - (GetSize(problem_cells) - GetSize(extra_problem_cells))); - #if 0 - for (auto cell : extra_problem_cells) - log(" cell: %s\n", log_id(cell)); - #endif - } + problem_cells.insert(extras.begin(), extras.end()); + report_new_assume_cells(extras, old_size, problem_cells); } } for (auto cell : problem_cells) { auto key = pair(cell, step+1); if (!imported_cells_cache.count(key) && !satgen.importCell(cell, step+1)) { - if (RTLIL::builtin_ff_cell_types().count(cell->type)) - log_cmd_error("No SAT model available for async FF cell %s (%s). Consider running `async2sync` or `clk2fflogic` first.\n", log_id(cell), log_id(cell->type)); - else - log_cmd_error("No SAT model available for cell %s (%s).\n", log_id(cell), log_id(cell->type)); + report_missing_model(cell); } imported_cells_cache.insert(key); } - if (set_assumes) { - if (verbose && step == max_seq) { - RTLIL::SigSpec assumes_a, assumes_en; - satgen.getAssumes(assumes_a, assumes_en, step+1); - for (int i = 0; i < GetSize(assumes_a); i++) - log(" Import constraint from assume cell: %s when %s (%d).\n", log_signal(assumes_a[i]), log_signal(assumes_en[i]), step); - } - ez->assume(satgen.importAssumes(step+1)); - } - - if (satgen.model_undef) { - for (auto bit : input_bits) - ez->assume(ez->NOT(satgen.importUndefSigBit(bit, step+1))); - } - - if (verbose) - log(" Problem size at t=%d: %d literals, %d clauses\n", step, ez->numCnfVariables(), ez->numCnfClauses()); + construct_ezsat(input_bits, step); if (!ez->solve(ez_context)) { - log(verbose ? " Proved equivalence! Marking $equiv cell as proven.\n" : " success!\n"); - equiv_cell->setPort(ID::B, equiv_cell->getPort(ID::A)); + log(cfg.verbose ? " Proved equivalence! Marking $equiv cell as proven.\n" : " success!\n"); + // Replace $equiv cell with a short + cell->setPort(ID::B, cell->getPort(ID::A)); ez->assume(ez->NOT(ez_context)); return true; } - if (verbose) - log(" Failed to prove equivalence with sequence length %d.\n", max_seq - step); + if (cfg.verbose) + log(" Failed to prove equivalence with sequence length %d.\n", cfg.max_seq - step); if (--step < 0) { - if (verbose) + if (cfg.verbose) log(" Reached sequence limit.\n"); break; } if (seed_a.empty() && seed_b.empty()) { - if (verbose) + if (cfg.verbose) log(" No nets to continue in previous time step.\n"); break; } if (seed_a.empty()) { - if (verbose) + if (cfg.verbose) log(" No nets on A-side to continue in previous time step.\n"); break; } if (seed_b.empty()) { - if (verbose) + if (cfg.verbose) log(" No nets on B-side to continue in previous time step.\n"); break; } - if (verbose) { + if (cfg.verbose) { #if 0 log(" Continuing analysis in previous time step with the following nets:\n"); for (auto bit : seed_a) @@ -307,7 +378,7 @@ struct EquivSimpleWorker } } - if (!verbose) + if (!cfg.verbose) log(" failed.\n"); ez->assume(ez->NOT(ez_context)); @@ -319,14 +390,13 @@ struct EquivSimpleWorker if (GetSize(equiv_cells) > 1) { SigSpec sig; for (auto c : equiv_cells) - sig.append(sigmap(c->getPort(ID::Y))); + sig.append(model.sigmap(c->getPort(ID::Y))); log(" Grouping SAT models for %s:\n", log_signal(sig)); } int counter = 0; for (auto c : equiv_cells) { - equiv_cell = c; - if (run_cell()) + if (prove_equiv_cell(c)) counter++; } return counter; @@ -366,37 +436,35 @@ struct EquivSimplePass : public Pass { } void execute(std::vector args, Design *design) override { - bool verbose = false, short_cones = false, model_undef = false, nogroup = false; - bool set_assumes = false; + EquivSimpleWorker::Config cfg = {}; int success_counter = 0; - int max_seq = 1; log_header(design, "Executing EQUIV_SIMPLE pass.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-v") { - verbose = true; + cfg.verbose = true; continue; } if (args[argidx] == "-short") { - short_cones = true; + cfg.short_cones = true; continue; } if (args[argidx] == "-undef") { - model_undef = true; + cfg.model_undef = true; continue; } if (args[argidx] == "-nogroup") { - nogroup = true; + cfg.nogroup = true; continue; } if (args[argidx] == "-seq" && argidx+1 < args.size()) { - max_seq = atoi(args[++argidx].c_str()); + cfg.max_seq = atoi(args[++argidx].c_str()); continue; } if (args[argidx] == "-set-assumes") { - set_assumes = true; + cfg.set_assumes = true; continue; } break; @@ -421,7 +489,7 @@ struct EquivSimplePass : public Pass { if (cell->type == ID($equiv) && cell->getPort(ID::A) != cell->getPort(ID::B)) { auto bit = sigmap(cell->getPort(ID::Y).as_bit()); auto bit_group = bit; - if (!nogroup && bit_group.wire) + if (!cfg.nogroup && bit_group.wire) bit_group.offset = 0; unproven_equiv_cells[bit_group][bit] = cell; unproven_cells_counter++; @@ -446,15 +514,16 @@ struct EquivSimplePass : public Pass { } unproven_equiv_cells.sort(); - for (auto it : unproven_equiv_cells) + for (auto [_, d] : unproven_equiv_cells) { - it.second.sort(); + d.sort(); vector cells; - for (auto it2 : it.second) - cells.push_back(it2.second); + for (auto [_, cell] : d) + cells.push_back(cell); - EquivSimpleWorker worker(cells, assumes, sigmap, bit2driver, max_seq, short_cones, verbose, model_undef, set_assumes); + EquivSimpleWorker::DesignModel model {sigmap, bit2driver}; + EquivSimpleWorker worker(cells, assumes, model, cfg); success_counter += worker.run(); } } From c9558b3d4f808e67b38628e39798ab5fc930f841 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 00:26:50 +0000 Subject: [PATCH 024/176] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b27a45424..cbc1e9cea 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+0 +YOSYS_VER := 0.56+15 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From e02f4469c0e035d17e80eea1501371edb99199d4 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 8 Aug 2025 12:22:07 +1200 Subject: [PATCH 025/176] equiv_simple: Avoid std::array VS build currently failing with `error C2641: cannot deduce template arguments for 'std::array'`. Changing to `std::array` gives `error C2027: use of undefined type` instead. --- passes/equiv/equiv_simple.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/equiv/equiv_simple.cc b/passes/equiv/equiv_simple.cc index f0c1b517c..8ba42595e 100644 --- a/passes/equiv/equiv_simple.cc +++ b/passes/equiv/equiv_simple.cc @@ -213,7 +213,7 @@ struct EquivSimpleWorker assume_seed.insert(model.sigmap(assume->getPort(ID::A)).as_bit()); assume_seed.insert(model.sigmap(assume->getPort(ID::EN)).as_bit()); - for (auto& cone : std::array{cone_a, cone_b}) { + for (auto& cone : {cone_a, cone_b}) { Cone assume_cone; ConeFinder{model, dummy_next_seed, assume_cone, cone, &overlap_bits} .find_input_cone(assume_seed); From 76e507f3078396c0b331f71eb953db4df8e78aea Mon Sep 17 00:00:00 2001 From: Hongce Zhang Date: Fri, 8 Aug 2025 16:17:37 +0800 Subject: [PATCH 026/176] update verilog_backend according to Github comments --- backends/verilog/verilog_backend.cc | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index b49927513..525ab5bcf 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -2358,16 +2358,12 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) dump_attributes(f, indent, module->attributes, "\n", /*modattr=*/true); f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str()); int cnt = 0; - - std::vector port_ordered; - for (auto port : module->ports) { Wire *wire = module->wire(port); if (wire) { if (port != module->ports[0]) f << stringf(", "); f << stringf("%s", id(wire->name).c_str()); - port_ordered.push_back(wire); if (cnt==20) { f << stringf("\n"); cnt = 0; } else cnt++; continue; } @@ -2378,13 +2374,13 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) f << indent + " " << "reg " << id(initial_id) << " = 0;\n"; } - // first dump input / output according to port_ordered; - for (auto w : port_ordered) - dump_wire(f, indent + " ", w); - + // first dump input / output according to their order in module->ports + for (auto port : module->ports) + dump_wire(f, indent + " ", module->wire(port)); + for (auto w : module->wires()) { // avoid duplication - if (std::find(port_ordered.begin(), port_ordered.end(), w) != port_ordered.end()) + if (w->port_id) continue; dump_wire(f, indent + " ", w); } From 6c84c4a4fc151f525865f3cca8d763e67e4fbdca Mon Sep 17 00:00:00 2001 From: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 9 Aug 2025 11:19:24 +1200 Subject: [PATCH 027/176] extra-builds.yml: Bump nix --- .github/workflows/extra-builds.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index d7ceb3fe3..8d64b2e0e 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -98,7 +98,7 @@ jobs: with: submodules: true persist-credentials: false - - uses: cachix/install-nix-action@v26 + - uses: cachix/install-nix-action@v31 with: - install_url: https://releases.nixos.org/nix/nix-2.18.1/install + install_url: https://releases.nixos.org/nix/nix-2.30.0/install - run: nix build .?submodules=1 -L From 0d4585dd5fa59efe8fa9c499cbe9dcc33e302e14 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 9 Aug 2025 00:24:43 +0000 Subject: [PATCH 028/176] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index cbc1e9cea..512c1410d 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+15 +YOSYS_VER := 0.56+30 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 98b3316f55e24dbd91f2b4551f1a2e277fc1f2e0 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 10 Jul 2025 21:13:28 +0200 Subject: [PATCH 029/176] Revert "verilog: fix parser "if" memory errors." This reverts commit 34a2abeddb5054df29140baf1c6d5af02a9aac63. --- frontends/verilog/verilog_parser.y | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index bd9f47034..3cd582378 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2885,7 +2885,6 @@ behavioral_stmt: } | if_attr TOK_IF '(' expr ')' { AstNode *node = 0; - AstNode *block = new AstNode(AST_BLOCK); AstNode *context = ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) { AstNode *outer = ast_stack[ast_stack.size() - 2]; @@ -2894,10 +2893,8 @@ behavioral_stmt: // parallel "else if": append condition to outer "if" node = outer; log_assert (node->children.size()); - ast_stack.pop_back(); delete node->children.back(); node->children.pop_back(); - ast_stack.push_back(block); } else if (outer->get_bool_attribute(ID::full_case)) (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); } @@ -2908,8 +2905,8 @@ behavioral_stmt: append_attr(node, $1); ast_stack.back()->children.push_back(node); node->children.push_back(node->get_bool_attribute(ID::parallel_case) ? AstNode::mkconst_int(1, false, 1) : expr); - } else - free_attr($1); + } + AstNode *block = new AstNode(AST_BLOCK); AstNode *cond = new AstNode(AST_COND, node->get_bool_attribute(ID::parallel_case) ? expr : AstNode::mkconst_int(1, false, 1), block); SET_AST_NODE_LOC(cond, @4, @4); node->children.push_back(cond); From 36491569d2da316f316c290a97d857385179c14f Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 10 Jul 2025 21:14:38 +0200 Subject: [PATCH 030/176] Revert "verilog: add support for SystemVerilog string literals." This reverts commit 5feb1a1752a7469fd5a02ec8afdb68794e55ef8f. --- docs/source/using_yosys/verilog.rst | 3 - frontends/verilog/verilog_lexer.l | 168 +++++------------- tests/verilog/bug5160.v | 5 + tests/verilog/string-literals.ys | 257 ---------------------------- 4 files changed, 47 insertions(+), 386 deletions(-) create mode 100644 tests/verilog/bug5160.v delete mode 100644 tests/verilog/string-literals.ys diff --git a/docs/source/using_yosys/verilog.rst b/docs/source/using_yosys/verilog.rst index 92f223e49..eb18cb699 100644 --- a/docs/source/using_yosys/verilog.rst +++ b/docs/source/using_yosys/verilog.rst @@ -379,6 +379,3 @@ from SystemVerilog: will process conditionals using these keywords by annotating their representation with the appropriate ``full_case`` and/or ``parallel_case`` attributes, which are described above.) - -- SystemVerilog string literals are supported (triple-quoted strings and - escape sequences such as line continuations and hex escapes). diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 19c0774af..c3ff981be 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -112,129 +112,6 @@ static bool isUserType(std::string &s) return false; } -static bool is_hex_dig(char c, int *val) -{ - if ('0' <= c && c <= '9') { - *val = c - '0'; - return true; - } else if ('a' <= c && c <= 'f') { - *val = c - 'a' + 0xA; - return true; - } else if ('A' <= c && c <= 'F') { - *val = c - 'A' + 0xA; - return true; - } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { - log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "'%c' not a valid digit in hex escape sequence.\n", c); - *val = 0; // not semantically valid in hex escape... - return true; // ...but still processed as part of hex token - } - - return false; -} - -static bool is_oct_dig(char c, int *val) -{ - if ('0' <= c && c <= '7') { - *val = c - '0'; - return true; - } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { - log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "'%c' not a valid digit in octal escape sequence.\n", c); - *val = 0; // not semantically valid in octal escape... - return true; // ...but still processed as part of octal token - } - - return false; -} - -static std::string *process_str(char *str, int len, bool triple) -{ - char *in, *out; // Overwrite input buffer: flex manual states "Actions - // are free to modify 'yytext' except for lengthening it". - - for (in = str, out = str; in < str + len; in++) - switch (*in) { - case '\n': - case '\r': - if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r')) - in++; - if (!triple) - log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "Multi-line string literals should be triple-quoted or escaped.\n"); - *out++ = '\n'; - break; - case '\\': - in++; - log_assert(in < str + len); - switch (*in) { - case 'a': - *out++ = '\a'; - break; - case 'f': - *out++ = '\f'; - break; - case 'n': - *out++ = '\n'; - break; - case 'r': /* not part of IEEE-1800 2023, but seems - like a good idea to support it anyway */ - *out++ = '\r'; - break; - case 't': - *out++ = '\t'; - break; - case 'v': - *out++ = '\v'; - break; - case 'x': - int val; - if (in + 1 < str + len && is_hex_dig(in[1], &val)) { - *out = val; - in++; - if (in + 1 < str + len && is_hex_dig(in[1], &val)) { - *out = *out * 0x10 + val; - in++; - } - out++; - } else - log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "ignoring invalid hex escape.\n"); - break; - case '\\': - *out++ = '\\'; - break; - case '"': - *out++ = '"'; - break; - case '\n': - case '\r': - if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r')) - in++; - break; - default: - if ('0' <= *in && *in <= '7') { - int val; - - *out = *in - '0'; - if (in + 1 < str + len && is_oct_dig(in[1], &val)) { - *out = *out * 010 + val; - in++; - if (in + 1 < str + len && is_oct_dig(in[1], &val)) { - if (*out >= 040) - log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "octal escape exceeds \\377\n"); - *out = *out * 010 + val; - in++; - } - } - out++; - } else - *out++ = *in; - } - break; - default: - *out++ = *in; - } - - return new std::string(str, out - str); -} - %} %option yylineno @@ -245,6 +122,7 @@ static std::string *process_str(char *str, int len, bool triple) %option prefix="frontend_verilog_yy" %x COMMENT +%x STRING %x SYNOPSYS_TRANSLATE_OFF %x SYNOPSYS_FLAGS %x IMPORT_DPI @@ -458,9 +336,47 @@ TIME_SCALE_SUFFIX [munpf]?s return TOK_REALVAL; } -\"([^\\"]|\\.|\\\n)*\" { yylval->string = process_str(yytext + 1, yyleng - 2, false); return TOK_STRING; } - -\"{3}(\"{0,2}([^\\"]|\\.|\\\n))*\"{3} { yylval->string = process_str(yytext + 3, yyleng - 6, true); return TOK_STRING; } +\" { BEGIN(STRING); } +([^\\"]|\\.)+ { yymore(); real_location = old_location; } +\" { + BEGIN(0); + char *yystr = strdup(yytext); + yystr[strlen(yytext) - 1] = 0; + int i = 0, j = 0; + while (yystr[i]) { + if (yystr[i] == '\\' && yystr[i + 1]) { + i++; + if (yystr[i] == 'a') + yystr[i] = '\a'; + else if (yystr[i] == 'f') + yystr[i] = '\f'; + else if (yystr[i] == 'n') + yystr[i] = '\n'; + else if (yystr[i] == 'r') + yystr[i] = '\r'; + else if (yystr[i] == 't') + yystr[i] = '\t'; + else if (yystr[i] == 'v') + yystr[i] = '\v'; + else if ('0' <= yystr[i] && yystr[i] <= '7') { + yystr[i] = yystr[i] - '0'; + if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { + yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; + i++; + } + if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { + yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; + i++; + } + } + } + yystr[j++] = yystr[i++]; + } + yystr[j] = 0; + yylval->string = new std::string(yystr, j); + free(yystr); + return TOK_STRING; +} and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 { yylval->string = new std::string(yytext); diff --git a/tests/verilog/bug5160.v b/tests/verilog/bug5160.v new file mode 100644 index 000000000..5b141a360 --- /dev/null +++ b/tests/verilog/bug5160.v @@ -0,0 +1,5 @@ +// Regression test for bug mentioned in #5160: +// https://github.com/YosysHQ/yosys/pull/5160#issuecomment-2983643084 +module top; + initial $display( "\\" ); +endmodule diff --git a/tests/verilog/string-literals.ys b/tests/verilog/string-literals.ys deleted file mode 100644 index a0f0f0460..000000000 --- a/tests/verilog/string-literals.ys +++ /dev/null @@ -1,257 +0,0 @@ -# Test valid escape sequences yield correct results: -logger -expect-no-warnings -read_verilog << EOF -module top; - wire[7:0] sp = "\ "; - wire[7:0] spval = 32; - wire[7:0] ex = "\!"; - wire[7:0] exval = 33; - wire[7:0] dq = "\""; - wire[7:0] dqval = 34; - wire[7:0] ha = "\#"; - wire[7:0] haval = 35; - wire[7:0] do = "\$"; - wire[7:0] doval = 36; - wire[7:0] pc = "\%"; - wire[7:0] pcval = 37; - wire[7:0] am = "\&"; - wire[7:0] amval = 38; - wire[7:0] sq = "\'"; - wire[7:0] sqval = 39; - wire[7:0] op = "\("; - wire[7:0] opval = 40; - wire[7:0] cp = "\)"; - wire[7:0] cpval = 41; - wire[7:0] as = "\*"; - wire[7:0] asval = 42; - wire[7:0] pl = "\+"; - wire[7:0] plval = 43; - wire[7:0] co = "\,"; - wire[7:0] coval = 44; - wire[7:0] mi = "\-"; - wire[7:0] mival = 45; - wire[7:0] do = "\."; - wire[7:0] doval = 46; - wire[7:0] sl = "\/"; - wire[7:0] slval = 47; - - wire[7:0] dig0 = "\012"; - wire[7:0] dig0val = 10; - wire[7:0] dig8 = "\8"; // not octal, a literal '8' - wire[7:0] dig8val = 56; - wire[7:0] dig9 = "\9"; // not octal, a literal '9' - wire[7:0] dig9val = 57; - - wire[7:0] cl = "\:"; - wire[7:0] clval = 58; - wire[7:0] sc = "\;"; - wire[7:0] scval = 59; - wire[7:0] lt = "\<"; - wire[7:0] ltval = 60; - wire[7:0] eq = "\="; - wire[7:0] eqval = 61; - wire[7:0] gt = "\>"; - wire[7:0] gtval = 62; - wire[7:0] qu = "\?"; - wire[7:0] quval = 63; - wire[7:0] at = "\@"; - wire[7:0] atval = 64; - - wire[7:0] A = "\A"; - wire[7:0] Aval = 65; // etc. etc. - - wire[7:0] os = "\["; - wire[7:0] osval = 91; - wire[7:0] bs = "\\"; - wire[7:0] bsval = 92; - wire[7:0] cs = "\]"; - wire[7:0] csval = 93; - wire[7:0] ca = "\^"; - wire[7:0] caval = 94; - wire[7:0] us = "\_"; - wire[7:0] usval = 95; - wire[7:0] bq = "\`"; - wire[7:0] bqval = 96; - - wire[7:0] a = "\a"; // alert, ASCII BEL=7 - wire[7:0] aval = 7; - wire[7:0] b = "\b"; - wire[7:0] bval = 98; - wire[7:0] c = "\c"; - wire[7:0] cval = 99; - wire[7:0] d = "\d"; - wire[7:0] dval = 100; - wire[7:0] e = "\e"; - wire[7:0] eval = 101; - wire[7:0] f = "\f"; // form feed, ASCII FF=12 - wire[7:0] fval = 12; - wire[7:0] g = "\g"; - wire[7:0] gval = 103; - wire[7:0] h = "\h"; - wire[7:0] hval = 104; - wire[7:0] i = "\i"; - wire[7:0] ival = 105; - wire[7:0] j = "\j"; - wire[7:0] jval = 106; - wire[7:0] k = "\k"; - wire[7:0] kval = 107; - wire[7:0] l = "\l"; - wire[7:0] lval = 108; - wire[7:0] m = "\m"; - wire[7:0] mval = 109; - wire[7:0] n = "\n"; // new line, ASCII LF=10 - wire[7:0] nval = 10; - wire[7:0] o = "\o"; - wire[7:0] oval = 111; - wire[7:0] p = "\p"; - wire[7:0] pval = 112; - wire[7:0] q = "\q"; - wire[7:0] qval = 113; - wire[7:0] r = "\r"; // carriage return, ASCII CR=13, not IEEE 1800-2023 - wire[7:0] rval = 13; - wire[7:0] s = "\s"; - wire[7:0] sval = 115; - wire[7:0] t = "\t"; // tab, ASCII HT=9 - wire[7:0] tval = 9; - wire[7:0] u = "\u"; - wire[7:0] uval = 117; - wire[7:0] v = "\v"; // vertical tab, ASCII VT=11 - wire[7:0] vval = 11; - wire[7:0] w = "\w"; - wire[7:0] wval = 119; - wire[7:0] x = "\x2A"; // hex escape - wire[7:0] xval = 42; - wire[7:0] y = "\y"; - wire[7:0] yval = 121; - wire[7:0] z = "\z"; - wire[7:0] zval = 122; - - wire[7:0] ob = "\{"; - wire[7:0] obval = 123; - wire[7:0] vb = "\|"; - wire[7:0] vbval = 124; - wire[7:0] cb = "\}"; - wire[7:0] cbval = 125; - wire[7:0] ti = "\~"; - wire[7:0] tival = 126; -endmodule -EOF -sat -prove sp spval -prove ex exval -prove dq dqval -prove ha haval -prove do doval -prove pc pcval -prove am amval -prove sq sqval -prove op opval -prove cp cpval -prove as asval -prove pl plval -prove co coval -prove mi mival -prove do doval -prove sl slval -verify -sat -prove dig0 dig0val -prove dig8 dig8val -prove dig9 dig9val -verify -sat -prove cl clval -prove sc scval -prove lt ltval -prove eq eqval -prove gt gtval -prove qu quval -prove at atval -prove A Aval -verify -sat -prove os osval -prove bs bsval -prove cs csval -prove ca caval -prove us usval -prove bq bqval -verify -sat -prove a aval -prove b bval -prove c cval -prove d dval -prove e eval -prove f fval -prove g gval -prove h hval -prove i ival -prove j jval -prove k kval -prove l lval -prove m mval -prove n nval -prove o oval -prove p pval -prove q qval -prove r rval -prove s sval -prove t tval -prove u uval -prove v vval -prove w wval -prove x xval -prove y yval -prove z zval -verify -sat -prove ob obval -prove vb vbval -prove cb cbval -prove ti tival -verify -logger -check-expected -design -reset - -# Test octal escape out of range. -logger -expect warning "octal escape exceeds \\377" 1 -read_verilog << EOF -module top; - wire[7:0] x = "\400"; -endmodule -EOF -logger -check-expected -design -reset - -# Test invalid octal digit. -logger -expect warning "'\?' not a valid digit in octal escape sequence" 1 -read_verilog << EOF -module top; - wire[7:0] x = "\0?"; -endmodule -EOF -logger -check-expected -design -reset - -# Test invalid hex digit. -logger -expect warning "'X' not a valid digit in hex escape sequence" 1 -read_verilog << EOF -module top; - wire[7:0] x = "\x0X"; -endmodule -EOF -logger -check-expected -design -reset - -# Test hex escape with no hex digits at all. -logger -expect warning "ignoring invalid hex escape" 1 -read_verilog << EOF -module top; - wire[7:0] x = "\xy"; -endmodule -EOF -logger -check-expected -design -reset - -# Test hex escape interrupted by end of string. -logger -expect warning "ignoring invalid hex escape" 1 -read_verilog << EOF -module top; - wire[7:0] x = "\x"; -endmodule -EOF -logger -check-expected -design -reset - -# Test multi-line string. -logger -expect warning "Multi-line string literals should be triple-quoted or escaped" 1 -read_verilog << EOF -module top; - wire[31:0] x = "A -BC"; - wire[31:0] xval = 32'h410A4243; -endmodule -EOF -logger -check-expected -design -reset - -# Test multi-line triple-quoted string. -logger -expect-no-warnings -read_verilog << EOF -module top; - wire[31:0] x = """A -BC"""; - wire[31:0] xval = 32'h410A4243; -endmodule -EOF -logger -check-expected -sat -prove x xval -verify -design -reset - -# Test escaped multi-line string. -logger -expect-no-warnings -read_verilog << EOF -module top; - wire[31:0] x = "AB\ -CD"; - wire[31:0] xval = 32'h41424344; -endmodule -EOF -logger -check-expected -sat -prove x xval -verify -design -reset - -# Test octal escape with surrounding data. -logger -expect-no-warnings -read_verilog << EOF -module top; - wire[31:0] x = "AB\234C"; - wire[31:0] xval = 32'h41429C43; -endmodule -EOF -logger -check-expected -sat -prove x xval -verify -design -reset - -# Test hex escape with surrounding data. -logger -expect-no-warnings -read_verilog << EOF -module top; - wire[31:0] x = "A\xBCDE"; - wire[31:0] xval = 32'h41BC4445; -endmodule -EOF -logger -check-expected -sat -prove x xval -verify From f27309136f063f4bcab96b56fc145cc62db3937e Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 10 Jul 2025 21:15:38 +0200 Subject: [PATCH 031/176] Revert "verilog: fix string literal regular expression (#5187)" This reverts commit 834a7294b7c790612e9d1a686b374130b43d814e. --- frontends/verilog/verilog_lexer.l | 2 +- tests/verilog/bug5160.v | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 tests/verilog/bug5160.v diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index c3ff981be..362288f29 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -337,7 +337,7 @@ TIME_SCALE_SUFFIX [munpf]?s } \" { BEGIN(STRING); } -([^\\"]|\\.)+ { yymore(); real_location = old_location; } +([^\"]|\\.)+ { yymore(); real_location = old_location; } \" { BEGIN(0); char *yystr = strdup(yytext); diff --git a/tests/verilog/bug5160.v b/tests/verilog/bug5160.v deleted file mode 100644 index 5b141a360..000000000 --- a/tests/verilog/bug5160.v +++ /dev/null @@ -1,5 +0,0 @@ -// Regression test for bug mentioned in #5160: -// https://github.com/YosysHQ/yosys/pull/5160#issuecomment-2983643084 -module top; - initial $display( "\\" ); -endmodule From c8e0ac0c616732aac82f02da01413154c7bba843 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 16 Jun 2025 22:55:24 +0200 Subject: [PATCH 032/176] ast, read_verilog: ownership in AST, use C++ styles for parser and lexer --- frontends/ast/ast.cc | 340 ++- frontends/ast/ast.h | 61 +- frontends/ast/dpicall.cc | 8 +- frontends/ast/genrtlil.cc | 206 +- frontends/ast/simplify.cc | 1433 +++++----- frontends/verilog/.gitignore | 3 + frontends/verilog/Makefile.inc | 1 + frontends/verilog/const2ast.cc | 52 +- frontends/verilog/preproc.cc | 9 +- frontends/verilog/preproc.h | 9 +- frontends/verilog/verilog_frontend.cc | 171 +- frontends/verilog/verilog_frontend.h | 86 +- frontends/verilog/verilog_lexer.h | 48 + frontends/verilog/verilog_lexer.l | 561 ++-- frontends/verilog/verilog_parser.y | 3595 ++++++++++++------------- kernel/rtlil.cc | 16 +- kernel/rtlil.h | 2 +- passes/cmds/design.cc | 6 - passes/memory/memlib.h | 2 +- 19 files changed, 3296 insertions(+), 3313 deletions(-) create mode 100644 frontends/verilog/verilog_lexer.h diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 04f749845..877c41283 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -39,8 +39,7 @@ using namespace AST_INTERNAL; // instantiate global variables (public API) namespace AST { std::string current_filename; - void (*set_line_num)(int) = NULL; - int (*get_line_num)() = NULL; + bool sv_mode; unsigned long long astnodes = 0; unsigned long long astnode_count() { return astnodes; } } @@ -193,16 +192,16 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id) if (attributes.count(id) == 0) return false; - AstNode *attr = attributes.at(id); - if (attr->type != AST_CONSTANT) - attr->input_error("Attribute `%s' with non-constant value!\n", id.c_str()); + AstNode& attr = *(attributes.at(id)); + if (attr.type != AST_CONSTANT) + attr.input_error("Attribute `%s' with non-constant value!\n", id.c_str()); - return attr->integer != 0; + return attr.integer != 0; } // create new node (AstNode constructor) // (the optional child arguments make it easier to create AST trees) -AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *child3, AstNode *child4) +AstNode::AstNode(AstNodeType type, std::unique_ptr child1, std::unique_ptr child2, std::unique_ptr child3, std::unique_ptr child4) { static unsigned int hashidx_count = 123456789; hashidx_count = mkhash_xorshift(hashidx_count); @@ -240,56 +239,74 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch in_param = false; if (child1) - children.push_back(child1); + children.push_back(std::move(child1)); if (child2) - children.push_back(child2); + children.push_back(std::move(child2)); if (child3) - children.push_back(child3); + children.push_back(std::move(child3)); if (child4) - children.push_back(child4); + children.push_back(std::move(child4)); fixup_hierarchy_flags(); } // create a (deep recursive) copy of a node -AstNode *AstNode::clone() const +std::unique_ptr AstNode::clone() const { - AstNode *that = new AstNode; - *that = *this; - for (auto &it : that->children) - it = it->clone(); - for (auto &it : that->attributes) - it.second = it.second->clone(); - - that->set_in_lvalue_flag(false); - that->set_in_param_flag(false); - that->fixup_hierarchy_flags(); // fixup to set flags on cloned children + auto that = std::make_unique(this->type); + cloneInto(*that.get()); return that; } // create a (deep recursive) copy of a node use 'other' as target root node -void AstNode::cloneInto(AstNode *other) const +void AstNode::cloneInto(AstNode &other) const { - AstNode *tmp = clone(); - tmp->in_lvalue_from_above = other->in_lvalue_from_above; - tmp->in_param_from_above = other->in_param_from_above; - other->delete_children(); - *other = *tmp; - tmp->children.clear(); - tmp->attributes.clear(); - other->fixup_hierarchy_flags(); - delete tmp; + other.type = type; + other.str = str; + other.bits = bits; + other.is_input = is_input; + other.is_output = is_output; + other.is_reg = is_reg; + other.is_logic = is_logic; + other.is_signed = is_signed; + other.is_string = is_string; + other.is_wand = is_wand; + other.is_wor = is_wor; + other.range_valid = range_valid; + other.range_swapped = range_swapped; + other.was_checked = was_checked; + other.is_unsized = is_unsized; + other.is_custom_type = is_custom_type; + other.port_id = port_id, + other.range_left = range_left, + other.range_right = range_right; + other.integer = integer; + other.realvalue = realvalue; + other.is_enum = is_enum; + other.dimensions = dimensions; + other.unpacked_dimensions = unpacked_dimensions; + other.id2ast = id2ast; + other.basic_prep = basic_prep; + other.lookahead = lookahead; + other.filename = filename; + other.location = location; + other.in_lvalue = in_lvalue; + other.in_param = in_param; + // Keep in_lvalue_from_above and in_param_from_above untouched + + other.delete_children(); + for (auto& child : this->children) + other.children.push_back(child->clone()); + for (auto& [key, val] : this->attributes) + other.attributes[key] = (val->clone()); + // fixup to set flags on cloned children + other.fixup_hierarchy_flags(); } // delete all children in this node void AstNode::delete_children() { - for (auto &it : children) - delete it; children.clear(); - - for (auto &it : attributes) - delete it.second; attributes.clear(); } @@ -424,18 +441,18 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const { case AST_MODULE: fprintf(f, "%s" "module %s(", indent.c_str(), id2vl(str).c_str()); - for (auto child : children) + for (const auto& child : children) if (child->type == AST_WIRE && (child->is_input || child->is_output)) { fprintf(f, "%s%s", first ? "" : ", ", id2vl(child->str).c_str()); first = false; } fprintf(f, ");\n"); - for (auto child : children) + for (const auto& child : children) if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || child->type == AST_DEFPARAM) child->dumpVlog(f, indent + " "); else - rem_children1.push_back(child); + rem_children1.push_back(child.get()); for (auto child : rem_children1) if (child->type == AST_WIRE || child->type == AST_AUTOWIRE || child->type == AST_MEMORY) @@ -471,7 +488,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const fprintf(f, "%s" "reg", (is_input || is_output) ? " " : indent.c_str()); if (is_signed) fprintf(f, " signed"); - for (auto child : children) { + for (const auto& child : children) { fprintf(f, " "); child->dumpVlog(f, ""); } @@ -487,7 +504,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const fprintf(f, "%s" "memory", indent.c_str()); if (is_signed) fprintf(f, " signed"); - for (auto child : children) { + for (const auto& child : children) { fprintf(f, " "); child->dumpVlog(f, ""); if (first) @@ -501,7 +518,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const if (0) { case AST_MEMINIT: txt = "@meminit@"; } if (0) { case AST_MEMWR: txt = "@memwr@"; } fprintf(f, "%s%s", indent.c_str(), txt.c_str()); - for (auto child : children) { + for (const auto& child : children) { fprintf(f, first ? "(" : ", "); child->dumpVlog(f, ""); first = false; @@ -518,7 +535,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const else fprintf(f, "[%d:%d]", range_left, range_right); } else { - for (auto child : children) { + for (const auto& child : children) { fprintf(f, "%c", first ? '[' : ':'); child->dumpVlog(f, ""); first = false; @@ -528,13 +545,13 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const break; case AST_MULTIRANGE: - for (auto child : children) + for (const auto& child : children) child->dumpVlog(f, ""); break; case AST_ALWAYS: fprintf(f, "%s" "always @", indent.c_str()); - for (auto child : children) { + for (const auto& child : children) { if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) continue; fprintf(f, first ? "(" : ", "); @@ -542,7 +559,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const first = false; } fprintf(f, first ? "*\n" : ")\n"); - for (auto child : children) { + for (const auto& child : children) { if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) child->dumpVlog(f, indent + " "); } @@ -550,7 +567,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const case AST_INITIAL: fprintf(f, "%s" "initial\n", indent.c_str()); - for (auto child : children) { + for (const auto& child : children) { if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) child->dumpVlog(f, indent + " "); } @@ -563,7 +580,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const fprintf(f, "posedge "); if (type == AST_NEGEDGE) fprintf(f, "negedge "); - for (auto child : children) + for (const auto& child : children) child->dumpVlog(f, ""); break; @@ -575,7 +592,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const else fprintf(f, "%s", id2vl(str).c_str()); } - for (auto child : children) + for (const auto& child : children) child->dumpVlog(f, ""); break; @@ -603,7 +620,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const children[0]->dumpVlog(f, indent); } else { fprintf(f, "%s" "begin\n", indent.c_str()); - for (auto child : children) + for (const auto& child : children) child->dumpVlog(f, indent + " "); fprintf(f, "%s" "end\n", indent.c_str()); } @@ -619,7 +636,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const children[0]->dumpVlog(f, ""); fprintf(f, ")\n"); for (size_t i = 1; i < children.size(); i++) { - AstNode *child = children[i]; + const auto& child = children[i]; child->dumpVlog(f, indent + " "); } fprintf(f, "%s" "endcase\n", indent.c_str()); @@ -628,7 +645,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const case AST_COND: case AST_CONDX: case AST_CONDZ: - for (auto child : children) { + for (const auto& child : children) { if (child->type == AST_BLOCK) { fprintf(f, ":\n"); child->dumpVlog(f, indent + " "); @@ -664,7 +681,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const case AST_CONCAT: fprintf(f, "{"); for (int i = GetSize(children)-1; i >= 0; i--) { - auto child = children[i]; + const auto& child = children[i]; if (!first) fprintf(f, ", "); child->dumpVlog(f, ""); @@ -819,16 +836,16 @@ bool AstNode::contains(const AstNode *other) const { if (this == other) return true; - for (auto child : children) + for (const auto& child : children) if (child->contains(other)) return true; return false; } // create an AST node for a constant (using a 32 bit int as value) -AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width) +std::unique_ptr AstNode::mkconst_int(uint32_t v, bool is_signed, int width) { - AstNode *node = new AstNode(AST_CONSTANT); + auto node = std::make_unique(AST_CONSTANT); node->integer = v; node->is_signed = is_signed; for (int i = 0; i < width; i++) { @@ -842,9 +859,9 @@ AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width) } // create an AST node for a constant (using a bit vector as value) -AstNode *AstNode::mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized) +std::unique_ptr AstNode::mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized) { - AstNode *node = new AstNode(AST_CONSTANT); + auto node = std::make_unique(AST_CONSTANT); node->is_signed = is_signed; node->bits = v; for (size_t i = 0; i < 32; i++) { @@ -860,15 +877,15 @@ AstNode *AstNode::mkconst_bits(const std::vector &v, bool is_signe return node; } -AstNode *AstNode::mkconst_bits(const std::vector &v, bool is_signed) +std::unique_ptr AstNode::mkconst_bits(const std::vector &v, bool is_signed) { return mkconst_bits(v, is_signed, false); } // create an AST node for a constant (using a string in bit vector form as value) -AstNode *AstNode::mkconst_str(const std::vector &v) +std::unique_ptr AstNode::mkconst_str(const std::vector &v) { - AstNode *node = mkconst_str(RTLIL::Const(v).decode_string()); + auto node = mkconst_str(RTLIL::Const(v).decode_string()); while (GetSize(node->bits) < GetSize(v)) node->bits.push_back(RTLIL::State::S0); log_assert(node->bits == v); @@ -876,9 +893,9 @@ AstNode *AstNode::mkconst_str(const std::vector &v) } // create an AST node for a constant (using a string as value) -AstNode *AstNode::mkconst_str(const std::string &str) +std::unique_ptr AstNode::mkconst_str(const std::string &str) { - AstNode *node; + std::unique_ptr node; // LRM 1364-2005 5.2.3.3 The empty string literal ("") shall be considered // equivalent to the ASCII NUL ("\0") @@ -903,18 +920,19 @@ AstNode *AstNode::mkconst_str(const std::string &str) } // create a temporary register -AstNode *AstNode::mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed) +std::unique_ptr AstNode::mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed) { - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(range_left, true), mkconst_int(range_right, true))); + auto wire_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(range_left, true), mkconst_int(range_right, true))); + auto* wire = wire_owned.get(); wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); if (nosync) wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire->is_signed = is_signed; wire->is_logic = true; - mod->children.push_back(wire); + mod->children.push_back(std::move(wire_owned)); while (wire->simplify(true, 1, -1, false)) { } - AstNode *ident = new AstNode(AST_IDENTIFIER); + auto ident = std::make_unique(AST_IDENTIFIER); ident->str = wire->str; ident->id2ast = wire; @@ -968,10 +986,9 @@ RTLIL::Const AstNode::asParaConst() const { if (type == AST_REALVALUE) { - AstNode *strnode = AstNode::mkconst_str(stringf("%f", realvalue)); + auto strnode = AstNode::mkconst_str(stringf("%f", realvalue)); RTLIL::Const val = strnode->asAttrConst(); val.flags |= RTLIL::CONST_FLAG_REAL; - delete strnode; return val; } @@ -1079,7 +1096,7 @@ void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast) obj->attributes[ID::src] = ast->loc_string(); } -static bool param_has_no_default(const AstNode *param) { +static bool param_has_no_default(const std::unique_ptr ¶m) { const auto &children = param->children; log_assert(param->type == AST_PARAMETER); log_assert(children.size() <= 2); @@ -1087,7 +1104,7 @@ static bool param_has_no_default(const AstNode *param) { (children.size() == 1 && children[0]->type == AST_RANGE); } -static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false) +static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool defer, std::unique_ptr original_ast = NULL, bool quiet = false) { log_assert(current_scope.empty()); log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE); @@ -1101,15 +1118,15 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d AstModule *module = new AstModule; current_module = module; - module->ast = NULL; + module->ast = nullptr; module->name = ast->str; set_src_attr(module, ast); module->set_bool_attribute(ID::cells_not_processed); current_ast_mod = ast; - AstNode *ast_before_simplify; + std::unique_ptr ast_before_simplify; if (original_ast != NULL) - ast_before_simplify = original_ast; + ast_before_simplify = std::move(original_ast); else ast_before_simplify = ast->clone(); @@ -1126,7 +1143,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d if (!defer) { - for (const AstNode *node : ast->children) + for (auto& node : ast->children) if (node->type == AST_PARAMETER && param_has_no_default(node)) node->input_error("Parameter `%s' has no default value and has not been overridden!\n", node->str.c_str()); @@ -1134,7 +1151,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d if (!blackbox_module && !flag_noblackbox) { blackbox_module = true; - for (auto child : ast->children) { + for (const auto& child : ast->children) { if (child->type == AST_WIRE && (child->is_input || child->is_output)) continue; if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM) @@ -1164,36 +1181,33 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d ast->dumpVlog(NULL, " "); log("--- END OF AST DUMP ---\n"); } - + for (auto &attr: ast->attributes) + log_assert((bool)attr.second.get()); if (flag_nowb && ast->attributes.count(ID::whitebox)) { - delete ast->attributes.at(ID::whitebox); ast->attributes.erase(ID::whitebox); } - + for (auto &attr: ast->attributes) + log_assert((bool)attr.second.get()); if (ast->attributes.count(ID::lib_whitebox)) { - if (!flag_lib || flag_nowb) { - delete ast->attributes.at(ID::lib_whitebox); - ast->attributes.erase(ID::lib_whitebox); - } else { - if (ast->attributes.count(ID::whitebox)) { - delete ast->attributes.at(ID::whitebox); - ast->attributes.erase(ID::whitebox); - } - AstNode *n = ast->attributes.at(ID::lib_whitebox); - ast->set_attribute(ID::whitebox, n); - ast->attributes.erase(ID::lib_whitebox); + if (flag_lib && !flag_nowb) { + ast->attributes[ID::whitebox] = std::move( + ast->attributes[ID::lib_whitebox] + ); } + ast->attributes.erase(ID::lib_whitebox); } + for (auto &attr: ast->attributes) + log_assert((bool)attr.second.get()); if (!blackbox_module && ast->attributes.count(ID::blackbox)) { - AstNode *n = ast->attributes.at(ID::blackbox); + auto& n = ast->attributes.at(ID::blackbox); if (n->type != AST_CONSTANT) ast->input_error("Got blackbox attribute with non-constant value!\n"); blackbox_module = n->asBool(); } if (blackbox_module && ast->attributes.count(ID::whitebox)) { - AstNode *n = ast->attributes.at(ID::whitebox); + auto& n = ast->attributes.at(ID::whitebox); if (n->type != AST_CONSTANT) ast->input_error("Got whitebox attribute with non-constant value!\n"); blackbox_module = !n->asBool(); @@ -1201,38 +1215,34 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d if (ast->attributes.count(ID::noblackbox)) { if (blackbox_module) { - AstNode *n = ast->attributes.at(ID::noblackbox); + auto& n = ast->attributes.at(ID::noblackbox); if (n->type != AST_CONSTANT) ast->input_error("Got noblackbox attribute with non-constant value!\n"); blackbox_module = !n->asBool(); } - delete ast->attributes.at(ID::noblackbox); ast->attributes.erase(ID::noblackbox); } - + for (auto &attr: ast->attributes) + log_assert((bool)attr.second.get()); if (blackbox_module) { if (ast->attributes.count(ID::whitebox)) { - delete ast->attributes.at(ID::whitebox); ast->attributes.erase(ID::whitebox); } if (ast->attributes.count(ID::lib_whitebox)) { - delete ast->attributes.at(ID::lib_whitebox); ast->attributes.erase(ID::lib_whitebox); } - std::vector new_children; - for (auto child : ast->children) { + std::vector> new_children; + for (auto& child : ast->children) { if (child->type == AST_WIRE && (child->is_input || child->is_output)) { - new_children.push_back(child); + new_children.push_back(std::move(child)); } else if (child->type == AST_PARAMETER) { - new_children.push_back(child); + new_children.push_back(std::move(child)); } else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE && (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) { - new_children.push_back(child); - } else { - delete child; + new_children.push_back(std::move(child)); } } @@ -1246,17 +1256,18 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d ignoreThisSignalsInInitial = RTLIL::SigSpec(); for (auto &attr : ast->attributes) { + log_assert((bool)attr.second.get()); if (attr.second->type != AST_CONSTANT) ast->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str()); module->attributes[attr.first] = attr.second->asAttrConst(); } for (size_t i = 0; i < ast->children.size(); i++) { - AstNode *node = ast->children[i]; + const auto& node = ast->children[i]; if (node->type == AST_WIRE || node->type == AST_MEMORY) node->genRTLIL(); } for (size_t i = 0; i < ast->children.size(); i++) { - AstNode *node = ast->children[i]; + const auto& node = ast->children[i]; if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL) node->genRTLIL(); } @@ -1264,7 +1275,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d ignoreThisSignalsInInitial.sort_and_unify(); for (size_t i = 0; i < ast->children.size(); i++) { - AstNode *node = ast->children[i]; + const auto& node = ast->children[i]; if (node->type == AST_INITIAL) node->genRTLIL(); } @@ -1278,14 +1289,14 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d continue; module->attributes[attr.first] = attr.second->asAttrConst(); } - for (const AstNode *node : ast->children) + for (const auto& node : ast->children) if (node->type == AST_PARAMETER) current_module->avail_parameters(node->str); } if (ast->type == AST_INTERFACE) module->set_bool_attribute(ID::is_interface); - module->ast = ast_before_simplify; + module->ast = std::move(ast_before_simplify); module->nolatches = flag_nolatches; module->nomeminit = flag_nomeminit; module->nomem2reg = flag_nomem2reg; @@ -1312,8 +1323,8 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d RTLIL::Module * AST_INTERNAL::process_and_replace_module(RTLIL::Design *design, RTLIL::Module *old_module, - AstNode *new_ast, - AstNode *original_ast) + AST::AstNode *new_ast, + std::unique_ptr original_ast) { // The old module will be deleted. Rename and mark for deletion, using // a static counter to make sure we get a unique name. @@ -1336,7 +1347,7 @@ AST_INTERNAL::process_and_replace_module(RTLIL::Design *design, } // Generate RTLIL from AST for the new module and add to the design: - RTLIL::Module* new_module = process_module(design, new_ast, false, original_ast); + RTLIL::Module* new_module = process_module(design, new_ast, false, std::move(original_ast)); if (is_top) new_module->set_bool_attribute(ID::top); @@ -1348,17 +1359,17 @@ AST_INTERNAL::process_and_replace_module(RTLIL::Design *design, static void rename_in_package_stmts(AstNode *pkg) { std::unordered_set idents; - for (AstNode *item : pkg->children) + for (auto& item : pkg->children) idents.insert(item->str); - std::function rename = - [&rename, &idents, pkg](AstNode *node) { - for (AstNode *child : node->children) { + std::function&)> rename = + [&rename, &idents, pkg](std::unique_ptr& node) { + for (auto& child : node->children) { if (idents.count(child->str)) child->str = pkg->str + "::" + child->str.substr(1); rename(child); } }; - for (AstNode *item : pkg->children) + for (auto& item : pkg->children) if (item->type == AST_FUNCTION || item->type == AST_TASK) rename(item); } @@ -1391,17 +1402,17 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump ast->fixup_hierarchy_flags(true); log_assert(current_ast->type == AST_DESIGN); - for (AstNode *child : current_ast->children) + for (const auto& child : current_ast->children) { if (child->type == AST_MODULE || child->type == AST_INTERFACE) { - for (auto n : design->verilog_globals) + for (auto& n : design->verilog_globals) child->children.push_back(n->clone()); // append nodes from previous packages using package-qualified names - for (auto &n : design->verilog_packages) { + for (auto& n : design->verilog_packages) { for (auto &o : n->children) { - AstNode *cloned_node = o->clone(); + auto cloned_node = o->clone(); // log("cloned node %s\n", type2str(cloned_node->type).c_str()); if (cloned_node->type == AST_ENUM) { for (auto &e : cloned_node->children) { @@ -1411,7 +1422,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump } else { cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1); } - child->children.push_back(cloned_node); + child->children.push_back(std::move(cloned_node)); } } @@ -1420,7 +1431,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump bool defer_local = defer; if (!defer_local) - for (const AstNode *node : child->children) + for (const auto& node : child->children) if (node->type == AST_PARAMETER && param_has_no_default(node)) { log("Deferring `%s' because it contains parameter(s) without defaults.\n", child->str.c_str()); @@ -1448,13 +1459,13 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump } } - process_module(design, child, defer_local); + process_module(design, child.get(), defer_local); current_ast_mod = nullptr; } else if (child->type == AST_PACKAGE) { // process enum/other declarations child->simplify(true, 1, -1, false); - rename_in_package_stmts(child); + rename_in_package_stmts(child.get()); design->verilog_packages.push_back(child->clone()); current_scope.clear(); } @@ -1471,16 +1482,9 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump current_scope.clear(); } } -} -// AstModule destructor -AstModule::~AstModule() -{ - if (ast != NULL) - delete ast; } - // An interface port with modport is specified like this: // . // This function splits the interface_name from the modport_name, and fails if it is not a valid combination @@ -1517,7 +1521,7 @@ AstNode * AST::find_modport(AstNode *intf, std::string name) for (auto &ch : intf->children) if (ch->type == AST_MODPORT) if (ch->str == name) // Modport found - return ch; + return ch.get(); return NULL; } @@ -1525,7 +1529,7 @@ AstNode * AST::find_modport(AstNode *intf, std::string name) void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport) { for (auto w : intfmodule->wires()){ - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); + auto wire = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); std::string origname = log_id(w->name); std::string newname = intfname + "." + origname; wire->str = newname; @@ -1544,16 +1548,13 @@ void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule } } if (found_in_modport) { - module_ast->children.push_back(wire); - } - else { // If not found in modport, do not create port - delete wire; + module_ast->children.push_back(std::move(wire)); } } else { // If no modport, set inout wire->is_input = true; wire->is_output = true; - module_ast->children.push_back(wire); + module_ast->children.push_back(std::move(wire)); } } } @@ -1571,7 +1572,7 @@ bool AstModule::reprocess_if_necessary(RTLIL::Design *design) log("Reprocessing module %s because instantiated module %s has become available.\n", log_id(name), log_id(modname)); loadconfig(); - process_and_replace_module(design, this, ast, NULL); + process_and_replace_module(design, this, ast.get(), NULL); return true; } } @@ -1584,32 +1585,32 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dictclone(); + auto new_ast = ast->clone(); for (auto &intf : local_interfaces) { std::string intfname = intf.first.str(); RTLIL::Module *intfmodule = intf.second; for (auto w : intfmodule->wires()){ - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); + auto wire = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); std::string newname = log_id(w->name); newname = intfname + "." + newname; wire->str = newname; - new_ast->children.push_back(wire); + new_ast->children.push_back(std::move(wire)); } } - AstNode *ast_before_replacing_interface_ports = new_ast->clone(); + auto ast_before_replacing_interface_ports = new_ast->clone(); // Explode all interface ports. Note this will only have an effect on 'top // level' modules. Other sub-modules will have their interface ports // exploded via the derive(..) function for (size_t i =0; ichildren.size(); i++) { - AstNode *ch2 = new_ast->children[i]; + const auto& ch2 = new_ast->children[i]; if (ch2->type == AST_INTERFACEPORT) { // Is an interface port std::string name_port = ch2->str; // Name of the interface port if (ch2->children.size() > 0) { for(size_t j=0; jchildren.size();j++) { - AstNode *ch = ch2->children[j]; + const auto& ch = ch2->children[j]; if(ch->type == AST_INTERFACEPORTTYPE) { // Found the AST node containing the type of the interface std::pair res = split_modport_from_type(ch->str); std::string interface_type = res.first; @@ -1617,11 +1618,11 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dictmodule(interface_type) != nullptr) { // Add a cell to the module corresponding to the interface port such that // it can further propagated down if needed: - AstNode *celltype_for_intf = new AstNode(AST_CELLTYPE); + auto celltype_for_intf = std::make_unique(AST_CELLTYPE); celltype_for_intf->str = interface_type; - AstNode *cell_for_intf = new AstNode(AST_CELL, celltype_for_intf); + auto cell_for_intf = std::make_unique(AST_CELL, std::move(celltype_for_intf)); cell_for_intf->str = name_port + "_inst_from_top_dummy"; - new_ast->children.push_back(cell_for_intf); + new_ast->children.push_back(std::move(cell_for_intf)); // Get all members of this non-overridden dummy interface instance: RTLIL::Module *intfmodule = design->module(interface_type); // All interfaces should at this point in time (assuming @@ -1629,9 +1630,9 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dictmodules_ AstModule *ast_module_of_interface = (AstModule*)intfmodule; std::string interface_modport_compare_str = "\\" + interface_modport; - AstNode *modport = find_modport(ast_module_of_interface->ast, interface_modport_compare_str); // modport == NULL if no modport + AstNode *modport = find_modport(ast_module_of_interface->ast.get(), interface_modport_compare_str); // modport == NULL if no modport // Iterate over all wires in the interface and add them to the module: - explode_interface_port(new_ast, intfmodule, name_port, modport); + explode_interface_port(new_ast.get(), intfmodule, name_port, modport); } break; } @@ -1643,9 +1644,7 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dictset_bool_attribute(ID::interfaces_replaced_in_module); @@ -1655,7 +1654,7 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dict ¶meters, const dict &interfaces, const dict &modports, bool /*mayfail*/) { - AstNode *new_ast = NULL; + std::unique_ptr new_ast = NULL; std::string modname = derive_common(design, parameters, &new_ast); // Since interfaces themselves may be instantiated with different parameters, @@ -1691,14 +1690,14 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict 0) { std::string interface_modport = modports.at(intfname).str(); AstModule *ast_module_of_interface = (AstModule*)intfmodule; - AstNode *ast_node_of_interface = ast_module_of_interface->ast; + AstNode *ast_node_of_interface = ast_module_of_interface->ast.get(); modport = find_modport(ast_node_of_interface, interface_modport); } // Iterate over all wires in the interface and add them to the module: - explode_interface_port(new_ast, intfmodule, intfname, modport); + explode_interface_port(new_ast.get(), intfmodule, intfname, modport); } - process_module(design, new_ast, false); + process_module(design, new_ast.get(), false); design->module(modname)->check(); RTLIL::Module* mod = design->module(modname); @@ -1735,7 +1734,6 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict new_ast = NULL; std::string modname = derive_common(design, parameters, &new_ast, quiet); if (!design->has(modname) && new_ast) { new_ast->str = modname; - process_module(design, new_ast, false, NULL, quiet); + process_module(design, new_ast.get(), false, NULL, quiet); design->module(modname)->check(); } else if (!quiet) { log("Found cached RTLIL representation for module `%s'.\n", modname.c_str()); } - delete new_ast; return modname; } @@ -1785,7 +1782,7 @@ std::string AST::derived_module_name(std::string stripped_name, const std::vecto } // create a new parametric module (when needed) and return the name of the generated module -std::string AstModule::derive_common(RTLIL::Design *design, const dict ¶meters, AstNode **new_ast_out, bool quiet) +std::string AstModule::derive_common(RTLIL::Design *design, const dict ¶meters, std::unique_ptr* new_ast_out, bool quiet) { std::string stripped_name = name.str(); (*new_ast_out) = nullptr; @@ -1795,7 +1792,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict> named_parameters; - for (const auto child : ast->children) { + for (const auto& child : ast->children) { if (child->type != AST_PARAMETER) continue; para_counter++; @@ -1829,12 +1826,12 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict rewritten; rewritten.reserve(GetSize(parameters)); - AstNode *new_ast = ast->clone(); + auto new_ast = ast->clone(); if (!new_ast->attributes.count(ID::hdlname)) new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(stripped_name.substr(1))); para_counter = 0; - for (auto child : new_ast->children) { + for (auto& child : new_ast->children) { if (child->type != AST_PARAMETER) continue; para_counter++; @@ -1854,9 +1851,8 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictchildren.insert(child->children.begin(), nullptr); - delete child->children.at(0); if ((it->second.flags & RTLIL::CONST_FLAG_REAL) != 0) { - child->children[0] = new AstNode(AST_REALVALUE); + child->children[0] = std::make_unique(AST_REALVALUE); child->children[0]->realvalue = std::stod(it->second.decode_string()); } else if ((it->second.flags & RTLIL::CONST_FLAG_STRING) != 0) child->children[0] = AstNode::mkconst_str(it->second.decode_string()); @@ -1869,17 +1865,17 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict(AST_DEFPARAM, std::make_unique(AST_IDENTIFIER)); defparam->children[0]->str = param.first.str(); if ((param.second.flags & RTLIL::CONST_FLAG_STRING) != 0) defparam->children.push_back(AstNode::mkconst_str(param.second.decode_string())); else defparam->children.push_back(AstNode::mkconst_bits(param.second.to_bits(), (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0)); - new_ast->children.push_back(defparam); + new_ast->children.push_back(std::move(defparam)); } new_ast->fixup_hierarchy_flags(true); - (*new_ast_out) = new_ast; + new_ast_out->reset(new_ast.release()); return modname; } diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 776b5c833..72dddab67 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -184,10 +184,10 @@ namespace AST AstNodeType type; // the list of child nodes for this node - std::vector children; + std::vector> children; // the list of attributes assigned to this node - std::map attributes; + std::map> attributes; bool get_bool_attribute(RTLIL::IdString id); // node content - most of it is unused in most node types @@ -213,7 +213,7 @@ namespace AST int unpacked_dimensions; // this is set by simplify and used during RTLIL generation - AstNode *id2ast; + AstNode* id2ast; // this is used by simplify to detect if basic analysis has been performed already on the node bool basic_prep; @@ -235,9 +235,9 @@ namespace AST bool in_param_from_above; // creating and deleting nodes - AstNode(AstNodeType type = AST_NONE, AstNode *child1 = nullptr, AstNode *child2 = nullptr, AstNode *child3 = nullptr, AstNode *child4 = nullptr); - AstNode *clone() const; - void cloneInto(AstNode *other) const; + AstNode(AstNodeType type = AST_NONE, std::unique_ptr child1 = nullptr, std::unique_ptr child2 = nullptr, std::unique_ptr child3 = nullptr, std::unique_ptr child4 = nullptr); + std::unique_ptr clone() const; + void cloneInto(AstNode &other) const; void delete_children(); ~AstNode(); @@ -265,15 +265,16 @@ namespace AST // simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc. // it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL() bool simplify(bool const_fold, int stage, int width_hint, bool sign_hint); + void null_check(); void replace_result_wire_name_in_function(const std::string &from, const std::string &to); - AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init); + std::unique_ptr readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init); void expand_genblock(const std::string &prefix); void label_genblks(std::set& existing, int &counter); void mem2reg_as_needed_pass1(dict> &mem2reg_places, dict &mem2reg_flags, dict &proc_flags, uint32_t &status_flags); - bool mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block); + bool mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *block, AstNode* async_block); bool mem2reg_check(pool &mem2reg_set); - void mem2reg_remove(pool &mem2reg_set, vector &delnodes); + void mem2reg_remove(pool &mem2reg_set); void meminfo(int &mem_width, int &mem_size, int &addr_bits); bool detect_latch(const std::string &var); const RTLIL::Module* lookup_cell_module(); @@ -289,7 +290,7 @@ namespace AST }; bool has_const_only_constructs(); bool replace_variables(std::map &variables, AstNode *fcall, bool must_succeed); - AstNode *eval_const_function(AstNode *fcall, bool must_succeed); + std::unique_ptr eval_const_function(AstNode *fcall, bool must_succeed); bool is_simple_const_expr(); // helper for parsing format strings @@ -306,29 +307,30 @@ namespace AST std::vector genBindings() const; // used by genRTLIL() for detecting expression width and sign - void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL); - void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = NULL); + void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = nullptr); + void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = nullptr); // create RTLIL code for this AST node // for expressions the resulting signal vector is returned // all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false); - RTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict *new_subst_ptr = NULL); + RTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict *new_subst_ptr = nullptr); // compare AST nodes bool operator==(const AstNode &other) const; bool operator!=(const AstNode &other) const; bool contains(const AstNode *other) const; + AstNode operator=(AstNode) = delete; // helper functions for creating AST nodes for constants - static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32); - static AstNode *mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized); - static AstNode *mkconst_bits(const std::vector &v, bool is_signed); - static AstNode *mkconst_str(const std::vector &v); - static AstNode *mkconst_str(const std::string &str); + static std::unique_ptr mkconst_int(uint32_t v, bool is_signed, int width = 32); + static std::unique_ptr mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized); + static std::unique_ptr mkconst_bits(const std::vector &v, bool is_signed); + static std::unique_ptr mkconst_str(const std::vector &v); + static std::unique_ptr mkconst_str(const std::string &str); // helper function to create an AST node for a temporary register - AstNode *mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed); + std::unique_ptr mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed); // helper function for creating sign-extended const objects RTLIL::Const bitsAsConst(int width, bool is_signed); @@ -357,12 +359,12 @@ namespace AST // helper to clone the node with some of its subexpressions replaced with zero (this is used // to evaluate widths of dynamic ranges) - AstNode *clone_at_zero(); + std::unique_ptr clone_at_zero(); - void set_attribute(RTLIL::IdString key, AstNode *node) + void set_attribute(RTLIL::IdString key, std::unique_ptr node) { - attributes[key] = node; node->set_in_param_flag(true); + attributes[key] = std::move(node); } // helper to set in_lvalue/in_param flags from the hierarchy context (the actual flag @@ -378,7 +380,7 @@ namespace AST void fixup_hierarchy_flags(bool force_descend = false); // helpers for indexing - AstNode *make_index_range(AstNode *node, bool unpacked_range = false); + std::unique_ptr make_index_range(AstNode *node, bool unpacked_range = false); AstNode *get_struct_member() const; // helper to print errors from simplify/genrtlil code @@ -392,12 +394,11 @@ namespace AST // parametric modules are supported directly by the AST library // therefore we need our own derivate of RTLIL::Module with overloaded virtual functions struct AstModule : RTLIL::Module { - AstNode *ast; + std::unique_ptr ast; bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire; - ~AstModule() override; RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, bool mayfail) override; RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, const dict &interfaces, const dict &modports, bool mayfail) override; - std::string derive_common(RTLIL::Design *design, const dict ¶meters, AstNode **new_ast_out, bool quiet = false); + std::string derive_common(RTLIL::Design *design, const dict ¶meters, std::unique_ptr* new_ast_out, bool quiet = false); void expand_interfaces(RTLIL::Design *design, const dict &local_interfaces) override; bool reprocess_if_necessary(RTLIL::Design *design) override; RTLIL::Module *clone() const override; @@ -408,8 +409,8 @@ namespace AST // the AstNode constructor then uses current_filename and get_line_num() // to initialize the filename and linenum properties of new nodes extern std::string current_filename; - extern void (*set_line_num)(int); - extern int (*get_line_num)(); + // also set by the language frontend to control some AST processing + extern bool sv_mode; // for stats unsigned long long astnode_count(); @@ -419,7 +420,7 @@ namespace AST void use_internal_line_num(); // call a DPI function - AstNode *dpi_call(const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector &args); + std::unique_ptr dpi_call(const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector> &args); // Helper functions related to handling SystemVerilog interfaces std::pair split_modport_from_type(std::string name_type); @@ -465,7 +466,7 @@ namespace AST_INTERNAL process_and_replace_module(RTLIL::Design *design, RTLIL::Module *old_module, AST::AstNode *new_ast, - AST::AstNode *original_ast = nullptr); + std::unique_ptr original_ast = nullptr); } YOSYS_NAMESPACE_END diff --git a/frontends/ast/dpicall.cc b/frontends/ast/dpicall.cc index d6fcc26bd..4fa375df7 100644 --- a/frontends/ast/dpicall.cc +++ b/frontends/ast/dpicall.cc @@ -64,9 +64,9 @@ static ffi_fptr resolve_fn (std::string symbol_name) log_error("unable to resolve '%s'.\n", symbol_name.c_str()); } -AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector &args) +std::unique_ptr AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector> &args) { - AST::AstNode *newNode = nullptr; + std::unique_ptr newNode = nullptr; union value { double f64; float f32; int32_t i32; void *ptr; }; std::vector value_store(args.size() + 1); std::vector types(args.size() + 1); @@ -125,11 +125,11 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname, ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values.data()); if (rtype == "real") { - newNode = new AstNode(AST_REALVALUE); + newNode = std::make_unique(AST_REALVALUE); newNode->realvalue = value_store[args.size()].f64; log(" return realvalue: %g\n", newNode->asReal(true)); } else if (rtype == "shortreal") { - newNode = new AstNode(AST_REALVALUE); + newNode = std::make_unique(AST_REALVALUE); newNode->realvalue = value_store[args.size()].f32; log(" return realvalue: %g\n", newNode->asReal(true)); } else if (rtype == "chandle") { diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 79e543376..5139aade2 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -85,7 +85,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s set_src_attr(wire, that); wire->is_signed = that->is_signed; - if (that != NULL) + if (that != nullptr) for (auto &attr : that->attributes) { if (attr.second->type != AST_CONSTANT) that->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str()); @@ -195,22 +195,22 @@ struct AST_INTERNAL::LookaheadRewriter if (node->lookahead) { log_assert(node->type == AST_IDENTIFIER); if (!lookaheadids.count(node->str)) { - AstNode *wire = new AstNode(AST_WIRE); - for (auto c : node->id2ast->children) + auto wire = std::make_unique(AST_WIRE); + for (auto& c : node->id2ast->children) wire->children.push_back(c->clone()); wire->fixup_hierarchy_flags(); wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++); wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire->is_logic = true; while (wire->simplify(true, 1, -1, false)) { } - current_ast_mod->children.push_back(wire); - lookaheadids[node->str] = make_pair(node->id2ast, wire); + lookaheadids[node->str] = make_pair(node->id2ast, wire.get()); wire->genRTLIL(); + current_ast_mod->children.push_back(std::move(wire)); } } - for (auto child : node->children) - collect_lookaheadids(child); + for (auto& child : node->children) + collect_lookaheadids(child.get()); } bool has_lookaheadids(AstNode *node) @@ -218,8 +218,8 @@ struct AST_INTERNAL::LookaheadRewriter if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) != 0) return true; - for (auto child : node->children) - if (has_lookaheadids(child)) + for (auto& child : node->children) + if (has_lookaheadids(child.get())) return true; return false; @@ -230,8 +230,8 @@ struct AST_INTERNAL::LookaheadRewriter if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) == 0) return true; - for (auto child : node->children) - if (has_nonlookaheadids(child)) + for (auto& child : node->children) + if (has_nonlookaheadids(child.get())) return true; return false; @@ -241,16 +241,16 @@ struct AST_INTERNAL::LookaheadRewriter { if (node->type == AST_ASSIGN_LE) { - if (has_lookaheadids(node->children[0])) + if (has_lookaheadids(node->children[0].get())) { - if (has_nonlookaheadids(node->children[0])) + if (has_nonlookaheadids(node->children[0].get())) log_error("incompatible mix of lookahead and non-lookahead IDs in LHS expression.\n"); - rewrite_lookaheadids(node->children[0], true); + rewrite_lookaheadids(node->children[0].get(), true); node->type = AST_ASSIGN_EQ; } - rewrite_lookaheadids(node->children[1], lhs); + rewrite_lookaheadids(node->children[1].get(), lhs); return; } @@ -261,21 +261,21 @@ struct AST_INTERNAL::LookaheadRewriter lhs = false; } - for (auto child : node->children) - rewrite_lookaheadids(child, lhs); + for (auto& child : node->children) + rewrite_lookaheadids(child.get(), lhs); } LookaheadRewriter(AstNode *top) { - // top->dumpAst(NULL, "REWRITE-BEFORE> "); - // top->dumpVlog(NULL, "REWRITE-BEFORE> "); + // top->dumpAst(nullptr, "REWRITE-BEFORE> "); + // top->dumpVlog(nullptr, "REWRITE-BEFORE> "); AstNode *block = nullptr; - for (auto c : top->children) + for (auto& c : top->children) if (c->type == AST_BLOCK) { log_assert(block == nullptr); - block = c; + block = c.get(); } log_assert(block != nullptr); @@ -284,25 +284,25 @@ struct AST_INTERNAL::LookaheadRewriter for (auto it : lookaheadids) { - AstNode *ref_orig = new AstNode(AST_IDENTIFIER); + auto ref_orig = std::make_unique(AST_IDENTIFIER); ref_orig->str = it.second.first->str; ref_orig->id2ast = it.second.first; ref_orig->was_checked = true; - AstNode *ref_temp = new AstNode(AST_IDENTIFIER); + auto ref_temp = std::make_unique(AST_IDENTIFIER); ref_temp->str = it.second.second->str; ref_temp->id2ast = it.second.second; ref_temp->was_checked = true; - AstNode *init_assign = new AstNode(AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone()); - AstNode *final_assign = new AstNode(AST_ASSIGN_LE, ref_orig, ref_temp); + auto init_assign = std::make_unique(AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone()); + auto final_assign = std::make_unique(AST_ASSIGN_LE, std::move(ref_orig), std::move(ref_temp)); - block->children.insert(block->children.begin(), init_assign); - block->children.push_back(final_assign); + block->children.insert(block->children.begin(), std::move(init_assign)); + block->children.push_back(std::move(final_assign)); } - // top->dumpAst(NULL, "REWRITE-AFTER> "); - // top->dumpVlog(NULL, "REWRITE-AFTER> "); + // top->dumpAst(nullptr, "REWRITE-AFTER> "); + // top->dumpVlog(nullptr, "REWRITE-AFTER> "); } }; @@ -310,7 +310,7 @@ struct AST_INTERNAL::LookaheadRewriter struct AST_INTERNAL::ProcessGenerator { // input and output structures - AstNode *always; + std::unique_ptr always; RTLIL::SigSpec initSyncSignals; RTLIL::Process *proc; RTLIL::SigSpec outputSignals; @@ -341,14 +341,14 @@ struct AST_INTERNAL::ProcessGenerator // The most recently assigned $print or $check cell \PRIORITY. int last_effect_priority; - ProcessGenerator(AstNode *always, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(always), initSyncSignals(initSyncSignalsArg), last_effect_priority(0) + ProcessGenerator(std::unique_ptr a, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(std::move(a)), initSyncSignals(initSyncSignalsArg), last_effect_priority(0) { // rewrite lookahead references - LookaheadRewriter la_rewriter(always); + LookaheadRewriter la_rewriter(always.get()); // generate process and simple root case proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(always->filename).c_str(), always->location.first_line, autoidx++)); - set_src_attr(proc, always); + set_src_attr(proc, always.get()); for (auto &attr : always->attributes) { if (attr.second->type != AST_CONSTANT) always->input_error("Attribute `%s' with non-constant value!\n", attr.first.c_str()); @@ -358,13 +358,13 @@ struct AST_INTERNAL::ProcessGenerator // create initial temporary signal for all output registers RTLIL::SigSpec subst_lvalue_from, subst_lvalue_to; - collect_lvalues(subst_lvalue_from, always, true, true); + collect_lvalues(subst_lvalue_from, always.get(), true, true); subst_lvalue_to = new_temp_signal(subst_lvalue_from); subst_lvalue_map = subst_lvalue_from.to_sigbit_map(subst_lvalue_to); bool found_global_syncs = false; bool found_anyedge_syncs = false; - for (auto child : always->children) + for (auto& child : always->children) { if ((child->type == AST_POSEDGE || child->type == AST_NEGEDGE) && GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->id2ast && child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute(ID::gclk)) { @@ -388,7 +388,7 @@ struct AST_INTERNAL::ProcessGenerator // create syncs for the process bool found_clocked_sync = false; - for (auto child : always->children) + for (auto& child : always->children) if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) { if (GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->id2ast && child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute(ID::gclk)) @@ -420,9 +420,9 @@ struct AST_INTERNAL::ProcessGenerator } // process the AST - for (auto child : always->children) + for (auto& child : always->children) if (child->type == AST_BLOCK) - processAst(child); + processAst(child.get()); for (auto sync: proc->syncs) processMemWrites(sync); @@ -472,7 +472,7 @@ struct AST_INTERNAL::ProcessGenerator for (int i = 0; i < GetSize(chunks); i++) { RTLIL::SigChunk &chunk = chunks[i]; - if (chunk.wire == NULL) + if (chunk.wire == nullptr) continue; std::string wire_name; @@ -484,7 +484,7 @@ struct AST_INTERNAL::ProcessGenerator } while (current_module->wires_.count(wire_name) > 0); RTLIL::Wire *wire = current_module->addWire(wire_name, chunk.width); - set_src_attr(wire, always); + set_src_attr(wire, always.get()); chunk.wire = wire; chunk.offset = 0; @@ -499,10 +499,10 @@ struct AST_INTERNAL::ProcessGenerator switch (ast->type) { case AST_CASE: - for (auto child : ast->children) + for (auto& child : ast->children) if (child != ast->children[0]) { log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); - collect_lvalues(reg, child, type_eq, type_le, false); + collect_lvalues(reg, child.get(), type_eq, type_le, false); } break; @@ -511,19 +511,19 @@ struct AST_INTERNAL::ProcessGenerator case AST_CONDZ: case AST_ALWAYS: case AST_INITIAL: - for (auto child : ast->children) + for (auto& child : ast->children) if (child->type == AST_BLOCK) - collect_lvalues(reg, child, type_eq, type_le, false); + collect_lvalues(reg, child.get(), type_eq, type_le, false); break; case AST_BLOCK: - for (auto child : ast->children) { + for (auto& child : ast->children) { if (child->type == AST_ASSIGN_EQ && type_eq) reg.append(child->children[0]->genRTLIL()); if (child->type == AST_ASSIGN_LE && type_le) reg.append(child->children[0]->genRTLIL()); if (child->type == AST_CASE || child->type == AST_BLOCK) - collect_lvalues(reg, child, type_eq, type_le, false); + collect_lvalues(reg, child.get(), type_eq, type_le, false); } break; @@ -583,8 +583,8 @@ struct AST_INTERNAL::ProcessGenerator switch (ast->type) { case AST_BLOCK: - for (auto child : ast->children) - processAst(child); + for (auto& child : ast->children) + processAst(child.get()); break; case AST_ASSIGN_EQ: @@ -641,9 +641,9 @@ struct AST_INTERNAL::ProcessGenerator RTLIL::SigSpec this_case_eq_rvalue = this_case_eq_lvalue; this_case_eq_rvalue.replace(subst_rvalue_map.stdmap()); - RTLIL::CaseRule *default_case = NULL; - RTLIL::CaseRule *last_generated_case = NULL; - for (auto child : ast->children) + RTLIL::CaseRule *default_case = nullptr; + RTLIL::CaseRule *last_generated_case = nullptr; + for (auto& child : ast->children) { if (child == ast->children[0]) continue; @@ -657,14 +657,14 @@ struct AST_INTERNAL::ProcessGenerator RTLIL::CaseRule *backup_case = current_case; current_case = new RTLIL::CaseRule; - set_src_attr(current_case, child); + set_src_attr(current_case, child.get()); last_generated_case = current_case; addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue); - for (auto node : child->children) { + for (auto& node : child->children) { if (node->type == AST_DEFAULT) default_case = current_case; else if (node->type == AST_BLOCK) - processAst(node); + processAst(node.get()); else current_case->compare.push_back(node->genWidthRTLIL(width_hint, sign_hint, &subst_rvalue_map.stdmap())); } @@ -678,7 +678,7 @@ struct AST_INTERNAL::ProcessGenerator subst_rvalue_map.restore(); } - if (last_generated_case != NULL && ast->get_bool_attribute(ID::full_case) && default_case == NULL) { + if (last_generated_case != nullptr && ast->get_bool_attribute(ID::full_case) && default_case == nullptr) { #if 0 // this is a valid transformation, but as optimization it is premature. // better: add a default case that assigns 'x' to everything, and let later @@ -690,7 +690,7 @@ struct AST_INTERNAL::ProcessGenerator sw->cases.push_back(default_case); #endif } else { - if (default_case == NULL) { + if (default_case == nullptr) { default_case = new RTLIL::CaseRule; addChunkActions(default_case->actions, this_case_eq_ltemp, this_case_eq_rvalue); } @@ -760,7 +760,7 @@ struct AST_INTERNAL::ProcessGenerator default_base = 16; std::vector args; - for (auto node : ast->children) { + for (auto& node : ast->children) { int width; bool is_signed; node->detectSignWidth(width, is_signed, nullptr); @@ -866,8 +866,8 @@ struct AST_INTERNAL::ProcessGenerator break; default: - // ast->dumpAst(NULL, "ast> "); - // current_ast_mod->dumpAst(NULL, "mod> "); + // ast->dumpAst(nullptr, "ast> "); + // current_ast_mod->dumpAst(nullptr, "mod> "); log_abort(); } } @@ -876,14 +876,14 @@ struct AST_INTERNAL::ProcessGenerator { // Maps per-memid AST_MEMWR IDs to indices in the mem_write_actions array. dict, int> port_map; - for (auto child : always->children) + for (auto& child : always->children) if (child->type == AST_MEMWR) { std::string memid = child->str; int portid = child->children[3]->asInt(false); int cur_idx = GetSize(sync->mem_write_actions); RTLIL::MemWriteAction action; - set_src_attr(&action, child); + set_src_attr(&action, child.get()); action.memid = memid; action.address = child->children[0]->genWidthRTLIL(-1, true, &subst_rvalue_map.stdmap()); action.data = child->children[1]->genWidthRTLIL(current_module->memories[memid]->width, true, &subst_rvalue_map.stdmap()); @@ -971,11 +971,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun bool sub_sign_hint = true; int sub_width_hint = -1; int this_width = 0; - AstNode *range = NULL; - AstNode *id_ast = NULL; + AstNode *range = nullptr; + AstNode *id_ast = nullptr; bool local_found_real = false; - if (found_real == NULL) + if (found_real == nullptr) found_real = &local_found_real; switch (type) @@ -1019,22 +1019,22 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun input_error("Failed to detect width for parameter %s!\n", str.c_str()); } if (children.size() != 0) - range = children[0]; + range = children[0].get(); } else if (id_ast->type == AST_WIRE || id_ast->type == AST_AUTOWIRE) { if (!id_ast->range_valid) { if (id_ast->type == AST_AUTOWIRE) this_width = 1; else { - // current_ast_mod->dumpAst(NULL, "mod> "); + // current_ast_mod->dumpAst(nullptr, "mod> "); // log("---\n"); - // id_ast->dumpAst(NULL, "decl> "); - // dumpAst(NULL, "ref> "); + // id_ast->dumpAst(nullptr, "decl> "); + // dumpAst(nullptr, "ref> "); input_error("Failed to detect width of signal access `%s'!\n", str.c_str()); } } else { this_width = id_ast->range_left - id_ast->range_right + 1; if (children.size() != 0) - range = children[0]; + range = children[0].get(); } } else if (id_ast->type == AST_GENVAR) { this_width = 32; @@ -1043,26 +1043,23 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun input_error("Failed to detect width of memory access `%s'!\n", str.c_str()); this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1; if (children.size() > 1) - range = children[1]; + range = children[1].get(); } else if (id_ast->type == AST_STRUCT_ITEM || id_ast->type == AST_STRUCT || id_ast->type == AST_UNION) { - AstNode *tmp_range = make_index_range(id_ast); + auto tmp_range = make_index_range(id_ast); this_width = tmp_range->range_left - tmp_range->range_right + 1; - delete tmp_range; } else input_error("Failed to detect width for identifier %s!\n", str.c_str()); if (range) { if (range->children.size() == 1) this_width = 1; else if (!range->range_valid) { - AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero(); - AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); + auto left_at_zero_ast = children[0]->children[0]->clone_at_zero(); + auto right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); while (left_at_zero_ast->simplify(true, 1, -1, false)) { } while (right_at_zero_ast->simplify(true, 1, -1, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; - delete left_at_zero_ast; - delete right_at_zero_ast; } else this_width = range->range_left - range->range_right + 1; sign_hint = false; @@ -1106,7 +1103,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun break; case AST_CONCAT: - for (auto child : children) { + for (auto& child : children) { sub_width_hint = 0; sub_sign_hint = true; child->detectSignWidthWorker(sub_width_hint, sub_sign_hint); @@ -1135,7 +1132,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_BIT_OR: case AST_BIT_XOR: case AST_BIT_XNOR: - for (auto child : children) + for (auto& child : children) child->detectSignWidthWorker(width_hint, sign_hint, found_real); break; @@ -1175,7 +1172,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_MUL: case AST_DIV: case AST_MOD: - for (auto child : children) + for (auto& child : children) child->detectSignWidthWorker(width_hint, sign_hint, found_real); break; @@ -1216,12 +1213,13 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun width_hint = max(width_hint, sub_width_hint); sign_hint &= sub_sign_hint; }; - visit_case_expr(children[0]); + visit_case_expr(children[0].get()); for (size_t i = 1; i < children.size(); i++) { - AstNode *child = children[i]; - for (AstNode *v : child->children) + AstNode *child = children[i].get(); + for (auto& v : child->children) { if (v->type != AST_DEFAULT && v->type != AST_BLOCK) - visit_case_expr(v); + visit_case_expr(v.get()); + } } break; } @@ -1269,9 +1267,9 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (func->type != AST_FUNCTION) input_error("Function call to %s resolved to something that isn't a function!\n", RTLIL::unescape_id(str).c_str()); const AstNode *wire = nullptr; - for (const AstNode *child : func->children) + for (const auto& child : func->children) if (child->str == func->str) { - wire = child; + wire = child.get(); break; } log_assert(wire && wire->type == AST_WIRE); @@ -1280,10 +1278,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (!wire->children.empty()) { log_assert(wire->children.size() == 1); - const AstNode *range = wire->children.at(0); + const AstNode *range = wire->children.at(0).get(); log_assert(range->type == AST_RANGE && range->children.size() == 2); - AstNode *left = range->children.at(0)->clone(); - AstNode *right = range->children.at(1)->clone(); + auto left = range->children.at(0)->clone(); + auto right = range->children.at(1)->clone(); left->set_in_param_flag(true); right->set_in_param_flag(true); while (left->simplify(true, 1, -1, false)) { } @@ -1292,8 +1290,6 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun input_error("Function %s has non-constant width!", RTLIL::unescape_id(str).c_str()); result_width = abs(int(left->asInt(true) - right->asInt(true))); - delete left; - delete right; } width_hint = max(width_hint, result_width); break; @@ -1306,6 +1302,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun for (auto f : log_files) current_scope_ast->dumpAst(f, "verilog-ast> "); input_error("Don't know how to detect sign and width for %s node!\n", type2str(type).c_str()); + } if (*found_real) @@ -1518,11 +1515,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // shifter cell is created and the output signal of this cell is returned case AST_IDENTIFIER: { - RTLIL::Wire *wire = NULL; + RTLIL::Wire *wire = nullptr; RTLIL::SigChunk chunk; bool is_interface = false; - AST::AstNode *member_node = NULL; + AST::AstNode *member_node = nullptr; int add_undef_bits_msb = 0; int add_undef_bits_lsb = 0; @@ -1609,14 +1606,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } if (!children[0]->range_valid) { - AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero(); - AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); + auto left_at_zero_ast = children[0]->children[0]->clone_at_zero(); + auto right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); while (left_at_zero_ast->simplify(true, 1, -1, false)) { } while (right_at_zero_ast->simplify(true, 1, -1, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; - AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? + auto fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : children[0]->children[0]->clone()); fake_ast->children[0]->delete_children(); if (member_node) @@ -1638,9 +1635,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (GetSize(shift_val) >= 32) fake_ast->children[1]->is_signed = true; RTLIL::SigSpec sig = binop2rtlil(fake_ast, ID($shiftx), width, fake_ast->children[0]->genRTLIL(), shift_val); - delete left_at_zero_ast; - delete right_at_zero_ast; - delete fake_ast; return sig; } else { chunk.width = children[0]->range_left - children[0]->range_right + 1; @@ -2093,7 +2087,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) cell->set_bool_attribute(ID::module_not_derived); for (auto it = children.begin(); it != children.end(); it++) { - AstNode *child = *it; + AstNode *child = it->get(); if (child->type == AST_CELLTYPE) { cell->type = child->str; if (flag_icells && cell->type.begins_with("\\$")) @@ -2102,7 +2096,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } if (child->type == AST_PARASET) { IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; - const AstNode *value = child->children[0]; + const AstNode *value = child->children[0].get(); if (value->type == AST_REALVALUE) log_file_warning(filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n", log_id(cell), log_id(paraname), value->realvalue); @@ -2115,7 +2109,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (child->type == AST_ARGUMENT) { RTLIL::SigSpec sig; if (child->children.size() > 0) { - AstNode *arg = child->children[0]; + AstNode *arg = child->children[0].get(); int local_width_hint = -1; bool local_sign_hint = false; // don't inadvertently attempt to detect the width of interfaces @@ -2187,16 +2181,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // use ProcessGenerator for always blocks case AST_ALWAYS: { - AstNode *always = this->clone(); - ProcessGenerator generator(always); + auto always = this->clone(); + ProcessGenerator generator(std::move(always)); ignoreThisSignalsInInitial.append(generator.outputSignals); - delete always; } break; case AST_INITIAL: { - AstNode *always = this->clone(); - ProcessGenerator generator(always, ignoreThisSignalsInInitial); - delete always; + auto always = this->clone(); + ProcessGenerator generator(std::move(always), ignoreThisSignalsInInitial); } break; case AST_TECALL: { diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 05cc57ba1..3f7176b20 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 @@ -87,7 +88,7 @@ void AstNode::fixup_hierarchy_flags(bool force_descend) case AST_PARASET: case AST_PREFIX: in_param = true; - for (auto child : children) + for (auto& child : children) child->set_in_param_flag(true, force_descend); break; @@ -95,7 +96,7 @@ void AstNode::fixup_hierarchy_flags(bool force_descend) case AST_WIRE: case AST_GENIF: case AST_GENCASE: - for (auto child : children) + for (auto& child : children) child->set_in_param_flag(in_param, force_descend); if (children.size() >= 1) children[0]->set_in_param_flag(true, force_descend); @@ -103,19 +104,21 @@ void AstNode::fixup_hierarchy_flags(bool force_descend) case AST_GENFOR: case AST_FOR: - for (auto child : children) + for (auto& child : children) { + log_assert((bool)child); child->set_in_param_flag(in_param, force_descend); + } if (children.size() >= 2) children[1]->set_in_param_flag(true, force_descend); break; default: in_param = in_param_from_above; - for (auto child : children) + for (auto& child : children) child->set_in_param_flag(in_param, force_descend); } - for (auto attr : attributes) + for (auto& attr : attributes) attr.second->set_in_param_flag(true, force_descend); in_lvalue = in_lvalue_from_above; @@ -131,14 +134,14 @@ void AstNode::fixup_hierarchy_flags(bool force_descend) break; default: - for (auto child : children) + for (auto& child : children) child->set_in_lvalue_flag(in_lvalue, force_descend); } if (force_descend) { - for (auto child : children) + for (auto& child : children) child->fixup_hierarchy_flags(true); - for (auto attr : attributes) + for (auto& attr : attributes) attr.second->fixup_hierarchy_flags(true); } } @@ -148,7 +151,7 @@ void AstNode::fixup_hierarchy_flags(bool force_descend) Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_t first_arg_at, bool may_fail) { std::vector args; for (size_t index = first_arg_at; index < children.size(); index++) { - AstNode *node_arg = children[index]; + AstNode *node_arg = children[index].get(); while (node_arg->simplify(true, stage, -1, false)) { } VerilogFmtArg arg = {}; @@ -199,7 +202,7 @@ void AstNode::annotateTypedEnums(AstNode *template_node) while (enum_node->simplify(true, 1, -1, false)) { } //get width from 1st enum item: log_assert(enum_node->children.size() >= 1); - AstNode *enum_item0 = enum_node->children[0]; + AstNode *enum_item0 = enum_node->children[0].get(); log_assert(enum_item0->type == AST_ENUM_ITEM); int width; if (!enum_item0->range_valid) @@ -210,7 +213,7 @@ void AstNode::annotateTypedEnums(AstNode *template_node) width = enum_item0->range_left - enum_item0->range_right + 1; log_assert(width > 0); //add declared enum items: - for (auto enum_item : enum_node->children){ + for (auto& enum_item : enum_node->children){ log_assert(enum_item->type == AST_ENUM_ITEM); //get is_signed bool is_signed; @@ -242,10 +245,10 @@ void AstNode::annotateTypedEnums(AstNode *template_node) } } -static AstNode *make_range(int left, int right, bool is_signed = false) +static std::unique_ptr make_range(int left, int right, bool is_signed = false) { // generate a pre-validated range node for a fixed signal range. - auto range = new AstNode(AST_RANGE); + auto range = std::make_unique(AST_RANGE); range->range_left = left; range->range_right = right; range->range_valid = true; @@ -287,7 +290,7 @@ static int size_packed_struct(AstNode *snode, int base_offset) int packed_width = -1; // examine members from last to first for (auto it = snode->children.rbegin(); it != snode->children.rend(); ++it) { - auto node = *it; + auto node = it->get(); int width; if (node->type == AST_STRUCT || node->type == AST_UNION) { // embedded struct or union @@ -297,14 +300,14 @@ static int size_packed_struct(AstNode *snode, int base_offset) log_assert(node->type == AST_STRUCT_ITEM); if (node->children.size() > 0 && node->children[0]->type == AST_RANGE) { // member width e.g. bit [7:0] a - width = range_width(node, node->children[0]); + width = range_width(node, node->children[0].get()); if (node->children.size() == 2) { // Unpacked array. Note that this is a Yosys extension; only packed data types // and integer data types are allowed in packed structs / unions in SystemVerilog. if (node->children[1]->type == AST_RANGE) { // Unpacked array, e.g. bit [63:0] a [0:3] // Pretend it's declared as a packed array, e.g. bit [0:3][63:0] a - auto rnode = node->children[1]; + auto rnode = node->children[1].get(); if (rnode->children.size() == 1) { // C-style array size, e.g. bit [63:0] a [4] node->dimensions.push_back({ 0, rnode->range_left, true }); @@ -312,7 +315,7 @@ static int size_packed_struct(AstNode *snode, int base_offset) } else { width *= add_dimension(node, rnode); } - add_dimension(node, node->children[0]); + add_dimension(node, node->children[0].get()); } else { // The Yosys extension for unpacked arrays in packed structs / unions @@ -321,11 +324,9 @@ static int size_packed_struct(AstNode *snode, int base_offset) } } else { // Vector - add_dimension(node, node->children[0]); + add_dimension(node, node->children[0].get()); } // range nodes are now redundant - for (AstNode *child : node->children) - delete child; node->children.clear(); } else if (node->children.size() > 0 && node->children[0]->type == AST_MULTIRANGE) { @@ -336,12 +337,10 @@ static int size_packed_struct(AstNode *snode, int base_offset) struct_array_packing_error(node); } width = 1; - for (auto rnode : node->children[0]->children) { - width *= add_dimension(node, rnode); + for (auto& rnode : node->children[0]->children) { + width *= add_dimension(node, rnode.get()); } // range nodes are now redundant - for (AstNode *child : node->children) - delete child; node->children.clear(); } else if (node->range_left < 0) { @@ -389,49 +388,49 @@ static int size_packed_struct(AstNode *snode, int base_offset) return width; } -static AstNode *node_int(int ival) +static std::unique_ptr node_int(int ival) { return AstNode::mkconst_int(ival, true); } -static AstNode *multiply_by_const(AstNode *expr_node, int stride) +static std::unique_ptr multiply_by_const(std::unique_ptr expr_node, int stride) { - return new AstNode(AST_MUL, expr_node, node_int(stride)); + return std::make_unique(AST_MUL, std::move(expr_node), node_int(stride)); } -static AstNode *normalize_index(AstNode *expr, AstNode *decl_node, int dimension) +static std::unique_ptr normalize_index(AstNode *expr, AstNode *decl_node, int dimension) { - expr = expr->clone(); + auto new_expr = expr->clone(); int offset = decl_node->dimensions[dimension].range_right; if (offset) { - expr = new AstNode(AST_SUB, expr, node_int(offset)); + new_expr = std::make_unique(AST_SUB, std::move(new_expr), node_int(offset)); } // Packed dimensions are normally indexed by lsb, while unpacked dimensions are normally indexed by msb. if ((dimension < decl_node->unpacked_dimensions) ^ decl_node->dimensions[dimension].range_swapped) { // Swap the index if the dimension is declared the "wrong" way. int left = decl_node->dimensions[dimension].range_width - 1; - expr = new AstNode(AST_SUB, node_int(left), expr); + new_expr = std::make_unique(AST_SUB, node_int(left), std::move(new_expr)); } - return expr; + return new_expr; } -static AstNode *index_offset(AstNode *offset, AstNode *rnode, AstNode *decl_node, int dimension, int &stride) +static std::unique_ptr index_offset(std::unique_ptr offset, AstNode *rnode, AstNode *decl_node, int dimension, int &stride) { stride /= decl_node->dimensions[dimension].range_width; - auto right = normalize_index(rnode->children.back(), decl_node, dimension); - auto add_offset = stride > 1 ? multiply_by_const(right, stride) : right; - return offset ? new AstNode(AST_ADD, offset, add_offset) : add_offset; + auto right = normalize_index(rnode->children.back().get(), decl_node, dimension); + auto add_offset = stride > 1 ? multiply_by_const(std::move(right), stride) : std::move(right); + return offset ? std::make_unique(AST_ADD, std::move(offset), std::move(add_offset)) : std::move(add_offset); } -static AstNode *index_msb_offset(AstNode *lsb_offset, AstNode *rnode, AstNode *decl_node, int dimension, int stride) +static std::unique_ptr index_msb_offset(std::unique_ptr lsb_offset, AstNode *rnode, AstNode *decl_node, int dimension, int stride) { log_assert(rnode->children.size() <= 2); // Offset to add to LSB - AstNode *add_offset; + std::unique_ptr add_offset; if (rnode->children.size() == 1) { // Index, e.g. s.a[i] add_offset = node_int(stride - 1); @@ -439,21 +438,21 @@ static AstNode *index_msb_offset(AstNode *lsb_offset, AstNode *rnode, AstNode *d else { // rnode->children.size() == 2 // Slice, e.g. s.a[i:j] - auto left = normalize_index(rnode->children[0], decl_node, dimension); - auto right = normalize_index(rnode->children[1], decl_node, dimension); - add_offset = new AstNode(AST_SUB, left, right); + auto left = normalize_index(rnode->children[0].get(), decl_node, dimension); + auto right = normalize_index(rnode->children[1].get(), decl_node, dimension); + add_offset = std::make_unique(AST_SUB, std::move(left), std::move(right)); if (stride > 1) { // offset = (msb - lsb + 1)*stride - 1 - auto slice_width = new AstNode(AST_ADD, add_offset, node_int(1)); - add_offset = new AstNode(AST_SUB, multiply_by_const(slice_width, stride), node_int(1)); + auto slice_width = std::make_unique(AST_ADD, std::move(add_offset), node_int(1)); + add_offset = std::make_unique(AST_SUB, multiply_by_const(std::move(slice_width), stride), node_int(1)); } } - return new AstNode(AST_ADD, lsb_offset, add_offset); + return std::make_unique(AST_ADD, std::move(lsb_offset), std::move(add_offset)); } -AstNode *AstNode::make_index_range(AstNode *decl_node, bool unpacked_range) +std::unique_ptr AstNode::make_index_range(AstNode *decl_node, bool unpacked_range) { // Work out the range in the packed array that corresponds to a struct member // taking into account any range operations applicable to the current node @@ -466,8 +465,8 @@ AstNode *AstNode::make_index_range(AstNode *decl_node, bool unpacked_range) log_assert(children.size() == 1); // Range operations - AstNode *rnode = children[0]; - AstNode *offset = NULL; + AstNode *rnode = children[0].get(); + std::unique_ptr offset = nullptr; int dim = unpacked_range ? 0 : decl_node->unpacked_dimensions; int max_dim = unpacked_range ? decl_node->unpacked_dimensions : GetSize(decl_node->dimensions); @@ -478,15 +477,15 @@ AstNode *AstNode::make_index_range(AstNode *decl_node, bool unpacked_range) // Calculate LSB offset for the final index / slice if (rnode->type == AST_RANGE) { - offset = index_offset(offset, rnode, decl_node, dim, stride); + offset = index_offset(std::move(offset), rnode, decl_node, dim, stride); } else if (rnode->type == AST_MULTIRANGE) { // Add offset for each dimension AstNode *mrnode = rnode; int stop_dim = std::min(GetSize(mrnode->children), max_dim); for (; dim < stop_dim; dim++) { - rnode = mrnode->children[dim]; - offset = index_offset(offset, rnode, decl_node, dim, stride); + rnode = mrnode->children[dim].get(); + offset = index_offset(std::move(offset), rnode, decl_node, dim, stride); } dim--; // Step back to the final index / slice } @@ -494,15 +493,15 @@ AstNode *AstNode::make_index_range(AstNode *decl_node, bool unpacked_range) input_error("Unsupported range operation for %s\n", str.c_str()); } - AstNode *index_range = new AstNode(AST_RANGE); + std::unique_ptrindex_range = std::make_unique(AST_RANGE); if (!unpacked_range && (stride > 1 || GetSize(rnode->children) == 2)) { // Calculate MSB offset for the final index / slice of packed dimensions. - AstNode *msb_offset = index_msb_offset(offset->clone(), rnode, decl_node, dim, stride); - index_range->children.push_back(msb_offset); + std::unique_ptrmsb_offset = index_msb_offset(offset->clone(), rnode, decl_node, dim, stride); + index_range->children.push_back(std::move(msb_offset)); } - index_range->children.push_back(offset); + index_range->children.push_back(std::move(offset)); return index_range; } @@ -510,8 +509,8 @@ AstNode *AstNode::make_index_range(AstNode *decl_node, bool unpacked_range) AstNode *AstNode::get_struct_member() const { AstNode *member_node; - if (attributes.count(ID::wiretype) && (member_node = attributes.at(ID::wiretype)) && - (member_node->type == AST_STRUCT_ITEM || member_node->type == AST_STRUCT || member_node->type == AST_UNION)) + if (attributes.count(ID::wiretype) && (member_node = attributes.at(ID::wiretype).get()) && + (member_node->type == AST_STRUCT_ITEM || member_node->type == AST_STRUCT || member_node->type == AST_UNION)) { return member_node; } @@ -523,20 +522,20 @@ static void add_members_to_scope(AstNode *snode, std::string name) // add all the members in a struct or union to local scope // in case later referenced in assignments log_assert(snode->type==AST_STRUCT || snode->type==AST_UNION); - for (auto *node : snode->children) { + for (auto &node : snode->children) { auto member_name = name + "." + node->str; - current_scope[member_name] = node; + current_scope[member_name] = node.get(); if (node->type != AST_STRUCT_ITEM) { // embedded struct or union - add_members_to_scope(node, name + "." + node->str); + add_members_to_scope(node.get(), name + "." + node->str); } } } -static AstNode *make_packed_struct(AstNode *template_node, std::string &name, decltype(AstNode::attributes) &attributes) +std::unique_ptr make_packed_struct(AstNode *template_node, std::string &name, decltype(AstNode::attributes) &attributes) { // create a wire for the packed struct - auto wnode = new AstNode(AST_WIRE, make_range(template_node->range_left, 0)); + auto wnode = std::make_unique(AST_WIRE, make_range(template_node->range_left, 0)); wnode->str = name; wnode->is_logic = true; wnode->range_valid = true; @@ -547,24 +546,24 @@ static AstNode *make_packed_struct(AstNode *template_node, std::string &name, de // resolve packed dimension while (wnode->simplify(true, 1, -1, false)) {} // make sure this node is the one in scope for this name - current_scope[name] = wnode; + current_scope[name] = wnode.get(); // add all the struct members to scope under the wire's name add_members_to_scope(template_node, name); return wnode; } -static void prepend_ranges(AstNode *&range, AstNode *range_add) +static void prepend_ranges(std::unique_ptr &range, AstNode *range_add) { // Convert range to multirange. if (range->type == AST_RANGE) - range = new AstNode(AST_MULTIRANGE, range); + range = std::make_unique(AST_MULTIRANGE, std::move(range)); // Add range or ranges. if (range_add->type == AST_RANGE) range->children.insert(range->children.begin(), range_add->clone()); else { int i = 0; - for (auto child : range_add->children) + for (auto& child : range_add->children) range->children.insert(range->children.begin() + i++, child->clone()); } } @@ -575,16 +574,16 @@ static bool node_contains_assignment_to(const AstNode* node, const AstNode* var) if (node->type == AST_ASSIGN_EQ || node->type == AST_ASSIGN_LE) { // current node is iteslf an assignment log_assert(node->children.size() >= 2); - const AstNode* lhs = node->children[0]; + const AstNode* lhs = node->children[0].get(); if (lhs->type == AST_IDENTIFIER && lhs->str == var->str) return false; } - for (const AstNode* child : node->children) { + for (auto& child : node->children) { // if this child shadows the given variable - if (child != var && child->str == var->str && child->type == AST_WIRE) + if (child.get() != var && child->str == var->str && child->type == AST_WIRE) break; // skip the remainder of this block/scope // depth-first short circuit - if (!node_contains_assignment_to(child, var)) + if (!node_contains_assignment_to(child.get(), var)) return false; } return true; @@ -625,9 +624,9 @@ const RTLIL::Module* AstNode::lookup_cell_module() }; const AstNode *celltype = nullptr; - for (const AstNode *child : children) + for (auto& child : children) if (child->type == AST_CELLTYPE) { - celltype = child; + celltype = child.get(); break; } log_assert(celltype != nullptr); @@ -644,7 +643,7 @@ const RTLIL::Module* AstNode::lookup_cell_module() // build a mapping from true param name to param value size_t para_counter = 0; dict cell_params_map; - for (AstNode *child : children) { + for (auto& child : children) { if (child->type != AST_PARASET) continue; @@ -652,7 +651,7 @@ const RTLIL::Module* AstNode::lookup_cell_module() return nullptr; // let hierarchy handle this error IdString paraname = child->str.empty() ? module->avail_parameters[para_counter++] : child->str; - const AstNode *value = child->children[0]; + const AstNode *value = child->children[0].get(); if (value->type != AST_REALVALUE && value->type != AST_CONSTANT) return nullptr; // let genrtlil handle this error cell_params_map[paraname] = value->asParaConst(); @@ -684,8 +683,8 @@ static bool contains_unbased_unsized(const AstNode *node) { if (node->type == AST_CONSTANT) return node->is_unsized; - for (const AstNode *child : node->children) - if (contains_unbased_unsized(child)) + for (auto& child : node->children) + if (contains_unbased_unsized(child.get())) return true; return false; } @@ -694,19 +693,19 @@ static bool contains_unbased_unsized(const AstNode *node) // dimensions of the given wire reference void add_wire_for_ref(const RTLIL::Wire *ref, const std::string &str) { - AstNode *left = AstNode::mkconst_int(ref->width - 1 + ref->start_offset, true); - AstNode *right = AstNode::mkconst_int(ref->start_offset, true); + std::unique_ptr left = AstNode::mkconst_int(ref->width - 1 + ref->start_offset, true); + std::unique_ptr right = AstNode::mkconst_int(ref->start_offset, true); if (ref->upto) std::swap(left, right); - AstNode *range = new AstNode(AST_RANGE, left, right); + std::unique_ptr range = std::make_unique(AST_RANGE, std::move(left), std::move(right)); - AstNode *wire = new AstNode(AST_WIRE, range); + std::unique_ptr wire = std::make_unique(AST_WIRE, std::move(range)); wire->is_signed = ref->is_signed; wire->is_logic = true; wire->str = str; - current_ast_mod->children.push_back(wire); - current_scope[str] = wire; + current_scope[str] = wire.get(); + current_ast_mod->children.push_back(std::move(wire)); } enum class IdentUsage { @@ -733,10 +732,10 @@ static IdentUsage always_asgn_before_use(const AstNode *node, const std::string bool all_defined = true; bool any_used = false; bool has_default = false; - for (const AstNode *child : node->children) { + for (auto& child : node->children) { if (child->type == AST_COND && child->children.at(0)->type == AST_DEFAULT) has_default = true; - IdentUsage nested = always_asgn_before_use(child, target); + IdentUsage nested = always_asgn_before_use(child.get(), target); if (nested != IdentUsage::Assigned && child->type == AST_COND) all_defined = false; if (nested == IdentUsage::SyncRequired) @@ -753,20 +752,20 @@ static IdentUsage always_asgn_before_use(const AstNode *node, const std::string // Check if this is an assignment to the target variable. For simplicity, we // don't analyze sub-ranges of the variable. if (node->type == AST_ASSIGN_EQ) { - const AstNode *ident = node->children.at(0); + auto& ident = node->children.at(0); if (ident->type == AST_IDENTIFIER && ident->str == target) return IdentUsage::Assigned; } - for (const AstNode *child : node->children) { - IdentUsage nested = always_asgn_before_use(child, target); + for (auto& child : node->children) { + IdentUsage nested = always_asgn_before_use(child.get(), target); if (nested != IdentUsage::NotReferenced) return nested; } return IdentUsage::NotReferenced; } -AstNode *AstNode::clone_at_zero() +std::unique_ptr AstNode::clone_at_zero() { int width_hint; bool sign_hint; @@ -795,8 +794,7 @@ AstNode *AstNode::clone_at_zero() break; } - AstNode *that = new AstNode; - *that = *this; + auto that = clone(); for (auto &it : that->children) it = it->clone_at_zero(); for (auto &it : that->attributes) @@ -818,8 +816,8 @@ static bool try_determine_range_width(AstNode *range, int &result_width) return true; } - AstNode *left_at_zero_ast = range->children[0]->clone_at_zero(); - AstNode *right_at_zero_ast = range->children[1]->clone_at_zero(); + std::unique_ptr left_at_zero_ast = range->children[0]->clone_at_zero(); + std::unique_ptr right_at_zero_ast = range->children[1]->clone_at_zero(); while (left_at_zero_ast->simplify(true, 1, -1, false)) {} while (right_at_zero_ast->simplify(true, 1, -1, false)) {} @@ -831,8 +829,6 @@ static bool try_determine_range_width(AstNode *range, int &result_width) result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; } - delete left_at_zero_ast; - delete right_at_zero_ast; return ok; } @@ -891,13 +887,22 @@ static void check_auto_nosync(AstNode *node) // remove the attributes we've "consumed" for (const RTLIL::IdString &str : attrs_to_drop) { auto it = node->attributes.find(str); - delete it->second; node->attributes.erase(it); } // check local variables in any nested blocks - for (AstNode *child : node->children) - check_auto_nosync(child); + for (auto& child : node->children) + check_auto_nosync(child.get()); +} + +void AstNode::null_check() +{ + for (auto& child : children) { + // if (!child) + // VALGRIND_PRINTF_BACKTRACE("null child"); + log_assert((bool) child); + child->null_check(); + } } // convert the AST into a simpler AST that has all parameters substituted by their @@ -908,6 +913,7 @@ static void check_auto_nosync(AstNode *node) // nodes that link to a different node using names and lexical scoping. bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hint) { + // null_check(); static int recursion_counter = 0; static bool deep_recursion_warning = false; @@ -918,7 +924,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin static bool unevaluated_tern_branch = false; - AstNode *newNode = NULL; + std::unique_ptr newNode = nullptr; bool did_something = false; #if 0 @@ -926,7 +932,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, filename.c_str(), location.first_line, type2str(type).c_str(), this); log("const_fold=%d, stage=%d, width_hint=%d, sign_hint=%d\n", int(const_fold), int(stage), int(width_hint), int(sign_hint)); - // dumpAst(NULL, "> "); + // dumpAst(nullptr, "> "); #endif if (stage == 0) @@ -1006,7 +1012,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin std::swap(data_range_left, data_range_right); for (int i = 0; i < mem_size; i++) { - AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE, + auto reg = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); reg->str = stringf("%s[%d]", node->str.c_str(), i); reg->is_reg = true; @@ -1016,19 +1022,15 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin reg->set_attribute(it.first, it.second->clone()); reg->filename = node->filename; reg->location = node->location; - children.push_back(reg); while (reg->simplify(true, 1, -1, false)) { } + children.push_back(std::move(reg)); } } - AstNode *async_block = NULL; - while (mem2reg_as_needed_pass2(mem2reg_set, this, NULL, async_block)) { } + AstNode* async_block = nullptr; + while (mem2reg_as_needed_pass2(mem2reg_set, this, nullptr, async_block)) { } - vector delnodes; - mem2reg_remove(mem2reg_set, delnodes); - - for (auto node : delnodes) - delete node; + mem2reg_remove(mem2reg_set); } while (simplify(const_fold, 2, width_hint, sign_hint)) { } @@ -1055,8 +1057,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } if ((type == AST_TCALL) && - (str == "$display" || str == "$displayb" || str == "$displayh" || str == "$displayo" || - str == "$write" || str == "$writeb" || str == "$writeh" || str == "$writeo")) + (str == "$display" || str == "$displayb" || str == "$displayh" || str == "$displayo" || + str == "$write" || str == "$writeb" || str == "$writeh" || str == "$writeo")) { if (!current_always) { log_file_warning(filename, location.first_line, "System task `%s' outside initial or always block is unsupported.\n", str.c_str()); @@ -1064,7 +1066,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin str = std::string(); } else { // simplify the expressions and convert them to a special cell later in genrtlil - for (auto node : children) + for (auto& node : children) while (node->simplify(true, stage, -1, false)) {} if (current_always->type == AST_INITIAL && !flag_nodisplay && stage == 2) { @@ -1170,16 +1172,13 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } } for (size_t i = 0; i < children.size(); i++) { - AstNode *node = children[i]; + AstNode* node = children[i].get(); if (node->type == AST_WIRE) { if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) { - for (auto c : node->children[0]->children) { - if (!c->is_simple_const_expr()) { - if (attributes.count(ID::dynports)) - delete attributes.at(ID::dynports); + for (auto& c : node->children[0]->children) { + if (!c->is_simple_const_expr()) set_attribute(ID::dynports, AstNode::mkconst_int(1, true)); - } } } if (this_wire_scope.count(node->str) > 0) { @@ -1189,16 +1188,15 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (!node->is_input && !node->is_output && node->is_reg && node->children.size() == 0) goto wires_are_compatible; if (first_node->children.size() == 0 && node->children.size() == 1 && node->children[0]->type == AST_RANGE) { - AstNode *r = node->children[0]; + AstNode* r = node->children[0].get(); if (r->range_valid && r->range_left == 0 && r->range_right == 0) { - delete r; node->children.pop_back(); } } if (first_node->children.size() != node->children.size()) goto wires_are_incompatible; for (size_t j = 0; j < node->children.size(); j++) { - AstNode *n1 = first_node->children[j], *n2 = node->children[j]; + auto &n1 = first_node->children[j], &n2 = node->children[j]; if (n1->type == AST_RANGE && n2->type == AST_RANGE && n1->range_valid && n2->range_valid) { if (n1->range_left != n2->range_left) goto wires_are_incompatible; @@ -1225,13 +1223,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (node->is_signed) first_node->is_signed = true; for (auto &it : node->attributes) { - if (first_node->attributes.count(it.first) > 0) - delete first_node->attributes[it.first]; first_node->set_attribute(it.first, it.second->clone()); } children.erase(children.begin()+(i--)); did_something = true; - delete node; continue; wires_are_incompatible: if (stage > 1) @@ -1249,22 +1244,22 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } if (node->type == AST_ENUM) { current_scope[node->str] = node; - for (auto enode : node->children) { + for (auto& enode : node->children) { log_assert(enode->type==AST_ENUM_ITEM); if (current_scope.count(enode->str) == 0) - current_scope[enode->str] = enode; + current_scope[enode->str] = enode.get(); else input_error("enum item %s already exists\n", enode->str.c_str()); } } } for (size_t i = 0; i < children.size(); i++) { - AstNode *node = children[i]; + auto& node = children[i]; if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY || node->type == AST_TYPEDEF) while (node->simplify(true, 1, -1, false)) did_something = true; if (node->type == AST_ENUM) { - for (auto enode : node->children){ + for (auto& enode : node->children){ log_assert(enode->type==AST_ENUM_ITEM); while (node->simplify(true, 1, -1, false)) did_something = true; @@ -1272,27 +1267,27 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } } - for (AstNode *child : children) + for (auto& child : children) if (child->type == AST_ALWAYS && child->attributes.count(ID::always_comb)) - check_auto_nosync(child); + check_auto_nosync(child.get()); } // create name resolution entries for all objects with names if (type == AST_PACKAGE) { //add names to package scope for (size_t i = 0; i < children.size(); i++) { - AstNode *node = children[i]; + auto& node = children[i]; // these nodes appear at the top level in a package and can define names if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_TYPEDEF || node->type == AST_FUNCTION || node->type == AST_TASK) { - current_scope[node->str] = node; + current_scope[node->str] = node.get(); } if (node->type == AST_ENUM) { - current_scope[node->str] = node; - for (auto enode : node->children) { + current_scope[node->str] = node.get(); + for (auto& enode : node->children) { log_assert(enode->type==AST_ENUM_ITEM); if (current_scope.count(enode->str) == 0) - current_scope[enode->str] = enode; + current_scope[enode->str] = enode.get(); else input_error("enum item %s already exists in package\n", enode->str.c_str()); } @@ -1316,7 +1311,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin current_always_clocked = false; if (type == AST_ALWAYS) - for (auto child : children) { + for (auto& child : children) { if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) current_always_clocked = true; if (child->type == AST_EDGE && GetSize(child->children) == 1 && @@ -1328,7 +1323,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (type == AST_CELL) { bool lookup_suggested = false; - for (AstNode *child : children) { + for (auto& child : children) { // simplify any parameters to constants if (child->type == AST_PARASET) while (child->simplify(true, 1, -1, false)) { } @@ -1338,7 +1333,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (child->type == AST_ARGUMENT) { if (child->children.size() != 1) continue; - const AstNode *value = child->children[0]; + const auto& value = child->children[0]; if (value->type == AST_IDENTIFIER) { const AstNode *elem = value->id2ast; if (elem == nullptr) { @@ -1355,7 +1350,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // to be indirected to produce an unsigned connection lookup_suggested = true; } - else if (contains_unbased_unsized(value)) + else if (contains_unbased_unsized(value.get())) // unbased unsized literals extend to width of the context lookup_suggested = true; } @@ -1366,7 +1361,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin module = lookup_cell_module(); if (module) { size_t port_counter = 0; - for (AstNode *child : children) { + for (auto& child : children) { if (child->type != AST_ARGUMENT) continue; @@ -1390,17 +1385,21 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin log_assert(child->children.size() <= 1); if (child->children.empty()) continue; - AstNode *arg = child->children[0]; - // plain identifiers never need indirection; this also prevents - // adding infinite levels of indirection - if (arg->type == AST_IDENTIFIER && arg->children.empty()) - continue; + { + auto arg_check = child->children[0].get(); - // only add indirection for standard inputs or outputs - if (ref->port_input == ref->port_output) - continue; + // plain identifiers never need indirection; this also prevents + // adding infinite levels of indirection + if (arg_check->type == AST_IDENTIFIER && arg_check->children.empty()) + continue; + // only add indirection for standard inputs or outputs + if (ref->port_input == ref->port_output) + continue; + } + + auto arg = std::move(child->children[0]); did_something = true; // create the indirection wire @@ -1409,20 +1408,21 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin std::string tmp_str = sstr.str(); add_wire_for_ref(ref, tmp_str); - AstNode *asgn = new AstNode(AST_ASSIGN); - current_ast_mod->children.push_back(asgn); + auto asgn_owned = std::make_unique(AST_ASSIGN); + auto* asgn = asgn_owned.get(); + current_ast_mod->children.push_back(std::move(asgn_owned)); - AstNode *ident = new AstNode(AST_IDENTIFIER); + auto ident = std::make_unique(AST_IDENTIFIER); ident->str = tmp_str; child->children[0] = ident->clone(); if (ref->port_input && !ref->port_output) { - asgn->children.push_back(ident); - asgn->children.push_back(arg); + asgn->children.push_back(std::move(ident)); + asgn->children.push_back(std::move(arg)); } else { log_assert(!ref->port_input && ref->port_output); - asgn->children.push_back(arg); - asgn->children.push_back(ident); + asgn->children.push_back(std::move(arg)); + asgn->children.push_back(std::move(ident)); } asgn->fixup_hierarchy_flags(); } @@ -1482,7 +1482,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin case AST_STRUCT: case AST_UNION: if (!basic_prep) { - for (auto *node : children) { + for (auto& node : children) { // resolve any ranges while (!node->basic_prep && node->simplify(true, stage, -1, false)) { did_something = true; @@ -1496,7 +1496,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // instance so add a wire for the packed structure auto wnode = make_packed_struct(this, str, attributes); log_assert(current_ast_mod); - current_ast_mod->children.push_back(wnode); + current_ast_mod->children.push_back(std::move(wnode)); } basic_prep = true; is_custom_type = false; @@ -1522,7 +1522,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin case AST_ENUM: //log("\nENUM %s: %d child %d\n", str.c_str(), basic_prep, children[0]->basic_prep); if (!basic_prep) { - for (auto item_node : children) { + for (auto& item_node : children) { while (!item_node->basic_prep && item_node->simplify(false, stage, -1, false)) did_something = true; } @@ -1539,8 +1539,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin auto item_node = current_scope[children[0]->str]; if (item_node->type == AST_STRUCT || item_node->type == AST_UNION) { set_attribute(ID::wiretype, item_node->clone()); - size_packed_struct(attributes[ID::wiretype], 0); - add_members_to_scope(attributes[ID::wiretype], str); + size_packed_struct(attributes[ID::wiretype].get(), 0); + add_members_to_scope(attributes[ID::wiretype].get(), str); } } while (!children[0]->basic_prep && children[0]->simplify(false, stage, -1, false) == true) @@ -1568,11 +1568,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin break; case AST_CAST_SIZE: { - int width = 1; - AstNode *node; - AstNode *child = children[0]; - - if (child->type == AST_WIRE) { + if (children[0]->type == AST_WIRE) { + int width = 1; + std::unique_ptr node; + AstNode* child = children[0].release(); if (child->children.size() == 0) { // Base type (e.g., int) width = child->range_left - child->range_right +1; @@ -1588,7 +1587,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (resolved_type_node->type != AST_TYPEDEF) input_error("`%s' does not name a type\n", type_name.c_str()); log_assert(resolved_type_node->children.size() == 1); - AstNode *template_node = resolved_type_node->children[0]; + AstNode *template_node = resolved_type_node->children[0].get(); // Ensure typedef itself is fully simplified while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; @@ -1597,7 +1596,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin { case AST_WIRE: { if (template_node->children.size() > 0 && template_node->children[0]->type == AST_RANGE) - width = range_width(this, template_node->children[0]); + width = range_width(this, template_node->children[0].get()); child->delete_children(); node = mkconst_int(width, true); break; @@ -1616,9 +1615,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } } - delete child; children.erase(children.begin()); - children.insert(children.begin(), node); + children.insert(children.begin(), std::move(node)); } detect_width_simple = true; @@ -1675,7 +1673,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin case AST_GT: width_hint = -1; sign_hint = true; - for (auto child : children) { + for (auto& child : children) { while (!child->basic_prep && child->simplify(false, stage, -1, false) == true) did_something = true; child->detectSignWidthWorker(width_hint, sign_hint); @@ -1713,7 +1711,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (type == AST_REPLICATE) while (children[0]->simplify(true, stage, -1, false) == true) did_something = true; - for (auto child : children) + for (auto& child : children) while (!child->basic_prep && child->simplify(false, stage, -1, false) == true) did_something = true; detectSignWidth(width_hint, sign_hint); @@ -1730,11 +1728,11 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin bool backup_unevaluated_tern_branch = unevaluated_tern_branch; AstNode *chosen = get_tern_choice().first; - unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == children[2]; + unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == children[2].get(); while (!children[1]->basic_prep && children[1]->simplify(false, stage, -1, false)) did_something = true; - unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == children[1]; + unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == children[1].get(); while (!children[2]->basic_prep && children[2]->simplify(false, stage, -1, false)) did_something = true; @@ -1771,12 +1769,12 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) { children[0]->is_signed = sign_hint; RTLIL::Const case_expr = children[0]->bitsAsConst(width_hint, sign_hint); - std::vector new_children; - new_children.push_back(children[0]); + std::vector> new_children; + new_children.push_back(std::move(children[0])); for (int i = 1; i < GetSize(children); i++) { - AstNode *child = children[i]; + auto& child = children[i]; log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); - for (auto v : child->children) { + for (auto& v : child->children) { if (v->type == AST_DEFAULT) goto keep_const_cond; if (v->type == AST_BLOCK) @@ -1787,8 +1785,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin RTLIL::Const match = const_eq(case_expr, case_item_expr, sign_hint, sign_hint, 1); log_assert(match.size() == 1); if (match.front() == RTLIL::State::S1) { - while (i+1 < GetSize(children)) - delete children[++i]; + // This is the only reachable case. Skip to the end + i = GetSize(children); goto keep_const_cond; } continue; @@ -1797,9 +1795,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } if (0) keep_const_cond: - new_children.push_back(child); - else - delete child; + new_children.push_back(std::move(child)); } new_children.swap(children); } @@ -1835,7 +1831,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin flag_autowire = true; if (type == AST_TERNARY && i > 0 && !unevaluated_tern_branch) { AstNode *chosen = get_tern_choice().first; - unevaluated_tern_branch = chosen && chosen != children[i]; + unevaluated_tern_branch = chosen && chosen != children[i].get(); } while (did_something_here && i < children.size()) { bool const_fold_here = const_fold; @@ -1847,10 +1843,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin const_fold_here = true; if (type == AST_BLOCK) { current_block = this; - current_block_child = children[i]; + current_block_child = children[i].get(); } if ((type == AST_ALWAYS || type == AST_INITIAL) && children[i]->type == AST_BLOCK) - current_top_block = children[i]; + current_top_block = children[i].get(); if (i == 0 && child_0_is_self_determined) width_hint_here = -1, sign_hint_here = false; if (i == 1 && child_1_is_self_determined) @@ -1864,7 +1860,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin did_something = true; } if (stage == 2 && children[i]->type == AST_INITIAL && current_ast_mod != this) { - current_ast_mod->children.push_back(children[i]); + current_ast_mod->children.push_back(std::move(children[i])); children.erase(children.begin() + (i--)); did_something = true; } @@ -1904,7 +1900,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin current_always_clocked = backup_current_always_clocked; for (auto it = backup_scope.begin(); it != backup_scope.end(); it++) { - if (it->second == NULL) + if (it->second == nullptr) current_scope.erase(it->first); else current_scope[it->first] = it->second; @@ -1944,18 +1940,18 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin input_error("Defparam argument `%s . %s` does not match a cell!\n", RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str()); - AstNode *paraset = new AstNode(AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : NULL); + auto paraset = std::make_unique(AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : nullptr); paraset->str = paramname; AstNode *cell = current_scope.at(modname); - cell->children.insert(cell->children.begin() + 1, paraset); + cell->children.insert(cell->children.begin() + 1, std::move(paraset)); delete_children(); } // resolve typedefs if (type == AST_TYPEDEF) { log_assert(children.size() == 1); - auto type_node = children[0]; + auto& type_node = children[0]; log_assert(type_node->type == AST_WIRE || type_node->type == AST_MEMORY || type_node->type == AST_STRUCT || type_node->type == AST_UNION); while (type_node->simplify(const_fold, stage, width_hint, sign_hint)) { did_something = true; @@ -1976,7 +1972,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (resolved_type_node->type != AST_TYPEDEF) input_error("`%s' does not name a type\n", type_name.c_str()); log_assert(resolved_type_node->children.size() == 1); - AstNode *template_node = resolved_type_node->children[0]; + auto& template_node = resolved_type_node->children[0]; // Resolve the typedef from the bottom up, recursing within the current // block of code. Defer further simplification until the complete type is @@ -1985,9 +1981,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) { // replace instance with wire representing the packed structure - newNode = make_packed_struct(template_node, str, attributes); - if (newNode->attributes.count(ID::wiretype)) - delete newNode->attributes[ID::wiretype]; + newNode = make_packed_struct(template_node.get(), str, attributes); newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); // add original input/output attribute to resolved wire newNode->is_input = this->is_input; @@ -1999,8 +1993,6 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // Prepare replacement node. newNode = template_node->clone(); newNode->str = str; - if (newNode->attributes.count(ID::wiretype)) - delete newNode->attributes[ID::wiretype]; newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); newNode->is_input = is_input; newNode->is_output = is_output; @@ -2010,7 +2002,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin newNode->set_attribute(pair.first, pair.second->clone()); // if an enum then add attributes to support simulator tracing - newNode->annotateTypedEnums(template_node); + newNode->annotateTypedEnums(template_node.get()); bool add_packed_dimensions = (type == AST_WIRE && GetSize(children) > 1) || (type == AST_MEMORY && GetSize(children) > 2); @@ -2020,20 +2012,20 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // Add packed dimensions. if (add_packed_dimensions) { - AstNode *packed = children[1]; + auto& packed = children[1]; if (newNode->children.empty()) newNode->children.insert(newNode->children.begin(), packed->clone()); else - prepend_ranges(newNode->children[0], packed); + prepend_ranges(newNode->children[0], packed.get()); } // Add unpacked dimensions. if (type == AST_MEMORY) { - AstNode *unpacked = children.back(); + auto& unpacked = children.back(); if (GetSize(newNode->children) < 2) newNode->children.push_back(unpacked->clone()); else - prepend_ranges(newNode->children[1], unpacked); + prepend_ranges(newNode->children[1], unpacked.get()); newNode->type = type; } @@ -2054,11 +2046,11 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // Pretend it's just a wire in order to resolve the type in the code block above. AstNodeType param_type = type; type = AST_WIRE; - AstNode *expr = children[0]; + std::unique_ptr expr = std::move(children.front()); children.erase(children.begin()); while (is_custom_type && simplify(const_fold, stage, width_hint, sign_hint)) {}; type = param_type; - children.insert(children.begin(), expr); + children.insert(children.begin(), std::move(expr)); if (children[1]->type == AST_MEMORY) input_error("unpacked array type `%s' cannot be used for a parameter\n", children[1]->str.c_str()); @@ -2071,7 +2063,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // resolve constant prefixes if (type == AST_PREFIX) { if (children[0]->type != AST_CONSTANT) { - // dumpAst(NULL, "> "); + // dumpAst(nullptr, "> "); input_error("Index in generate block prefix syntax is not constant!\n"); } if (children[1]->type == AST_PREFIX) @@ -2136,13 +2128,13 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin range_right = children[0]->range_right; bool force_upto = false, force_downto = false; if (attributes.count(ID::force_upto)) { - AstNode *val = attributes[ID::force_upto]; + AstNode *val = attributes[ID::force_upto].get(); if (val->type != AST_CONSTANT) input_error("Attribute `force_upto' with non-constant value!\n"); force_upto = val->asAttrConst().as_bool(); } if (attributes.count(ID::force_downto)) { - AstNode *val = attributes[ID::force_downto]; + AstNode *val = attributes[ID::force_downto].get(); if (val->type != AST_CONSTANT) input_error("Attribute `force_downto' with non-constant value!\n"); force_downto = val->asAttrConst().as_bool(); @@ -2163,10 +2155,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin range_swapped = false; range_left = 0; range_right = 0; - if (attributes.count(ID::single_bit_vector)) { - delete attributes[ID::single_bit_vector]; - attributes.erase(ID::single_bit_vector); - } + attributes.erase(ID::single_bit_vector); } } @@ -2177,19 +2166,18 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (int i = std::min(GetSize(children), 2) - 1; i >= 0; i--) { if (children[i]->type == AST_MULTIRANGE) { int width = 1; - for (auto range : children[i]->children) { - width *= add_dimension(this, range); + for (auto& range : children[i]->children) { + width *= add_dimension(this, range.get()); if (i) unpacked_dimensions++; } - delete children[i]; int left = width - 1, right = 0; if (i) std::swap(left, right); - children[i] = new AstNode(AST_RANGE, mkconst_int(left, true), mkconst_int(right, true)); + children[i] = std::make_unique(AST_RANGE, mkconst_int(left, true), mkconst_int(right, true)); fixup_hierarchy_flags(); did_something = true; } else if (children[i]->type == AST_RANGE) { - add_dimension(this, children[i]); + add_dimension(this, children[i].get()); if (i) unpacked_dimensions++; } } @@ -2201,15 +2189,15 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // Resolve multidimensional array access. if (type == AST_IDENTIFIER && !basic_prep && id2ast && (id2ast->type == AST_WIRE || id2ast->type == AST_MEMORY) && - children.size() > 0 && (children[0]->type == AST_RANGE || children[0]->type == AST_MULTIRANGE)) + children.size() > 0 && (children[0]->type == AST_RANGE || children[0]->type == AST_MULTIRANGE)) { int dims_sel = children[0]->type == AST_MULTIRANGE ? children[0]->children.size() : 1; // Save original number of dimensions for $size() etc. integer = dims_sel; // Split access into unpacked and packed parts. - AstNode *unpacked_range = nullptr; - AstNode *packed_range = nullptr; + std::unique_ptr unpacked_range = nullptr; + std::unique_ptr packed_range = nullptr; if (id2ast->unpacked_dimensions) { if (id2ast->unpacked_dimensions > 1) { @@ -2217,8 +2205,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin unpacked_range = make_index_range(id2ast, true); } else { // Index into one-dimensional unpacked part; unlink simple range node. - AstNode *&range = children[0]->type == AST_MULTIRANGE ? children[0]->children[0] : children[0]; - unpacked_range = range; + auto& range = children[0]->type == AST_MULTIRANGE ? children[0]->children[0] : children[0]; + unpacked_range = std::move(range); range = nullptr; } } @@ -2229,21 +2217,19 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin packed_range = make_index_range(id2ast, false); } else { // Index into one-dimensional packed part; unlink simple range node. - AstNode *&range = children[0]->type == AST_MULTIRANGE ? children[0]->children[dims_sel - 1] : children[0]; - packed_range = range; + auto& range = children[0]->type == AST_MULTIRANGE ? children[0]->children[dims_sel - 1] : children[0]; + packed_range = std::move(range); range = nullptr; } } - for (auto &it : children) - delete it; children.clear(); if (unpacked_range) - children.push_back(unpacked_range); + children.push_back(std::move(unpacked_range)); if (packed_range) - children.push_back(packed_range); + children.push_back(std::move(packed_range)); fixup_hierarchy_flags(); basic_prep = true; @@ -2260,7 +2246,6 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin RTLIL::Const constvalue = children[0]->realAsConst(width); log_file_warning(filename, location.first_line, "converting real value %e to binary %s.\n", children[0]->realvalue, log_signal(constvalue)); - delete children[0]; children[0] = mkconst_bits(constvalue.to_bits(), sign_hint); fixup_hierarchy_flags(); did_something = true; @@ -2269,9 +2254,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (width != int(children[0]->bits.size())) { RTLIL::SigSpec sig(children[0]->bits); sig.extend_u0(width, children[0]->is_signed); - AstNode *old_child_0 = children[0]; children[0] = mkconst_bits(sig.as_const().to_bits(), is_signed); - delete old_child_0; fixup_hierarchy_flags(); } children[0]->is_signed = is_signed; @@ -2283,8 +2266,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } else if (children.size() > 1 && children[1]->type == AST_REALVALUE && children[0]->type == AST_CONSTANT) { double as_realvalue = children[0]->asReal(sign_hint); - delete children[0]; - children[0] = new AstNode(AST_REALVALUE); + children[0] = std::make_unique(AST_REALVALUE); children[0]->realvalue = as_realvalue; fixup_hierarchy_flags(); did_something = true; @@ -2313,7 +2295,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (found_sname) { // structure member, rewrite this node to reference the packed struct wire auto range = make_index_range(item_node); - newNode = new AstNode(AST_IDENTIFIER, range); + newNode = std::make_unique(AST_IDENTIFIER, std::move(range)); newNode->str = sname; // save type and original number of dimensions for $size() etc. newNode->set_attribute(ID::wiretype, item_node->clone()); @@ -2325,7 +2307,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } newNode->basic_prep = true; if (item_node->is_signed) - newNode = new AstNode(AST_TO_SIGNED, newNode); + newNode = std::make_unique(AST_TO_SIGNED, std::move(newNode)); goto apply_newNode; } } @@ -2336,7 +2318,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (current_scope.count(str) == 0) { AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod; str = try_pop_module_prefix(); - for (auto node : current_scope_ast->children) { + for (auto& node : current_scope_ast->children) { //log("looking at mod scope child %s\n", type2str(node->type).c_str()); switch (node->type) { case AST_PARAMETER: @@ -2351,16 +2333,16 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin //log("found child %s, %s\n", type2str(node->type).c_str(), node->str.c_str()); if (str == node->str) { //log("add %s, type %s to scope\n", str.c_str(), type2str(node->type).c_str()); - current_scope[node->str] = node; + current_scope[node->str] = node.get(); } break; case AST_ENUM: - current_scope[node->str] = node; - for (auto enum_node : node->children) { + current_scope[node->str] = node.get(); + for (auto& enum_node : node->children) { log_assert(enum_node->type==AST_ENUM_ITEM); if (str == enum_node->str) { //log("\nadding enum item %s to scope\n", str.c_str()); - current_scope[str] = enum_node; + current_scope[str] = enum_node.get(); } } break; @@ -2373,10 +2355,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (current_ast_mod == nullptr) { input_error("Identifier `%s' is implicitly declared outside of a module.\n", str.c_str()); } else if (flag_autowire || str == "\\$global_clock") { - AstNode *auto_wire = new AstNode(AST_AUTOWIRE); + auto auto_wire = std::make_unique(AST_AUTOWIRE); auto_wire->str = str; - current_ast_mod->children.push_back(auto_wire); - current_scope[str] = auto_wire; + current_scope[str] = auto_wire.get(); + current_ast_mod->children.push_back(std::move(auto_wire)); did_something = true; } else { input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); @@ -2391,7 +2373,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // split memory access with bit select to individual statements if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE && !in_lvalue && stage == 2) { - if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1) + if (id2ast == nullptr || id2ast->type != AST_MEMORY || children[0]->children.size() != 1) input_error("Invalid bit-select on memory access!\n"); int mem_width, mem_size, addr_bits; @@ -2407,38 +2389,38 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin sstr << "$mem2bits$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); std::string wire_id = sstr.str(); - AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); + auto wire_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); + auto* wire = wire_owned.get(); + current_ast_mod->children.push_back(std::move(wire_owned)); wire->str = wire_id; if (current_block) wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); - current_ast_mod->children.push_back(wire); while (wire->simplify(true, 1, -1, false)) { } - AstNode *data = clone(); - delete data->children[1]; + auto data = clone(); data->children.pop_back(); - AstNode *assign = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), data); + auto assign = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), std::move(data)); assign->children[0]->str = wire_id; assign->children[0]->was_checked = true; if (current_block) { size_t assign_idx = 0; - while (assign_idx < current_block->children.size() && current_block->children[assign_idx] != current_block_child) + while (assign_idx < current_block->children.size() && current_block->children[assign_idx].get() != current_block_child) assign_idx++; log_assert(assign_idx < current_block->children.size()); - current_block->children.insert(current_block->children.begin()+assign_idx, assign); + current_block->children.insert(current_block->children.begin()+assign_idx, std::move(assign)); wire->is_reg = true; } else { - AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK)); - proc->children[0]->children.push_back(assign); - current_ast_mod->children.push_back(proc); + auto proc = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK)); + proc->children[0]->children.push_back(std::move(assign)); + current_ast_mod->children.push_back(std::move(proc)); } - newNode = new AstNode(AST_IDENTIFIER, children[1]->clone()); + newNode = std::make_unique(AST_IDENTIFIER, children[1]->clone()); newNode->str = wire_id; newNode->integer = integer; // save original number of dimensions for $size() etc. newNode->id2ast = wire; @@ -2450,8 +2432,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (type == AST_REPEAT) { - AstNode *count = children[0]; - AstNode *body = children[1]; + auto count = std::move(children[0]); + auto body = std::move(children[1]); // eval count expression while (count->simplify(true, stage, 32, true)) { } @@ -2465,22 +2447,20 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (int i = 0; i < count->bitsAsConst().as_int(); i++) children.insert(children.begin(), body->clone()); - delete count; - delete body; did_something = true; } // unroll for loops and generate-for blocks if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0) { - AstNode *init_ast = children[0]; - AstNode *while_ast = children[1]; - AstNode *next_ast = children[2]; - AstNode *body_ast = children[3]; + auto& init_ast = children[0]; + auto& while_ast = children[1]; + auto& next_ast = children[2]; + auto* body_ast = children[3].get(); while (body_ast->type == AST_GENBLOCK && body_ast->str.empty() && body_ast->children.size() == 1 && body_ast->children.at(0)->type == AST_GENBLOCK) - body_ast = body_ast->children.at(0); + body_ast = body_ast->children.at(0).get(); const char* loop_type_str = "procedural"; const char* var_type_str = "register"; @@ -2496,16 +2476,16 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (next_ast->type != AST_ASSIGN_EQ) input_error("Unsupported 3rd expression of %s for-loop!\n", loop_type_str); - if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != var_type) + if (init_ast->children[0]->id2ast == nullptr || init_ast->children[0]->id2ast->type != var_type) input_error("Left hand side of 1st expression of %s for-loop is not a %s!\n", loop_type_str, var_type_str); - if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != var_type) + if (next_ast->children[0]->id2ast == nullptr || next_ast->children[0]->id2ast->type != var_type) input_error("Left hand side of 3rd expression of %s for-loop is not a %s!\n", loop_type_str, var_type_str); if (init_ast->children[0]->id2ast != next_ast->children[0]->id2ast) input_error("Incompatible left-hand sides in 1st and 3rd expression of %s for-loop!\n", loop_type_str); // eval 1st expression - AstNode *varbuf = init_ast->children[1]->clone(); + auto varbuf = init_ast->children[1]->clone(); { int expr_width_hint = -1; bool expr_sign_hint = true; @@ -2530,23 +2510,23 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } } - varbuf = new AstNode(AST_LOCALPARAM, varbuf); + varbuf = std::make_unique(AST_LOCALPARAM, std::move(varbuf)); varbuf->str = init_ast->children[0]->str; AstNode *backup_scope_varbuf = current_scope[varbuf->str]; - current_scope[varbuf->str] = varbuf; + current_scope[varbuf->str] = varbuf.get(); size_t current_block_idx = 0; if (type == AST_FOR) { while (current_block_idx < current_block->children.size() && - current_block->children[current_block_idx] != current_block_child) + current_block->children[current_block_idx].get() != current_block_child) current_block_idx++; } while (1) { // eval 2nd expression - AstNode *buf = while_ast->clone(); + auto buf = while_ast->clone(); { int expr_width_hint = -1; bool expr_sign_hint = true; @@ -2558,10 +2538,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin input_error("2nd expression of %s for-loop is not constant!\n", loop_type_str); if (buf->integer == 0) { - delete buf; break; } - delete buf; // expand body int index = varbuf->children[0]->integer; @@ -2574,27 +2552,26 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin std::string prefix = sstr.str(); // create a scoped localparam for the current value of the loop variable - AstNode *local_index = varbuf->clone(); + auto local_index = varbuf->clone(); size_t pos = local_index->str.rfind('.'); if (pos != std::string::npos) // remove outer prefix local_index->str = "\\" + local_index->str.substr(pos + 1); local_index->str = prefix_id(prefix, local_index->str); - current_scope[local_index->str] = local_index; - current_ast_mod->children.push_back(local_index); + current_scope[local_index->str] = local_index.get(); + current_ast_mod->children.push_back(std::move(local_index)); buf->expand_genblock(prefix); if (type == AST_GENFOR) { for (size_t i = 0; i < buf->children.size(); i++) { buf->children[i]->simplify(const_fold, stage, -1, false); - current_ast_mod->children.push_back(buf->children[i]); + current_ast_mod->children.push_back(std::move(buf->children[i])); } } else { for (size_t i = 0; i < buf->children.size(); i++) - current_block->children.insert(current_block->children.begin() + current_block_idx++, buf->children[i]); + current_block->children.insert(current_block->children.begin() + current_block_idx++, std::move(buf->children[i])); } buf->children.clear(); - delete buf; // eval 3rd expression buf = next_ast->children[1]->clone(); @@ -2609,19 +2586,16 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (buf->type != AST_CONSTANT) input_error("Right hand side of 3rd expression of %s for-loop is not constant (%s)!\n", loop_type_str, type2str(buf->type).c_str()); - delete varbuf->children[0]; - varbuf->children[0] = buf; + varbuf->children[0] = std::move(buf); } if (type == AST_FOR) { - AstNode *buf = next_ast->clone(); - delete buf->children[1]; + auto buf = next_ast->clone(); buf->children[1] = varbuf->children[0]->clone(); - current_block->children.insert(current_block->children.begin() + current_block_idx++, buf); + current_block->children.insert(current_block->children.begin() + current_block_idx++, std::move(buf)); } current_scope[varbuf->str] = backup_scope_varbuf; - delete varbuf; delete_children(); did_something = true; } @@ -2632,7 +2606,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (size_t i = 0; i < children.size(); i++) if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF) { - log_assert(!VERILOG_FRONTEND::sv_mode); + log_assert(!sv_mode); children[i]->input_error("Local declaration in unnamed block is only supported in SystemVerilog mode!\n"); } } @@ -2647,19 +2621,19 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin && is_autonamed_block(str)) // track local variables in this block so we can consider adding // nosync once the block has been fully elaborated - for (AstNode *child : children) + for (auto& child : children) if (child->type == AST_WIRE && !child->attributes.count(ID::nosync)) - mark_auto_nosync(this, child); + mark_auto_nosync(this, child.get()); - std::vector new_children; + std::vector> new_children; for (size_t i = 0; i < children.size(); i++) if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF) { children[i]->simplify(false, stage, -1, false); - current_ast_mod->children.push_back(children[i]); - current_scope[children[i]->str] = children[i]; + current_scope[children[i]->str] = children[i].get(); + current_ast_mod->children.push_back(std::move(children[i])); } else - new_children.push_back(children[i]); + new_children.push_back(std::move(children[i])); children.swap(new_children); did_something = true; @@ -2675,7 +2649,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (size_t i = 0; i < children.size(); i++) { children[i]->simplify(const_fold, stage, -1, false); - current_ast_mod->children.push_back(children[i]); + current_ast_mod->children.push_back(std::move(children[i])); } children.clear(); @@ -2685,7 +2659,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // simplify generate-if blocks if (type == AST_GENIF && children.size() != 0) { - AstNode *buf = children[0]->clone(); + auto buf = children[0]->clone(); while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) @@ -2693,17 +2667,15 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin input_error("Condition for generate if is not constant!\n"); } if (buf->asBool() != 0) { - delete buf; buf = children[1]->clone(); } else { - delete buf; - buf = children.size() > 2 ? children[2]->clone() : NULL; + buf = children.size() > 2 ? children[2]->clone() : nullptr; } if (buf) { if (buf->type != AST_GENBLOCK) - buf = new AstNode(AST_GENBLOCK, buf); + buf = std::make_unique(AST_GENBLOCK, std::move(buf)); if (!buf->str.empty()) { buf->expand_genblock(buf->str + "."); @@ -2711,11 +2683,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (size_t i = 0; i < buf->children.size(); i++) { buf->children[i]->simplify(const_fold, stage, -1, false); - current_ast_mod->children.push_back(buf->children[i]); + current_ast_mod->children.push_back(std::move(buf->children[i])); } buf->children.clear(); - delete buf; } delete_children(); @@ -2725,7 +2696,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // simplify generate-case blocks if (type == AST_GENCASE && children.size() != 0) { - AstNode *buf = children[0]->clone(); + auto buf = children[0]->clone(); while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) @@ -2735,24 +2706,23 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin bool ref_signed = buf->is_signed; RTLIL::Const ref_value = buf->bitsAsConst(); - delete buf; - AstNode *selected_case = NULL; + AstNode *selected_case = nullptr; for (size_t i = 1; i < children.size(); i++) { log_assert(children.at(i)->type == AST_COND || children.at(i)->type == AST_CONDX || children.at(i)->type == AST_CONDZ); - AstNode *this_genblock = NULL; - for (auto child : children.at(i)->children) { - log_assert(this_genblock == NULL); + AstNode *this_genblock = nullptr; + for (auto& child : children.at(i)->children) { + log_assert(this_genblock == nullptr); if (child->type == AST_GENBLOCK) - this_genblock = child; + this_genblock = child.get(); } - for (auto child : children.at(i)->children) + for (auto& child : children.at(i)->children) { if (child->type == AST_DEFAULT) { - if (selected_case == NULL) + if (selected_case == nullptr) selected_case = this_genblock; continue; } @@ -2769,7 +2739,6 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } bool is_selected = RTLIL::const_eq(ref_value, buf->bitsAsConst(), ref_signed && buf->is_signed, ref_signed && buf->is_signed, 1).as_bool(); - delete buf; if (is_selected) { selected_case = this_genblock; @@ -2779,7 +2748,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } } - if (selected_case != NULL) + if (selected_case != nullptr) { log_assert(selected_case->type == AST_GENBLOCK); buf = selected_case->clone(); @@ -2790,11 +2759,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (size_t i = 0; i < buf->children.size(); i++) { buf->children[i]->simplify(const_fold, stage, -1, false); - current_ast_mod->children.push_back(buf->children[i]); + current_ast_mod->children.push_back(std::move(buf->children[i])); } buf->children.clear(); - delete buf; } delete_children(); @@ -2807,13 +2775,14 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (!children.at(0)->range_valid) input_error("Non-constant array range on cell array.\n"); - newNode = new AstNode(AST_GENBLOCK); + newNode = std::make_unique(AST_GENBLOCK); int num = max(children.at(0)->range_left, children.at(0)->range_right) - min(children.at(0)->range_left, children.at(0)->range_right) + 1; for (int i = 0; i < num; i++) { int idx = children.at(0)->range_left > children.at(0)->range_right ? children.at(0)->range_right + i : children.at(0)->range_right - i; - AstNode *new_cell = children.at(1)->clone(); - newNode->children.push_back(new_cell); + auto new_cell_owned = children.at(1)->clone(); + auto* new_cell = new_cell_owned.get(); + newNode->children.push_back(std::move(new_cell_owned)); new_cell->str += stringf("[%d]", idx); if (new_cell->type == AST_PRIMITIVE) { input_error("Cell arrays of primitives are currently not supported.\n"); @@ -2833,13 +2802,12 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (children.size() < 2) input_error("Insufficient number of arguments for primitive `%s'!\n", str.c_str()); - std::vector children_list; - for (auto child : children) { + std::vector> children_list; + for (auto& child : children) { log_assert(child->type == AST_ARGUMENT); log_assert(child->children.size() == 1); - children_list.push_back(child->children[0]); + children_list.push_back(std::move(child->children[0])); child->children.clear(); - delete child; } children.clear(); @@ -2850,39 +2818,38 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin std::vector z_const(1, RTLIL::State::Sz); - AstNode *mux_input = children_list.at(1); + auto& mux_input = children_list.at(1); if (str == "notif0" || str == "notif1") { - mux_input = new AstNode(AST_BIT_NOT, mux_input); + mux_input = std::make_unique(AST_BIT_NOT, std::move(mux_input)); } - AstNode *node = new AstNode(AST_TERNARY, children_list.at(2)); + auto node = std::make_unique(AST_TERNARY, std::move(children_list.at(2))); if (str == "bufif0") { node->children.push_back(AstNode::mkconst_bits(z_const, false)); - node->children.push_back(mux_input); + node->children.push_back(std::move(mux_input)); } else { - node->children.push_back(mux_input); + node->children.push_back(std::move(mux_input)); node->children.push_back(AstNode::mkconst_bits(z_const, false)); } str.clear(); type = AST_ASSIGN; - children.push_back(children_list.at(0)); + children.push_back(std::move(children_list.at(0))); children.back()->was_checked = true; - children.push_back(node); + children.push_back(std::move(node)); fixup_hierarchy_flags(); did_something = true; } else if (str == "buf" || str == "not") { - AstNode *input = children_list.back(); + auto& input = children_list.back(); if (str == "not") - input = new AstNode(AST_BIT_NOT, input); + input = std::make_unique(AST_BIT_NOT, std::move(input)); - newNode = new AstNode(AST_GENBLOCK); + newNode = std::make_unique(AST_GENBLOCK); for (auto it = children_list.begin(); it != std::prev(children_list.end()); it++) { - newNode->children.push_back(new AstNode(AST_ASSIGN, *it, input->clone())); + newNode->children.push_back(std::make_unique(AST_ASSIGN, std::move(*it), input->clone())); newNode->children.back()->was_checked = true; } - delete input; did_something = true; } @@ -2905,20 +2872,20 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin op_type = AST_BIT_XOR, invert_results = true; log_assert(op_type != AST_NONE); - AstNode *node = children_list[1]; + auto& node = children_list[1]; if (op_type != AST_POS) for (size_t i = 2; i < children_list.size(); i++) { - node = new AstNode(op_type, node, children_list[i]); + node = std::make_unique(op_type, std::move(node), std::move(children_list[i])); node->location = location; } if (invert_results) - node = new AstNode(AST_BIT_NOT, node); + node = std::make_unique(AST_BIT_NOT, std::move(node)); str.clear(); type = AST_ASSIGN; - children.push_back(children_list[0]); + children.push_back(std::move(children_list[0])); children.back()->was_checked = true; - children.push_back(node); + children.push_back(std::move(node)); fixup_hierarchy_flags(); did_something = true; } @@ -2933,7 +2900,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin goto skip_dynamic_range_lvalue_expansion; if (children[0]->children[0]->range_valid || did_something) goto skip_dynamic_range_lvalue_expansion; - if (children[0]->id2ast == NULL || children[0]->id2ast->type != AST_WIRE) + if (children[0]->id2ast == nullptr || children[0]->id2ast->type != AST_WIRE) goto skip_dynamic_range_lvalue_expansion; if (!children[0]->id2ast->range_valid) goto skip_dynamic_range_lvalue_expansion; @@ -2945,10 +2912,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin int wire_offset = children[0]->id2ast->range_right; int result_width = 1; - AstNode *shift_expr = NULL; - AstNode *range = children[0]->children[0]; + std::unique_ptr shift_expr = nullptr; + auto& range = children[0]->children[0]; - if (!try_determine_range_width(range, result_width)) + if (!try_determine_range_width(range.get(), result_width)) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); if (range->children.size() >= 2) @@ -2992,14 +2959,14 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin AstNode *lsb_expr = shift_expr->type == AST_ADD && shift_expr->children[0]->type == AST_SELFSZ && shift_expr->children[1]->type == AST_CONSTANT && shift_expr->children[1]->integer == 0 ? - shift_expr->children[0]->children[0] : - shift_expr; + shift_expr->children[0]->children[0].get() : + shift_expr.get(); // Extract stride from indexing of two-dimensional packed arrays and // variable slices on the form dst[i*stride +: width] = src. if (lsb_expr->type == AST_MUL && - (lsb_expr->children[0]->type == AST_CONSTANT || - lsb_expr->children[1]->type == AST_CONSTANT)) + (lsb_expr->children[0]->type == AST_CONSTANT || + lsb_expr->children[1]->type == AST_CONSTANT)) { int stride_ix = lsb_expr->children[1]->type == AST_CONSTANT; stride = (int)lsb_expr->children[stride_ix]->integer; @@ -3047,11 +3014,14 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin int rvalue_width; bool rvalue_sign; children[1]->detectSignWidth(rvalue_width, rvalue_sign); - AstNode *rvalue = mktemp_logic("$bitselwrite$rvalue$", current_ast_mod, true, rvalue_width - 1, 0, rvalue_sign); - AstNode *caseNode = new AstNode(AST_CASE, shift_expr); - newNode = new AstNode(AST_BLOCK, - new AstNode(AST_ASSIGN_EQ, rvalue, children[1]->clone()), - caseNode); + auto rvalue = mktemp_logic("$bitselwrite$rvalue$", current_ast_mod, true, rvalue_width - 1, 0, rvalue_sign); + auto* rvalue_leaky = rvalue.get(); + log("make 1\n"); + auto case_node_owned = std::make_unique(AST_CASE, std::move(shift_expr)); + auto* case_node = case_node_owned.get(); + newNode = std::make_unique(AST_BLOCK, + std::make_unique(AST_ASSIGN_EQ, std::move(rvalue), children[1]->clone()), + std::move(case_node_owned)); did_something = true; for (int i = 1 - result_width; i < wire_width; i++) { @@ -3064,26 +3034,26 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (start_bit%bitno_div != 0 || (stride == 0 && start_bit != 0)) continue; - AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, case_sign_hint, max_width)); - AstNode *lvalue = children[0]->clone(); + auto cond = std::make_unique(AST_COND, mkconst_int(start_bit, case_sign_hint, max_width)); + auto lvalue = children[0]->clone(); lvalue->delete_children(); if (member_node) lvalue->set_attribute(ID::wiretype, member_node->clone()); - lvalue->children.push_back(new AstNode(AST_RANGE, + lvalue->children.push_back(std::make_unique(AST_RANGE, mkconst_int(end_bit, true), mkconst_int(start_bit, true))); - cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, rvalue->clone()))); - caseNode->children.push_back(cond); + cond->children.push_back(std::make_unique(AST_BLOCK, std::make_unique(std::move(type), std::move(lvalue), rvalue_leaky->clone()))); + case_node->children.push_back(std::move(cond)); } } else { // mask and shift operations // dst = (dst & ~(width'1 << lsb)) | unsigned'(width'(src)) << lsb) - AstNode *lvalue = children[0]->clone(); + auto lvalue = children[0]->clone(); lvalue->delete_children(); if (member_node) lvalue->set_attribute(ID::wiretype, member_node->clone()); - AstNode *old_data = lvalue->clone(); + auto old_data = lvalue->clone(); if (type == AST_ASSIGN_LE) old_data->lookahead = true; @@ -3092,51 +3062,52 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin shift_expr->detectSignWidth(shift_width_hint, shift_sign_hint); // All operations are carried out in a new block. - newNode = new AstNode(AST_BLOCK); + newNode = std::make_unique(AST_BLOCK); // Temporary register holding the result of the bit- or part-select position expression. - AstNode *pos = mktemp_logic("$bitselwrite$pos$", current_ast_mod, true, shift_width_hint - 1, 0, shift_sign_hint); - newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, pos, shift_expr)); - + auto pos = mktemp_logic("$bitselwrite$pos$", current_ast_mod, true, shift_width_hint - 1, 0, shift_sign_hint); // Calculate lsb from position. - AstNode *shift_val = pos->clone(); + auto shift_val = pos->clone(); + + newNode->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::move(pos), std::move(shift_expr))); // If the expression is signed, we must add an extra bit for possible negation of the most negative number. // If the expression is unsigned, we must add an extra bit for sign. - shift_val = new AstNode(AST_CAST_SIZE, mkconst_int(shift_width_hint + 1, true), shift_val); + shift_val = std::make_unique(AST_CAST_SIZE, mkconst_int(shift_width_hint + 1, true), std::move(shift_val)); if (!shift_sign_hint) - shift_val = new AstNode(AST_TO_SIGNED, shift_val); + shift_val = std::make_unique(AST_TO_SIGNED, std::move(shift_val)); // offset the shift amount by the lower bound of the dimension if (wire_offset != 0) - shift_val = new AstNode(AST_SUB, shift_val, mkconst_int(wire_offset, true)); + shift_val = std::make_unique(AST_SUB, std::move(shift_val), mkconst_int(wire_offset, true)); // reflect the shift amount if the dimension is swapped if (children[0]->id2ast->range_swapped) - shift_val = new AstNode(AST_SUB, mkconst_int(wire_width - result_width, true), shift_val); + shift_val = std::make_unique(AST_SUB, mkconst_int(wire_width - result_width, true), std::move(shift_val)); // AST_SHIFT uses negative amounts for shifting left - shift_val = new AstNode(AST_NEG, shift_val); + shift_val = std::make_unique(AST_NEG, std::move(shift_val)); + auto also_shift_val = shift_val->clone(); // dst = (dst & ~(width'1 << lsb)) | unsigned'(width'(src)) << lsb) did_something = true; - AstNode *bitmask = mkconst_bits(std::vector(result_width, State::S1), false); + auto bitmask = mkconst_bits(std::vector(result_width, State::S1), false); newNode->children.push_back( - new AstNode(type, - lvalue, - new AstNode(AST_BIT_OR, - new AstNode(AST_BIT_AND, - old_data, - new AstNode(AST_BIT_NOT, - new AstNode(AST_SHIFT, - bitmask, - shift_val->clone()))), - new AstNode(AST_SHIFT, - new AstNode(AST_TO_UNSIGNED, - new AstNode(AST_CAST_SIZE, - mkconst_int(result_width, true), - children[1]->clone())), - shift_val)))); + std::make_unique(std::move(type), + std::move(lvalue), + std::make_unique(AST_BIT_OR, + std::make_unique(AST_BIT_AND, + std::move(old_data), + std::make_unique(AST_BIT_NOT, + std::make_unique(AST_SHIFT, + std::move(bitmask), + std::move(shift_val)))), + std::make_unique(AST_SHIFT, + std::make_unique(AST_TO_UNSIGNED, + std::make_unique(AST_CAST_SIZE, + mkconst_int(result_width, true), + children[1]->clone())), + std::move(also_shift_val))))); newNode->fixup_hierarchy_flags(true); } @@ -3146,11 +3117,11 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin skip_dynamic_range_lvalue_expansion:; // found right-hand side identifier for memory -> replace with memory read port - if (stage > 1 && type == AST_IDENTIFIER && id2ast != NULL && id2ast->type == AST_MEMORY && !in_lvalue && + if (stage > 1 && type == AST_IDENTIFIER && id2ast != nullptr && id2ast->type == AST_MEMORY && !in_lvalue && children.size() == 1 && children[0]->type == AST_RANGE && children[0]->children.size() == 1) { if (integer < (unsigned)id2ast->unpacked_dimensions) input_error("Insufficient number of array indices for %s.\n", log_id(str)); - newNode = new AstNode(AST_MEMRD, children[0]->children[0]->clone()); + newNode = std::make_unique(AST_MEMRD, children[0]->children[0]->clone()); newNode->str = str; newNode->id2ast = id2ast; goto apply_newNode; @@ -3161,39 +3132,41 @@ skip_dynamic_range_lvalue_expansion:; { bool found_nontrivial_member = false; - for (auto child : children[0]->children) { - if (child->type == AST_IDENTIFIER && child->id2ast != NULL && child->id2ast->type == AST_MEMORY) + for (auto& child : children[0]->children) { + if (child->type == AST_IDENTIFIER && child->id2ast != nullptr && child->id2ast->type == AST_MEMORY) found_nontrivial_member = true; } if (found_nontrivial_member) { - newNode = new AstNode(AST_BLOCK); + newNode = std::make_unique(AST_BLOCK); - AstNode *wire_tmp = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); + auto wire_tmp_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); + auto wire_tmp = wire_tmp_owned.get(); wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); - current_ast_mod->children.push_back(wire_tmp); current_scope[wire_tmp->str] = wire_tmp; + current_ast_mod->children.push_back(std::move(wire_tmp_owned)); wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); while (wire_tmp->simplify(true, 1, -1, false)) { } wire_tmp->is_logic = true; - AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER); + auto wire_tmp_id_owned = std::make_unique(AST_IDENTIFIER); + auto* wire_tmp_id = wire_tmp_id_owned.get(); wire_tmp_id->str = wire_tmp->str; - newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, wire_tmp_id, children[1]->clone())); + newNode->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::move(wire_tmp_id_owned), children[1]->clone())); newNode->children.back()->was_checked = true; int cursor = 0; - for (auto child : children[0]->children) + for (auto& child : children[0]->children) { int child_width_hint = -1; bool child_sign_hint = true; child->detectSignWidth(child_width_hint, child_sign_hint); - AstNode *rhs = wire_tmp_id->clone(); - rhs->children.push_back(new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+child_width_hint-1, true), AstNode::mkconst_int(cursor, true))); - newNode->children.push_back(new AstNode(type, child->clone(), rhs)); + auto rhs = wire_tmp_id->clone(); + rhs->children.push_back(std::make_unique(AST_RANGE, AstNode::mkconst_int(cursor+child_width_hint-1, true), AstNode::mkconst_int(cursor, true))); + newNode->children.push_back(std::make_unique(type, child->clone(), std::move(rhs))); cursor += child_width_hint; } @@ -3219,8 +3192,8 @@ skip_dynamic_range_lvalue_expansion:; bool mem_signed = children[0]->id2ast->is_signed; children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); - newNode = new AstNode(AST_BLOCK); - AstNode *defNode = new AstNode(AST_BLOCK); + newNode = std::make_unique(AST_BLOCK); + auto defNode = std::make_unique(AST_BLOCK); int data_range_left = children[0]->id2ast->children[0]->range_left; int data_range_right = children[0]->id2ast->children[0]->range_right; @@ -3239,74 +3212,75 @@ skip_dynamic_range_lvalue_expansion:; for (int i = 0; i < mem_width; i++) set_bits_en.push_back(RTLIL::State::S1); - AstNode *node_addr = nullptr; + std::unique_ptr node_addr = nullptr; if (children[0]->children[0]->children[0]->isConst()) { node_addr = children[0]->children[0]->children[0]->clone(); } else { - AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); + auto wire_addr_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); + auto* wire_addr = wire_addr_owned.get(); wire_addr->str = id_addr; wire_addr->was_checked = true; - current_ast_mod->children.push_back(wire_addr); + current_ast_mod->children.push_back(std::move(wire_addr_owned)); current_scope[wire_addr->str] = wire_addr; while (wire_addr->simplify(true, 1, -1, false)) { } - AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); + auto assign_addr = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; - defNode->children.push_back(assign_addr); + defNode->children.push_back(std::move(assign_addr)); - assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); + assign_addr = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; - newNode->children.push_back(assign_addr); + newNode->children.push_back(std::move(assign_addr)); - node_addr = new AstNode(AST_IDENTIFIER); + node_addr = std::make_unique(AST_IDENTIFIER); node_addr->str = id_addr; } - AstNode *node_data = nullptr; + std::unique_ptr node_data = nullptr; if (children[0]->children.size() == 1 && children[1]->isConst()) { node_data = children[1]->clone(); } else { - AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_data_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto* wire_data = wire_data_owned.get(); wire_data->str = id_data; wire_data->was_checked = true; wire_data->is_signed = mem_signed; - current_ast_mod->children.push_back(wire_data); current_scope[wire_data->str] = wire_data; + current_ast_mod->children.push_back(std::move(wire_data_owned)); while (wire_data->simplify(true, 1, -1, false)) { } - AstNode *assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); + auto assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; - defNode->children.push_back(assign_data); + defNode->children.push_back(std::move(assign_data)); - node_data = new AstNode(AST_IDENTIFIER); + node_data = std::make_unique(AST_IDENTIFIER); node_data->str = id_data; } - AstNode *wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_en_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto* wire_en = wire_en_owned.get(); wire_en->str = id_en; wire_en->was_checked = true; - current_ast_mod->children.push_back(wire_en); current_scope[wire_en->str] = wire_en; + current_ast_mod->children.push_back(std::move(wire_en_owned)); while (wire_en->simplify(true, 1, -1, false)) { } - AstNode *assign_en_first = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); + auto assign_en_first = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); assign_en_first->children[0]->str = id_en; assign_en_first->children[0]->was_checked = true; - defNode->children.push_back(assign_en_first); + defNode->children.push_back(std::move(assign_en_first)); - AstNode *node_en = new AstNode(AST_IDENTIFIER); + auto node_en = std::make_unique(AST_IDENTIFIER); node_en->str = id_en; if (!defNode->children.empty()) - current_top_block->children.insert(current_top_block->children.begin(), defNode); - else - delete defNode; + current_top_block->children.insert(current_top_block->children.begin(), std::move(defNode)); - AstNode *assign_data = nullptr; - AstNode *assign_en = nullptr; + std::unique_ptr assign_data = nullptr; + std::unique_ptr assign_en = nullptr; if (children[0]->children.size() == 2) { if (children[0]->children[1]->range_valid) @@ -3317,24 +3291,24 @@ skip_dynamic_range_lvalue_expansion:; std::vector padding_x(offset, RTLIL::State::Sx); - assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), - new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone())); + assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), + std::make_unique(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone())); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; for (int i = 0; i < mem_width; i++) set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0; - assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); + assign_en = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; } else { - AstNode *the_range = children[0]->children[1]; - AstNode *offset_ast; + std::unique_ptr& the_range = children[0]->children[1]; + std::unique_ptr offset_ast; int width; - if (!try_determine_range_width(the_range, width)) + if (!try_determine_range_width(the_range.get(), width)) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); if (the_range->children.size() >= 2) @@ -3343,44 +3317,43 @@ skip_dynamic_range_lvalue_expansion:; offset_ast = the_range->children[0]->clone(); if (mem_data_range_offset) - offset_ast = new AstNode(AST_SUB, offset_ast, mkconst_int(mem_data_range_offset, true)); + offset_ast = std::make_unique(AST_SUB, std::move(offset_ast), mkconst_int(mem_data_range_offset, true)); - assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), - new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone())); + assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), + std::make_unique(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone())); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; for (int i = 0; i < mem_width; i++) set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0; - assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), - new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); + assign_en = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), + std::make_unique(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; - delete offset_ast; } } else { if (!(children[0]->children.size() == 1 && children[1]->isConst())) { - assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[1]->clone()); + assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), children[1]->clone()); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; } - assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); + assign_en = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; } if (assign_data) - newNode->children.push_back(assign_data); + newNode->children.push_back(std::move(assign_data)); if (assign_en) - newNode->children.push_back(assign_en); + newNode->children.push_back(std::move(assign_en)); - AstNode *wrnode; + std::unique_ptr wrnode; if (current_always->type == AST_INITIAL) - wrnode = new AstNode(AST_MEMINIT, node_addr, node_data, node_en, mkconst_int(1, false)); + wrnode = std::make_unique(AST_MEMINIT, std::move(node_addr), std::move(node_data), std::move(node_en), mkconst_int(1, false)); else - wrnode = new AstNode(AST_MEMWR, node_addr, node_data, node_en); + wrnode = std::make_unique(AST_MEMWR, std::move(node_addr), std::move(node_data), std::move(node_en)); wrnode->str = children[0]->str; wrnode->id2ast = children[0]->id2ast; wrnode->location = location; @@ -3394,14 +3367,13 @@ skip_dynamic_range_lvalue_expansion:; } wrnode->children.push_back(mkconst_bits(priority_mask, false)); current_memwr_visible[wrnode->str].insert(portid); - current_always->children.push_back(wrnode); + current_always->children.push_back(std::move(wrnode)); } else { - current_ast_mod->children.push_back(wrnode); + current_ast_mod->children.push_back(std::move(wrnode)); } if (newNode->children.empty()) { - delete newNode; - newNode = new AstNode(); + newNode = std::make_unique(); } goto apply_newNode; } @@ -3415,21 +3387,22 @@ skip_dynamic_range_lvalue_expansion:; { int myidx = autoidx++; - AstNode *wire = new AstNode(AST_WIRE); + auto wire_owned = std::make_unique(AST_WIRE); + auto* wire = wire_owned.get(); + current_ast_mod->children.push_back(std::move(wire_owned)); wire->str = stringf("$initstate$%d_wire", myidx); - current_ast_mod->children.push_back(wire); while (wire->simplify(true, 1, -1, false)) { } - AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE), new AstNode(AST_ARGUMENT, new AstNode(AST_IDENTIFIER))); + auto cell = std::make_unique(AST_CELL, std::make_unique(AST_CELLTYPE), std::make_unique(AST_ARGUMENT, std::make_unique(AST_IDENTIFIER))); cell->str = stringf("$initstate$%d", myidx); cell->children[0]->str = "$initstate"; cell->children[1]->str = "\\Y"; cell->children[1]->children[0]->str = wire->str; cell->children[1]->children[0]->id2ast = wire; - current_ast_mod->children.push_back(cell); + current_ast_mod->children.push_back(std::move(cell)); while (cell->simplify(true, 1, -1, false)) { } - newNode = new AstNode(AST_IDENTIFIER); + newNode = std::make_unique(AST_IDENTIFIER); newNode->str = wire->str; newNode->id2ast = wire; goto apply_newNode; @@ -3452,20 +3425,19 @@ skip_dynamic_range_lvalue_expansion:; if (GetSize(children) == 2) { - AstNode *buf = children[1]->clone(); + auto buf = children[1]->clone(); while (buf->simplify(true, stage, -1, false)) { } if (buf->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); num_steps = buf->asInt(true); - delete buf; } AstNode *block = nullptr; - for (auto child : current_always->children) + for (auto& child : current_always->children) if (child->type == AST_BLOCK) - block = child; + block = child.get(); log_assert(block != nullptr); @@ -3475,41 +3447,42 @@ skip_dynamic_range_lvalue_expansion:; } int myidx = autoidx++; - AstNode *outreg = nullptr; + AstNode* outreg = nullptr; for (int i = 0; i < num_steps; i++) { - AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE, + auto reg_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); + auto* reg = reg_owned.get(); + current_ast_mod->children.push_back(std::move(reg_owned)); reg->str = stringf("$past$%s:%d$%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, myidx, i); reg->is_reg = true; reg->is_signed = sign_hint; - current_ast_mod->children.push_back(reg); while (reg->simplify(true, 1, -1, false)) { } - AstNode *regid = new AstNode(AST_IDENTIFIER); + auto regid = std::make_unique(AST_IDENTIFIER); regid->str = reg->str; regid->id2ast = reg; regid->was_checked = true; - AstNode *rhs = nullptr; + std::unique_ptr rhs = nullptr; if (outreg == nullptr) { rhs = children.at(0)->clone(); } else { - rhs = new AstNode(AST_IDENTIFIER); + rhs = std::make_unique(AST_IDENTIFIER); rhs->str = outreg->str; rhs->id2ast = outreg; } - block->children.push_back(new AstNode(AST_ASSIGN_LE, regid, rhs)); + block->children.push_back(std::make_unique(AST_ASSIGN_LE, std::move(regid), std::move(rhs))); outreg = reg; } - newNode = new AstNode(AST_IDENTIFIER); + newNode = std::make_unique(AST_IDENTIFIER); newNode->str = outreg->str; newNode->id2ast = outreg; goto apply_newNode; @@ -3525,25 +3498,25 @@ skip_dynamic_range_lvalue_expansion:; input_error("System function %s is only allowed in clocked blocks.\n", RTLIL::unescape_id(str).c_str()); - AstNode *present = children.at(0)->clone(); - AstNode *past = clone(); + auto present = children.at(0)->clone(); + auto past = clone(); past->str = "\\$past"; if (str == "\\$stable") - newNode = new AstNode(AST_EQ, past, present); + newNode = std::make_unique(AST_EQ, std::move(past), std::move(present)); else if (str == "\\$changed") - newNode = new AstNode(AST_NE, past, present); + newNode = std::make_unique(AST_NE, std::move(past), std::move(present)); else if (str == "\\$rose") - newNode = new AstNode(AST_LOGIC_AND, - new AstNode(AST_LOGIC_NOT, new AstNode(AST_BIT_AND, past, mkconst_int(1,false))), - new AstNode(AST_BIT_AND, present, mkconst_int(1,false))); + newNode = std::make_unique(AST_LOGIC_AND, + std::make_unique(AST_LOGIC_NOT, std::make_unique(AST_BIT_AND, std::move(past), mkconst_int(1,false))), + std::make_unique(AST_BIT_AND, std::move(present), mkconst_int(1,false))); else if (str == "\\$fell") - newNode = new AstNode(AST_LOGIC_AND, - new AstNode(AST_BIT_AND, past, mkconst_int(1,false)), - new AstNode(AST_LOGIC_NOT, new AstNode(AST_BIT_AND, present, mkconst_int(1,false)))); + newNode = std::make_unique(AST_LOGIC_AND, + std::make_unique(AST_BIT_AND, std::move(past), mkconst_int(1,false)), + std::make_unique(AST_LOGIC_NOT, std::make_unique(AST_BIT_AND, std::move(present), mkconst_int(1,false)))); else log_abort(); @@ -3563,7 +3536,7 @@ skip_dynamic_range_lvalue_expansion:; input_error("System function %s got %d arguments, expected 1.\n", RTLIL::unescape_id(str).c_str(), int(children.size())); - AstNode *buf = children[0]->clone(); + auto buf = children[0]->clone(); while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); @@ -3571,7 +3544,6 @@ skip_dynamic_range_lvalue_expansion:; RTLIL::Const arg_value = buf->bitsAsConst(); if (arg_value.as_bool()) arg_value = const_sub(arg_value, 1, false, false, GetSize(arg_value)); - delete buf; uint32_t result = 0; for (auto i = 0; i < arg_value.size(); i++) @@ -3583,7 +3555,7 @@ skip_dynamic_range_lvalue_expansion:; } if (str == "\\$dimensions" || str == "\\$unpacked_dimensions" || - str == "\\$increment" || str == "\\$size" || str == "\\$bits" || str == "\\$high" || str == "\\$low" || str == "\\$left" || str == "\\$right") + str == "\\$increment" || str == "\\$size" || str == "\\$bits" || str == "\\$high" || str == "\\$low" || str == "\\$left" || str == "\\$right") { int dim = 1; if (str == "\\$dimensions" || str == "\\$unpacked_dimensions" || str == "\\$bits") { @@ -3595,24 +3567,23 @@ skip_dynamic_range_lvalue_expansion:; input_error("System function %s got %d arguments, expected 1 or 2.\n", RTLIL::unescape_id(str).c_str(), int(children.size())); if (children.size() == 2) { - AstNode *buf = children[1]->clone(); + auto buf = children[1]->clone(); // Evaluate constant expression while (buf->simplify(true, stage, width_hint, sign_hint)) { } dim = buf->asInt(false); - delete buf; } } - AstNode *buf = children[0]->clone(); + auto buf = children[0]->clone(); int mem_depth = 1; int result, high = 0, low = 0, left = 0, right = 0, width = 1; // defaults for a simple wire int expr_dimensions = 0, expr_unpacked_dimensions = 0; - AstNode *id_ast = NULL; + AstNode *id_ast = nullptr; buf->detectSignWidth(width_hint, sign_hint); if (buf->type == AST_IDENTIFIER) { id_ast = buf->id2ast; - if (id_ast == NULL && current_scope.count(buf->str)) + if (id_ast == nullptr && current_scope.count(buf->str)) id_ast = current_scope.at(buf->str); if (!id_ast) input_error("Failed to resolve identifier %s for width detection!\n", buf->str.c_str()); @@ -3651,7 +3622,6 @@ skip_dynamic_range_lvalue_expansion:; left = high = width - 1; expr_dimensions = 1; } - delete buf; if (str == "\\$dimensions") result = expr_dimensions; else if (str == "\\$unpacked_dimensions") @@ -3719,8 +3689,8 @@ skip_dynamic_range_lvalue_expansion:; if (str == "\\$rtoi") { newNode = AstNode::mkconst_int(x, true); } else { - newNode = new AstNode(AST_REALVALUE); - if (str == "\\$ln") newNode->realvalue = ::log(x); + newNode = std::make_unique(AST_REALVALUE); + if (str == "\\$ln") newNode->realvalue = ::log(x); else if (str == "\\$log10") newNode->realvalue = ::log10(x); else if (str == "\\$exp") newNode->realvalue = ::exp(x); else if (str == "\\$sqrt") newNode->realvalue = ::sqrt(x); @@ -3762,7 +3732,7 @@ skip_dynamic_range_lvalue_expansion:; // Determine which bits to count for (size_t i = 1; i < children.size(); i++) { - AstNode *node = children[i]; + auto& node = children[i]; while (node->simplify(true, stage, -1, false)) { } if (node->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant control bit argument.\n", str.c_str()); @@ -3774,39 +3744,37 @@ skip_dynamic_range_lvalue_expansion:; // Detect width of exp (first argument of $countbits) int exp_width = -1; bool exp_sign = false; - AstNode *exp = children[0]; - exp->detectSignWidth(exp_width, exp_sign, NULL); + auto& exp = children[0]; + exp->detectSignWidth(exp_width, exp_sign, nullptr); newNode = mkconst_int(0, false); for (int i = 0; i < exp_width; i++) { // Generate nodes for: exp << i >> ($size(exp) - 1) - // ^^ ^^ - AstNode *lsh_node = new AstNode(AST_SHIFT_LEFT, exp->clone(), mkconst_int(i, false)); - AstNode *rsh_node = new AstNode(AST_SHIFT_RIGHT, lsh_node, mkconst_int(exp_width - 1, false)); + // ^^ ^^ + auto lsh_node = std::make_unique(AST_SHIFT_LEFT, exp->clone(), mkconst_int(i, false)); + auto rsh_node = std::make_unique(AST_SHIFT_RIGHT, std::move(lsh_node), mkconst_int(exp_width - 1, false)); - AstNode *or_node = nullptr; + std::unique_ptr or_node = nullptr; for (RTLIL::State control_bit : control_bits) { // Generate node for: (exp << i >> ($size(exp) - 1)) === control_bit - // ^^^ - AstNode *eq_node = new AstNode(AST_EQX, rsh_node->clone(), mkconst_bits({control_bit}, false)); + // ^^^ + auto eq_node = std::make_unique(AST_EQX, rsh_node->clone(), mkconst_bits({control_bit}, false)); // Or the result for each checked bit value if (or_node) - or_node = new AstNode(AST_LOGIC_OR, or_node, eq_node); + or_node = std::make_unique(AST_LOGIC_OR, std::move(or_node), std::move(eq_node)); else - or_node = eq_node; + or_node = std::move(eq_node); } // We should have at least one element in control_bits, // because we checked for the number of arguments above log_assert(or_node != nullptr); - delete rsh_node; - // Generate node for adding with result of previous bit - newNode = new AstNode(AST_ADD, newNode, or_node); + newNode = std::make_unique(AST_ADD, std::move(newNode), std::move(or_node)); } goto apply_newNode; @@ -3817,22 +3785,22 @@ skip_dynamic_range_lvalue_expansion:; input_error("System function %s got %d arguments, expected 1.\n", RTLIL::unescape_id(str).c_str(), int(children.size())); - AstNode *countbits = clone(); + auto countbits = clone(); countbits->str = "\\$countbits"; if (str == "\\$countones") { countbits->children.push_back(mkconst_bits({RTLIL::State::S1}, false)); - newNode = countbits; + newNode = std::move(countbits); } else if (str == "\\$isunknown") { countbits->children.push_back(mkconst_bits({RTLIL::Sx}, false)); countbits->children.push_back(mkconst_bits({RTLIL::Sz}, false)); - newNode = new AstNode(AST_GT, countbits, mkconst_int(0, false)); + newNode = std::make_unique(AST_GT, std::move(countbits), mkconst_int(0, false)); } else if (str == "\\$onehot") { countbits->children.push_back(mkconst_bits({RTLIL::State::S1}, false)); - newNode = new AstNode(AST_EQ, countbits, mkconst_int(1, false)); + newNode = std::make_unique(AST_EQ, std::move(countbits), mkconst_int(1, false)); } else if (str == "\\$onehot0") { countbits->children.push_back(mkconst_bits({RTLIL::State::S1}, false)); - newNode = new AstNode(AST_LE, countbits, mkconst_int(1, false)); + newNode = std::make_unique(AST_LE, std::move(countbits), mkconst_int(1, false)); } else { log_abort(); } @@ -3846,7 +3814,7 @@ skip_dynamic_range_lvalue_expansion:; std::string rtype, fname; std::vector argtypes; - std::vector args; + std::vector> args; rtype = RTLIL::unescape_id(dpi_decl->children.at(0)->str); fname = RTLIL::unescape_id(dpi_decl->children.at(1)->str); @@ -3866,9 +3834,6 @@ skip_dynamic_range_lvalue_expansion:; newNode = dpi_call(rtype, fname, argtypes, args); - for (auto arg : args) - delete arg; - goto apply_newNode; } @@ -3894,12 +3859,12 @@ skip_dynamic_range_lvalue_expansion:; input_error("System function %s got %d arguments, expected 2-4.\n", RTLIL::unescape_id(str).c_str(), int(children.size())); - AstNode *node_filename = children[0]->clone(); + auto node_filename = children[0]->clone(); while (node_filename->simplify(true, stage, width_hint, sign_hint)) { } if (node_filename->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str()); - AstNode *node_memory = children[1]->clone(); + auto node_memory = children[1]->clone(); while (node_memory->simplify(true, stage, width_hint, sign_hint)) { } if (node_memory->type != AST_IDENTIFIER || node_memory->id2ast == nullptr || node_memory->id2ast->type != AST_MEMORY) input_error("Failed to evaluate system function `%s' with non-memory 2nd argument.\n", str.c_str()); @@ -3907,7 +3872,7 @@ skip_dynamic_range_lvalue_expansion:; int start_addr = -1, finish_addr = -1; if (GetSize(children) > 2) { - AstNode *node_addr = children[2]->clone(); + auto node_addr = children[2]->clone(); while (node_addr->simplify(true, stage, width_hint, sign_hint)) { } if (node_addr->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant 3rd argument.\n", str.c_str()); @@ -3915,7 +3880,7 @@ skip_dynamic_range_lvalue_expansion:; } if (GetSize(children) > 3) { - AstNode *node_addr = children[3]->clone(); + auto node_addr = children[3]->clone(); while (node_addr->simplify(true, stage, width_hint, sign_hint)) { } if (node_addr->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant 4th argument.\n", str.c_str()); @@ -3926,22 +3891,20 @@ skip_dynamic_range_lvalue_expansion:; if (current_always->type == AST_INITIAL) { pool queue; log_assert(current_always->children[0]->type == AST_BLOCK); - queue.insert(current_always->children[0]); + queue.insert(current_always->children[0].get()); while (!unconditional_init && !queue.empty()) { pool next_queue; - for (auto n : queue) - for (auto c : n->children) { - if (c == this) + for (auto& n : queue) + for (auto& c : n->children) { + if (c.get() == this) unconditional_init = true; - next_queue.insert(c); + next_queue.insert(c.get()); } next_queue.swap(queue); } } newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init); - delete node_filename; - delete node_memory; goto apply_newNode; } @@ -3956,10 +3919,11 @@ skip_dynamic_range_lvalue_expansion:; sstr << str << "$func$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++) << '.'; std::string prefix = sstr.str(); - AstNode *decl = current_scope[str]; + auto* decl = current_scope[str]; if (unevaluated_tern_branch && decl->is_recursive_function()) goto replace_fcall_later; - decl = decl->clone(); + auto decl_clone = decl->clone(); + decl = decl_clone.get(); // sketchy? decl->replace_result_wire_name_in_function(str, "$result"); // enables recursion decl->expand_genblock(prefix); @@ -3967,20 +3931,19 @@ skip_dynamic_range_lvalue_expansion:; { bool require_const_eval = decl->has_const_only_constructs(); bool all_args_const = true; - for (auto child : children) { + for (auto& child : children) { while (child->simplify(true, 1, -1, false)) { } if (child->type != AST_CONSTANT && child->type != AST_REALVALUE) all_args_const = false; } if (all_args_const) { - AstNode *func_workspace = decl->clone(); + auto func_workspace = decl->clone(); func_workspace->set_in_param_flag(true); func_workspace->str = prefix_id(prefix, "$result"); + // func_workspace->dumpAst(stdout, "func_workspace "); newNode = func_workspace->eval_const_function(this, in_param || require_const_eval); - delete func_workspace; if (newNode) { - delete decl; goto apply_newNode; } } @@ -3993,36 +3956,37 @@ skip_dynamic_range_lvalue_expansion:; size_t arg_count = 0; dict wire_cache; - vector new_stmts; - vector output_assignments; + vector> new_stmts; + vector> output_assignments; - if (current_block == NULL) + if (current_block == nullptr) { log_assert(type == AST_FCALL); - AstNode *wire = NULL; + std::unique_ptr wire = nullptr; std::string res_name = prefix_id(prefix, "$result"); - for (auto child : decl->children) + for (auto& child : decl->children) if (child->type == AST_WIRE && child->str == res_name) wire = child->clone(); - log_assert(wire != NULL); + log_assert(wire != nullptr); wire->port_id = 0; wire->is_input = false; wire->is_output = false; - current_scope[wire->str] = wire; - current_ast_mod->children.push_back(wire); - while (wire->simplify(true, 1, -1, false)) { } + auto* wire_leaky = wire.get(); + current_scope[wire->str] = wire_leaky; + current_ast_mod->children.push_back(std::move(wire)); + while (wire_leaky->simplify(true, 1, -1, false)) { } - AstNode *lvalue = new AstNode(AST_IDENTIFIER); - lvalue->str = wire->str; + auto lvalue = std::make_unique(AST_IDENTIFIER); + lvalue->str = wire_leaky->str; - AstNode *always = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK, - new AstNode(AST_ASSIGN_EQ, lvalue, clone()))); + auto always = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK, + std::make_unique(AST_ASSIGN_EQ, std::move(lvalue), clone()))); always->children[0]->children[0]->was_checked = true; - current_ast_mod->children.push_back(always); + current_ast_mod->children.push_back(std::move(always)); goto replace_fcall_with_id; } @@ -4039,57 +4003,57 @@ skip_dynamic_range_lvalue_expansion:; } else celltype = RTLIL::escape_id(celltype); - AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE)); + auto cell = std::make_unique(AST_CELL, std::make_unique(AST_CELLTYPE)); cell->str = prefix.substr(0, GetSize(prefix)-1); cell->children[0]->str = celltype; - for (auto attr : decl->attributes) + for (auto& attr : decl->attributes) if (attr.first.str().rfind("\\via_celltype_defparam_", 0) == 0) { - AstNode *cell_arg = new AstNode(AST_PARASET, attr.second->clone()); + auto cell_arg = std::make_unique(AST_PARASET, attr.second->clone()); cell_arg->str = RTLIL::escape_id(attr.first.substr(strlen("\\via_celltype_defparam_"))); - cell->children.push_back(cell_arg); + cell->children.push_back(std::move(cell_arg)); } - for (auto child : decl->children) + for (auto& child : decl->children) if (child->type == AST_WIRE && (child->is_input || child->is_output || (type == AST_FCALL && child->str == str))) { - AstNode *wire = child->clone(); + auto wire = child->clone(); wire->port_id = 0; wire->is_input = false; wire->is_output = false; - current_ast_mod->children.push_back(wire); + current_ast_mod->children.push_back(std::move(wire)); while (wire->simplify(true, 1, -1, false)) { } - AstNode *wire_id = new AstNode(AST_IDENTIFIER); + auto wire_id = std::make_unique(AST_IDENTIFIER); wire_id->str = wire->str; if ((child->is_input || child->is_output) && arg_count < children.size()) { - AstNode *arg = children[arg_count++]->clone(); - AstNode *assign = child->is_input ? - new AstNode(AST_ASSIGN_EQ, wire_id->clone(), arg) : - new AstNode(AST_ASSIGN_EQ, arg, wire_id->clone()); + auto arg = children[arg_count++]->clone(); + auto assign = child->is_input ? + std::make_unique(AST_ASSIGN_EQ, wire_id->clone(), std::move(arg)) : + std::make_unique(AST_ASSIGN_EQ, std::move(arg), wire_id->clone()); assign->children[0]->was_checked = true; for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { - if (*it != current_block_child) + if (it->get() != current_block_child) continue; - current_block->children.insert(it, assign); + current_block->children.insert(it, std::move(assign)); break; } } - AstNode *cell_arg = new AstNode(AST_ARGUMENT, wire_id); + auto cell_arg = std::make_unique(AST_ARGUMENT, std::move(wire_id)); cell_arg->str = child->str == str ? outport : child->str; - cell->children.push_back(cell_arg); + cell->children.push_back(std::move(cell_arg)); } - current_ast_mod->children.push_back(cell); + current_ast_mod->children.push_back(std::move(cell)); goto replace_fcall_with_id; } - for (auto child : decl->children) + for (auto& child : decl->children) if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || child->type == AST_ENUM_ITEM) { AstNode *wire = nullptr; @@ -4099,7 +4063,7 @@ skip_dynamic_range_lvalue_expansion:; wire = wire_cache.at(child->str); bool contains_value = wire->type == AST_LOCALPARAM; if (wire->children.size() == contains_value) { - for (auto c : child->children) + for (auto& c : child->children) wire->children.push_back(c->clone()); } else if (!child->children.empty()) { while (child->simplify(true, stage, -1, false)) { } @@ -4115,38 +4079,36 @@ skip_dynamic_range_lvalue_expansion:; } else { - wire = child->clone(); + current_ast_mod->children.push_back(child->clone()); + wire = current_ast_mod->children.back().get(); wire->port_id = 0; wire->is_input = false; wire->is_output = false; wire->is_reg = true; wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); if (child->type == AST_ENUM_ITEM) - wire->set_attribute(ID::enum_base_type, child->attributes[ID::enum_base_type]); + wire->set_attribute(ID::enum_base_type, std::move(child->attributes[ID::enum_base_type])); wire_cache[child->str] = wire; current_scope[wire->str] = wire; - current_ast_mod->children.push_back(wire); } while (wire->simplify(true, 1, -1, false)) { } if ((child->is_input || child->is_output) && arg_count < children.size()) { - AstNode *arg = children[arg_count++]->clone(); + auto arg = children[arg_count++]->clone(); // convert purely constant arguments into localparams - if (child->is_input && child->type == AST_WIRE && arg->type == AST_CONSTANT && node_contains_assignment_to(decl, child)) { + if (child->is_input && child->type == AST_WIRE && arg->type == AST_CONSTANT && node_contains_assignment_to(decl, child.get())) { wire->type = AST_LOCALPARAM; - if (wire->attributes.count(ID::nosync)) - delete wire->attributes.at(ID::nosync); wire->attributes.erase(ID::nosync); wire->children.insert(wire->children.begin(), arg->clone()); // args without a range implicitly have width 1 if (wire->children.back()->type != AST_RANGE) { // check if this wire is redeclared with an explicit size bool uses_explicit_size = false; - for (const AstNode *other_child : decl->children) + for (auto& other_child : decl->children) if (other_child->type == AST_WIRE && child->str == other_child->str && !other_child->children.empty() && other_child->children.back()->type == AST_RANGE) { @@ -4154,56 +4116,53 @@ skip_dynamic_range_lvalue_expansion:; break; } if (!uses_explicit_size) { - AstNode* range = new AstNode(); + auto range = std::make_unique(); range->type = AST_RANGE; - wire->children.push_back(range); range->children.push_back(mkconst_int(0, true)); range->children.push_back(mkconst_int(0, true)); + wire->children.push_back(std::move(range)); } } wire->fixup_hierarchy_flags(); // updates the sizing while (wire->simplify(true, 1, -1, false)) { } - delete arg; continue; } - AstNode *wire_id = new AstNode(AST_IDENTIFIER); + auto wire_id = std::make_unique(AST_IDENTIFIER); wire_id->str = wire->str; - if (child->is_input) { - AstNode *assign = new AstNode(AST_ASSIGN_EQ, wire_id->clone(), arg->clone()); + auto assign = std::make_unique(AST_ASSIGN_EQ, wire_id->clone(), arg->clone()); assign->children[0]->was_checked = true; - new_stmts.push_back(assign); + new_stmts.push_back(std::move(assign)); } if (child->is_output) { - AstNode *assign = new AstNode(AST_ASSIGN_EQ, arg->clone(), wire_id->clone()); + auto assign = std::make_unique(AST_ASSIGN_EQ, arg->clone(), wire_id->clone()); assign->children[0]->was_checked = true; - output_assignments.push_back(assign); + output_assignments.push_back(std::move(assign)); } - - delete arg; - delete wire_id; } } - for (auto child : decl->children) + for (auto& child : decl->children) if (child->type != AST_WIRE && child->type != AST_MEMORY && child->type != AST_PARAMETER && child->type != AST_LOCALPARAM) new_stmts.push_back(child->clone()); - new_stmts.insert(new_stmts.end(), output_assignments.begin(), output_assignments.end()); + new_stmts.reserve(new_stmts.size() + output_assignments.size()); + std::move(output_assignments.begin(), output_assignments.end(), std::back_inserter(new_stmts)); for (auto it = current_block->children.begin(); ; it++) { log_assert(it != current_block->children.end()); - if (*it == current_block_child) { - current_block->children.insert(it, new_stmts.begin(), new_stmts.end()); + if (it->get() == current_block_child) { + current_block->children.insert(it, + std::make_move_iterator(new_stmts.begin()), + std::make_move_iterator(new_stmts.end())); break; } } replace_fcall_with_id: - delete decl; if (type == AST_FCALL) { delete_children(); type = AST_IDENTIFIER; @@ -4319,14 +4278,14 @@ replace_fcall_later:; if (0) { case AST_SHIFT_RIGHT: const_func = RTLIL::const_shr; } if (0) { case AST_SHIFT_SLEFT: const_func = RTLIL::const_sshl; } if (0) { case AST_SHIFT_SRIGHT: const_func = RTLIL::const_sshr; } - if (0) { case AST_POW: const_func = RTLIL::const_pow; } + if (0) { case AST_POW: const_func = RTLIL::const_pow; } if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), RTLIL::Const(children[1]->bits), sign_hint, type == AST_POW ? children[1]->is_signed : false, width_hint); newNode = mkconst_bits(y.to_bits(), sign_hint); } else if (type == AST_POW && children[0]->isConst() && children[1]->isConst()) { - newNode = new AstNode(AST_REALVALUE); + newNode = std::make_unique(AST_REALVALUE); newNode->realvalue = pow(children[0]->asReal(sign_hint), children[1]->asReal(sign_hint)); } break; @@ -4371,7 +4330,7 @@ replace_fcall_later:; newNode = mkconst_bits(y.to_bits(), sign_hint); } else if (children[0]->isConst() && children[1]->isConst()) { - newNode = new AstNode(AST_REALVALUE); + newNode = std::make_unique(AST_REALVALUE); switch (type) { case AST_ADD: newNode->realvalue = children[0]->asReal(sign_hint) + children[1]->asReal(sign_hint); break; case AST_SUB: newNode->realvalue = children[0]->asReal(sign_hint) - children[1]->asReal(sign_hint); break; @@ -4390,7 +4349,7 @@ replace_fcall_later:; newNode = mkconst_bits(y.to_bits(), sign_hint); } else if (children[0]->isConst()) { - newNode = new AstNode(AST_REALVALUE); + newNode = std::make_unique(AST_REALVALUE); if (type == AST_NEG) newNode->realvalue = -children[0]->asReal(sign_hint); else @@ -4404,13 +4363,13 @@ replace_fcall_later:; AstNode *choice = pair.first; AstNode *not_choice = pair.second; - if (choice != NULL) { + if (choice != nullptr) { if (choice->type == AST_CONSTANT) { int other_width_hint = width_hint; bool other_sign_hint = sign_hint, other_real = false; not_choice->detectSignWidth(other_width_hint, other_sign_hint, &other_real); if (other_real) { - newNode = new AstNode(AST_REALVALUE); + newNode = std::make_unique(AST_REALVALUE); choice->detectSignWidth(width_hint, sign_hint); newNode->realvalue = choice->asReal(sign_hint); } else { @@ -4433,7 +4392,7 @@ replace_fcall_later:; a.bits()[i] = RTLIL::State::Sx; newNode = mkconst_bits(a.to_bits(), sign_hint); } else if (children[1]->isConst() && children[2]->isConst()) { - newNode = new AstNode(AST_REALVALUE); + newNode = std::make_unique(AST_REALVALUE); if (children[1]->asReal(sign_hint) == children[2]->asReal(sign_hint)) newNode->realvalue = children[1]->asReal(sign_hint); else @@ -4485,12 +4444,12 @@ apply_newNode: // fprintf(stderr, "----\n"); // dumpAst(stderr, "- "); // newNode->dumpAst(stderr, "+ "); - log_assert(newNode != NULL); + log_assert(newNode != nullptr); + // newNode->null_check(); newNode->filename = filename; newNode->location = location; - newNode->cloneInto(this); + newNode->cloneInto(*this); fixup_hierarchy_flags(); - delete newNode; did_something = true; } @@ -4503,21 +4462,21 @@ apply_newNode: void AstNode::replace_result_wire_name_in_function(const std::string &from, const std::string &to) { - for (AstNode *child : children) + for (auto& child : children) child->replace_result_wire_name_in_function(from, to); if (str == from && type != AST_FCALL && type != AST_TCALL) str = to; } // replace a readmem[bh] TCALL ast node with a block of memory assignments -AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init) +std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init) { int mem_width, mem_size, addr_bits; memory->meminfo(mem_width, mem_size, addr_bits); - AstNode *block = new AstNode(AST_BLOCK); + auto block = std::make_unique(AST_BLOCK); - AstNode *meminit = nullptr; + AstNode* meminit = nullptr; int next_meminit_cursor=0; vector meminit_bits; vector en_bits; @@ -4591,7 +4550,8 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m continue; } - AstNode *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) { @@ -4602,7 +4562,8 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m meminit->children[3] = AstNode::mkconst_int(meminit_size, false); } - meminit = new AstNode(AST_MEMINIT); + auto meminit_owned = std::make_unique(AST_MEMINIT); + meminit = meminit_owned.get(); meminit->children.push_back(AstNode::mkconst_int(cursor, false)); meminit->children.push_back(nullptr); meminit->children.push_back(AstNode::mkconst_bits(en_bits, false)); @@ -4612,18 +4573,17 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m meminit_bits.clear(); meminit_size = 0; - current_ast_mod->children.push_back(meminit); + current_ast_mod->children.push_back(std::move(meminit_owned)); next_meminit_cursor = cursor; } meminit_size++; next_meminit_cursor++; meminit_bits.insert(meminit_bits.end(), value->bits.begin(), value->bits.end()); - delete value; } else { - block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value)); + block->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER, std::make_unique(AST_RANGE, AstNode::mkconst_int(cursor, false))), std::move(value))); block->children.back()->children[0]->str = memory->str; block->children.back()->children[0]->id2ast = memory; block->children.back()->children[0]->was_checked = true; @@ -4700,7 +4660,7 @@ void AstNode::expand_genblock(const std::string &prefix) }; for (size_t i = 0; i < children.size(); i++) { - AstNode *child = children[i]; + auto* child = children[i].get(); switch (child->type) { case AST_WIRE: @@ -4726,9 +4686,9 @@ void AstNode::expand_genblock(const std::string &prefix) case AST_ENUM: current_scope[child->str] = child; - for (auto enode : child->children){ + for (auto& enode : child->children){ log_assert(enode->type == AST_ENUM_ITEM); - prefix_node(enode); + prefix_node(enode.get()); } break; @@ -4738,7 +4698,7 @@ void AstNode::expand_genblock(const std::string &prefix) } for (size_t i = 0; i < children.size(); i++) { - AstNode *child = children[i]; + auto& child = children[i]; // AST_PREFIX member names should not be prefixed; we recurse into them // as normal to ensure indices and ranges are properly resolved, and // then restore the previous string @@ -4770,7 +4730,7 @@ void AstNode::label_genblks(std::set& existing, int &counter) // seeing a proper generate control flow construct increments the // counter once ++counter; - for (AstNode *child : children) + for (auto& child : children) child->label_genblks(existing, counter); break; @@ -4787,7 +4747,7 @@ void AstNode::label_genblks(std::set& existing, int &counter) // within a genblk, the counter starts fresh std::set existing_local = existing; int counter_local = 0; - for (AstNode *child : children) + for (auto& child : children) child->label_genblks(existing_local, counter_local); break; } @@ -4796,7 +4756,7 @@ void AstNode::label_genblks(std::set& existing, int &counter) // track names which could conflict with implicit genblk names if (str.rfind("\\genblk", 0) == 0) existing.insert(str); - for (AstNode *child : children) + for (auto& child : children) child->label_genblks(existing, counter); break; } @@ -4807,7 +4767,7 @@ static void mark_memories_assign_lhs_complex(dict> & dict &mem2reg_candidates, AstNode *that) { for (auto &child : that->children) - mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, child); + mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, child.get()); if (that->type == AST_IDENTIFIER && that->id2ast && that->id2ast->type == AST_MEMORY) { AstNode *mem = that->id2ast; @@ -4831,7 +4791,7 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg { // mark all memories that are used in a complex expression on the left side of an assignment for (auto &lhs_child : children[0]->children) - mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, lhs_child); + mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, lhs_child.get()); if (children[0]->type == AST_IDENTIFIER && children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY) { @@ -4897,11 +4857,11 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg if ((type == AST_MODULE || type == AST_INTERFACE) && get_bool_attribute(ID::mem2reg)) children_flags |= AstNode::MEM2REG_FL_ALL; - dict *proc_flags_p = NULL; + dict *proc_flags_p = nullptr; if (type == AST_ALWAYS) { int count_edge_events = 0; - for (auto child : children) + for (auto& child : children) if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) count_edge_events++; if (count_edge_events != 1) @@ -4917,12 +4877,12 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg flags |= children_flags; log_assert((flags & ~0x000000ff) == 0); - for (auto child : children) + for (auto& child : children) { if (lhs_children_counter > 0) { lhs_children_counter--; if (child->children.size() && child->children[0]->type == AST_RANGE && child->children[0]->children.size()) { - for (auto c : child->children[0]->children) { + for (auto& c : child->children[0]->children) { if (proc_flags_p) c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags); else @@ -4958,7 +4918,7 @@ bool AstNode::mem2reg_check(pool &mem2reg_set) return true; } -void AstNode::mem2reg_remove(pool &mem2reg_set, vector &delnodes) +void AstNode::mem2reg_remove(pool &mem2reg_set) { log_assert(mem2reg_set.count(this) == 0); @@ -4966,17 +4926,16 @@ void AstNode::mem2reg_remove(pool &mem2reg_set, vector &deln id2ast = nullptr; for (size_t i = 0; i < children.size(); i++) { - if (mem2reg_set.count(children[i]) > 0) { - delnodes.push_back(children[i]); + if (mem2reg_set.count(children[i].get()) > 0) { children.erase(children.begin() + (i--)); } else { - children[i]->mem2reg_remove(mem2reg_set, delnodes); + children[i]->mem2reg_remove(mem2reg_set); } } } // actually replace memories with registers -bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block) +bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *block, AstNode* async_block) { bool did_something = false; @@ -5003,9 +4962,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, if (length != 0) { - AstNode *block = new AstNode(AST_INITIAL, new AstNode(AST_BLOCK)); - mod->children.push_back(block); - block = block->children[0]; + auto block_owned = std::make_unique(AST_INITIAL, std::make_unique(AST_BLOCK)); + auto block = block_owned.get(); + mod->children.push_back(std::move(block_owned)); + block = block->children[0].get(); int wordsz = GetSize(data) / length; @@ -5019,11 +4979,11 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, while (epos < wordsz && en[epos] == State::S1) epos++; int clen = epos - pos; - AstNode *range = new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false)); + auto range = std::make_unique(AST_RANGE, AstNode::mkconst_int(cursor+i, false)); if (pos != 0 || epos != wordsz) { int left; int right; - AstNode *mrange = id2ast->children[0]; + auto& mrange = id2ast->children[0]; if (mrange->range_left < mrange->range_right) { right = mrange->range_right - pos; left = mrange->range_right - epos + 1; @@ -5031,42 +4991,39 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, right = mrange->range_right + pos; left = mrange->range_right + epos - 1; } - range = new AstNode(AST_MULTIRANGE, range, new AstNode(AST_RANGE, AstNode::mkconst_int(left, true), AstNode::mkconst_int(right, true))); + range = std::make_unique(AST_MULTIRANGE, std::move(range), std::make_unique(AST_RANGE, AstNode::mkconst_int(left, true), AstNode::mkconst_int(right, true))); } - AstNode *target = new AstNode(AST_IDENTIFIER, range); + auto target = std::make_unique(AST_IDENTIFIER, std::move(range)); target->str = str; target->id2ast = id2ast; target->was_checked = true; - block->children.push_back(new AstNode(AST_ASSIGN_EQ, target, mkconst_bits(data.extract(i*wordsz + pos, clen).to_bits(), false))); + block->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::move(target), mkconst_bits(data.extract(i*wordsz + pos, clen).to_bits(), false))); pos = epos; } } } } - AstNode *newNode = new AstNode(AST_NONE); - newNode->cloneInto(this); - delete newNode; - + auto newNode = std::make_unique(AST_NONE); + newNode->cloneInto(*this); did_something = true; } - if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set)) + if (type == AST_ASSIGN && block == nullptr && children[0]->mem2reg_check(mem2reg_set)) { - if (async_block == NULL) { - async_block = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK)); - mod->children.push_back(async_block); + if (async_block == nullptr) { + auto async_block_owned = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK)); + async_block = async_block_owned.get(); + mod->children.push_back(std::move(async_block_owned)); } - AstNode *newNode = clone(); + auto newNode = clone(); newNode->type = AST_ASSIGN_EQ; newNode->children[0]->was_checked = true; - async_block->children[0]->children.push_back(newNode); - - newNode = new AstNode(AST_NONE); - newNode->cloneInto(this); - delete newNode; + async_block->children[0]->children.push_back(std::move(newNode)); + newNode = std::make_unique(AST_NONE); + newNode->cloneInto(*this); did_something = true; } @@ -5081,57 +5038,57 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, bool mem_signed = children[0]->id2ast->is_signed; children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); - AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); + auto wire_addr = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); wire_addr->str = id_addr; wire_addr->is_reg = true; wire_addr->was_checked = true; wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); - mod->children.push_back(wire_addr); while (wire_addr->simplify(true, 1, -1, false)) { } + mod->children.push_back(std::move(wire_addr)); - AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_data = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; wire_data->is_reg = true; wire_data->was_checked = true; wire_data->is_signed = mem_signed; wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); - mod->children.push_back(wire_data); while (wire_data->simplify(true, 1, -1, false)) { } + mod->children.push_back(std::move(wire_data)); - log_assert(block != NULL); + log_assert(block != nullptr); size_t assign_idx = 0; - while (assign_idx < block->children.size() && block->children[assign_idx] != this) + while (assign_idx < block->children.size() && block->children[assign_idx].get() != this) assign_idx++; log_assert(assign_idx < block->children.size()); - AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); + auto assign_addr = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; - block->children.insert(block->children.begin()+assign_idx+1, assign_addr); + block->children.insert(block->children.begin()+assign_idx+1, std::move(assign_addr)); - AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER)); + auto case_node = std::make_unique(AST_CASE, std::make_unique(AST_IDENTIFIER)); case_node->children[0]->str = id_addr; for (int i = 0; i < mem_size; i++) { if (children[0]->children[0]->children[0]->type == AST_CONSTANT && int(children[0]->children[0]->children[0]->integer) != i) continue; - AstNode *cond_node = new AstNode(AST_COND, AstNode::mkconst_int(i, false, addr_bits), new AstNode(AST_BLOCK)); - AstNode *assign_reg = new AstNode(type, new AstNode(AST_IDENTIFIER), new AstNode(AST_IDENTIFIER)); + auto cond_node = std::make_unique(AST_COND, AstNode::mkconst_int(i, false, addr_bits), std::make_unique(AST_BLOCK)); + auto assign_reg = std::make_unique(type, std::make_unique(AST_IDENTIFIER), std::make_unique(AST_IDENTIFIER)); if (children[0]->children.size() == 2) assign_reg->children[0]->children.push_back(children[0]->children[1]->clone()); assign_reg->children[0]->str = stringf("%s[%d]", children[0]->str.c_str(), i); assign_reg->children[1]->str = id_data; - cond_node->children[1]->children.push_back(assign_reg); - case_node->children.push_back(cond_node); + cond_node->children[1]->children.push_back(std::move(assign_reg)); + case_node->children.push_back(std::move(cond_node)); } // fixup on the full hierarchy below case_node case_node->fixup_hierarchy_flags(true); - block->children.insert(block->children.begin()+assign_idx+2, case_node); + block->children.insert(block->children.begin()+assign_idx+2, std::move(case_node)); children[0]->delete_children(); children[0]->range_valid = false; - children[0]->id2ast = NULL; + children[0]->id2ast = nullptr; children[0]->str = id_data; type = AST_ASSIGN_EQ; children[0]->was_checked = true; @@ -5142,7 +5099,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, if (mem2reg_check(mem2reg_set)) { - AstNode *bit_part_sel = NULL; + std::unique_ptr bit_part_sel = nullptr; if (children.size() == 2) bit_part_sel = children[1]->clone(); @@ -5159,7 +5116,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, str = stringf("%s[%d]", str.c_str(), id); delete_children(); range_valid = false; - id2ast = NULL; + id2ast = nullptr; } else { @@ -5172,7 +5129,6 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, else width = bit_part_sel->children[0]->integer - bit_part_sel->children[1]->integer; - delete bit_part_sel; bit_part_sel = nullptr; } else @@ -5187,9 +5143,8 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, std::vector x_bits; for (int i = 0; i < width; i++) x_bits.push_back(RTLIL::State::Sx); - AstNode *constant = AstNode::mkconst_bits(x_bits, false); - constant->cloneInto(this); - delete constant; + std::unique_ptr constant = AstNode::mkconst_bits(x_bits, false); + constant->cloneInto(*this); } } else @@ -5202,54 +5157,54 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, bool mem_signed = id2ast->is_signed; id2ast->meminfo(mem_width, mem_size, addr_bits); - AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); + auto wire_addr = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); wire_addr->str = id_addr; wire_addr->is_reg = true; wire_addr->was_checked = true; if (block) wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); - mod->children.push_back(wire_addr); while (wire_addr->simplify(true, 1, -1, false)) { } + mod->children.push_back(std::move(wire_addr)); - AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_data = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; wire_data->is_reg = true; wire_data->was_checked = true; wire_data->is_signed = mem_signed; if (block) wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); - mod->children.push_back(wire_data); while (wire_data->simplify(true, 1, -1, false)) { } + mod->children.push_back(std::move(wire_data)); - AstNode *assign_addr = new AstNode(block ? AST_ASSIGN_EQ : AST_ASSIGN, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone()); + auto assign_addr = std::make_unique(block ? AST_ASSIGN_EQ : AST_ASSIGN, std::make_unique(AST_IDENTIFIER), children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; - AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER)); + auto case_node = std::make_unique(AST_CASE, std::make_unique(AST_IDENTIFIER)); case_node->children[0]->str = id_addr; for (int i = 0; i < mem_size; i++) { if (children[0]->children[0]->type == AST_CONSTANT && int(children[0]->children[0]->integer) != i) continue; - AstNode *cond_node = new AstNode(AST_COND, AstNode::mkconst_int(i, false, addr_bits), new AstNode(AST_BLOCK)); - AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), new AstNode(AST_IDENTIFIER)); + auto cond_node = std::make_unique(AST_COND, AstNode::mkconst_int(i, false, addr_bits), std::make_unique(AST_BLOCK)); + auto assign_reg = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), std::make_unique(AST_IDENTIFIER)); assign_reg->children[0]->str = id_data; assign_reg->children[0]->was_checked = true; assign_reg->children[1]->str = stringf("%s[%d]", str.c_str(), i); - cond_node->children[1]->children.push_back(assign_reg); - case_node->children.push_back(cond_node); + cond_node->children[1]->children.push_back(std::move(assign_reg)); + case_node->children.push_back(std::move(cond_node)); } std::vector x_bits; for (int i = 0; i < mem_width; i++) x_bits.push_back(RTLIL::State::Sx); - AstNode *cond_node = new AstNode(AST_COND, new AstNode(AST_DEFAULT), new AstNode(AST_BLOCK)); - AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false)); + auto cond_node = std::make_unique(AST_COND, std::make_unique(AST_DEFAULT), std::make_unique(AST_BLOCK)); + auto assign_reg = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false)); assign_reg->children[0]->str = id_data; assign_reg->children[0]->was_checked = true; - cond_node->children[1]->children.push_back(assign_reg); - case_node->children.push_back(cond_node); + cond_node->children[1]->children.push_back(std::move(assign_reg)); + case_node->children.push_back(std::move(cond_node)); // fixup on the full hierarchy below case_node case_node->fixup_hierarchy_flags(true); @@ -5260,34 +5215,37 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, while (assign_idx < block->children.size() && !block->children[assign_idx]->contains(this)) assign_idx++; log_assert(assign_idx < block->children.size()); - block->children.insert(block->children.begin()+assign_idx, case_node); - block->children.insert(block->children.begin()+assign_idx, assign_addr); + block->children.insert(block->children.begin()+assign_idx, std::move(case_node)); + block->children.insert(block->children.begin()+assign_idx, std::move(assign_addr)); } else { - AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK, case_node)); - mod->children.push_back(proc); - mod->children.push_back(assign_addr); + auto proc = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK, std::move(case_node))); + mod->children.push_back(std::move(proc)); + mod->children.push_back(std::move(assign_addr)); mod->fixup_hierarchy_flags(); } delete_children(); range_valid = false; - id2ast = NULL; + id2ast = nullptr; str = id_data; } if (bit_part_sel) { - children.push_back(bit_part_sel); + children.push_back(std::move(bit_part_sel)); fixup_hierarchy_flags(); } did_something = true; } - log_assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0); + log_assert(id2ast == nullptr || mem2reg_set.count(id2ast) == 0); + + std::vector children_list; + for (auto& child : children) + children_list.push_back(child.get()); - auto children_list = children; for (size_t i = 0; i < children_list.size(); i++) if (children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block, async_block)) did_something = true; @@ -5372,7 +5330,7 @@ bool AstNode::has_const_only_constructs() { if (type == AST_WHILE || type == AST_REPEAT) return true; - for (auto child : children) + for (auto& child : children) if (child->has_const_only_constructs()) return true; return false; @@ -5382,7 +5340,7 @@ bool AstNode::is_simple_const_expr() { if (type == AST_IDENTIFIER) return false; - for (auto child : children) + for (auto& child : children) if (!child->is_simple_const_expr()) return false; return true; @@ -5417,9 +5375,8 @@ bool AstNode::replace_variables(std::map &varia offset = -offset; std::vector &var_bits = variables.at(str).val.bits(); std::vector new_bits(var_bits.begin() + offset, var_bits.begin() + offset + width); - AstNode *newNode = mkconst_bits(new_bits, variables.at(str).is_signed); - newNode->cloneInto(this); - delete newNode; + auto newNode = mkconst_bits(new_bits, variables.at(str).is_signed); + newNode->cloneInto(*this); return true; } @@ -5430,32 +5387,34 @@ bool AstNode::replace_variables(std::map &varia } // attempt to statically evaluate a functions with all-const arguments -AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) +std::unique_ptr AstNode::eval_const_function(AstNode *fcall, bool must_succeed) { std::map backup_scope = current_scope; std::map variables; - std::vector to_delete; - AstNode *block = new AstNode(AST_BLOCK); - AstNode *result = nullptr; + auto block = std::make_unique(AST_BLOCK); + std::unique_ptr result = nullptr; size_t argidx = 0; - for (auto child : children) + for (auto& child : children) { block->children.push_back(child->clone()); } block->set_in_param_flag(true); + std::vector> temporary_nodes; while (!block->children.empty()) { - AstNode *stmt = block->children.front(); + // log("%zu left in block %p\n", block->children.size(), block.get()); + std::unique_ptr& stmt = block->children.front(); #if 0 log("-----------------------------------\n"); for (auto &it : variables) log("%20s %40s\n", it.first.c_str(), log_signal(it.second.val)); - stmt->dumpAst(NULL, "stmt> "); + stmt->dumpAst(nullptr, "stmt> "); #endif - + // log("A\n"); + // log("%s\n", type2str(stmt->type).c_str()); if (stmt->type == AST_WIRE) { while (stmt->simplify(true, 1, -1, false)) { } @@ -5480,7 +5439,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) stmt->children.back()->type == AST_RANGE; // identify the argument corresponding to this wire, if applicable if (stmt->is_input && argidx < fcall->children.size()) { - variable.arg = fcall->children.at(argidx++); + variable.arg = fcall->children.at(argidx++).get(); } // load the constant arg's value into this variable if (variable.arg) { @@ -5491,10 +5450,10 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) variable.val = variable.arg->realAsConst(width); } } - current_scope[stmt->str] = stmt; + current_scope[stmt->str] = stmt.get(); + temporary_nodes.push_back(std::move(stmt)); block->children.erase(block->children.begin()); - to_delete.push_back(stmt); continue; } @@ -5504,10 +5463,10 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) { while (stmt->simplify(true, 1, -1, false)) { } - current_scope[stmt->str] = stmt; + current_scope[stmt->str] = stmt.get(); + temporary_nodes.push_back(std::move(stmt)); block->children.erase(block->children.begin()); - to_delete.push_back(stmt); continue; } @@ -5548,7 +5507,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (stmt->children.at(0)->children.empty()) { variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.size()); } else { - AstNode *range = stmt->children.at(0)->children.at(0); + AstNode *range = stmt->children.at(0)->children.at(0).get(); if (!range->range_valid) { if (!must_succeed) goto finished; @@ -5566,24 +5525,28 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) } } - delete block->children.front(); block->children.erase(block->children.begin()); continue; } if (stmt->type == AST_FOR) { - block->children.insert(block->children.begin(), stmt->children.at(0)); - stmt->children.at(3)->children.push_back(stmt->children.at(2)); + stmt->type = AST_WHILE; + log_assert(stmt->children.size() > 2); + auto yoink0 = std::move(stmt->children.at(0)); + log_assert(stmt->children.size() > 2); + auto yoink2 = std::move(stmt->children.at(2)); + stmt->children.at(3)->children.push_back(std::move(yoink2)); stmt->children.erase(stmt->children.begin() + 2); stmt->children.erase(stmt->children.begin()); - stmt->type = AST_WHILE; + block->children.insert(block->children.begin(), std::move(yoink0)); + log_assert(stmt->children.size() == 2); continue; } if (stmt->type == AST_WHILE) { - AstNode *cond = stmt->children.at(0)->clone(); + auto cond = stmt->children.at(0)->clone(); if (!cond->replace_variables(variables, fcall, must_succeed)) goto finished; cond->set_in_param_flag(true); @@ -5599,17 +5562,14 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (cond->asBool()) { block->children.insert(block->children.begin(), stmt->children.at(1)->clone()); } else { - delete block->children.front(); block->children.erase(block->children.begin()); } - - delete cond; continue; } if (stmt->type == AST_REPEAT) { - AstNode *num = stmt->children.at(0)->clone(); + auto num = stmt->children.at(0)->clone(); if (!num->replace_variables(variables, fcall, must_succeed)) goto finished; num->set_in_param_flag(true); @@ -5622,41 +5582,41 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) fcall->loc_string().c_str()); } + temporary_nodes.push_back(std::move(stmt)); block->children.erase(block->children.begin()); for (int i = 0; i < num->bitsAsConst().as_int(); i++) - block->children.insert(block->children.begin(), stmt->children.at(1)->clone()); + block->children.insert(block->children.begin(), temporary_nodes.back()->children.at(1)->clone()); - delete stmt; - delete num; continue; } if (stmt->type == AST_CASE) { - AstNode *expr = stmt->children.at(0)->clone(); + auto expr = stmt->children.at(0)->clone(); if (!expr->replace_variables(variables, fcall, must_succeed)) goto finished; expr->set_in_param_flag(true); while (expr->simplify(true, 1, -1, false)) { } - AstNode *sel_case = NULL; + AstNode *sel_case = nullptr; + std::unique_ptr sel_case_copy = nullptr; for (size_t i = 1; i < stmt->children.size(); i++) { bool found_match = false; log_assert(stmt->children.at(i)->type == AST_COND || stmt->children.at(i)->type == AST_CONDX || stmt->children.at(i)->type == AST_CONDZ); if (stmt->children.at(i)->children.front()->type == AST_DEFAULT) { - sel_case = stmt->children.at(i)->children.back(); + sel_case = stmt->children.at(i)->children.back().get(); continue; } for (size_t j = 0; j+1 < stmt->children.at(i)->children.size() && !found_match; j++) { - AstNode *cond = stmt->children.at(i)->children.at(j)->clone(); + auto cond = stmt->children.at(i)->children.at(j)->clone(); if (!cond->replace_variables(variables, fcall, must_succeed)) goto finished; - cond = new AstNode(AST_EQ, expr->clone(), cond); + cond = std::make_unique(AST_EQ, expr->clone(), std::move(cond)); cond->set_in_param_flag(true); while (cond->simplify(true, 1, -1, false)) { } @@ -5668,20 +5628,19 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) } found_match = cond->asBool(); - delete cond; } if (found_match) { - sel_case = stmt->children.at(i)->children.back(); + sel_case = stmt->children.at(i)->children.back().get(); break; } } + if (sel_case) + sel_case_copy = sel_case->clone(); block->children.erase(block->children.begin()); - if (sel_case) - block->children.insert(block->children.begin(), sel_case->clone()); - delete stmt; - delete expr; + if (sel_case_copy) + block->children.insert(block->children.begin(), std::move(sel_case_copy)); continue; } @@ -5689,15 +5648,19 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) { if (!stmt->str.empty()) stmt->expand_genblock(stmt->str + "."); - + auto* stmt_leaky = stmt.get(); + temporary_nodes.push_back(std::move(stmt)); block->children.erase(block->children.begin()); - block->children.insert(block->children.begin(), stmt->children.begin(), stmt->children.end()); - stmt->children.clear(); + block->children.reserve(block->children.size() + stmt_leaky->children.size()); + block->children.insert(block->children.begin(), + std::make_move_iterator(stmt_leaky->children.begin()), + std::make_move_iterator(stmt_leaky->children.end())); + stmt_leaky->children.clear(); block->fixup_hierarchy_flags(); - delete stmt; continue; } + // log("C\n"); if (!must_succeed) goto finished; stmt->input_error("Unsupported language construct in constant function\n%s: ... called from here.\n", @@ -5708,14 +5671,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) result = AstNode::mkconst_bits(variables.at(str).val.to_bits(), variables.at(str).is_signed); finished: - delete block; current_scope = backup_scope; - - for (auto it : to_delete) { - delete it; - } - to_delete.clear(); - return result; } @@ -5726,14 +5682,13 @@ void AstNode::allocateDefaultEnumValues() if (children.front()->attributes.count(ID::enum_base_type)) return; // already elaborated int last_enum_int = -1; - for (auto node : children) { + for (auto& node : children) { log_assert(node->type==AST_ENUM_ITEM); node->set_attribute(ID::enum_base_type, mkconst_str(str)); for (size_t i = 0; i < node->children.size(); i++) { switch (node->children[i]->type) { case AST_NONE: // replace with auto-incremented constant - delete node->children[i]; node->children[i] = AstNode::mkconst_int(++last_enum_int, true); break; case AST_CONSTANT: @@ -5762,8 +5717,8 @@ bool AstNode::is_recursive_function() const if (it != current_scope.end() && visit(it->second)) return true; } - for (const AstNode *child : node->children) { - if (visit(child)) + for (auto& child : node->children) { + if (visit(child.get())) return true; } return false; @@ -5793,9 +5748,9 @@ std::pair AstNode::get_tern_choice() AstNode *choice = nullptr, *not_choice = nullptr; if (found_sure_true) - choice = children[1], not_choice = children[2]; + choice = children[1].get(), not_choice = children[2].get(); else if (!found_maybe_true) - choice = children[2], not_choice = children[1]; + choice = children[2].get(), not_choice = children[1].get(); return {choice, not_choice}; } diff --git a/frontends/verilog/.gitignore b/frontends/verilog/.gitignore index aadbcdcdd..a6d4c8b86 100644 --- a/frontends/verilog/.gitignore +++ b/frontends/verilog/.gitignore @@ -2,3 +2,6 @@ verilog_lexer.cc verilog_parser.output verilog_parser.tab.cc verilog_parser.tab.hh +position.hh +location.hh +stack.hh diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 2c923f0b7..2d26f1930 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -9,6 +9,7 @@ frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y $(P) $(BISON) -Wall -Werror -o $@ -d -r all -b frontends/verilog/verilog_parser $< frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc +frontends/verilog/verilog_frontend.h: frontends/verilog/verilog_parser.tab.hh frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l frontends/verilog/verilog_parser.tab.cc $(Q) mkdir -p $(dir $@) diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index a4dfbc7ec..9c4a2e76c 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -42,14 +42,35 @@ YOSYS_NAMESPACE_BEGIN using namespace AST; +using namespace VERILOG_FRONTEND; + +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; @@ -60,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) { @@ -71,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; @@ -102,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) @@ -126,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) @@ -140,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 -AstNode *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) { - AstNode *ret = const2ast(code, case_type); + 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; } @@ -172,7 +191,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn ch = ch >> 1; } } - AstNode *ast = AstNode::mkconst_bits(data, false); + auto ast = AstNode::mkconst_bits(data, false); ast->str = code; return ast; } @@ -245,4 +264,5 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn return NULL; } + YOSYS_NAMESPACE_END diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index e33b0a2c3..d07e39189 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -34,6 +34,7 @@ #include "preproc.h" #include "verilog_frontend.h" +#include "verilog_parser.tab.hh" #include "kernel/log.h" #include #include @@ -749,7 +750,9 @@ frontend_verilog_preproc(std::istream &f, std::string filename, const define_map_t &pre_defines, define_map_t &global_defines_cache, - const std::list &include_dirs) + const std::list &include_dirs, + ParseState &parse_state, + ParseMode &parse_mode) { define_map_t defines; defines.merge(pre_defines); @@ -961,11 +964,11 @@ frontend_verilog_preproc(std::istream &f, } if (tok == "`resetall") { - default_nettype_wire = true; + parse_state.default_nettype_wire = true; continue; } - if (tok == "`undefineall" && sv_mode) { + if (tok == "`undefineall" && parse_mode.sv) { defines.clear(); global_defines_cache.clear(); continue; diff --git a/frontends/verilog/preproc.h b/frontends/verilog/preproc.h index 330855a92..51562787a 100644 --- a/frontends/verilog/preproc.h +++ b/frontends/verilog/preproc.h @@ -35,6 +35,11 @@ YOSYS_NAMESPACE_BEGIN struct define_body_t; struct arg_map_t; +namespace VERILOG_FRONTEND { + struct ParseState; + struct ParseMode; +}; + struct define_map_t { define_map_t(); @@ -71,7 +76,9 @@ frontend_verilog_preproc(std::istream &f, std::string filename, const define_map_t &pre_defines, define_map_t &global_defines_cache, - const std::list &include_dirs); + const std::list &include_dirs, + VERILOG_FRONTEND::ParseState &parse_state, + VERILOG_FRONTEND::ParseMode &parse_mode); YOSYS_NAMESPACE_END diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 1f272ca4f..f2a341f54 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -31,6 +31,7 @@ #endif #include "verilog_frontend.h" +#include "verilog_lexer.h" #include "preproc.h" #include "kernel/yosys.h" #include "libs/sha1/sha1.h" @@ -48,11 +49,11 @@ static void error_on_dpi_function(AST::AstNode *node) { if (node->type == AST::AST_DPI_FUNCTION) 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); + for (auto& child : node->children) + error_on_dpi_function(child.get()); } -static void add_package_types(dict &user_types, std::vector &package_list) +static void add_package_types(dict &user_types, std::vector> &package_list) { // prime the parser's user type lookup table with the package qualified names // of typedefed names in the packages seen so far. @@ -61,14 +62,22 @@ static void add_package_types(dict &user_types, std 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; + user_types[s] = node.get(); } } } } struct VerilogFrontend : public Frontend { - VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { } + ParseMode parse_mode; + ParseState parse_state; + VerilogLexer lexer; + frontend_verilog_yy::parser parser; + VerilogFrontend() : Frontend("verilog", "read modules from Verilog file"), + parse_mode(), + parse_state(), + lexer(&parse_state, &parse_mode), + parser(&lexer, &parse_state, &parse_mode) { } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -266,22 +275,24 @@ struct VerilogFrontend : public Frontend { bool flag_noblackbox = false; bool flag_nowb = false; bool flag_nosynthesis = false; + bool flag_yydebug = false; define_map_t defines_map; std::list include_dirs; std::list attributes; - frontend_verilog_yydebug = false; - sv_mode = false; - formal_mode = false; - noassert_mode = false; - noassume_mode = false; - norestrict_mode = false; - assume_asserts_mode = false; - assert_assumes_mode = false; - lib_mode = false; - specify_mode = false; - default_nettype_wire = true; + lexer.set_debug(false); + parser.set_debug_level(0); + parse_mode.sv = false; + parse_mode.formal = false; + parse_mode.noassert = false; + parse_mode.noassume = false; + parse_mode.norestrict = false; + parse_mode.assume_asserts = false; + parse_mode.assert_assumes = false; + parse_mode.lib = false; + parse_mode.specify = false; + parse_state.default_nettype_wire = true; args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end()); @@ -289,11 +300,11 @@ struct VerilogFrontend : public Frontend { for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if (arg == "-sv") { - sv_mode = true; + parse_mode.sv = true; continue; } if (arg == "-formal") { - formal_mode = true; + parse_mode.formal = true; continue; } if (arg == "-nosynthesis") { @@ -301,23 +312,23 @@ struct VerilogFrontend : public Frontend { continue; } if (arg == "-noassert") { - noassert_mode = true; + parse_mode.noassert = true; continue; } if (arg == "-noassume") { - noassume_mode = true; + parse_mode.noassume = true; continue; } if (arg == "-norestrict") { - norestrict_mode = true; + parse_mode.norestrict = true; continue; } if (arg == "-assume-asserts") { - assume_asserts_mode = true; + parse_mode.assume_asserts = true; continue; } if (arg == "-assert-assumes") { - assert_assumes_mode = true; + parse_mode.assert_assumes = true; continue; } if (arg == "-nodisplay") { @@ -329,7 +340,8 @@ struct VerilogFrontend : public Frontend { flag_dump_ast2 = true; flag_dump_vlog1 = true; flag_dump_vlog2 = true; - frontend_verilog_yydebug = true; + lexer.set_debug(true); + parser.set_debug_level(1); continue; } if (arg == "-dump_ast1") { @@ -357,7 +369,7 @@ struct VerilogFrontend : public Frontend { continue; } if (arg == "-yydebug") { - frontend_verilog_yydebug = true; + flag_yydebug = true; continue; } if (arg == "-nolatches") { @@ -393,7 +405,7 @@ struct VerilogFrontend : public Frontend { continue; } if (arg == "-lib") { - lib_mode = true; + parse_mode.lib = true; defines_map.add("BLACKBOX", ""); continue; } @@ -402,7 +414,7 @@ struct VerilogFrontend : public Frontend { continue; } if (arg == "-specify") { - specify_mode = true; + parse_mode.specify = true; continue; } if (arg == "-noopt") { @@ -432,7 +444,7 @@ struct VerilogFrontend : public Frontend { continue; } if (arg == "-noautowire") { - default_nettype_wire = false; + parse_state.default_nettype_wire = false; continue; } if (arg == "-setattr" && argidx+1 < args.size()) { @@ -469,54 +481,59 @@ struct VerilogFrontend : public Frontend { break; } - if (formal_mode || !flag_nosynthesis) - defines_map.add(formal_mode ? "FORMAL" : "SYNTHESIS", "1"); + if (parse_mode.formal || !flag_nosynthesis) + defines_map.add(parse_mode.formal ? "FORMAL" : "SYNTHESIS", "1"); extra_args(f, filename, args, argidx); log_header(design, "Executing Verilog-2005 frontend: %s\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()); + parse_mode.formal ? "formal " : "", parse_mode.sv ? "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; + AST::sv_mode = parse_mode.sv; - current_ast = new AST::AstNode(AST::AST_DESIGN); + parse_state.current_ast = new AST::AstNode(AST::AST_DESIGN); - lexin = f; + parse_state.lexin = f; std::string code_after_preproc; if (!flag_nopp) { - code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs); + code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs, parse_state, parse_mode); if (flag_ppdump) log("-- Verilog code after preprocessor --\n%s-- END OF DUMP --\n", code_after_preproc.c_str()); - lexin = new std::istringstream(code_after_preproc); + parse_state.lexin = new std::istringstream(code_after_preproc); } // make package typedefs available to parser - add_package_types(pkg_user_types, design->verilog_packages); + add_package_types(parse_state.pkg_user_types, design->verilog_packages); UserTypeMap global_types_map; - for (auto def : design->verilog_globals) { + for (auto& def : design->verilog_globals) { if (def->type == AST::AST_TYPEDEF) { - global_types_map[def->str] = def; + global_types_map[def->str] = def.get(); } } - log_assert(user_type_stack.empty()); + log_assert(parse_state.user_type_stack.empty()); // use previous global typedefs as bottom level of user type stack - user_type_stack.push_back(std::move(global_types_map)); + parse_state.user_type_stack.push_back(std::move(global_types_map)); // add a new empty type map to allow overriding existing global definitions - user_type_stack.push_back(UserTypeMap()); + parse_state.user_type_stack.push_back(UserTypeMap()); - frontend_verilog_yyset_lineno(1); - frontend_verilog_yyrestart(NULL); - frontend_verilog_yyparse(); - frontend_verilog_yylex_destroy(); + parser.~parser(); + lexer.~VerilogLexer(); + new (&lexer) VerilogLexer(&parse_state, &parse_mode); + new (&parser) frontend_verilog_yy::parser(&lexer, &parse_state, &parse_mode); + if (flag_yydebug) { + lexer.set_debug(true); + parser.set_debug_level(1); + } + parser.parse(); + // frontend_verilog_yyset_lineno(1); - for (auto &child : current_ast->children) { + for (auto &child : parse_state.current_ast->children) { if (child->type == AST::AST_MODULE) for (auto &attr : attributes) if (child->attributes.count(attr) == 0) @@ -524,21 +541,21 @@ struct VerilogFrontend : public Frontend { } if (flag_nodpi) - error_on_dpi_function(current_ast); + error_on_dpi_function(parse_state.current_ast); - AST::process(design, current_ast, flag_nodisplay, 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); + AST::process(design, parse_state.current_ast, flag_nodisplay, 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, parse_mode.lib, flag_nowb, flag_noopt, flag_icells, flag_pwires, flag_nooverwrite, flag_overwrite, flag_defer, parse_state.default_nettype_wire); if (!flag_nopp) - delete lexin; + delete parse_state.lexin; // only the previous and new global type maps remain - log_assert(user_type_stack.size() == 2); - user_type_stack.clear(); + log_assert(parse_state.user_type_stack.size() == 2); + parse_state.user_type_stack.clear(); - delete current_ast; - current_ast = NULL; + delete parse_state.current_ast; + parse_state.current_ast = NULL; log("Successfully finished Verilog frontend.\n"); } @@ -759,19 +776,33 @@ struct VerilogFileList : public Pass { #endif -YOSYS_NAMESPACE_END - -// the yyerror function used by bison to report parser errors -void frontend_verilog_yyerror(char const *fmt, ...) +[[noreturn]] +void VERILOG_FRONTEND::verr_at(std::string filename, int begin_line, char const *fmt, va_list ap) { - va_list ap; - char buffer[1024]; - char *p = buffer; - 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_file_error(YOSYS_NAMESPACE_PREFIX AST::current_filename, frontend_verilog_yyget_lineno(), - "%s", buffer); - exit(1); + char buffer[1024]; + char *p = buffer; + p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap); + p += snprintf(p, buffer + sizeof(buffer) - p, "\n"); + YOSYS_NAMESPACE_PREFIX log_file_error(filename, begin_line, "%s", buffer); + exit(1); } + +[[noreturn]] +void VERILOG_FRONTEND::err_at_loc(parser::location_type loc, char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + verr_at(AST::current_filename, loc.begin.line, fmt, args); + va_end(args); +} + +[[noreturn]] +void VERILOG_FRONTEND::err_at_ast(AstSrcLocType loc, char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + verr_at(AST::current_filename, loc.first_line, fmt, args); + va_end(args); +} + +YOSYS_NAMESPACE_END diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index 8454e7999..6426f57d8 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -31,6 +31,13 @@ #include "kernel/yosys.h" #include "frontends/ast/ast.h" +#include "frontends/verilog/location.hh" + +#if ! defined(yyFlexLexerOnce) +#define yyFlexLexer frontend_verilog_yyFlexLexer +#include +#endif + #include #include #include @@ -39,62 +46,33 @@ YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { - // this variable is set to a new AST_DESIGN node and then filled with the AST by the bison parser - extern struct AST::AstNode *current_ast; + /* 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); - // 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 in a stack - typedef std::map UserTypeMap; - extern std::vector user_type_stack; - - // names of package typedef'ed types - extern dict pkg_user_types; - - // state of `default_nettype - extern bool default_nettype_wire; - - // running in SystemVerilog mode - extern bool sv_mode; - - // running in -formal mode - extern bool formal_mode; - - // running in -noassert mode - extern bool noassert_mode; - - // running in -noassume mode - extern bool noassume_mode; - - // running in -norestrict mode - extern bool norestrict_mode; - - // running in -assume-asserts mode - extern bool assume_asserts_mode; - - // running in -assert-assumes mode - extern bool assert_assumes_mode; - - // running in -lib mode - extern bool lib_mode; - - // running in -specify mode - extern bool specify_mode; - - // lexer input stream - extern std::istream *lexin; -} + }; + [[noreturn]] + extern void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap); + [[noreturn]] + extern void err_at_loc(frontend_verilog_yy::location loc, char const *fmt, ...); + [[noreturn]] + extern void err_at_ast(AST::AstSrcLocType loc, char const *fmt, ...); +}; YOSYS_NAMESPACE_END -// the usual bison/flex stuff -extern int frontend_verilog_yydebug; -void frontend_verilog_yyerror(char const *fmt, ...); -void frontend_verilog_yyrestart(FILE *f); -int frontend_verilog_yyparse(void); -int frontend_verilog_yylex_destroy(void); -int frontend_verilog_yyget_lineno(void); -void frontend_verilog_yyset_lineno (int); - #endif diff --git a/frontends/verilog/verilog_lexer.h b/frontends/verilog/verilog_lexer.h new file mode 100644 index 000000000..7d73ae193 --- /dev/null +++ b/frontends/verilog/verilog_lexer.h @@ -0,0 +1,48 @@ +#ifndef VERILOG_LEXER_H +#define VERILOG_LEXER_H + +#include "kernel/yosys.h" +#include "frontends/ast/ast.h" +#include "frontends/verilog/verilog_parser.tab.hh" + +YOSYS_NAMESPACE_BEGIN + +namespace VERILOG_FRONTEND { + // lexer input stream + using parser = frontend_verilog_yy::parser; + class VerilogLexer : public frontend_verilog_yyFlexLexer { + ParseState* extra; + ParseMode* mode; + public: + VerilogLexer(ParseState* e, ParseMode* m) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) {} + ~VerilogLexer() override {} + // autogenerated body due to YY_DECL + parser::symbol_type nextToken(); + // get rid of override virtual function warning + using FlexLexer::yylex; + parser::symbol_type terminate() { + return parser::make_FRONTEND_VERILOG_YYEOF(out_loc); + } + parser::location_type out_loc; + [[noreturn]] + void err(char const *fmt, ...) + { + va_list args; + va_start(args, fmt); + verr_at(AST::current_filename, yylineno, fmt, args); + } + private: + std::vector fn_stack; + std::vector ln_stack; + parser::location_type real_loc; + parser::location_type old_loc; + int LexerInput(char* buf, int max_size) override { + return readsome(*extra->lexin, buf, max_size); + } + }; + +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 362288f29..0bc192327 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -32,6 +32,13 @@ * */ +%option c++ +%option yyclass="VerilogLexer" +%option noyywrap +%option nounput +%option yylineno +%option prefix="frontend_verilog_yy" + %{ #ifdef __clang__ @@ -41,85 +48,112 @@ #pragma clang diagnostic ignored "-Wmisleading-indentation" #endif -#include "kernel/log.h" -#include "frontends/verilog/verilog_frontend.h" +#include "frontends/verilog/verilog_lexer.h" #include "frontends/ast/ast.h" -#include "verilog_parser.tab.hh" +#include "kernel/log.h" +#include USING_YOSYS_NAMESPACE using namespace AST; using namespace VERILOG_FRONTEND; - -#define YYSTYPE FRONTEND_VERILOG_YYSTYPE -#define YYLTYPE FRONTEND_VERILOG_YYLTYPE +using parser = frontend_verilog_yy::parser; +//#define YYSTYPE FRONTEND_VERILOG_YYSTYPE +//#define YYLTYPE FRONTEND_VERILOG_YYLTYPE YOSYS_NAMESPACE_BEGIN -namespace VERILOG_FRONTEND { - std::vector fn_stack; - std::vector ln_stack; - YYLTYPE real_location; - YYLTYPE old_location; -} +#undef YY_DECL +#define YY_DECL parser::symbol_type VerilogLexer::nextToken() + +#undef yyterminate +#define yyterminate() terminate() + YOSYS_NAMESPACE_END #define SV_KEYWORD(_tok) \ - if (sv_mode) return _tok; \ + if (mode->sv) 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()); \ - yylval->string = new std::string(std::string("\\") + yytext); \ - return TOK_ID; + "recognized unless read_verilog is called with -sv!\n", YYText(), \ + AST::current_filename.c_str(), yylineno); \ + string_t val = new std::string(std::string("\\") + YYText()); \ + return parser::make_TOK_ID(val, out_loc); #define NON_KEYWORD() \ - yylval->string = new std::string(std::string("\\") + yytext); \ - return TOK_ID; + string_t val = new std::string(std::string("\\") + YYText()); \ + return parser::make_TOK_ID(val, out_loc); -#define YY_INPUT(buf,result,max_size) \ - result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size) +// #define YY_INPUT(buf,result,max_size) \ +// result = readsome(*extra->lexin, buf, max_size) #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; + real_loc.begin = real_loc.end; \ + for(int i = 0; YYText()[i] != '\0'; ++i){ \ + if(YYText()[i] == '\n') { \ + real_loc.end.line++; \ + real_loc.end.column = 1; \ + } \ + else { \ + real_loc.end.column++; \ + } \ + } \ + out_loc = real_loc; #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); - -static bool isUserType(std::string &s) +static bool isUserType(ParseState* extra, std::string &s) { // check current scope then outer scopes for a name - for (auto it = user_type_stack.rbegin(); it != user_type_stack.rend(); ++it) { + for (auto it = extra->user_type_stack.rbegin(); it != extra->user_type_stack.rend(); ++it) { if (it->count(s) > 0) { - return true; + return true; } } return false; } -%} +parser::symbol_type char_tok(char c, parser::location_type loc) { + switch (c) { + case '!': return parser::make_TOK_EXCL(loc); + case '#': return parser::make_TOK_HASH(loc); + case '%': return parser::make_TOK_PERC(loc); + case '&': return parser::make_TOK_AMP(loc); + case '(': return parser::make_TOK_LPAREN(loc); + case ')': return parser::make_TOK_RPAREN(loc); + case '*': return parser::make_TOK_ASTER(loc); + case '+': return parser::make_TOK_PLUS(loc); + case ',': return parser::make_TOK_COMMA(loc); + case '-': return parser::make_TOK_MINUS(loc); + case '.': return parser::make_TOK_DOT(loc); + case '/': return parser::make_TOK_SLASH(loc); + case ':': return parser::make_TOK_COL(loc); + case ';': return parser::make_TOK_SEMICOL(loc); + case '<': return parser::make_TOK_LT(loc); + case '=': return parser::make_TOK_EQ(loc); + case '>': return parser::make_TOK_GT(loc); + case '?': return parser::make_TOK_QUE(loc); + case '@': return parser::make_TOK_AT(loc); + case '[': return parser::make_TOK_LBRA(loc); + case ']': return parser::make_TOK_RBRA(loc); + case '^': return parser::make_TOK_CARET(loc); + case '_': return parser::make_TOK_UNDER(loc); + case '{': return parser::make_TOK_LCURL(loc); + case '|': return parser::make_TOK_PIPE(loc); + case '}': return parser::make_TOK_RCURL(loc); + case '~': return parser::make_TOK_TILDE(loc); + case 'n': return parser::make_TOK_n(loc); + case 'p': return parser::make_TOK_p(loc); + case 'x': return parser::make_TOK_x(loc); + case 'z': return parser::make_TOK_z(loc); + case 0: return parser::make_FRONTEND_VERILOG_YYEOF(loc); + default: + return parser::make_ch_t(c, loc); + } +} -%option yylineno -%option noyywrap -%option nounput -%option bison-locations -%option bison-bridge -%option prefix="frontend_verilog_yy" +%} %x COMMENT %x STRING @@ -134,47 +168,48 @@ FIXED_POINT_NUMBER_NO_DEC [0-9][0-9_]*[eE][-+]?[0-9_]+ TIME_SCALE_SUFFIX [munpf]?s %% + // Initialise comment_caller to something to avoid a "maybe undefined" // warning from GCC. int comment_caller = INITIAL; "`file_push "[^\n]* { fn_stack.push_back(current_filename); - ln_stack.push_back(frontend_verilog_yyget_lineno()); - current_filename = yytext+11; + ln_stack.push_back(yylineno); + 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); - yylloc->first_line = yylloc->last_line = 0; - real_location.first_line = real_location.last_line = 0; + yylineno = (0); + out_loc.begin.line = out_loc.end.line = 0; + real_loc.begin.line = real_loc.end.line = 0; } "`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(); + yylineno = (ln_stack.back()); + out_loc.begin.line = out_loc.end.line = ln_stack.back(); + real_loc.begin.line = real_loc.end.line = ln_stack.back(); ln_stack.pop_back(); } "`line"[ \t]+[^ \t\r\n]+[ \t]+\"[^ \r\n]+\"[^\r\n]*\n { - char *p = yytext + 5; + const 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); + yylineno = (atoi(p)); + out_loc.begin.line = out_loc.end.line = atoi(p); + real_loc.begin.line = real_loc.end.line = atoi(p); while (*p && *p != ' ' && *p != '\t') p++; while (*p == ' ' || *p == '\t') p++; - char *q = *p ? p + 1 : p; + const char *q = *p ? p + 1 : p; while (*q && *q != '"') q++; current_filename = std::string(p).substr(1, q-p-1); } "`file_notfound "[^\n]* { - log_error("Can't open include file `%s'!\n", yytext + 15); + log_error("Can't open include file `%s'!\n", YYText() + 15); } "`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */ @@ -183,165 +218,165 @@ TIME_SCALE_SUFFIX [munpf]?s "`endcelldefine"[^\n]* /* ignore `endcelldefine */ "`default_nettype"[ \t]+[^ \t\r\n/]+ { - char *p = yytext; + const char *p = YYText(); while (*p != 0 && *p != ' ' && *p != '\t') p++; while (*p == ' ' || *p == '\t') p++; if (!strcmp(p, "none")) - VERILOG_FRONTEND::default_nettype_wire = false; + extra->default_nettype_wire = false; else if (!strcmp(p, "wire")) - VERILOG_FRONTEND::default_nettype_wire = true; + extra->default_nettype_wire = true; else - frontend_verilog_yyerror("Unsupported default nettype: %s", p); + err("Unsupported default nettype: %s", p); } "`protect"[^\n]* /* ignore `protect*/ "`endprotect"[^\n]* /* ignore `endprotect*/ "`"[a-zA-Z_$][a-zA-Z0-9_$]* { - frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext); + err("Unimplemented compiler directive or undefined macro %s.", YYText()); } -"module" { return TOK_MODULE; } -"endmodule" { return TOK_ENDMODULE; } -"function" { return TOK_FUNCTION; } -"endfunction" { return TOK_ENDFUNCTION; } -"task" { return TOK_TASK; } -"endtask" { return TOK_ENDTASK; } -"specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; } -"endspecify" { return TOK_ENDSPECIFY; } -"specparam" { return TOK_SPECPARAM; } -"package" { SV_KEYWORD(TOK_PACKAGE); } -"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); } -"import" { SV_KEYWORD(TOK_IMPORT); } -"interface" { SV_KEYWORD(TOK_INTERFACE); } -"endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); } -"modport" { SV_KEYWORD(TOK_MODPORT); } -"parameter" { return TOK_PARAMETER; } -"localparam" { return TOK_LOCALPARAM; } -"defparam" { return TOK_DEFPARAM; } -"assign" { return TOK_ASSIGN; } -"always" { return TOK_ALWAYS; } -"initial" { return TOK_INITIAL; } -"begin" { return TOK_BEGIN; } -"end" { return TOK_END; } -"if" { return TOK_IF; } -"else" { return TOK_ELSE; } -"for" { return TOK_FOR; } -"posedge" { return TOK_POSEDGE; } -"negedge" { return TOK_NEGEDGE; } -"or" { return TOK_OR; } -"case" { return TOK_CASE; } -"casex" { return TOK_CASEX; } -"casez" { return TOK_CASEZ; } -"endcase" { return TOK_ENDCASE; } -"default" { return TOK_DEFAULT; } -"generate" { return TOK_GENERATE; } -"endgenerate" { return TOK_ENDGENERATE; } -"while" { return TOK_WHILE; } -"repeat" { return TOK_REPEAT; } -"automatic" { return TOK_AUTOMATIC; } +"module" { return parser::make_TOK_MODULE(out_loc); } +"endmodule" { return parser::make_TOK_ENDMODULE(out_loc); } +"function" { return parser::make_TOK_FUNCTION(out_loc); } +"endfunction" { return parser::make_TOK_ENDFUNCTION(out_loc); } +"task" { return parser::make_TOK_TASK(out_loc); } +"endtask" { return parser::make_TOK_ENDTASK(out_loc); } +"specify" { return mode->specify ? parser::make_TOK_SPECIFY(out_loc) : parser::make_TOK_IGNORED_SPECIFY(out_loc); } +"endspecify" { return parser::make_TOK_ENDSPECIFY(out_loc); } +"specparam" { return parser::make_TOK_SPECPARAM(out_loc); } +"package" { SV_KEYWORD(parser::make_TOK_PACKAGE(out_loc)); } +"endpackage" { SV_KEYWORD(parser::make_TOK_ENDPACKAGE(out_loc)); } +"import" { SV_KEYWORD(parser::make_TOK_IMPORT(out_loc)); } +"interface" { SV_KEYWORD(parser::make_TOK_INTERFACE(out_loc)); } +"endinterface" { SV_KEYWORD(parser::make_TOK_ENDINTERFACE(out_loc)); } +"modport" { SV_KEYWORD(parser::make_TOK_MODPORT(out_loc)); } +"parameter" { return parser::make_TOK_PARAMETER(out_loc); } +"localparam" { return parser::make_TOK_LOCALPARAM(out_loc); } +"defparam" { return parser::make_TOK_DEFPARAM(out_loc); } +"assign" { return parser::make_TOK_ASSIGN(out_loc); } +"always" { return parser::make_TOK_ALWAYS(out_loc); } +"initial" { return parser::make_TOK_INITIAL(out_loc); } +"begin" { return parser::make_TOK_BEGIN(out_loc); } +"end" { return parser::make_TOK_END(out_loc); } +"if" { return parser::make_TOK_IF(out_loc); } +"else" { return parser::make_TOK_ELSE(out_loc); } +"for" { return parser::make_TOK_FOR(out_loc); } +"posedge" { return parser::make_TOK_POSEDGE(out_loc); } +"negedge" { return parser::make_TOK_NEGEDGE(out_loc); } +"or" { return parser::make_TOK_OR(out_loc); } +"case" { return parser::make_TOK_CASE(out_loc); } +"casex" { return parser::make_TOK_CASEX(out_loc); } +"casez" { return parser::make_TOK_CASEZ(out_loc); } +"endcase" { return parser::make_TOK_ENDCASE(out_loc); } +"default" { return parser::make_TOK_DEFAULT(out_loc); } +"generate" { return parser::make_TOK_GENERATE(out_loc); } +"endgenerate" { return parser::make_TOK_ENDGENERATE(out_loc); } +"while" { return parser::make_TOK_WHILE(out_loc); } +"repeat" { return parser::make_TOK_REPEAT(out_loc); } +"automatic" { return parser::make_TOK_AUTOMATIC(out_loc); } -"unique" { SV_KEYWORD(TOK_UNIQUE); } -"unique0" { SV_KEYWORD(TOK_UNIQUE0); } -"priority" { SV_KEYWORD(TOK_PRIORITY); } +"unique" { SV_KEYWORD(parser::make_TOK_UNIQUE(out_loc)); } +"unique0" { SV_KEYWORD(parser::make_TOK_UNIQUE0(out_loc)); } +"priority" { SV_KEYWORD(parser::make_TOK_PRIORITY(out_loc)); } -"always_comb" { SV_KEYWORD(TOK_ALWAYS_COMB); } -"always_ff" { SV_KEYWORD(TOK_ALWAYS_FF); } -"always_latch" { SV_KEYWORD(TOK_ALWAYS_LATCH); } +"always_comb" { SV_KEYWORD(parser::make_TOK_ALWAYS_COMB(out_loc)); } +"always_ff" { SV_KEYWORD(parser::make_TOK_ALWAYS_FF(out_loc)); } +"always_latch" { SV_KEYWORD(parser::make_TOK_ALWAYS_LATCH(out_loc)); } /* use special token for labels on assert, assume, cover, and restrict because it's insanley complex to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some global state.. its a mess) */ [a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] { - if (!strcmp(yytext, "default")) - return TOK_DEFAULT; - yylval->string = new std::string(std::string("\\") + yytext); - return TOK_SVA_LABEL; + if (!strcmp(YYText(), "default")) + return parser::make_TOK_DEFAULT(out_loc); + string_t val = new std::string(std::string("\\") + YYText()); + return parser::make_TOK_SVA_LABEL(val, out_loc); } -"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); } -"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); } -"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); } -"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); } -"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); } -"rand" { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); } -"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } -"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } -"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } -"bind" { if (formal_mode) return TOK_BIND; SV_KEYWORD(TOK_BIND); } -"final" { SV_KEYWORD(TOK_FINAL); } -"logic" { SV_KEYWORD(TOK_LOGIC); } -"var" { SV_KEYWORD(TOK_VAR); } -"bit" { SV_KEYWORD(TOK_LOGIC); } -"int" { SV_KEYWORD(TOK_INT); } -"byte" { SV_KEYWORD(TOK_BYTE); } -"shortint" { SV_KEYWORD(TOK_SHORTINT); } -"longint" { SV_KEYWORD(TOK_LONGINT); } -"void" { SV_KEYWORD(TOK_VOID); } +"assert" { if (mode->formal) return parser::make_TOK_ASSERT(out_loc); SV_KEYWORD(parser::make_TOK_ASSERT(out_loc)); } +"assume" { if (mode->formal) return parser::make_TOK_ASSUME(out_loc); SV_KEYWORD(parser::make_TOK_ASSUME(out_loc)); } +"cover" { if (mode->formal) return parser::make_TOK_COVER(out_loc); SV_KEYWORD(parser::make_TOK_COVER(out_loc)); } +"restrict" { if (mode->formal) return parser::make_TOK_RESTRICT(out_loc); SV_KEYWORD(parser::make_TOK_RESTRICT(out_loc)); } +"property" { if (mode->formal) return parser::make_TOK_PROPERTY(out_loc); SV_KEYWORD(parser::make_TOK_PROPERTY(out_loc)); } +"rand" { if (mode->formal) return parser::make_TOK_RAND(out_loc); SV_KEYWORD(parser::make_TOK_RAND(out_loc)); } +"const" { if (mode->formal) return parser::make_TOK_CONST(out_loc); SV_KEYWORD(parser::make_TOK_CONST(out_loc)); } +"checker" { if (mode->formal) return parser::make_TOK_CHECKER(out_loc); SV_KEYWORD(parser::make_TOK_CHECKER(out_loc)); } +"endchecker" { if (mode->formal) return parser::make_TOK_ENDCHECKER(out_loc); SV_KEYWORD(parser::make_TOK_ENDCHECKER(out_loc)); } +"bind" { if (mode->formal) return parser::make_TOK_BIND(out_loc); SV_KEYWORD(parser::make_TOK_BIND(out_loc)); } +"final" { SV_KEYWORD(parser::make_TOK_FINAL(out_loc)); } +"logic" { SV_KEYWORD(parser::make_TOK_LOGIC(out_loc)); } +"var" { SV_KEYWORD(parser::make_TOK_VAR(out_loc)); } +"bit" { SV_KEYWORD(parser::make_TOK_LOGIC(out_loc)); } +"int" { SV_KEYWORD(parser::make_TOK_INT(out_loc)); } +"byte" { SV_KEYWORD(parser::make_TOK_BYTE(out_loc)); } +"shortint" { SV_KEYWORD(parser::make_TOK_SHORTINT(out_loc)); } +"longint" { SV_KEYWORD(parser::make_TOK_LONGINT(out_loc)); } +"void" { SV_KEYWORD(parser::make_TOK_VOID(out_loc)); } -"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } -"s_eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } +"eventually" { if (mode->formal) return parser::make_TOK_EVENTUALLY(out_loc); SV_KEYWORD(parser::make_TOK_EVENTUALLY(out_loc)); } +"s_eventually" { if (mode->formal) return parser::make_TOK_EVENTUALLY(out_loc); SV_KEYWORD(parser::make_TOK_EVENTUALLY(out_loc)); } -"input" { return TOK_INPUT; } -"output" { return TOK_OUTPUT; } -"inout" { return TOK_INOUT; } -"wire" { return TOK_WIRE; } -"tri" { return TOK_WIRE; } -"wor" { return TOK_WOR; } -"trior" { return TOK_WOR; } -"wand" { return TOK_WAND; } -"triand" { return TOK_WAND; } -"reg" { return TOK_REG; } -"integer" { return TOK_INTEGER; } -"signed" { return TOK_SIGNED; } -"unsigned" { SV_KEYWORD(TOK_UNSIGNED); } -"genvar" { return TOK_GENVAR; } -"real" { return TOK_REAL; } +"input" { return parser::make_TOK_INPUT(out_loc); } +"output" { return parser::make_TOK_OUTPUT(out_loc); } +"inout" { return parser::make_TOK_INOUT(out_loc); } +"wire" { return parser::make_TOK_WIRE(out_loc); } +"tri" { return parser::make_TOK_WIRE(out_loc); } +"wor" { return parser::make_TOK_WOR(out_loc); } +"trior" { return parser::make_TOK_WOR(out_loc); } +"wand" { return parser::make_TOK_WAND(out_loc); } +"triand" { return parser::make_TOK_WAND(out_loc); } +"reg" { return parser::make_TOK_REG(out_loc); } +"integer" { return parser::make_TOK_INTEGER(out_loc); } +"signed" { return parser::make_TOK_SIGNED(out_loc); } +"unsigned" { SV_KEYWORD(parser::make_TOK_UNSIGNED(out_loc)); } +"genvar" { return parser::make_TOK_GENVAR(out_loc); } +"real" { return parser::make_TOK_REAL(out_loc); } -"enum" { SV_KEYWORD(TOK_ENUM); } -"typedef" { SV_KEYWORD(TOK_TYPEDEF); } -"struct" { SV_KEYWORD(TOK_STRUCT); } -"union" { SV_KEYWORD(TOK_UNION); } -"packed" { SV_KEYWORD(TOK_PACKED); } +"enum" { SV_KEYWORD(parser::make_TOK_ENUM(out_loc)); } +"typedef" { SV_KEYWORD(parser::make_TOK_TYPEDEF(out_loc)); } +"struct" { SV_KEYWORD(parser::make_TOK_STRUCT(out_loc)); } +"union" { SV_KEYWORD(parser::make_TOK_UNION(out_loc)); } +"packed" { SV_KEYWORD(parser::make_TOK_PACKED(out_loc)); } {UNSIGNED_NUMBER} { - yylval->string = new std::string(yytext); - return TOK_CONSTVAL; + string_t val = new std::string(YYText()); + return parser::make_TOK_CONSTVAL(val, out_loc); } \'[01zxZX] { - yylval->string = new std::string(yytext); - return TOK_UNBASED_UNSIZED_CONSTVAL; + string_t val = new std::string(YYText()); + return parser::make_TOK_UNBASED_UNSIZED_CONSTVAL(val, out_loc); } \'[sS]?[bodhBODH] { BEGIN(BASED_CONST); - yylval->string = new std::string(yytext); - return TOK_BASE; + string_t val = new std::string(YYText()); + return parser::make_TOK_BASE(val, out_loc); } [0-9a-fA-FzxZX?][0-9a-fA-FzxZX?_]* { BEGIN(0); - yylval->string = new std::string(yytext); - return TOK_BASED_CONSTVAL; + string_t val = new std::string(YYText()); + return parser::make_TOK_BASED_CONSTVAL(val, out_loc); } {FIXED_POINT_NUMBER_DEC} { - yylval->string = new std::string(yytext); - return TOK_REALVAL; + string_t val = new std::string(YYText()); + return parser::make_TOK_REALVAL(val, out_loc); } {FIXED_POINT_NUMBER_NO_DEC} { - yylval->string = new std::string(yytext); - return TOK_REALVAL; + string_t val = new std::string(YYText()); + return parser::make_TOK_REALVAL(val, out_loc); } \" { BEGIN(STRING); } -([^\"]|\\.)+ { yymore(); real_location = old_location; } +([^\"]|\\.)+ { yymore(); } \" { BEGIN(0); - char *yystr = strdup(yytext); - yystr[strlen(yytext) - 1] = 0; + char *yystr = strdup(YYText()); + yystr[strlen(YYText()) - 1] = 0; int i = 0, j = 0; while (yystr[i]) { if (yystr[i] == '\\' && yystr[i + 1]) { @@ -373,71 +408,71 @@ TIME_SCALE_SUFFIX [munpf]?s yystr[j++] = yystr[i++]; } yystr[j] = 0; - yylval->string = new std::string(yystr, j); + string_t val = new std::string(yystr, j); free(yystr); - return TOK_STRING; + return parser::make_TOK_STRING(val, out_loc); } and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 { - yylval->string = new std::string(yytext); - return TOK_PRIMITIVE; + auto val = new std::string(YYText()); + return parser::make_TOK_PRIMITIVE(val, out_loc); } -supply0 { return TOK_SUPPLY0; } -supply1 { return TOK_SUPPLY1; } +supply0 { return parser::make_TOK_SUPPLY0(out_loc); } +supply1 { return parser::make_TOK_SUPPLY1(out_loc); } "$"(display[bho]?|write[bho]?|strobe|monitor|time|realtime|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) { - yylval->string = new std::string(yytext); - return TOK_ID; + auto val = new std::string(YYText()); + return parser::make_TOK_ID(val, out_loc); } "$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) { - if (!specify_mode) REJECT; - yylval->string = new std::string(yytext); - return TOK_ID; + if (!mode->specify) REJECT; + auto val = new std::string(YYText()); + return parser::make_TOK_ID(val, out_loc); } "$"(info|warning|error|fatal) { - yylval->string = new std::string(yytext); - return TOK_MSG_TASKS; + auto val = new std::string(YYText()); + return parser::make_TOK_MSG_TASKS(val, out_loc); } -"$signed" { return TOK_TO_SIGNED; } -"$unsigned" { return TOK_TO_UNSIGNED; } +"$signed" { return parser::make_TOK_TO_SIGNED(out_loc); } +"$unsigned" { return parser::make_TOK_TO_UNSIGNED(out_loc); } [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) { + auto s = std::string("\\") + YYText(); + if (extra->pkg_user_types.count(s) > 0) { // package qualified typedefed name - yylval->string = new std::string(s); - return TOK_PKG_USER_TYPE; + auto val = new std::string(s); + return parser::make_TOK_PKG_USER_TYPE(val, out_loc); } else { // backup before :: just return first part - size_t len = strchr(yytext, ':') - yytext; + size_t len = strchr(YYText(), ':') - YYText(); yyless(len); - yylval->string = new std::string(std::string("\\") + yytext); - return TOK_ID; + auto val = new std::string(std::string("\\") + YYText()); + return parser::make_TOK_ID(val, out_loc); } } [a-zA-Z_$][a-zA-Z0-9_$]* { - auto s = std::string("\\") + yytext; - if (isUserType(s)) { + auto s = std::string("\\") + YYText(); + if (isUserType(extra, s)) { // previously typedefed name - yylval->string = new std::string(s); - return TOK_USER_TYPE; + auto val = new std::string(s); + return parser::make_TOK_USER_TYPE(val, out_loc); } else { - yylval->string = new std::string(std::string("\\") + yytext); - return TOK_ID; + auto val = new std::string(std::string("\\") + YYText()); + return parser::make_TOK_ID(val, out_loc); } } [a-zA-Z_$][a-zA-Z0-9_$\.]* { - yylval->string = new std::string(std::string("\\") + yytext); - return TOK_ID; + auto val = new std::string(std::string("\\") + YYText()); + return parser::make_TOK_ID(val, out_loc); } "/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" { @@ -473,7 +508,7 @@ supply1 { return TOK_SUPPLY1; } ); printed_warning = true; } - return TOK_SYNOPSYS_FULL_CASE; + return parser::make_TOK_SYNOPSYS_FULL_CASE(out_loc); } parallel_case { static bool printed_warning = false; @@ -487,119 +522,115 @@ supply1 { return TOK_SUPPLY1; } ); printed_warning = true; } - return TOK_SYNOPSYS_PARALLEL_CASE; + return parser::make_TOK_SYNOPSYS_PARALLEL_CASE(out_loc); } . /* ignore everything else */ "*/" { BEGIN(0); } import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { BEGIN(IMPORT_DPI); - return TOK_DPI_FUNCTION; + return parser::make_TOK_DPI_FUNCTION(out_loc); } [a-zA-Z_$][a-zA-Z0-9_$]* { - yylval->string = new std::string(std::string("\\") + yytext); - return TOK_ID; + auto val = new std::string(std::string("\\") + YYText()); + return parser::make_TOK_ID(val, out_loc); } [ \t\r\n] /* ignore whitespaces */ ";" { BEGIN(0); - return *yytext; + return char_tok(*YYText(), out_loc); } . { - return *yytext; + return char_tok(*YYText(), out_loc); } "\\"[^ \t\r\n]+ { - yylval->string = new std::string(yytext); - return TOK_ID; + auto val = new std::string(YYText()); + return parser::make_TOK_ID(val, out_loc); } -"(*" { return ATTR_BEGIN; } -"*)" { return ATTR_END; } +"(*" { return parser::make_ATTR_BEGIN(out_loc); } +"*)" { return parser::make_ATTR_END(out_loc); } -"{*" { return DEFATTR_BEGIN; } -"*}" { return DEFATTR_END; } +"{*" { return parser::make_DEFATTR_BEGIN(out_loc); } +"*}" { return parser::make_DEFATTR_END(out_loc); } -"**" { return OP_POW; } -"||" { return OP_LOR; } -"&&" { return OP_LAND; } -"==" { return OP_EQ; } -"!=" { return OP_NE; } -"<=" { return OP_LE; } -">=" { return OP_GE; } +"**" { return parser::make_OP_POW(out_loc); } +"||" { return parser::make_OP_LOR(out_loc); } +"&&" { return parser::make_OP_LAND(out_loc); } +"==" { return parser::make_OP_EQ(out_loc); } +"!=" { return parser::make_OP_NE(out_loc); } +"<=" { return parser::make_OP_LE(out_loc); } +">=" { return parser::make_OP_GE(out_loc); } -"===" { return OP_EQX; } -"!==" { return OP_NEX; } +"===" { return parser::make_OP_EQX(out_loc); } +"!==" { return parser::make_OP_NEX(out_loc); } -"~&" { return OP_NAND; } -"~|" { return OP_NOR; } -"~^" { return OP_XNOR; } -"^~" { return OP_XNOR; } +"~&" { return parser::make_OP_NAND(out_loc); } +"~|" { return parser::make_OP_NOR(out_loc); } +"~^" { return parser::make_OP_XNOR(out_loc); } +"^~" { return parser::make_OP_XNOR(out_loc); } -"<<" { return OP_SHL; } -">>" { return OP_SHR; } -"<<<" { return OP_SSHL; } -">>>" { return OP_SSHR; } +"<<" { return parser::make_OP_SHL(out_loc); } +">>" { return parser::make_OP_SHR(out_loc); } +"<<<" { return parser::make_OP_SSHL(out_loc); } +">>>" { return parser::make_OP_SSHR(out_loc); } -"'" { return OP_CAST; } +"'" { return parser::make_OP_CAST(out_loc); } -"::" { return TOK_PACKAGESEP; } -"++" { return TOK_INCREMENT; } -"--" { return TOK_DECREMENT; } +"::" { return parser::make_TOK_PACKAGESEP(out_loc); } +"++" { return parser::make_TOK_INCREMENT(out_loc); } +"--" { return parser::make_TOK_DECREMENT(out_loc); } -"+:" { return TOK_POS_INDEXED; } -"-:" { return TOK_NEG_INDEXED; } +"+:" { return parser::make_TOK_POS_INDEXED(out_loc); } +"-:" { return parser::make_TOK_NEG_INDEXED(out_loc); } -".*" { return TOK_WILDCARD_CONNECT; } +".*" { return parser::make_TOK_WILDCARD_CONNECT(out_loc); } -"|=" { SV_KEYWORD(TOK_BIT_OR_ASSIGN); } -"&=" { SV_KEYWORD(TOK_BIT_AND_ASSIGN); } -"+=" { SV_KEYWORD(TOK_ADD_ASSIGN); } -"-=" { SV_KEYWORD(TOK_SUB_ASSIGN); } -"^=" { SV_KEYWORD(TOK_BIT_XOR_ASSIGN); } -"/=" { SV_KEYWORD(TOK_DIV_ASSIGN); } -"%=" { SV_KEYWORD(TOK_MOD_ASSIGN); } -"*=" { SV_KEYWORD(TOK_MUL_ASSIGN); } -"<<=" { SV_KEYWORD(TOK_SHL_ASSIGN); } -">>=" { SV_KEYWORD(TOK_SHR_ASSIGN); } -"<<<=" { SV_KEYWORD(TOK_SSHL_ASSIGN); } -">>>=" { SV_KEYWORD(TOK_SSHR_ASSIGN); } +"|=" { SV_KEYWORD(parser::make_TOK_BIT_OR_ASSIGN(out_loc)); } +"&=" { SV_KEYWORD(parser::make_TOK_BIT_AND_ASSIGN(out_loc)); } +"+=" { SV_KEYWORD(parser::make_TOK_ADD_ASSIGN(out_loc)); } +"-=" { SV_KEYWORD(parser::make_TOK_SUB_ASSIGN(out_loc)); } +"^=" { SV_KEYWORD(parser::make_TOK_BIT_XOR_ASSIGN(out_loc)); } +"/=" { SV_KEYWORD(parser::make_TOK_DIV_ASSIGN(out_loc)); } +"%=" { SV_KEYWORD(parser::make_TOK_MOD_ASSIGN(out_loc)); } +"*=" { SV_KEYWORD(parser::make_TOK_MUL_ASSIGN(out_loc)); } +"<<=" { SV_KEYWORD(parser::make_TOK_SHL_ASSIGN(out_loc)); } +">>=" { SV_KEYWORD(parser::make_TOK_SHR_ASSIGN(out_loc)); } +"<<<=" { SV_KEYWORD(parser::make_TOK_SSHL_ASSIGN(out_loc)); } +">>>=" { SV_KEYWORD(parser::make_TOK_SSHR_ASSIGN(out_loc)); } [-+]?[=*]> { - if (!specify_mode) REJECT; - yylval->string = new std::string(yytext); - return TOK_SPECIFY_OPER; + if (!mode->specify) REJECT; + auto val = new std::string(YYText()); + return parser::make_TOK_SPECIFY_OPER(val, out_loc); } "&&&" { - if (!specify_mode) return TOK_IGNORED_SPECIFY_AND; - return TOK_SPECIFY_AND; + if (!mode->specify) return parser::make_TOK_IGNORED_SPECIFY_AND(out_loc); + return parser::make_TOK_SPECIFY_AND(out_loc); } -{UNSIGNED_NUMBER}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; } -{FIXED_POINT_NUMBER_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; } -{FIXED_POINT_NUMBER_NO_DEC}{TIME_SCALE_SUFFIX} { return TOK_TIME_SCALE; } +{UNSIGNED_NUMBER}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); } +{FIXED_POINT_NUMBER_DEC}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); } +{FIXED_POINT_NUMBER_NO_DEC}{TIME_SCALE_SUFFIX} { return parser::make_TOK_TIME_SCALE(out_loc); } "/*" { comment_caller=YY_START; BEGIN(COMMENT); } . /* ignore comment body */ \n /* ignore comment body */ "*/" { BEGIN(comment_caller); } + [ \t\r\n] /* ignore whitespaces */ \\[\r\n] /* ignore continuation sequence */ "//"[^\r\n]* /* ignore one-line comments */ -. { return *yytext; } -<*>. { BEGIN(0); return *yytext; } +. { return char_tok(*YYText(), out_loc); } +<*>. { BEGIN(0); return char_tok(*YYText(), out_loc); } %% -// this is a hack to avoid the 'yyinput defined but not used' error msgs -void *frontend_verilog_avoid_input_warnings() { - return (void*)&yyinput; -} - diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 3cd582378..14ea0d615 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -34,366 +34,479 @@ */ %require "3.0" +%language "c++" +%define api.value.type variant +%define api.prefix {frontend_verilog_yy} +%define api.token.constructor -%{ -#include -#include -#include -#include "frontends/verilog/verilog_frontend.h" -#include "frontends/verilog/verilog_parser.tab.hh" -#include "kernel/log.h" +%param { YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::VerilogLexer* lexer } +%parse-param { YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::ParseState* extra } +%parse-param { YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::ParseMode* mode } -#define YYLEX_PARAM &yylval, &yylloc - -USING_YOSYS_NAMESPACE -using namespace AST; -using namespace VERILOG_FRONTEND; - -YOSYS_NAMESPACE_BEGIN -namespace VERILOG_FRONTEND { - int port_counter; - dict port_stubs; - dict *attr_list, default_attr_list; - std::stack *> attr_list_stack; - dict *albuf; - std::vector user_type_stack; - dict pkg_user_types; - std::vector ast_stack; - struct AstNode *astbuf1, *astbuf2, *astbuf3; - struct AstNode *current_function_or_task; - struct AstNode *current_ast, *current_ast_mod; - int current_function_or_task_port_id; - std::vector case_type_stack; - bool do_not_require_port_stubs; - bool default_nettype_wire; - bool sv_mode, formal_mode, lib_mode, specify_mode; - bool noassert_mode, noassume_mode, norestrict_mode; - bool assume_asserts_mode, assert_assumes_mode; - bool current_wire_rand, current_wire_const; - bool current_modport_input, current_modport_output; - std::istream *lexin; +%code requires { + #include "kernel/yosys_common.h" + // #include "frontends/verilog/verilog_lexer.h" + // start requires + YOSYS_NAMESPACE_BEGIN + namespace VERILOG_FRONTEND { + struct ParseState; + struct ParseMode; + class VerilogLexer; + }; + YOSYS_NAMESPACE_END + // end requires } -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) +%code provides { + // start provides + USING_YOSYS_NAMESPACE; + using namespace AST; + using namespace VERILOG_FRONTEND; + using parser = frontend_verilog_yy::parser; + YOSYS_NAMESPACE_BEGIN + namespace VERILOG_FRONTEND { + typedef std::map UserTypeMap; + struct ParseState { + // TODO initialization? + int port_counter; + dict port_stubs; + dict> *attr_list, default_attr_list; + std::stack> *> attr_list_stack; + dict> *albuf; + std::vector user_type_stack; + dict pkg_user_types; + std::vector ast_stack; + std::unique_ptr astbuf1, astbuf2, astbuf3; + AstNode* cell_hack; + AstNode* member_hack; + struct AstNode *current_function_or_task; + struct AstNode *current_ast, *current_ast_mod; + int current_function_or_task_port_id; + std::vector case_type_stack; + bool do_not_require_port_stubs; + bool current_wire_rand, current_wire_const; + bool current_modport_input, current_modport_output; + bool default_nettype_wire = true; + std::istream* lexin; -#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) + AstNode* saveChild(std::unique_ptr child); + AstNode* pushChild(std::unique_ptr child); + void addWiretypeNode(std::string *name, AstNode* node); + void addTypedefNode(std::string *name, std::unique_ptr node); + void enterTypeScope(); + void exitTypeScope(); + bool isInLocalScope(const std::string *name); + void rewriteGenForDeclInit(AstNode *loop); + void ensureAsgnExprAllowed(const parser::location_type loc, bool sv_mode); + const AstNode *addIncOrDecStmt(dict> *stmt_attr, + std::unique_ptr lhs, + dict> *op_attr, AST::AstNodeType op, + parser::location_type begin, parser::location_type end); + std::unique_ptr addIncOrDecExpr(std::unique_ptr lhs, dict> *attr, AST::AstNodeType op, parser::location_type begin, parser::location_type end, bool undo, bool sv_mode); + // add a binary operator assignment statement, e.g., a += b + std::unique_ptr addAsgnBinopStmt(dict> *attr, std::unique_ptr eq_lhs, AST::AstNodeType op, std::unique_ptr rhs, parser::location_type begin, parser::location_type end); + }; + struct ParseMode { + bool noassert = false; + bool noassume = false; + bool norestrict = false; + bool sv = false; + bool formal = false; + bool lib = false; + bool specify = false; + bool assume_asserts = false; + bool assert_assumes = false; + }; + }; + YOSYS_NAMESPACE_END + // end provides +} -int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param); +%code { + // start unqual + #include + #include + #include + #include + #include "kernel/log.h" + #include "frontends/verilog/verilog_lexer.h" -static void append_attr(AstNode *ast, dict *al) -{ - for (auto &it : *al) { - if (ast->attributes.count(it.first) > 0) - delete ast->attributes[it.first]; - ast->attributes[it.first] = it.second; + USING_YOSYS_NAMESPACE + using namespace AST; + using namespace VERILOG_FRONTEND; + + // Silly little C adapter between C++ bison and C++ flex + auto frontend_verilog_yylex(YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::VerilogLexer* lexer) { + return lexer->nextToken(); } - delete al; -} -static void append_attr_clone(AstNode *ast, dict *al) -{ - for (auto &it : *al) { - if (ast->attributes.count(it.first) > 0) - delete ast->attributes[it.first]; - ast->attributes[it.first] = it.second->clone(); - } -} + #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) -static void free_attr(dict *al) -{ - for (auto &it : *al) - delete it.second; - delete al; -} + #define SET_AST_NODE_LOC(WHICH, BEGIN, END) SET_LOC((WHICH)->location, BEGIN, END) -struct specify_target { - char polarity_op; - AstNode *dst, *dat; -}; + #define SET_RULE_LOC(LHS, BEGIN, END) \ + do { (LHS).begin = BEGIN.begin; \ + (LHS).end = (END).end; } while(0) -struct specify_triple { - AstNode *t_min, *t_avg, *t_max; -}; - -struct specify_rise_fall { - specify_triple rise; - specify_triple fall; -}; - -static void addWiretypeNode(std::string *name, AstNode *node) -{ - log_assert(node); - node->is_custom_type = true; - node->children.push_back(new AstNode(AST_WIRETYPE)); - node->children.back()->str = *name; - delete name; -} - -static void addTypedefNode(std::string *name, AstNode *node) -{ - log_assert(node); - auto *tnode = new AstNode(AST_TYPEDEF, node); - tnode->str = *name; - auto &user_types = user_type_stack.back(); - 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 void enterTypeScope() -{ - user_type_stack.push_back(UserTypeMap()); -} - -static void exitTypeScope() -{ - user_type_stack.pop_back(); -} - -static bool isInLocalScope(const std::string *name) -{ - // tests if a name was declared in the current block scope - auto &user_types = user_type_stack.back(); - return (user_types.count(*name) > 0); -} - -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); -} - -static AstNode *checkRange(AstNode *type_node, AstNode *range_node) -{ - if (type_node->range_left >= 0 && type_node->range_right >= 0) { - // type already restricts the range - if (range_node) { - frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions."); + 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; } - else { - range_node = makeRange(type_node->range_left, type_node->range_right, false); + static void append_attr(AstNode *ast, dict> *al) + { + for (auto &it : *al) { + ast->attributes[it.first] = std::move(it.second); + } + delete al; } - } - if (range_node) { - bool valid = true; - if (range_node->type == AST_RANGE) { - valid = range_node->children.size() == 2; - } else { // AST_MULTIRANGE - for (auto child : range_node->children) { - valid = valid && child->children.size() == 2; + static void append_attr_clone(AstNode *ast, dict> *al) + { + for (auto &it : *al) { + ast->attributes[it.first] = it.second->clone(); } } - if (!valid) - frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form [:]"); - } - return range_node; -} + static void free_attr(dict> *al) + { + delete al; + } -static void rewriteRange(AstNode *rangeNode) -{ - if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) { - // SV array size [n], rewrite as [0:n-1] - rangeNode->children.push_back(new AstNode(AST_SUB, rangeNode->children[0], AstNode::mkconst_int(1, true))); - rangeNode->children[0] = AstNode::mkconst_int(0, false); - } -} + static std::unique_ptr makeRange(int msb = 31, int lsb = 0, bool isSigned = true) + { + auto range = std::make_unique(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 rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode) -{ - node->type = AST_MEMORY; - if (rangeNode->type == AST_MULTIRANGE) { - for (auto *itr : rangeNode->children) - rewriteRange(itr); - } else - rewriteRange(rangeNode); - node->children.push_back(rangeNode); -} + static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = true) + { + auto range = makeRange(msb, lsb, isSigned); + parent->children.push_back(std::move(range)); + } -static void checkLabelsMatch(const char *element, const std::string *before, const std::string *after) -{ - if (!before && after) - frontend_verilog_yyerror("%s missing where end label (%s) was given.", - element, after->c_str() + 1); - if (before && after && *before != *after) - frontend_verilog_yyerror("%s (%s) and end label (%s) don't match.", - element, before->c_str() + 1, after->c_str() + 1); -} + static std::unique_ptr checkRange(AstNode *type_node, std::unique_ptr range_node) + { + if (type_node->range_left >= 0 && type_node->range_right >= 0) { + // type already restricts the range + if (range_node) { + err_at_ast(type_node->location, "integer/genvar types cannot have packed dimensions."); + } + else { + range_node = makeRange(type_node->range_left, type_node->range_right, false); + } + } -// This transforms a loop like -// for (genvar i = 0; i < 10; i++) begin : blk -// to -// genvar _i; -// for (_i = 0; _i < 10; _i++) begin : blk -// localparam i = _i; -// where `_i` is actually some auto-generated name. -static void rewriteGenForDeclInit(AstNode *loop) -{ - // check if this generate for loop contains an inline declaration - log_assert(loop->type == AST_GENFOR); - AstNode *decl = loop->children[0]; - if (decl->type == AST_ASSIGN_EQ) - return; - log_assert(decl->type == AST_GENVAR); - log_assert(loop->children.size() == 5); + if (range_node) { + bool valid = true; + if (range_node->type == AST_RANGE) { + valid = range_node->children.size() == 2; + } else { // AST_MULTIRANGE + for (auto& child : range_node->children) { + valid = valid && child->children.size() == 2; + } + } + if (!valid) + err_at_ast(type_node->location, "wire/reg/logic packed dimension must be of the form [:]"); + } - // identify each component of the loop - AstNode *init = loop->children[1]; - AstNode *cond = loop->children[2]; - AstNode *incr = loop->children[3]; - AstNode *body = loop->children[4]; - log_assert(init->type == AST_ASSIGN_EQ); - log_assert(incr->type == AST_ASSIGN_EQ); - log_assert(body->type == AST_GENBLOCK); + return range_node; + } - // create a unique name for the genvar - std::string old_str = decl->str; - std::string new_str = stringf("$genfordecl$%d$%s", autoidx++, old_str.c_str()); + static void rewriteRange(AstNode *rangeNode) + { + if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) { + // SV array size [n], rewrite as [0:n-1] + rangeNode->children.push_back(std::make_unique(AST_SUB, std::move(rangeNode->children[0]), AstNode::mkconst_int(1, true))); + rangeNode->children[0] = AstNode::mkconst_int(0, false); + } + } - // rename and move the genvar declaration to the containing description - decl->str = new_str; - loop->children.erase(loop->children.begin()); - log_assert(current_ast_mod != nullptr); - current_ast_mod->children.push_back(decl); + static void rewriteAsMemoryNode(AstNode *node, std::unique_ptr rangeNode) + { + node->type = AST_MEMORY; + if (rangeNode->type == AST_MULTIRANGE) { + for (auto& child : rangeNode->children) + rewriteRange(child.get()); + } else + rewriteRange(rangeNode.get()); + node->children.push_back(std::move(rangeNode)); + } - // create a new localparam with old name so that the items in the loop - // can simply use the old name and shadow it as necessary - AstNode *indirect = new AstNode(AST_LOCALPARAM); - indirect->str = old_str; - AstNode *ident = new AstNode(AST_IDENTIFIER); - ident->str = new_str; - indirect->children.push_back(ident); + static void checkLabelsMatch(const frontend_verilog_yy::parser::location_type& loc, const char *element, const std::string *before, const std::string *after) + { + if (!before && after) + err_at_loc(loc, "%s missing where end label (%s) was given.", + element, after->c_str() + 1); + if (before && after && *before != *after) + err_at_loc(loc, "%s (%s) and end label (%s) don't match.", + element, before->c_str() + 1, after->c_str() + 1); + } - body->children.insert(body->children.begin(), indirect); + AstNode* ParseState::saveChild(std::unique_ptr child) { + auto* child_leaky = child.get(); + ast_stack.back()->children.push_back(std::move(child)); + return child_leaky; + } + AstNode* ParseState::pushChild(std::unique_ptr child) { + auto* child_leaky = saveChild(std::move(child)); + ast_stack.push_back(child_leaky); + return child_leaky; + } - // only perform the renaming for the initialization, guard, and - // incrementation to enable proper shadowing of the synthetic localparam - std::function substitute = [&](AstNode *node) { - if (node->type == AST_IDENTIFIER && node->str == old_str) - node->str = new_str; - for (AstNode *child : node->children) - substitute(child); + void ParseState::addWiretypeNode(std::string *name, AstNode* node) + { + log_assert(node); + node->is_custom_type = true; + node->children.push_back(std::make_unique(AST_WIRETYPE)); + node->children.back()->str = *name; + delete name; + } + + void ParseState::addTypedefNode(std::string *name, std::unique_ptr node) + { + log_assert((bool)node); + AstNode* tnode = saveChild(std::make_unique(AST_TYPEDEF, std::move(node))); + log_assert((bool)name); + tnode->str = *name; + auto &user_types = user_type_stack.back(); + 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; + } + + void ParseState::enterTypeScope() + { + user_type_stack.push_back(UserTypeMap()); + } + + void ParseState::exitTypeScope() + { + user_type_stack.pop_back(); + } + + bool ParseState::isInLocalScope(const std::string *name) + { + // tests if a name was declared in the current block scope + auto &user_types = user_type_stack.back(); + return (user_types.count(*name) > 0); + } + + // This transforms a loop like + // for (genvar i = 0; i < 10; i++) begin : blk + // to + // genvar _i; + // for (_i = 0; _i < 10; _i++) begin : blk + // localparam i = _i; + // where `_i` is actually some auto-generated name. + void ParseState::rewriteGenForDeclInit(AstNode *loop) + { + // check if this generate for loop contains an inline declaration + log_assert(loop->type == AST_GENFOR); + auto& decl = loop->children[0]; + if (decl->type == AST_ASSIGN_EQ) + return; + + log_assert(decl->type == AST_GENVAR); + log_assert(loop->children.size() == 5); + + // identify each component of the loop + AstNode *init = loop->children[1].get(); + AstNode *cond = loop->children[2].get(); + AstNode *incr = loop->children[3].get(); + AstNode *body = loop->children[4].get(); + log_assert(init->type == AST_ASSIGN_EQ); + log_assert(incr->type == AST_ASSIGN_EQ); + log_assert(body->type == AST_GENBLOCK); + + // create a unique name for the genvar + std::string old_str = decl->str; + std::string new_str = stringf("$genfordecl$%d$%s", autoidx++, old_str.c_str()); + + // rename and move the genvar declaration to the containing description + decl->str = new_str; + log_assert(current_ast_mod != nullptr); + current_ast_mod->children.push_back(std::move(decl)); + + // create a new localparam with old name so that the items in the loop + // can simply use the old name and shadow it as necessary + auto indirect = std::make_unique(AST_LOCALPARAM); + indirect->str = old_str; + auto ident = std::make_unique(AST_IDENTIFIER); + ident->str = new_str; + indirect->children.push_back(std::move(ident)); + + body->children.insert(body->children.begin(), std::move(indirect)); + + // only perform the renaming for the initialization, guard, and + // incrementation to enable proper shadowing of the synthetic localparam + std::function substitute = [&](AstNode *node) { + if (node->type == AST_IDENTIFIER && node->str == old_str) + node->str = new_str; + for (auto& child : node->children) + substitute(child.get()); + }; + substitute(init); + substitute(cond); + substitute(incr); + loop->children.erase(loop->children.begin()); + } + + void ParseState::ensureAsgnExprAllowed(const parser::location_type loc, bool sv_mode) + { + if (!sv_mode) + err_at_loc(loc, "Assignments within expressions are only supported in SystemVerilog mode."); + if (ast_stack.back()->type != AST_BLOCK) + err_at_loc(loc, "Assignments within expressions are only permitted within procedures."); + } + + // add a pre/post-increment/decrement statement + const AstNode *ParseState::addIncOrDecStmt(dict> *stmt_attr, + std::unique_ptr lhs, + dict> *op_attr, AST::AstNodeType op, + frontend_verilog_yy::location begin, frontend_verilog_yy::location end) + { + auto one = AstNode::mkconst_int(1, true); + auto rhs = std::make_unique(op, lhs->clone(), std::move(one)); + if (op_attr != nullptr) + append_attr(rhs.get(), op_attr); + auto stmt_owned = std::make_unique(AST_ASSIGN_EQ, std::move(lhs), std::move(rhs)); + auto* stmt = stmt_owned.get(); + ast_stack.back()->children.push_back(std::move(stmt_owned)); + SET_AST_NODE_LOC(stmt, begin, end); + if (stmt_attr != nullptr) + append_attr(stmt, stmt_attr); + return stmt; + } + + // create a pre/post-increment/decrement expression, and add the corresponding statement + std::unique_ptr ParseState::addIncOrDecExpr(std::unique_ptr lhs, dict> *attr, AST::AstNodeType op, frontend_verilog_yy::location begin, frontend_verilog_yy::location end, bool undo, bool sv_mode) + { + ensureAsgnExprAllowed(begin, sv_mode); + const AstNode *stmt = addIncOrDecStmt(nullptr, std::move(lhs), attr, op, begin, end); + log_assert(stmt->type == AST_ASSIGN_EQ); + auto expr = stmt->children[0]->clone(); + if (undo) { + auto one = AstNode::mkconst_int(1, false, 1); + auto minus_one = std::make_unique(AST_NEG, std::move(one)); + expr = std::make_unique(op, std::move(expr), std::move(minus_one)); + } + SET_AST_NODE_LOC(expr.get(), begin, end); + return expr; + } + + // add a binary operator assignment statement, e.g., a += b + std::unique_ptr ParseState::addAsgnBinopStmt(dict> *attr, std::unique_ptr eq_lhs, AST::AstNodeType op, std::unique_ptr rhs, frontend_verilog_yy::location begin, frontend_verilog_yy::location end) + { + SET_AST_NODE_LOC(rhs.get(), end, end); + if (op == AST_SHIFT_LEFT || op == AST_SHIFT_RIGHT || + op == AST_SHIFT_SLEFT || op == AST_SHIFT_SRIGHT) { + rhs = std::make_unique(AST_TO_UNSIGNED, std::move(rhs)); + SET_AST_NODE_LOC(rhs.get(), end, end); + } + auto binop_lhs = eq_lhs->clone(); + auto eq_rhs_owned = std::make_unique(op, std::move(binop_lhs), std::move(rhs)); + auto* eq_rhs = eq_rhs_owned.get(); + auto ret_lhs = eq_lhs->clone(); + auto stmt_owned = std::make_unique(AST_ASSIGN_EQ, std::move(eq_lhs), std::move(eq_rhs_owned)); + auto* stmt = stmt_owned.get(); + SET_AST_NODE_LOC(eq_rhs, begin, end); + SET_AST_NODE_LOC(stmt, begin, end); + ast_stack.back()->children.push_back(std::move(stmt_owned)); + if (attr != nullptr) + append_attr(stmt, attr); + return ret_lhs; + } }; - substitute(init); - substitute(cond); - substitute(incr); -} + YOSYS_NAMESPACE_END -static void ensureAsgnExprAllowed() -{ - if (!sv_mode) - frontend_verilog_yyerror("Assignments within expressions are only supported in SystemVerilog mode."); - if (ast_stack.back()->type != AST_BLOCK) - frontend_verilog_yyerror("Assignments within expressions are only permitted within procedures."); -} - -// add a pre/post-increment/decrement statement -static const AstNode *addIncOrDecStmt(dict *stmt_attr, AstNode *lhs, - dict *op_attr, AST::AstNodeType op, - YYLTYPE begin, YYLTYPE end) -{ - AstNode *one = AstNode::mkconst_int(1, true); - AstNode *rhs = new AstNode(op, lhs->clone(), one); - if (op_attr != nullptr) - append_attr(rhs, op_attr); - AstNode *stmt = new AstNode(AST_ASSIGN_EQ, lhs, rhs); - SET_AST_NODE_LOC(stmt, begin, end); - if (stmt_attr != nullptr) - append_attr(stmt, stmt_attr); - ast_stack.back()->children.push_back(stmt); - return stmt; -} - -// create a pre/post-increment/decrement expression, and add the corresponding statement -static AstNode *addIncOrDecExpr(AstNode *lhs, dict *attr, AST::AstNodeType op, YYLTYPE begin, YYLTYPE end, bool undo) -{ - ensureAsgnExprAllowed(); - const AstNode *stmt = addIncOrDecStmt(nullptr, lhs, attr, op, begin, end); - log_assert(stmt->type == AST_ASSIGN_EQ); - AstNode *expr = stmt->children[0]->clone(); - if (undo) { - AstNode *one = AstNode::mkconst_int(1, false, 1); - AstNode *minus_one = new AstNode(AST_NEG, one); - expr = new AstNode(op, expr, minus_one); + void frontend_verilog_yy::parser::error(const frontend_verilog_yy::parser::location_type& loc, const std::string& msg) + { + err_at_loc(loc, "%s", msg.c_str()); } - SET_AST_NODE_LOC(expr, begin, end); - return expr; + // end unqual } -// add a binary operator assignment statement, e.g., a += b -static const AstNode *addAsgnBinopStmt(dict *attr, AstNode *lhs, AST::AstNodeType op, AstNode *rhs, YYLTYPE begin, YYLTYPE end) -{ - SET_AST_NODE_LOC(rhs, end, end); - if (op == AST_SHIFT_LEFT || op == AST_SHIFT_RIGHT || - op == AST_SHIFT_SLEFT || op == AST_SHIFT_SRIGHT) { - rhs = new AstNode(AST_TO_UNSIGNED, rhs); - SET_AST_NODE_LOC(rhs, end, end); - } - rhs = new AstNode(op, lhs->clone(), rhs); - AstNode *stmt = new AstNode(AST_ASSIGN_EQ, lhs, rhs); - SET_AST_NODE_LOC(rhs, begin, end); - SET_AST_NODE_LOC(stmt, begin, end); - ast_stack.back()->children.push_back(stmt); - if (attr != nullptr) - append_attr(stmt, attr); - return lhs; -} - -%} - -%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 - */ %code requires { -#include -#include -#include "frontends/verilog/verilog_frontend.h" + // start requires + #include + #include + #include + #include "frontends/verilog/verilog_frontend.h" + + struct specify_target { + char polarity_op; + std::unique_ptr dst, dat; + specify_target& operator=(specify_target&& other) noexcept { + if (this != &other) { + dst = std::move(other.dst); + dat = std::move(other.dat); + polarity_op = other.polarity_op; + } + return *this; + } + }; + + struct specify_triple { + std::unique_ptr t_min, t_avg, t_max; + specify_triple& operator=(specify_triple&& other) noexcept { + if (this != &other) { + t_min = std::move(other.t_min); + t_avg = std::move(other.t_avg); + t_max = std::move(other.t_max); + } + return *this; + } + }; + + struct specify_rise_fall { + specify_triple rise; + specify_triple fall; + }; + + using string_t = std::string *; + using ast_t = std::unique_ptr; + using al_t = YOSYS_NAMESPACE_PREFIX dict>*; + using specify_target_ptr_t = std::unique_ptr; + using specify_triple_ptr_t = std::unique_ptr; + using specify_rise_fall_ptr_t = std::unique_ptr; + using boolean_t = bool; + using ch_t = char; + using integer_t = int; + using ast_node_type_t = YOSYS_NAMESPACE_PREFIX AST::AstNodeType; + // end requires } -%union { - std::string *string; - struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast; - YOSYS_NAMESPACE_PREFIX dict *al; - struct specify_target *specify_target_ptr; - struct specify_triple *specify_triple_ptr; - struct specify_rise_fall *specify_rise_fall_ptr; - bool boolean; - char ch; - int integer; - YOSYS_NAMESPACE_PREFIX AST::AstNodeType ast_node_type; -} +%token string_t "string" +%token ast_t +%token al_t +%token specify_target_ptr_t "specify target" +%token specify_triple_ptr_t "specify triple" +%token specify_rise_fall_ptr_t "specify rise and fall" +%token boolean_t "boolean" +%token ch_t "invalid token" +%token integer_t "integer" +%token ast_node_type_t -%token TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE -%token TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS -%token TOK_BASE TOK_BASED_CONSTVAL TOK_UNBASED_UNSIZED_CONSTVAL -%token TOK_USER_TYPE TOK_PKG_USER_TYPE +%token TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE +%token TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS +%token TOK_BASE TOK_BASED_CONSTVAL TOK_UNBASED_UNSIZED_CONSTVAL +%token TOK_USER_TYPE TOK_PKG_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 @@ -420,41 +533,73 @@ static const AstNode *addAsgnBinopStmt(dict *attr, AstNode * %token TOK_BIND TOK_TIME_SCALE %token TOK_IMPORT -%type range range_or_multirange non_opt_range non_opt_multirange -%type wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type -%type opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id integral_number -%type type_name -%type opt_enum_init enum_type struct_type enum_struct_type func_return_type typedef_base_type -%type opt_property always_comb_or_latch always_or_always_ff -%type opt_signedness_default_signed opt_signedness_default_unsigned -%type integer_atom_type integer_vector_type -%type attr if_attr case_attr -%type struct_union -%type asgn_binop inc_or_dec_op -%type genvar_identifier +%token TOK_EXCL "'!'" +%token TOK_HASH "'#'" +%token TOK_PERC "'%'" +%token TOK_AMP "'&'" +%token TOK_LPAREN "'('" +%token TOK_RPAREN "')'" +%token TOK_ASTER "'*'" +%token TOK_PLUS "'+'" +%token TOK_COMMA "','" +%token TOK_MINUS "'-'" +%token TOK_DOT "'.'" +%token TOK_SLASH "'/'" +%token TOK_COL "':'" +%token TOK_SEMICOL "';'" +%token TOK_LT "'<'" +%token TOK_EQ "'='" +%token TOK_GT "'>'" +%token TOK_QUE "'?'" +%token TOK_AT "'@'" +%token TOK_LBRA "'['" +%token TOK_RBRA "']'" +%token TOK_CARET "'^'" +%token TOK_UNDER "'_'" +%token TOK_LCURL "'{'" +%token TOK_PIPE "'|'" +%token TOK_RCURL "'}'" +%token TOK_TILDE "'~'" +%token TOK_n "'n'" +%token TOK_p "'p'" +%token TOK_x "'x'" +%token TOK_z "'z'" -%type specify_target -%type specify_triple specify_opt_triple -%type specify_rise_fall -%type specify_if specify_condition -%type specify_edge +%type range range_or_multirange non_opt_range non_opt_multirange +%type wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type +%type opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id integral_number +%type type_name +%type opt_enum_init enum_type struct_type enum_struct_type func_return_type typedef_base_type +%type opt_property always_comb_or_latch always_or_always_ff +%type opt_signedness_default_signed opt_signedness_default_unsigned +%type integer_atom_type integer_vector_type +%type attr if_attr case_attr +%type struct_union +%type asgn_binop inc_or_dec_op +%type genvar_identifier + +%type specify_target +%type specify_triple specify_opt_triple +%type specify_rise_fall +%type specify_if specify_condition +%type specify_edge // operator precedence from low to high %left OP_LOR %left OP_LAND -%left '|' OP_NOR -%left '^' OP_XNOR -%left '&' OP_NAND +%left TOK_PIPE OP_NOR +%left TOK_CARET OP_XNOR +%left TOK_AMP OP_NAND %left OP_EQ OP_NE OP_EQX OP_NEX -%left '<' OP_LE OP_GE '>' +%left TOK_LT OP_LE OP_GE TOK_GT %left OP_SHL OP_SHR OP_SSHL OP_SSHR -%left '+' '-' -%left '*' '/' '%' +%left TOK_PLUS TOK_MINUS +%left TOK_ASTER TOK_SLASH TOK_PERC %left OP_POW %precedence OP_CAST %precedence UNARY_OPS -%define parse.error verbose +%define parse.error detailed %define parse.lac full %precedence FAKE_THEN @@ -466,15 +611,13 @@ static const AstNode *addAsgnBinopStmt(dict *attr, AstNode * %% input: { - (void)frontend_verilog_yynerrs; - ast_stack.clear(); - ast_stack.push_back(current_ast); + (void)yynerrs_; + extra->ast_stack.clear(); + extra->ast_stack.push_back(extra->current_ast); } design { - ast_stack.pop_back(); - log_assert(GetSize(ast_stack) == 0); - for (auto &it : default_attr_list) - delete it.second; - default_attr_list.clear(); + extra->ast_stack.pop_back(); + log_assert(GetSize(extra->ast_stack) == 0); + extra->default_attr_list.clear(); }; design: @@ -492,18 +635,18 @@ design: attr: { - if (attr_list != nullptr) - attr_list_stack.push(attr_list); - attr_list = new dict; - for (auto &it : default_attr_list) - (*attr_list)[it.first] = it.second->clone(); + if (extra->attr_list != nullptr) + extra->attr_list_stack.push(extra->attr_list); + extra->attr_list = new dict>; + for (auto &it : extra->default_attr_list) + (*extra->attr_list)[it.first] = it.second->clone(); } attr_opt { - $$ = attr_list; - if (!attr_list_stack.empty()) { - attr_list = attr_list_stack.top(); - attr_list_stack.pop(); + $$ = extra->attr_list; + if (!extra->attr_list_stack.empty()) { + extra->attr_list = extra->attr_list_stack.top(); + extra->attr_list_stack.pop(); } else - attr_list = nullptr; + extra->attr_list = nullptr; }; attr_opt: @@ -514,20 +657,18 @@ attr_opt: defattr: DEFATTR_BEGIN { - if (attr_list != nullptr) - attr_list_stack.push(attr_list); - attr_list = new dict; - for (auto &it : default_attr_list) - delete it.second; - default_attr_list.clear(); + if (extra->attr_list != nullptr) + extra->attr_list_stack.push(extra->attr_list); + extra->attr_list = new dict>; + extra->default_attr_list.clear(); } opt_attr_list { - attr_list->swap(default_attr_list); - delete attr_list; - if (!attr_list_stack.empty()) { - attr_list = attr_list_stack.top(); - attr_list_stack.pop(); + extra->attr_list->swap(extra->default_attr_list); + delete extra->attr_list; + if (!extra->attr_list_stack.empty()) { + extra->attr_list = extra->attr_list_stack.top(); + extra->attr_list_stack.pop(); } else - attr_list = nullptr; + extra->attr_list = nullptr; } DEFATTR_END; opt_attr_list: @@ -535,20 +676,14 @@ opt_attr_list: attr_list: attr_assign | - attr_list ',' attr_assign; + attr_list TOK_COMMA attr_assign; attr_assign: hierarchical_id { - if (attr_list->count(*$1) != 0) - delete (*attr_list)[*$1]; - (*attr_list)[*$1] = AstNode::mkconst_int(1, false); - delete $1; + (*extra->attr_list)[*$1] = AstNode::mkconst_int(1, false); } | - hierarchical_id '=' expr { - if (attr_list->count(*$1) != 0) - delete (*attr_list)[*$1]; - (*attr_list)[*$1] = $3; - delete $1; + hierarchical_id TOK_EQ expr { + (*extra->attr_list)[*$1] = std::move($3); }; hierarchical_id: @@ -560,170 +695,151 @@ hierarchical_id: *$1 += "::" + $3->substr(1); else *$1 += "::" + *$3; - delete $3; $$ = $1; } | - hierarchical_id '.' TOK_ID { + hierarchical_id TOK_DOT TOK_ID { if ($3->compare(0, 1, "\\") == 0) *$1 += "." + $3->substr(1); else *$1 += "." + *$3; - delete $3; $$ = $1; }; hierarchical_type_id: TOK_USER_TYPE | TOK_PKG_USER_TYPE // package qualified type name - | '(' TOK_USER_TYPE ')' { $$ = $2; } // non-standard grammar + | TOK_LPAREN TOK_USER_TYPE TOK_RPAREN { $$ = $2; } // non-standard grammar ; module: attr TOK_MODULE { - enterTypeScope(); + extra->enterTypeScope(); } TOK_ID { - do_not_require_port_stubs = false; - AstNode *mod = new AstNode(AST_MODULE); - ast_stack.back()->children.push_back(mod); - ast_stack.push_back(mod); - current_ast_mod = mod; - port_stubs.clear(); - port_counter = 0; + extra->do_not_require_port_stubs = false; + AstNode* mod = extra->pushChild(std::make_unique(AST_MODULE)); + extra->current_ast_mod = mod; + extra->port_stubs.clear(); + extra->port_counter = 0; mod->str = *$4; append_attr(mod, $1); - } module_para_opt module_args_opt ';' module_body TOK_ENDMODULE opt_label { - 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); - checkLabelsMatch("Module name", $4, $11); - current_ast_mod = NULL; - delete $4; - delete $11; - exitTypeScope(); + } module_para_opt module_args_opt TOK_SEMICOL module_body TOK_ENDMODULE opt_label { + if (extra->port_stubs.size() != 0) + lexer->err("Missing details for module port `%s'.", + extra->port_stubs.begin()->first.c_str()); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @$); + extra->ast_stack.pop_back(); + log_assert(extra->ast_stack.size() == 1); + checkLabelsMatch(@11, "Module name", $4, $11); + extra->current_ast_mod = nullptr; + extra->exitTypeScope(); }; module_para_opt: - '#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | %empty; + TOK_HASH TOK_LPAREN module_para_list TOK_RPAREN | %empty; module_para_list: - single_module_para | module_para_list ',' single_module_para; + single_module_para | module_para_list TOK_COMMA single_module_para; single_module_para: %empty | attr TOK_PARAMETER { - if (astbuf1) delete astbuf1; - astbuf1 = new AstNode(AST_PARAMETER); - astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - append_attr(astbuf1, $1); + extra->astbuf1 = std::make_unique(AST_PARAMETER); + extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + append_attr(extra->astbuf1.get(), $1); } param_type single_param_decl | attr TOK_LOCALPARAM { - if (astbuf1) delete astbuf1; - astbuf1 = new AstNode(AST_LOCALPARAM); - astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - append_attr(astbuf1, $1); + extra->astbuf1 = std::make_unique(AST_LOCALPARAM); + extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + append_attr(extra->astbuf1.get(), $1); } param_type single_param_decl | single_param_decl; module_args_opt: - '(' ')' | %empty | '(' module_args optional_comma ')'; + TOK_LPAREN TOK_RPAREN | %empty | TOK_LPAREN module_args optional_comma TOK_RPAREN; module_args: - module_arg | module_args ',' module_arg; + module_arg | module_args TOK_COMMA module_arg; optional_comma: - ',' | %empty; + TOK_COMMA | %empty; module_arg_opt_assignment: - '=' expr { - if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) { - if (ast_stack.back()->children.back()->is_input) { - AstNode *n = ast_stack.back()->children.back(); - if (n->attributes.count(ID::defaultvalue)) - delete n->attributes.at(ID::defaultvalue); - n->attributes[ID::defaultvalue] = $2; + TOK_EQ expr { + if (extra->ast_stack.back()->children.size() > 0 && extra->ast_stack.back()->children.back()->type == AST_WIRE) { + if (extra->ast_stack.back()->children.back()->is_input) { + auto& n = extra->ast_stack.back()->children.back(); + n->attributes[ID::defaultvalue] = std::move($2); } else { - AstNode *wire = new AstNode(AST_IDENTIFIER); - wire->str = ast_stack.back()->children.back()->str; - if (ast_stack.back()->children.back()->is_reg || ast_stack.back()->children.back()->is_logic) - ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $2)))); + auto wire = std::make_unique(AST_IDENTIFIER); + wire->str = extra->ast_stack.back()->children.back()->str; + if (extra->ast_stack.back()->children.back()->is_reg || extra->ast_stack.back()->children.back()->is_logic) + extra->ast_stack.back()->children.push_back(std::make_unique(AST_INITIAL, std::make_unique(AST_BLOCK, std::make_unique(AST_ASSIGN_LE, std::move(wire), std::move($2))))); else - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2)); + extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::move(wire), std::move($2))); } } else - frontend_verilog_yyerror("SystemVerilog interface in module port list cannot have a default value."); + lexer->err("SystemVerilog interface in module port list cannot have a default value."); } | %empty; module_arg: TOK_ID { - if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) { - AstNode *node = ast_stack.back()->children.back()->clone(); + if (extra->ast_stack.back()->children.size() > 0 && extra->ast_stack.back()->children.back()->type == AST_WIRE) { + auto node = extra->ast_stack.back()->children.back()->clone(); node->str = *$1; - node->port_id = ++port_counter; - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @1, @1); + node->port_id = ++extra->port_counter; + SET_AST_NODE_LOC(node.get(), @1, @1); + extra->ast_stack.back()->children.push_back(std::move(node)); } else { - if (port_stubs.count(*$1) != 0) - frontend_verilog_yyerror("Duplicate module port `%s'.", $1->c_str()); - port_stubs[*$1] = ++port_counter; + if (extra->port_stubs.count(*$1) != 0) + lexer->err("Duplicate module port `%s'.", $1->c_str()); + extra->port_stubs[*$1] = ++extra->port_counter; } - delete $1; } module_arg_opt_assignment | TOK_ID { - astbuf1 = new AstNode(AST_INTERFACEPORT); - astbuf1->children.push_back(new AstNode(AST_INTERFACEPORTTYPE)); - astbuf1->children[0]->str = *$1; - delete $1; + extra->astbuf1 = std::make_unique(AST_INTERFACEPORT); + extra->astbuf1->children.push_back(std::make_unique(AST_INTERFACEPORTTYPE)); + extra->astbuf1->children[0]->str = *$1; } TOK_ID { /* SV interfaces */ - if (!sv_mode) - frontend_verilog_yyerror("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str()); - astbuf2 = astbuf1->clone(); // really only needed if multiple instances of same type. - astbuf2->str = *$3; - delete $3; - astbuf2->port_id = ++port_counter; - ast_stack.back()->children.push_back(astbuf2); - delete astbuf1; // really only needed if multiple instances of same type. + if (!mode->sv) + lexer->err("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str()); + extra->astbuf2 = extra->astbuf1->clone(); // really only needed if multiple instances of same type. + extra->astbuf2->str = *$3; + extra->astbuf2->port_id = ++extra->port_counter; + extra->ast_stack.back()->children.push_back(std::move(extra->astbuf2)); } module_arg_opt_assignment | attr wire_type range_or_multirange TOK_ID { - AstNode *node = $2; + auto node = std::move($2); node->str = *$4; - SET_AST_NODE_LOC(node, @4, @4); - node->port_id = ++port_counter; - AstNode *range = checkRange(node, $3); - if (range != NULL) - node->children.push_back(range); + SET_AST_NODE_LOC(node.get(), @4, @4); + node->port_id = ++extra->port_counter; + auto range = checkRange(node.get(), std::move($3)); + if (range != nullptr) + node->children.push_back(std::move(range)); 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 && !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); - delete $4; + lexer->err("Module port `%s' is neither input nor output.", $4->c_str()); + if (node->is_reg && node->is_input && !node->is_output && !mode->sv) + lexer->err("Input port `%s' is declared as register.", $4->c_str()); + append_attr(node.get(), $1); + extra->ast_stack.back()->children.push_back(std::move(node)); } module_arg_opt_assignment | - '.' '.' '.' { - do_not_require_port_stubs = true; + TOK_DOT TOK_DOT TOK_DOT { + extra->do_not_require_port_stubs = true; }; package: attr TOK_PACKAGE { - enterTypeScope(); + extra->enterTypeScope(); } TOK_ID { - AstNode *mod = new AstNode(AST_PACKAGE); - ast_stack.back()->children.push_back(mod); - ast_stack.push_back(mod); - current_ast_mod = mod; + AstNode* mod = extra->pushChild(std::make_unique(AST_PACKAGE)); + extra->current_ast_mod = mod; mod->str = *$4; append_attr(mod, $1); - } ';' package_body TOK_ENDPACKAGE opt_label { - ast_stack.pop_back(); - checkLabelsMatch("Package name", $4, $9); - current_ast_mod = NULL; - delete $4; - delete $9; - exitTypeScope(); + } TOK_SEMICOL package_body TOK_ENDPACKAGE opt_label { + extra->ast_stack.pop_back(); + checkLabelsMatch(@9, "Package name", $4, $9); + extra->current_ast_mod = nullptr; + extra->exitTypeScope(); }; package_body: @@ -743,25 +859,22 @@ import_stmt: interface: TOK_INTERFACE { - enterTypeScope(); + extra->enterTypeScope(); } TOK_ID { - do_not_require_port_stubs = false; - AstNode *intf = new AstNode(AST_INTERFACE); - ast_stack.back()->children.push_back(intf); - ast_stack.push_back(intf); - current_ast_mod = intf; - port_stubs.clear(); - port_counter = 0; + extra->do_not_require_port_stubs = false; + AstNode* intf = extra->pushChild(std::make_unique(AST_INTERFACE)); + extra->current_ast_mod = intf; + extra->port_stubs.clear(); + extra->port_counter = 0; intf->str = *$3; - delete $3; - } module_para_opt module_args_opt ';' interface_body TOK_ENDINTERFACE { - if (port_stubs.size() != 0) - frontend_verilog_yyerror("Missing details for module port `%s'.", - port_stubs.begin()->first.c_str()); - ast_stack.pop_back(); - log_assert(ast_stack.size() == 1); - current_ast_mod = NULL; - exitTypeScope(); + } module_para_opt module_args_opt TOK_SEMICOL interface_body TOK_ENDINTERFACE { + if (extra->port_stubs.size() != 0) + lexer->err("Missing details for module port `%s'.", + extra->port_stubs.begin()->first.c_str()); + extra->ast_stack.pop_back(); + log_assert(extra->ast_stack.size() == 1); + extra->current_ast_mod = nullptr; + extra->exitTypeScope(); }; interface_body: @@ -773,27 +886,24 @@ interface_body_stmt: bind_directive: TOK_BIND { - AstNode *bnode = new AstNode(AST_BIND); - ast_stack.back()->children.push_back(bnode); - ast_stack.push_back(bnode); + (void)extra->pushChild(std::make_unique(AST_BIND)); } bind_target { // bind_target should have added at least one child - log_assert(ast_stack.back()->children.size() >= 1); + log_assert(extra->ast_stack.back()->children.size() >= 1); } TOK_ID { - // The single_cell parser in cell_list_no_array uses astbuf1 as + // The single_cell parser in cell_list_no_array uses extra->astbuf1 as // a sort of template for constructing cells. - astbuf1 = new AstNode(AST_CELL); - astbuf1->children.push_back(new AstNode(AST_CELLTYPE)); - astbuf1->children[0]->str = *$5; - delete $5; + extra->astbuf1 = std::make_unique(AST_CELL); + extra->astbuf1->children.push_back(std::make_unique(AST_CELLTYPE)); + extra->astbuf1->children[0]->str = *$5; } - cell_parameter_list_opt cell_list_no_array ';' { + cell_parameter_list_opt cell_list_no_array TOK_SEMICOL { // cell_list should have added at least one more child - log_assert(ast_stack.back()->children.size() >= 2); - delete astbuf1; - ast_stack.pop_back(); + log_assert(extra->ast_stack.back()->children.size() >= 2); + (void)extra->astbuf1.reset(); + extra->ast_stack.pop_back(); }; // bind_target matches the target of the bind (everything before @@ -802,7 +912,7 @@ bind_directive: // We can't use the BNF from the spec directly because it's ambiguous: // something like "bind foo bar_i (.*)" can either be interpreted with "foo" as // a module or interface identifier (matching bind_target_scope in the spec) or -// by considering foo as a degenerate hierarchical identifier with no '.' +// by considering foo as a degenerate hierarchical identifier with no TOK_DOT // characters, followed by no bit select (which matches bind_target_instance in // the spec). // @@ -814,82 +924,81 @@ bind_target: // An optional list of target instances for a bind statement, introduced by a // colon. opt_bind_target_instance_list: - ':' bind_target_instance_list | + TOK_COL bind_target_instance_list | %empty; bind_target_instance_list: bind_target_instance | - bind_target_instance_list ',' bind_target_instance; + bind_target_instance_list TOK_COMMA bind_target_instance; -// A single target instance for a bind statement. The top of ast_stack will be +// A single target instance for a bind statement. The top of extra->ast_stack will be // the bind node where we should add it. bind_target_instance: hierarchical_id { - auto *node = new AstNode(AST_IDENTIFIER); + auto node = std::make_unique(AST_IDENTIFIER); node->str = *$1; - delete $1; - ast_stack.back()->children.push_back(node); + extra->ast_stack.back()->children.push_back(std::move(node)); }; mintypmax_expr: - expr { delete $1; } | - expr ':' expr ':' expr { delete $1; delete $3; delete $5; }; + expr { } | + expr TOK_COL expr TOK_COL expr { }; non_opt_delay: - '#' TOK_ID { delete $2; } | - '#' TOK_CONSTVAL { delete $2; } | - '#' TOK_REALVAL { delete $2; } | + TOK_HASH TOK_ID { } | + TOK_HASH TOK_CONSTVAL { } | + TOK_HASH TOK_REALVAL { } | // our `expr` doesn't have time_scale, so we need the parenthesized variant - '#' TOK_TIME_SCALE | - '#' '(' TOK_TIME_SCALE ')' | - '#' '(' mintypmax_expr ')' | - '#' '(' mintypmax_expr ',' mintypmax_expr ')' | - '#' '(' mintypmax_expr ',' mintypmax_expr ',' mintypmax_expr ')'; + TOK_HASH TOK_TIME_SCALE | + TOK_HASH TOK_LPAREN TOK_TIME_SCALE TOK_RPAREN | + TOK_HASH TOK_LPAREN mintypmax_expr TOK_RPAREN | + TOK_HASH TOK_LPAREN mintypmax_expr TOK_COMMA mintypmax_expr TOK_RPAREN | + TOK_HASH TOK_LPAREN mintypmax_expr TOK_COMMA mintypmax_expr TOK_COMMA mintypmax_expr TOK_RPAREN; delay: non_opt_delay | %empty; io_wire_type: - { astbuf3 = new AstNode(AST_WIRE); current_wire_rand = false; current_wire_const = false; } + { extra->astbuf3 = std::make_unique(AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; } wire_type_token_io wire_type_const_rand opt_wire_type_token wire_type_signedness - { $$ = astbuf3; SET_RULE_LOC(@$, @2, @$); }; + { $$ = std::move(extra->astbuf3); SET_RULE_LOC(@$, @2, @$); }; non_io_wire_type: - { astbuf3 = new AstNode(AST_WIRE); current_wire_rand = false; current_wire_const = false; } + { extra->astbuf3 = std::make_unique(AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; } wire_type_const_rand wire_type_token wire_type_signedness - { $$ = astbuf3; SET_RULE_LOC(@$, @2, @$); }; + { $$ = std::move(extra->astbuf3); SET_RULE_LOC(@$, @2, @$); }; wire_type: - io_wire_type | - non_io_wire_type; + io_wire_type { $$ = std::move($1); } | + non_io_wire_type { $$ = std::move($1); }; wire_type_token_io: TOK_INPUT { - astbuf3->is_input = true; + extra->astbuf3->is_input = true; } | TOK_OUTPUT { - astbuf3->is_output = true; + extra->astbuf3->is_output = true; } | TOK_INOUT { - astbuf3->is_input = true; - astbuf3->is_output = true; + extra->astbuf3->is_input = true; + extra->astbuf3->is_output = true; }; wire_type_signedness: - TOK_SIGNED { astbuf3->is_signed = true; } | - TOK_UNSIGNED { astbuf3->is_signed = false; } | + TOK_SIGNED { extra->astbuf3->is_signed = true; } | + TOK_UNSIGNED { extra->astbuf3->is_signed = false; } | %empty; wire_type_const_rand: TOK_RAND TOK_CONST { - current_wire_rand = true; - current_wire_const = true; + extra->current_wire_rand = true; + extra->current_wire_const = true; } | TOK_CONST { - current_wire_const = true; + extra->current_wire_const = true; } | TOK_RAND { - current_wire_rand = true; + extra->current_wire_rand = true; } | %empty; @@ -904,35 +1013,35 @@ wire_type_token: } | // regs TOK_REG { - astbuf3->is_reg = true; + extra->astbuf3->is_reg = true; } | TOK_VAR TOK_REG { - astbuf3->is_reg = true; + extra->astbuf3->is_reg = true; } | // logics TOK_VAR { - astbuf3->is_logic = true; + extra->astbuf3->is_logic = true; } | TOK_VAR logic_type { - astbuf3->is_logic = true; + extra->astbuf3->is_logic = true; } | logic_type { - astbuf3->is_logic = true; + extra->astbuf3->is_logic = true; } | TOK_GENVAR { - astbuf3->type = AST_GENVAR; - astbuf3->is_reg = true; - astbuf3->is_signed = true; - astbuf3->range_left = 31; - astbuf3->range_right = 0; + extra->astbuf3->type = AST_GENVAR; + extra->astbuf3->is_reg = true; + extra->astbuf3->is_signed = true; + extra->astbuf3->range_left = 31; + extra->astbuf3->range_right = 0; }; net_type: TOK_WOR { - astbuf3->is_wor = true; + extra->astbuf3->is_wor = true; } | TOK_WAND { - astbuf3->is_wand = true; + extra->astbuf3->is_wand = true; } | TOK_WIRE; @@ -940,12 +1049,12 @@ logic_type: TOK_LOGIC { } | integer_atom_type { - astbuf3->range_left = $1 - 1; - astbuf3->range_right = 0; - astbuf3->is_signed = true; + extra->astbuf3->range_left = $1 - 1; + extra->astbuf3->range_right = 0; + extra->astbuf3->is_signed = true; } | hierarchical_type_id { - addWiretypeNode($1, astbuf3); + extra->addWiretypeNode($1, extra->astbuf3.get()); }; integer_atom_type: @@ -956,59 +1065,59 @@ integer_atom_type: TOK_BYTE { $$ = 8; } ; integer_vector_type: - TOK_LOGIC { $$ = TOK_LOGIC; } | - TOK_REG { $$ = TOK_REG; } ; + TOK_LOGIC { $$ = token::TOK_LOGIC; } | + TOK_REG { $$ = token::TOK_REG; } ; non_opt_range: - '[' expr ':' expr ']' { - $$ = new AstNode(AST_RANGE); - $$->children.push_back($2); - $$->children.push_back($4); + TOK_LBRA expr TOK_COL expr TOK_RBRA { + $$ = std::make_unique(AST_RANGE); + $$->children.push_back(std::move($2)); + $$->children.push_back(std::move($4)); } | - '[' expr TOK_POS_INDEXED expr ']' { - $$ = new AstNode(AST_RANGE); - AstNode *expr = new AstNode(AST_SELFSZ, $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))); + TOK_LBRA expr TOK_POS_INDEXED expr TOK_RBRA { + $$ = std::make_unique(AST_RANGE); + auto expr = std::make_unique(AST_SELFSZ, std::move($2)); + $$->children.push_back(std::make_unique(AST_SUB, std::make_unique(AST_ADD, expr->clone(), std::move($4)), AstNode::mkconst_int(1, true))); + $$->children.push_back(std::make_unique(AST_ADD, std::move(expr), AstNode::mkconst_int(0, true))); } | - '[' expr TOK_NEG_INDEXED expr ']' { - $$ = new AstNode(AST_RANGE); - AstNode *expr = new AstNode(AST_SELFSZ, $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)); + TOK_LBRA expr TOK_NEG_INDEXED expr TOK_RBRA { + $$ = std::make_unique(AST_RANGE); + auto expr = std::make_unique(AST_SELFSZ, std::move($2)); + $$->children.push_back(std::make_unique(AST_ADD, expr->clone(), AstNode::mkconst_int(0, true))); + $$->children.push_back(std::make_unique(AST_SUB, std::make_unique(AST_ADD, std::move(expr), AstNode::mkconst_int(1, true)), std::move($4))); } | - '[' expr ']' { - $$ = new AstNode(AST_RANGE); - $$->children.push_back($2); + TOK_LBRA expr TOK_RBRA { + $$ = std::make_unique(AST_RANGE); + $$->children.push_back(std::move($2)); }; non_opt_multirange: non_opt_range non_opt_range { - $$ = new AstNode(AST_MULTIRANGE, $1, $2); + $$ = std::make_unique(AST_MULTIRANGE, std::move($1), std::move($2)); } | non_opt_multirange non_opt_range { - $$ = $1; - $$->children.push_back($2); + $$ = std::move($1); + $$->children.push_back(std::move($2)); }; range: non_opt_range { - $$ = $1; + $$ = std::move($1); } | %empty { - $$ = NULL; + $$ = nullptr; }; range_or_multirange: - range { $$ = $1; } | - non_opt_multirange { $$ = $1; }; + range { $$ = std::move($1); } | + non_opt_multirange { $$ = std::move($1); }; module_body: module_body module_body_stmt | /* the following line makes the generate..endgenrate keywords optional */ module_body gen_stmt | module_body gen_block | - module_body ';' | + module_body TOK_SEMICOL | %empty; module_body_stmt: @@ -1017,61 +1126,43 @@ module_body_stmt: always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block; checker_decl: - TOK_CHECKER TOK_ID ';' { - AstNode *node = new AstNode(AST_GENBLOCK); + TOK_CHECKER TOK_ID TOK_SEMICOL { + AstNode* node = extra->pushChild(std::make_unique(AST_GENBLOCK)); node->str = *$2; - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); } module_body TOK_ENDCHECKER { - delete $2; - ast_stack.pop_back(); + extra->ast_stack.pop_back(); }; task_func_decl: attr TOK_DPI_FUNCTION TOK_ID TOK_ID { - current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$3), AstNode::mkconst_str(*$4)); - current_function_or_task->str = *$4; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - delete $3; - delete $4; - } opt_dpi_function_args ';' { - current_function_or_task = NULL; + extra->current_function_or_task = extra->saveChild(std::make_unique(AST_DPI_FUNCTION, AstNode::mkconst_str(*$3), AstNode::mkconst_str(*$4))); + extra->current_function_or_task->str = *$4; + append_attr(extra->current_function_or_task, $1); + } opt_dpi_function_args TOK_SEMICOL { + extra->current_function_or_task = nullptr; } | - attr TOK_DPI_FUNCTION TOK_ID '=' TOK_ID TOK_ID { - current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$5), AstNode::mkconst_str(*$3)); - current_function_or_task->str = *$6; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - delete $3; - delete $5; - delete $6; - } opt_dpi_function_args ';' { - current_function_or_task = NULL; + attr TOK_DPI_FUNCTION TOK_ID TOK_EQ TOK_ID TOK_ID { + extra->current_function_or_task = extra->saveChild(std::make_unique(AST_DPI_FUNCTION, AstNode::mkconst_str(*$5), AstNode::mkconst_str(*$3))); + extra->current_function_or_task->str = *$6; + append_attr(extra->current_function_or_task, $1); + } opt_dpi_function_args TOK_SEMICOL { + extra->current_function_or_task = nullptr; } | - attr TOK_DPI_FUNCTION TOK_ID ':' TOK_ID '=' TOK_ID TOK_ID { - current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$7), AstNode::mkconst_str(*$3 + ":" + RTLIL::unescape_id(*$5))); - current_function_or_task->str = *$8; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - delete $3; - delete $5; - delete $7; - delete $8; - } opt_dpi_function_args ';' { - current_function_or_task = NULL; + attr TOK_DPI_FUNCTION TOK_ID TOK_COL TOK_ID TOK_EQ TOK_ID TOK_ID { + extra->current_function_or_task = extra->saveChild(std::make_unique(AST_DPI_FUNCTION, AstNode::mkconst_str(*$7), AstNode::mkconst_str(*$3 + ":" + RTLIL::unescape_id(*$5)))); + extra->current_function_or_task->str = *$8; + append_attr(extra->current_function_or_task, $1); + } opt_dpi_function_args TOK_SEMICOL { + extra->current_function_or_task = nullptr; } | attr TOK_TASK opt_automatic TOK_ID { - current_function_or_task = new AstNode(AST_TASK); - current_function_or_task->str = *$4; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - ast_stack.push_back(current_function_or_task); - current_function_or_task_port_id = 1; - delete $4; - } task_func_args_opt ';' task_func_body TOK_ENDTASK { - current_function_or_task = NULL; - ast_stack.pop_back(); + extra->current_function_or_task = extra->pushChild(std::make_unique(AST_TASK)); + extra->current_function_or_task->str = *$4; + append_attr(extra->current_function_or_task, $1); + extra->current_function_or_task_port_id = 1; + } task_func_args_opt TOK_SEMICOL task_func_body TOK_ENDTASK { + extra->current_function_or_task = nullptr; + extra->ast_stack.pop_back(); } | attr TOK_FUNCTION opt_automatic TOK_VOID TOK_ID { // The difference between void functions and tasks is that @@ -1079,52 +1170,45 @@ task_func_decl: // inlined, but ignores signals read only in tasks. This only matters // for event based simulation, and for synthesis we can treat a void // function like a task. - current_function_or_task = new AstNode(AST_TASK); - current_function_or_task->str = *$5; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - ast_stack.push_back(current_function_or_task); - current_function_or_task_port_id = 1; - delete $5; - } task_func_args_opt ';' task_func_body TOK_ENDFUNCTION { - current_function_or_task = NULL; - ast_stack.pop_back(); + extra->current_function_or_task = extra->pushChild(std::make_unique(AST_TASK)); + extra->current_function_or_task->str = *$5; + append_attr(extra->current_function_or_task, $1); + extra->current_function_or_task_port_id = 1; + } task_func_args_opt TOK_SEMICOL task_func_body TOK_ENDFUNCTION { + extra->current_function_or_task = nullptr; + extra->ast_stack.pop_back(); } | attr TOK_FUNCTION opt_automatic func_return_type TOK_ID { - current_function_or_task = new AstNode(AST_FUNCTION); - current_function_or_task->str = *$5; - append_attr(current_function_or_task, $1); - ast_stack.back()->children.push_back(current_function_or_task); - ast_stack.push_back(current_function_or_task); - AstNode *outreg = new AstNode(AST_WIRE); + extra->current_function_or_task = extra->pushChild(std::make_unique(AST_FUNCTION)); + extra->current_function_or_task->str = *$5; + append_attr(extra->current_function_or_task, $1); + auto outreg = std::make_unique(AST_WIRE); outreg->str = *$5; outreg->is_signed = false; outreg->is_reg = true; - if ($4 != NULL) { - outreg->children.push_back($4); + if ($4 != nullptr) { outreg->is_signed = $4->is_signed; $4->is_signed = false; outreg->is_custom_type = $4->type == AST_WIRETYPE; + outreg->children.push_back(std::move($4)); } - current_function_or_task->children.push_back(outreg); - current_function_or_task_port_id = 1; - delete $5; - } task_func_args_opt ';' task_func_body TOK_ENDFUNCTION { - current_function_or_task = NULL; - ast_stack.pop_back(); + extra->current_function_or_task->children.push_back(std::move(outreg)); + extra->current_function_or_task_port_id = 1; + } task_func_args_opt TOK_SEMICOL task_func_body TOK_ENDFUNCTION { + extra->current_function_or_task = nullptr; + extra->ast_stack.pop_back(); }; func_return_type: hierarchical_type_id { - $$ = new AstNode(AST_WIRETYPE); + $$ = std::make_unique(AST_WIRETYPE); $$->str = *$1; - delete $1; } | opt_type_vec opt_signedness_default_unsigned { $$ = makeRange(0, 0, $2); } | opt_type_vec opt_signedness_default_unsigned non_opt_range { - $$ = $3; + $$ = std::move($3); $$->is_signed = $2; } | integer_atom_type opt_signedness_default_signed { @@ -1150,22 +1234,19 @@ opt_signedness_default_unsigned: dpi_function_arg: TOK_ID TOK_ID { - current_function_or_task->children.push_back(AstNode::mkconst_str(*$1)); - delete $1; - delete $2; + extra->current_function_or_task->children.push_back(AstNode::mkconst_str(*$1)); } | TOK_ID { - current_function_or_task->children.push_back(AstNode::mkconst_str(*$1)); - delete $1; + extra->current_function_or_task->children.push_back(AstNode::mkconst_str(*$1)); }; opt_dpi_function_args: - '(' dpi_function_args ')' | + TOK_LPAREN dpi_function_args TOK_RPAREN | %empty; dpi_function_args: - dpi_function_args ',' dpi_function_arg | - dpi_function_args ',' | + dpi_function_args TOK_COMMA dpi_function_arg | + dpi_function_args TOK_COMMA | dpi_function_arg | %empty; @@ -1174,52 +1255,52 @@ opt_automatic: %empty; task_func_args_opt: - '(' ')' | %empty | '(' { - albuf = nullptr; - astbuf1 = nullptr; - astbuf2 = nullptr; + TOK_LPAREN TOK_RPAREN | %empty | TOK_LPAREN { + extra->albuf = nullptr; + extra->astbuf1 = nullptr; + extra->astbuf2 = nullptr; } task_func_args optional_comma { - delete astbuf1; - if (astbuf2 != NULL) - delete astbuf2; - free_attr(albuf); - } ')'; + (void)extra->astbuf1.reset(); + if (extra->astbuf2 != nullptr) + (void)extra->astbuf2.reset(); + free_attr(extra->albuf); + } TOK_RPAREN; task_func_args: - task_func_port | task_func_args ',' task_func_port; + task_func_port | task_func_args TOK_COMMA task_func_port; task_func_port: attr wire_type range_or_multirange { bool prev_was_input = true; bool prev_was_output = false; - if (albuf) { - prev_was_input = astbuf1->is_input; - prev_was_output = astbuf1->is_output; - delete astbuf1; - if (astbuf2 != NULL) - delete astbuf2; - free_attr(albuf); + if (extra->albuf) { + prev_was_input = extra->astbuf1->is_input; + prev_was_output = extra->astbuf1->is_output; + (void)extra->astbuf1.reset(); + if (extra->astbuf2 != nullptr) + (void)extra->astbuf2.reset(); + free_attr(extra->albuf); } - albuf = $1; - astbuf1 = $2; - astbuf2 = checkRange(astbuf1, $3); - if (!astbuf1->is_input && !astbuf1->is_output) { - if (!sv_mode) - frontend_verilog_yyerror("task/function argument direction missing"); - astbuf1->is_input = prev_was_input; - astbuf1->is_output = prev_was_output; + extra->albuf = $1; + extra->astbuf1 = std::move($2); + extra->astbuf2 = checkRange(extra->astbuf1.get(), std::move($3)); + if (!extra->astbuf1->is_input && !extra->astbuf1->is_output) { + if (!mode->sv) + lexer->err("task/function argument direction missing"); + extra->astbuf1->is_input = prev_was_input; + extra->astbuf1->is_output = prev_was_output; } } wire_name | { - if (!astbuf1) { - if (!sv_mode) - frontend_verilog_yyerror("task/function argument direction missing"); - albuf = new dict; - astbuf1 = new AstNode(AST_WIRE); - current_wire_rand = false; - current_wire_const = false; - astbuf1->is_input = true; - astbuf2 = NULL; + if (!extra->astbuf1) { + if (!mode->sv) + lexer->err("task/function argument direction missing"); + extra->albuf = new dict>; + extra->astbuf1 = std::make_unique(AST_WIRE); + extra->current_wire_rand = false; + extra->current_wire_const = false; + extra->astbuf1->is_input = true; + extra->astbuf2 = nullptr; } } wire_name; @@ -1237,23 +1318,24 @@ specify_item_list: %empty; specify_item: - specify_if '(' specify_edge expr TOK_SPECIFY_OPER specify_target ')' '=' specify_rise_fall ';' { - AstNode *en_expr = $1; + specify_if TOK_LPAREN specify_edge expr TOK_SPECIFY_OPER specify_target TOK_RPAREN TOK_EQ specify_rise_fall TOK_SEMICOL { + auto en_expr = std::move($1); char specify_edge = $3; - AstNode *src_expr = $4; + auto src_expr = std::move($4); string *oper = $5; - specify_target *target = $6; - specify_rise_fall *timing = $9; + specify_target_ptr_t target = std::move($6); + specify_rise_fall_ptr_t timing = std::move($9); if (specify_edge != 0 && target->dat == nullptr) - frontend_verilog_yyerror("Found specify edge but no data spec.\n"); + lexer->err("Found specify edge but no data spec.\n"); - AstNode *cell = new AstNode(AST_CELL); - ast_stack.back()->children.push_back(cell); + auto cell_owned = std::make_unique(AST_CELL); + auto cell = cell_owned.get(); + extra->ast_stack.back()->children.push_back(std::move(cell_owned)); cell->str = stringf("$specify$%d", autoidx++); - cell->children.push_back(new AstNode(AST_CELLTYPE)); + cell->children.push_back(std::make_unique(AST_CELLTYPE)); cell->children.back()->str = target->dat ? "$specify3" : "$specify2"; - SET_AST_NODE_LOC(cell, en_expr ? @1 : @2, @10); + SET_AST_NODE_LOC(cell, en_expr.get() ? @1 : @2, @10); char oper_polarity = 0; char oper_type = oper->at(0); @@ -1263,148 +1345,143 @@ specify_item: oper_type = oper->at(1); } - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1))); cell->children.back()->str = "\\FULL"; - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1))); cell->children.back()->str = "\\SRC_DST_PEN"; - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1))); cell->children.back()->str = "\\SRC_DST_POL"; - cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_min)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->rise.t_min))); cell->children.back()->str = "\\T_RISE_MIN"; - cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_avg)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->rise.t_avg))); cell->children.back()->str = "\\T_RISE_TYP"; - cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_max)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->rise.t_max))); cell->children.back()->str = "\\T_RISE_MAX"; - cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_min)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->fall.t_min))); cell->children.back()->str = "\\T_FALL_MIN"; - cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_avg)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->fall.t_avg))); cell->children.back()->str = "\\T_FALL_TYP"; - cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_max)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->fall.t_max))); cell->children.back()->str = "\\T_FALL_MAX"; - cell->children.push_back(new AstNode(AST_ARGUMENT, en_expr ? en_expr : AstNode::mkconst_int(1, false, 1))); + cell->children.push_back(std::make_unique(AST_ARGUMENT, en_expr ? std::move(en_expr) : AstNode::mkconst_int(1, false, 1))); cell->children.back()->str = "\\EN"; - cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr)); + cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(src_expr))); cell->children.back()->str = "\\SRC"; - cell->children.push_back(new AstNode(AST_ARGUMENT, target->dst)); + cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(target->dst))); cell->children.back()->str = "\\DST"; if (target->dat) { - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1))); cell->children.back()->str = "\\EDGE_EN"; - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1))); cell->children.back()->str = "\\EDGE_POL"; - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1))); cell->children.back()->str = "\\DAT_DST_PEN"; - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1))); cell->children.back()->str = "\\DAT_DST_POL"; - cell->children.push_back(new AstNode(AST_ARGUMENT, target->dat)); + cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(target->dat))); cell->children.back()->str = "\\DAT"; } delete oper; - delete target; - delete timing; } | - TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' specify_triple specify_opt_triple ')' ';' { + TOK_ID TOK_LPAREN specify_edge expr specify_condition TOK_COMMA specify_edge expr specify_condition TOK_COMMA specify_triple specify_opt_triple TOK_RPAREN TOK_SEMICOL { 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()); + lexer->err("Unsupported specify rule type: %s\n", $1->c_str()); - AstNode *src_pen = AstNode::mkconst_int($3 != 0, false, 1); - AstNode *src_pol = AstNode::mkconst_int($3 == 'p', false, 1); - AstNode *src_expr = $4, *src_en = $5 ? $5 : AstNode::mkconst_int(1, false, 1); + auto src_pen = AstNode::mkconst_int($3 != 0, false, 1); + auto src_pol = AstNode::mkconst_int($3 == 'p', false, 1); + auto src_expr = std::move($4), src_en = $5 ? std::move($5) : AstNode::mkconst_int(1, false, 1); - AstNode *dst_pen = AstNode::mkconst_int($7 != 0, false, 1); - AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1); - AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1); + auto dst_pen = AstNode::mkconst_int($7 != 0, false, 1); + auto dst_pol = AstNode::mkconst_int($7 == 'p', false, 1); + auto dst_expr = std::move($8), dst_en = $9 ? std::move($9) : AstNode::mkconst_int(1, false, 1); - specify_triple *limit = $11; - specify_triple *limit2 = $12; + specify_triple_ptr_t limit = std::move($11); + specify_triple_ptr_t limit2 = std::move($12); - AstNode *cell = new AstNode(AST_CELL); - ast_stack.back()->children.push_back(cell); + auto cell_owned = std::make_unique(AST_CELL); + auto cell = cell_owned.get(); + extra->ast_stack.back()->children.push_back(std::move(cell_owned)); cell->str = stringf("$specify$%d", autoidx++); - cell->children.push_back(new AstNode(AST_CELLTYPE)); + cell->children.push_back(std::make_unique(AST_CELLTYPE)); cell->children.back()->str = "$specrule"; SET_AST_NODE_LOC(cell, @1, @14); - cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1))); + cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_str(*$1))); cell->children.back()->str = "\\TYPE"; - cell->children.push_back(new AstNode(AST_PARASET, limit->t_min)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(limit->t_min))); cell->children.back()->str = "\\T_LIMIT_MIN"; - cell->children.push_back(new AstNode(AST_PARASET, limit->t_avg)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(limit->t_avg))); cell->children.back()->str = "\\T_LIMIT_TYP"; - cell->children.push_back(new AstNode(AST_PARASET, limit->t_max)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(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.push_back(std::make_unique(AST_PARASET, limit2 ? std::move(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.push_back(std::make_unique(AST_PARASET, limit2 ? std::move(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.push_back(std::make_unique(AST_PARASET, limit2 ? std::move(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.push_back(std::make_unique(AST_PARASET, std::move(src_pen))); cell->children.back()->str = "\\SRC_PEN"; - cell->children.push_back(new AstNode(AST_PARASET, src_pol)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(src_pol))); cell->children.back()->str = "\\SRC_POL"; - cell->children.push_back(new AstNode(AST_PARASET, dst_pen)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(dst_pen))); cell->children.back()->str = "\\DST_PEN"; - cell->children.push_back(new AstNode(AST_PARASET, dst_pol)); + cell->children.push_back(std::make_unique(AST_PARASET, std::move(dst_pol))); cell->children.back()->str = "\\DST_POL"; - cell->children.push_back(new AstNode(AST_ARGUMENT, src_en)); + cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(src_en))); cell->children.back()->str = "\\SRC_EN"; - cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr)); + cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(src_expr))); cell->children.back()->str = "\\SRC"; - cell->children.push_back(new AstNode(AST_ARGUMENT, dst_en)); + cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(dst_en))); cell->children.back()->str = "\\DST_EN"; - cell->children.push_back(new AstNode(AST_ARGUMENT, dst_expr)); + cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(dst_expr))); cell->children.back()->str = "\\DST"; - - delete $1; - delete limit; - delete limit2; }; specify_opt_triple: - ',' specify_triple { - $$ = $2; + TOK_COMMA specify_triple { + $$ = std::move($2); } | %empty { $$ = nullptr; }; specify_if: - TOK_IF '(' expr ')' { - $$ = $3; + TOK_IF TOK_LPAREN expr TOK_RPAREN { + $$ = std::move($3); } | %empty { $$ = nullptr; @@ -1412,7 +1489,7 @@ specify_if: specify_condition: TOK_SPECIFY_AND expr { - $$ = $2; + $$ = std::move($2); } | %empty { $$ = nullptr; @@ -1420,28 +1497,28 @@ specify_condition: specify_target: expr { - $$ = new specify_target; + $$ = std::make_unique(); $$->polarity_op = 0; - $$->dst = $1; + $$->dst = std::move($1); $$->dat = nullptr; } | - '(' expr ':' expr ')'{ - $$ = new specify_target; + TOK_LPAREN expr TOK_COL expr TOK_RPAREN{ + $$ = std::make_unique(); $$->polarity_op = 0; - $$->dst = $2; - $$->dat = $4; + $$->dst = std::move($2); + $$->dat = std::move($4); } | - '(' expr TOK_NEG_INDEXED expr ')'{ - $$ = new specify_target; + TOK_LPAREN expr TOK_NEG_INDEXED expr TOK_RPAREN{ + $$ = std::make_unique(); $$->polarity_op = '-'; - $$->dst = $2; - $$->dat = $4; + $$->dst = std::move($2); + $$->dat = std::move($4); } | - '(' expr TOK_POS_INDEXED expr ')'{ - $$ = new specify_target; + TOK_LPAREN expr TOK_POS_INDEXED expr TOK_RPAREN{ + $$ = std::make_unique(); $$->polarity_op = '+'; - $$->dst = $2; - $$->dat = $4; + $$->dst = std::move($2); + $$->dat = std::move($4); }; specify_edge: @@ -1451,72 +1528,48 @@ specify_edge: specify_rise_fall: specify_triple { - $$ = new specify_rise_fall; - $$->rise = *$1; + $$ = std::make_unique(); $$->fall.t_min = $1->t_min->clone(); $$->fall.t_avg = $1->t_avg->clone(); $$->fall.t_max = $1->t_max->clone(); - delete $1; + $$->rise = std::move(*$1); } | - '(' specify_triple ',' specify_triple ')' { - $$ = new specify_rise_fall; - $$->rise = *$2; - $$->fall = *$4; - delete $2; - delete $4; + TOK_LPAREN specify_triple TOK_COMMA specify_triple TOK_RPAREN { + $$ = std::make_unique(); + $$->rise = std::move(*$2); + $$->fall = std::move(*$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"); + TOK_LPAREN specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_RPAREN { + $$ = std::make_unique(); + $$->rise = std::move(*$2); + $$->fall = std::move(*$4); + log_file_warning(current_filename, @$.begin.line, "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"); + TOK_LPAREN specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_RPAREN { + $$ = std::make_unique(); + $$->rise = std::move(*$2); + $$->fall = std::move(*$4); + log_file_warning(current_filename, @$.begin.line, "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"); + TOK_LPAREN specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_RPAREN { + $$ = std::make_unique(); + $$->rise = std::move(*$2); + $$->fall = std::move(*$4); + log_file_warning(current_filename, @$.begin.line, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } specify_triple: expr { - $$ = new specify_triple; - $$->t_min = $1; + $$ = std::make_unique(); $$->t_avg = $1->clone(); $$->t_max = $1->clone(); + $$->t_min = std::move($1); } | - expr ':' expr ':' expr { - $$ = new specify_triple; - $$->t_min = $1; - $$->t_avg = $3; - $$->t_max = $5; + expr TOK_COL expr TOK_COL expr { + $$ = std::make_unique(); + $$->t_min = std::move($1); + $$->t_avg = std::move($3); + $$->t_max = std::move($5); }; /******************** ignored specify parser **************************/ @@ -1538,58 +1591,58 @@ ignored_specify_item: ; specparam_declaration: - TOK_SPECPARAM list_of_specparam_assignments ';' | - TOK_SPECPARAM specparam_range list_of_specparam_assignments ';' ; + TOK_SPECPARAM list_of_specparam_assignments TOK_SEMICOL | + TOK_SPECPARAM specparam_range list_of_specparam_assignments TOK_SEMICOL ; // IEEE 1364-2005 calls this sinmply 'range' but the current 'range' rule allows empty match // and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005 // exxxxtending this for SV specparam would change this anyhow specparam_range: - '[' ignspec_constant_expression ':' ignspec_constant_expression ']' ; + TOK_LBRA ignspec_constant_expression TOK_COL ignspec_constant_expression TOK_RBRA ; list_of_specparam_assignments: - specparam_assignment | list_of_specparam_assignments ',' specparam_assignment; + specparam_assignment | list_of_specparam_assignments TOK_COMMA specparam_assignment; specparam_assignment: - ignspec_id '=' ignspec_expr ; + ignspec_id TOK_EQ ignspec_expr ; ignspec_opt_cond: - TOK_IF '(' ignspec_expr ')' | %empty; + TOK_IF TOK_LPAREN ignspec_expr TOK_RPAREN | %empty; path_declaration : - simple_path_declaration ';' + simple_path_declaration TOK_SEMICOL // | edge_sensitive_path_declaration // | state_dependent_path_declaration ; simple_path_declaration : - ignspec_opt_cond parallel_path_description '=' path_delay_value | - ignspec_opt_cond full_path_description '=' path_delay_value + ignspec_opt_cond parallel_path_description TOK_EQ path_delay_value | + ignspec_opt_cond full_path_description TOK_EQ path_delay_value ; path_delay_value : - '(' ignspec_expr list_of_path_delay_extra_expressions ')' + TOK_LPAREN ignspec_expr list_of_path_delay_extra_expressions TOK_RPAREN | ignspec_expr | ignspec_expr list_of_path_delay_extra_expressions ; list_of_path_delay_extra_expressions : - ',' ignspec_expr - | ',' ignspec_expr list_of_path_delay_extra_expressions + TOK_COMMA ignspec_expr + | TOK_COMMA ignspec_expr list_of_path_delay_extra_expressions ; specify_edge_identifier : TOK_POSEDGE | TOK_NEGEDGE ; parallel_path_description : - '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' | - '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor opt_polarity_operator ':' ignspec_expr ')' ')' | - '(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor TOK_POS_INDEXED ignspec_expr ')' ')' ; + TOK_LPAREN specify_input_terminal_descriptor opt_polarity_operator TOK_EQ TOK_GT specify_output_terminal_descriptor TOK_RPAREN | + TOK_LPAREN specify_edge_identifier specify_input_terminal_descriptor TOK_EQ TOK_GT TOK_LPAREN specify_output_terminal_descriptor opt_polarity_operator TOK_COL ignspec_expr TOK_RPAREN TOK_RPAREN | + TOK_LPAREN specify_edge_identifier specify_input_terminal_descriptor TOK_EQ TOK_GT TOK_LPAREN specify_output_terminal_descriptor TOK_POS_INDEXED ignspec_expr TOK_RPAREN TOK_RPAREN ; full_path_description : - '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' | - '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs opt_polarity_operator ':' ignspec_expr ')' ')' | - '(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs TOK_POS_INDEXED ignspec_expr ')' ')' ; + TOK_LPAREN list_of_path_inputs TOK_ASTER TOK_GT list_of_path_outputs TOK_RPAREN | + TOK_LPAREN specify_edge_identifier list_of_path_inputs TOK_ASTER TOK_GT TOK_LPAREN list_of_path_outputs opt_polarity_operator TOK_COL ignspec_expr TOK_RPAREN TOK_RPAREN | + TOK_LPAREN specify_edge_identifier list_of_path_inputs TOK_ASTER TOK_GT TOK_LPAREN list_of_path_outputs TOK_POS_INDEXED ignspec_expr TOK_RPAREN TOK_RPAREN ; // This was broken into 2 rules to solve shift/reduce conflicts list_of_path_inputs : @@ -1597,15 +1650,15 @@ list_of_path_inputs : specify_input_terminal_descriptor more_path_inputs opt_polarity_operator ; more_path_inputs : - ',' specify_input_terminal_descriptor | - more_path_inputs ',' specify_input_terminal_descriptor ; + TOK_COMMA specify_input_terminal_descriptor | + more_path_inputs TOK_COMMA specify_input_terminal_descriptor ; list_of_path_outputs : specify_output_terminal_descriptor | - list_of_path_outputs ',' specify_output_terminal_descriptor ; + list_of_path_outputs TOK_COMMA specify_output_terminal_descriptor ; opt_polarity_operator : - '+' | '-' | %empty; + TOK_PLUS | TOK_MINUS | %empty; // Good enough for the time being specify_input_terminal_descriptor : @@ -1616,7 +1669,7 @@ specify_output_terminal_descriptor : ignspec_id ; system_timing_declaration : - ignspec_id '(' system_timing_args ')' ';' ; + ignspec_id TOK_LPAREN system_timing_args TOK_RPAREN TOK_SEMICOL ; system_timing_arg : TOK_POSEDGE ignspec_id | @@ -1626,140 +1679,135 @@ 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 ; + system_timing_args TOK_COMMA system_timing_arg ; // for the time being this is OK, but we may write our own expr here. // as I'm not sure it is legal to use a full expr here (probably not) // On the other hand, other rules requiring constant expressions also use 'expr' // (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness ignspec_constant_expression: - expr { delete $1; }; + expr { }; ignspec_expr: - expr { delete $1; } | - expr ':' expr ':' expr { - delete $1; - delete $3; - delete $5; + expr { } | + expr TOK_COL expr TOK_COL expr { }; ignspec_id: - TOK_ID { delete $1; } - range_or_multirange { delete $3; }; + TOK_ID { } + range_or_multirange { }; /**********************************************************************/ param_signed: TOK_SIGNED { - astbuf1->is_signed = true; + extra->astbuf1->is_signed = true; } | TOK_UNSIGNED { - astbuf1->is_signed = false; + extra->astbuf1->is_signed = false; } | %empty; param_integer: type_atom { - astbuf1->is_reg = false; + extra->astbuf1->is_reg = false; }; param_real: TOK_REAL { - astbuf1->children.push_back(new AstNode(AST_REALVALUE)); + extra->astbuf1->children.push_back(std::make_unique(AST_REALVALUE)); }; param_range: range { - if ($1 != NULL) { - astbuf1->children.push_back($1); + if ($1 != nullptr) { + extra->astbuf1->children.push_back(std::move($1)); } }; param_integer_type: param_integer param_signed; param_range_type: type_vec param_signed { - addRange(astbuf1, 0, 0); + addRange(extra->astbuf1.get(), 0, 0); } | type_vec param_signed non_opt_range { - astbuf1->children.push_back($3); + extra->astbuf1->children.push_back(std::move($3)); }; param_implicit_type: param_signed param_range; param_type: param_integer_type | param_real | param_range_type | param_implicit_type | hierarchical_type_id { - addWiretypeNode($1, astbuf1); + extra->addWiretypeNode($1, extra->astbuf1.get()); }; param_decl: attr TOK_PARAMETER { - astbuf1 = new AstNode(AST_PARAMETER); - astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - append_attr(astbuf1, $1); - } param_type param_decl_list ';' { - delete astbuf1; + extra->astbuf1 = std::make_unique(AST_PARAMETER); + extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + append_attr(extra->astbuf1.get(), $1); + } param_type param_decl_list TOK_SEMICOL { + (void)extra->astbuf1.reset(); }; localparam_decl: attr TOK_LOCALPARAM { - astbuf1 = new AstNode(AST_LOCALPARAM); - astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - append_attr(astbuf1, $1); - } param_type param_decl_list ';' { - delete astbuf1; + extra->astbuf1 = std::make_unique(AST_LOCALPARAM); + extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + append_attr(extra->astbuf1.get(), $1); + } param_type param_decl_list TOK_SEMICOL { + (void)extra->astbuf1.reset(); }; param_decl_list: - single_param_decl | param_decl_list ',' single_param_decl; + single_param_decl | param_decl_list TOK_COMMA single_param_decl; single_param_decl: - single_param_decl_ident '=' expr { - AstNode *decl = ast_stack.back()->children.back(); + single_param_decl_ident TOK_EQ expr { + AstNode *decl = extra->ast_stack.back()->children.back().get(); log_assert(decl->type == AST_PARAMETER || decl->type == AST_LOCALPARAM); - delete decl->children[0]; - decl->children[0] = $3; + decl->children[0] = std::move($3); } | single_param_decl_ident { - AstNode *decl = ast_stack.back()->children.back(); + AstNode *decl = extra->ast_stack.back()->children.back().get(); if (decl->type != AST_PARAMETER) { log_assert(decl->type == AST_LOCALPARAM); - frontend_verilog_yyerror("localparam initialization is missing!"); + lexer->err("localparam initialization is missing!"); } - if (!sv_mode) - frontend_verilog_yyerror("Parameter defaults can only be omitted in SystemVerilog mode!"); - delete decl->children[0]; + if (!mode->sv) + lexer->err("Parameter defaults can only be omitted in SystemVerilog mode!"); decl->children.erase(decl->children.begin()); }; single_param_decl_ident: TOK_ID { - AstNode *node; - if (astbuf1 == nullptr) { - if (!sv_mode) - frontend_verilog_yyerror("In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword"); - node = new AstNode(AST_PARAMETER); - node->children.push_back(AstNode::mkconst_int(0, true)); + std::unique_ptr node_owned; + if (extra->astbuf1 == nullptr) { + if (!mode->sv) + lexer->err("In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword"); + node_owned = std::make_unique(AST_PARAMETER); + node_owned->children.push_back(AstNode::mkconst_int(0, true)); } else { - node = astbuf1->clone(); + node_owned = extra->astbuf1->clone(); } - node->str = *$1; - ast_stack.back()->children.push_back(node); - delete $1; + node_owned->str = *$1; + auto node = node_owned.get(); + extra->ast_stack.back()->children.push_back(std::move(node_owned)); SET_AST_NODE_LOC(node, @1, @1); }; defparam_decl: - TOK_DEFPARAM defparam_decl_list ';'; + TOK_DEFPARAM defparam_decl_list TOK_SEMICOL; defparam_decl_list: - single_defparam_decl | defparam_decl_list ',' single_defparam_decl; + single_defparam_decl | defparam_decl_list TOK_COMMA single_defparam_decl; single_defparam_decl: - range rvalue '=' expr { - AstNode *node = new AstNode(AST_DEFPARAM); - node->children.push_back($2); - node->children.push_back($4); - if ($1 != NULL) - node->children.push_back($1); - ast_stack.back()->children.push_back(node); + range rvalue TOK_EQ expr { + auto node = std::make_unique(AST_DEFPARAM); + node->children.push_back(std::move($2)); + node->children.push_back(std::move($4)); + if ($1 != nullptr) + node->children.push_back(std::move($1)); + extra->ast_stack.back()->children.push_back(std::move(node)); }; ///////// @@ -1769,90 +1817,89 @@ single_defparam_decl: 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++); + extra->astbuf2 = std::make_unique(AST_ENUM); + extra->astbuf2->str = std::string("$enum"); + extra->astbuf2->str += std::to_string(enum_count++); + log_assert(!extra->cell_hack); + extra->cell_hack = extra->astbuf2.get(); + extra->ast_stack.back()->children.push_back(std::move(extra->astbuf2)); // create the template for the names - astbuf1 = new AstNode(AST_ENUM_ITEM); - astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - } enum_base_type '{' enum_name_list optional_comma '}' { + extra->astbuf1 = std::make_unique(AST_ENUM_ITEM); + extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + } enum_base_type TOK_LCURL enum_name_list optional_comma TOK_RCURL { // create template for the enum vars - auto tnode = astbuf1->clone(); - delete astbuf1; - astbuf1 = tnode; + log_assert(extra->cell_hack); + auto tnode_owned = extra->astbuf1->clone(); + auto* tnode = tnode_owned.get(); + extra->astbuf1 = std::move(tnode_owned); tnode->type = AST_WIRE; - tnode->attributes[ID::enum_type] = AstNode::mkconst_str(astbuf2->str); + tnode->attributes[ID::enum_type] = AstNode::mkconst_str(extra->cell_hack->str); + extra->cell_hack = nullptr; // drop constant but keep any range - delete tnode->children[0]; tnode->children.erase(tnode->children.begin()); - $$ = astbuf1; + $$ = extra->astbuf1->clone(); }; enum_base_type: type_atom type_signing - | type_vec type_signing range { if ($3) astbuf1->children.push_back($3); } - | %empty { astbuf1->is_reg = true; addRange(astbuf1); } + | type_vec type_signing range { if ($3) extra->astbuf1->children.push_back(std::move($3)); } + | %empty { extra->astbuf1->is_reg = true; addRange(extra->astbuf1.get()); } ; type_atom: integer_atom_type { - astbuf1->is_reg = true; - astbuf1->is_signed = true; - addRange(astbuf1, $1 - 1, 0); + extra->astbuf1->is_reg = true; + extra->astbuf1->is_signed = true; + addRange(extra->astbuf1.get(), $1 - 1, 0); }; -type_vec: TOK_REG { astbuf1->is_reg = true; } // unsigned - | TOK_LOGIC { astbuf1->is_logic = true; } // unsigned +type_vec: TOK_REG { extra->astbuf1->is_reg = true; } // unsigned + | TOK_LOGIC { extra->astbuf1->is_logic = true; } // unsigned ; type_signing: - TOK_SIGNED { astbuf1->is_signed = true; } - | TOK_UNSIGNED { astbuf1->is_signed = false; } + TOK_SIGNED { extra->astbuf1->is_signed = true; } + | TOK_UNSIGNED { extra->astbuf1->is_signed = false; } | %empty ; enum_name_list: enum_name_decl - | enum_name_list ',' enum_name_decl + | enum_name_list TOK_COMMA enum_name_decl ; enum_name_decl: TOK_ID opt_enum_init { // put in fn - log_assert(astbuf1); - log_assert(astbuf2); - auto node = astbuf1->clone(); + log_assert((bool)extra->astbuf1); + log_assert((bool)extra->cell_hack); + auto node = extra->astbuf1->clone(); node->str = *$1; - delete $1; - SET_AST_NODE_LOC(node, @1, @1); - delete node->children[0]; - node->children[0] = $2 ? $2 : new AstNode(AST_NONE); - astbuf2->children.push_back(node); + SET_AST_NODE_LOC(node.get(), @1, @1); + node->children[0] = $2 ? std::move($2) : std::make_unique(AST_NONE); + extra->cell_hack->children.push_back(std::move(node)); } ; opt_enum_init: - '=' basic_expr { $$ = $2; } // TODO: restrict this - | %empty { $$ = NULL; } + TOK_EQ basic_expr { $$ = std::move($2); } // TODO: restrict this + | %empty { $$ = nullptr; } ; enum_var_list: enum_var - | enum_var_list ',' enum_var + | enum_var_list TOK_COMMA enum_var ; enum_var: TOK_ID { - log_assert(astbuf1); - log_assert(astbuf2); - auto node = astbuf1->clone(); - ast_stack.back()->children.push_back(node); + log_assert((bool)extra->astbuf1); + auto node = extra->astbuf1->clone(); node->str = *$1; - delete $1; - SET_AST_NODE_LOC(node, @1, @1); + SET_AST_NODE_LOC(node.get(), @1, @1); node->is_enum = true; + extra->ast_stack.back()->children.push_back(std::move(node)); } ; -enum_decl: enum_type enum_var_list ';' { delete $1; } +enum_decl: enum_type enum_var_list TOK_SEMICOL { } ; ////////////////// @@ -1861,30 +1908,36 @@ enum_decl: enum_type enum_var_list ';' { delete $1; } struct_decl: attr struct_type { - append_attr($2, $1); - } struct_var_list ';' { - delete astbuf2; + append_attr(extra->astbuf2.get(), $1); + } struct_var_list TOK_SEMICOL { + (void)extra->astbuf2.reset(); } ; -struct_type: struct_union { astbuf2 = $1; astbuf2->is_custom_type = true; } struct_body { $$ = astbuf2; } +struct_type: + struct_union { + extra->astbuf2 = std::move($1); + extra->astbuf2->is_custom_type = true; + } struct_body { + $$ = extra->astbuf2->clone(); + } ; struct_union: - TOK_STRUCT { $$ = new AstNode(AST_STRUCT); } - | TOK_UNION { $$ = new AstNode(AST_UNION); } + TOK_STRUCT { $$ = std::make_unique(AST_STRUCT); } + | TOK_UNION { $$ = std::make_unique(AST_UNION); } ; -struct_body: opt_packed '{' struct_member_list '}' +struct_body: opt_packed TOK_LCURL struct_member_list TOK_RCURL ; opt_packed: TOK_PACKED opt_signed_struct | - %empty { frontend_verilog_yyerror("Only PACKED supported at this time"); }; + %empty { lexer->err("Only PACKED supported at this time"); }; opt_signed_struct: - TOK_SIGNED { astbuf2->is_signed = true; } - | TOK_UNSIGNED { astbuf2->is_signed = false; } + TOK_SIGNED { extra->astbuf2->is_signed = true; } + | TOK_UNSIGNED { extra->astbuf2->is_signed = false; } | %empty // default is unsigned ; @@ -1892,62 +1945,68 @@ struct_member_list: struct_member | struct_member_list struct_member ; -struct_member: struct_member_type member_name_list ';' { delete astbuf1; } +struct_member: struct_member_type member_name_list TOK_SEMICOL { (void)extra->astbuf1.reset(); } ; member_name_list: member_name - | member_name_list ',' member_name + | member_name_list TOK_COMMA member_name ; member_name: TOK_ID { - astbuf1->str = $1->substr(1); - delete $1; - astbuf3 = astbuf1->clone(); - SET_AST_NODE_LOC(astbuf3, @1, @1); - astbuf2->children.push_back(astbuf3); - } range { if ($3) astbuf3->children.push_back($3); } + extra->astbuf1->str = $1->substr(1); + extra->astbuf3 = extra->astbuf1->clone(); + log_assert(!extra->member_hack); + extra->member_hack = extra->astbuf3.get(); + SET_AST_NODE_LOC(extra->member_hack, @1, @1); + extra->astbuf2->children.push_back(std::move(extra->astbuf3)); + } range { + log_assert((bool)extra->member_hack); + if ($3) extra->member_hack->children.push_back(std::move($3)); + extra->member_hack = nullptr; + } ; -struct_member_type: { astbuf1 = new AstNode(AST_STRUCT_ITEM); } member_type_token +struct_member_type: { extra->astbuf1 = std::make_unique(AST_STRUCT_ITEM); } member_type_token ; member_type_token: member_type range_or_multirange { - AstNode *range = checkRange(astbuf1, $2); + auto range = checkRange(extra->astbuf1.get(), std::move($2)); if (range) - astbuf1->children.push_back(range); + extra->astbuf1->children.push_back(std::move(range)); } | { - delete astbuf1; + (void)extra->astbuf1.reset(); } struct_union { - // stash state on ast_stack - ast_stack.push_back(astbuf2); - astbuf2 = $2; + // stash state on extra->ast_stack + // sketchy! + extra->ast_stack.push_back(extra->astbuf2.release()); + extra->astbuf2 = std::move($2); } struct_body { - astbuf1 = astbuf2; + extra->astbuf1 = std::move(extra->astbuf2); // recover state - astbuf2 = ast_stack.back(); - ast_stack.pop_back(); + extra->astbuf2.reset(extra->ast_stack.back()); + extra->ast_stack.pop_back(); } ; member_type: type_atom type_signing | type_vec type_signing - | hierarchical_type_id { addWiretypeNode($1, astbuf1); } + | hierarchical_type_id { extra->addWiretypeNode($1, extra->astbuf1.get()); } ; struct_var_list: struct_var - | struct_var_list ',' struct_var + | struct_var_list TOK_COMMA struct_var ; -struct_var: TOK_ID { auto *var_node = astbuf2->clone(); - var_node->str = *$1; - delete $1; - SET_AST_NODE_LOC(var_node, @1, @1); - ast_stack.back()->children.push_back(var_node); - } - ; +struct_var: + TOK_ID { + auto var_node = extra->astbuf2->clone(); + var_node->str = *$1; + SET_AST_NODE_LOC(var_node.get(), @1, @1); + extra->ast_stack.back()->children.push_back(std::move(var_node)); + }; ///////// // wire @@ -1955,46 +2014,43 @@ struct_var: TOK_ID { auto *var_node = astbuf2->clone(); wire_decl: attr wire_type range_or_multirange { - albuf = $1; - astbuf1 = $2; - astbuf2 = checkRange(astbuf1, $3); + extra->albuf = $1; + extra->astbuf1 = std::move($2); + extra->astbuf2 = checkRange(extra->astbuf1.get(), std::move($3)); } delay wire_name_list { - delete astbuf1; - if (astbuf2 != NULL) - delete astbuf2; - free_attr(albuf); - } ';' | + (void)extra->astbuf1.reset(); + if (extra->astbuf2 != nullptr) + (void)extra->astbuf2.reset(); + free_attr(extra->albuf); + } TOK_SEMICOL | 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; - } opt_supply_wires ';' | + extra->ast_stack.back()->children.push_back(std::make_unique(AST_WIRE)); + extra->ast_stack.back()->children.back()->str = *$3; + append_attr(extra->ast_stack.back()->children.back().get(), $1); + extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::make_unique(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1))); + extra->ast_stack.back()->children.back()->children[0]->str = *$3; + } opt_supply_wires TOK_SEMICOL | 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 ';'; + extra->ast_stack.back()->children.push_back(std::make_unique(AST_WIRE)); + extra->ast_stack.back()->children.back()->str = *$3; + append_attr(extra->ast_stack.back()->children.back().get(), $1); + extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::make_unique(AST_IDENTIFIER), AstNode::mkconst_int(1, false, 1))); + extra->ast_stack.back()->children.back()->children[0]->str = *$3; + } opt_supply_wires TOK_SEMICOL; 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(); + opt_supply_wires TOK_COMMA TOK_ID { + auto wire_node = extra->ast_stack.back()->children.at(GetSize(extra->ast_stack.back()->children)-2)->clone(); + auto assign_node = extra->ast_stack.back()->children.at(GetSize(extra->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; + extra->ast_stack.back()->children.push_back(std::move(wire_node)); + extra->ast_stack.back()->children.push_back(std::move(assign_node)); }; wire_name_list: - wire_name_and_opt_assign | wire_name_list ',' wire_name_and_opt_assign; + wire_name_and_opt_assign | wire_name_list TOK_COMMA wire_name_and_opt_assign; wire_name_and_opt_assign: wire_name { @@ -2002,31 +2058,27 @@ wire_name_and_opt_assign: bool attr_anyseq = false; bool attr_allconst = false; bool attr_allseq = false; - if (ast_stack.back()->children.back()->get_bool_attribute(ID::anyconst)) { - delete ast_stack.back()->children.back()->attributes.at(ID::anyconst); - ast_stack.back()->children.back()->attributes.erase(ID::anyconst); + if (extra->ast_stack.back()->children.back()->get_bool_attribute(ID::anyconst)) { + extra->ast_stack.back()->children.back()->attributes.erase(ID::anyconst); attr_anyconst = true; } - if (ast_stack.back()->children.back()->get_bool_attribute(ID::anyseq)) { - delete ast_stack.back()->children.back()->attributes.at(ID::anyseq); - ast_stack.back()->children.back()->attributes.erase(ID::anyseq); + if (extra->ast_stack.back()->children.back()->get_bool_attribute(ID::anyseq)) { + extra->ast_stack.back()->children.back()->attributes.erase(ID::anyseq); attr_anyseq = true; } - if (ast_stack.back()->children.back()->get_bool_attribute(ID::allconst)) { - delete ast_stack.back()->children.back()->attributes.at(ID::allconst); - ast_stack.back()->children.back()->attributes.erase(ID::allconst); + if (extra->ast_stack.back()->children.back()->get_bool_attribute(ID::allconst)) { + extra->ast_stack.back()->children.back()->attributes.erase(ID::allconst); attr_allconst = true; } - if (ast_stack.back()->children.back()->get_bool_attribute(ID::allseq)) { - delete ast_stack.back()->children.back()->attributes.at(ID::allseq); - ast_stack.back()->children.back()->attributes.erase(ID::allseq); + if (extra->ast_stack.back()->children.back()->get_bool_attribute(ID::allseq)) { + extra->ast_stack.back()->children.back()->attributes.erase(ID::allseq); attr_allseq = true; } - if (current_wire_rand || attr_anyconst || attr_anyseq || attr_allconst || attr_allseq) { - AstNode *wire = new AstNode(AST_IDENTIFIER); - AstNode *fcall = new AstNode(AST_FCALL); - wire->str = ast_stack.back()->children.back()->str; - fcall->str = current_wire_const ? "\\$anyconst" : "\\$anyseq"; + if (extra->current_wire_rand || attr_anyconst || attr_anyseq || attr_allconst || attr_allseq) { + auto wire = std::make_unique(AST_IDENTIFIER); + auto fcall = std::make_unique(AST_FCALL); + wire->str = extra->ast_stack.back()->children.back()->str; + fcall->str = extra->current_wire_const ? "\\$anyconst" : "\\$anyseq"; if (attr_anyconst) fcall->str = "\\$anyconst"; if (attr_anyseq) @@ -2036,125 +2088,122 @@ wire_name_and_opt_assign: if (attr_allseq) fcall->str = "\\$allseq"; fcall->attributes[ID::reg] = AstNode::mkconst_str(RTLIL::unescape_id(wire->str)); - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, fcall)); + extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::move(wire), std::move(fcall))); } } | - wire_name '=' expr { - AstNode *wire = new AstNode(AST_IDENTIFIER); - wire->str = ast_stack.back()->children.back()->str; - if (astbuf1->is_input) { - if (astbuf1->attributes.count(ID::defaultvalue)) - delete astbuf1->attributes.at(ID::defaultvalue); - astbuf1->attributes[ID::defaultvalue] = $3; + wire_name TOK_EQ expr { + auto wire = std::make_unique(AST_IDENTIFIER); + wire->str = extra->ast_stack.back()->children.back()->str; + if (extra->astbuf1->is_input) { + extra->astbuf1->attributes[ID::defaultvalue] = std::move($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); + else if (extra->astbuf1->is_reg || extra->astbuf1->is_logic){ + auto assign = std::make_unique(AST_ASSIGN_LE, std::move(wire), std::move($3)); + SET_AST_NODE_LOC(assign.get(), @1, @3); + auto block = std::make_unique(AST_BLOCK, std::move(assign)); + SET_AST_NODE_LOC(block.get(), @1, @3); + auto init = std::make_unique(AST_INITIAL, std::move(block)); + SET_AST_NODE_LOC(init.get(), @1, @3); - 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); + extra->ast_stack.back()->children.push_back(std::move(init)); } else { - AstNode *assign = new AstNode(AST_ASSIGN, wire, $3); - SET_AST_NODE_LOC(assign, @1, @3); - ast_stack.back()->children.push_back(assign); + auto assign = std::make_unique(AST_ASSIGN, std::move(wire), std::move($3)); + SET_AST_NODE_LOC(assign.get(), @1, @3); + extra->ast_stack.back()->children.push_back(std::move(assign)); } }; wire_name: TOK_ID range_or_multirange { - if (astbuf1 == nullptr) - frontend_verilog_yyerror("Internal error - should not happen - no AST_WIRE node."); - AstNode *node = astbuf1->clone(); + if (extra->astbuf1 == nullptr) + lexer->err("Internal error - should not happen - no AST_WIRE node."); + auto node = extra->astbuf1->clone(); node->str = *$1; - append_attr_clone(node, albuf); - if (astbuf2 != NULL) - node->children.push_back(astbuf2->clone()); - if ($2 != NULL) { + append_attr_clone(node.get(), extra->albuf); + if (extra->astbuf2 != nullptr) + node->children.push_back(extra->astbuf2->clone()); + if ($2 != nullptr) { if (node->is_input || node->is_output) - frontend_verilog_yyerror("input/output/inout ports cannot have unpacked dimensions."); - if (!astbuf2 && !node->is_custom_type) { - addRange(node, 0, 0, false); + lexer->err("input/output/inout ports cannot have unpacked dimensions."); + if (!extra->astbuf2 && !node->is_custom_type) { + addRange(node.get(), 0, 0, false); } - rewriteAsMemoryNode(node, $2); + rewriteAsMemoryNode(node.get(), std::move($2)); } - if (current_function_or_task) { + if (extra->current_function_or_task) { if (node->is_input || node->is_output) - node->port_id = current_function_or_task_port_id++; - } else if (ast_stack.back()->type == AST_GENBLOCK) { + node->port_id = extra->current_function_or_task_port_id++; + } else if (extra->ast_stack.back()->type == AST_GENBLOCK) { if (node->is_input || node->is_output) - frontend_verilog_yyerror("Cannot declare module port `%s' within a generate block.", $1->c_str()); + lexer->err("Cannot declare module port `%s' within a generate block.", $1->c_str()); } else { - if (do_not_require_port_stubs && (node->is_input || node->is_output) && port_stubs.count(*$1) == 0) { - port_stubs[*$1] = ++port_counter; + if (extra->do_not_require_port_stubs && (node->is_input || node->is_output) && extra->port_stubs.count(*$1) == 0) { + extra->port_stubs[*$1] = ++extra->port_counter; } - if (port_stubs.count(*$1) != 0) { + if (extra->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 && !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); + lexer->err("Module port `%s' is neither input nor output.", $1->c_str()); + if (node->is_reg && node->is_input && !node->is_output && !mode->sv) + lexer->err("Input port `%s' is declared as register.", $1->c_str()); + node->port_id = extra->port_stubs[*$1]; + extra->port_stubs.erase(*$1); } else { if (node->is_input || node->is_output) - frontend_verilog_yyerror("Module port `%s' is not declared in module header.", $1->c_str()); + lexer->err("Module port `%s' is not declared in module header.", $1->c_str()); } } //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); + SET_AST_NODE_LOC(node.get(), @1, @1); + extra->ast_stack.back()->children.push_back(std::move(node)); - delete $1; }; assign_stmt: - TOK_ASSIGN delay assign_expr_list ';'; + TOK_ASSIGN delay assign_expr_list TOK_SEMICOL; assign_expr_list: - assign_expr | assign_expr_list ',' assign_expr; + assign_expr | assign_expr_list TOK_COMMA assign_expr; assign_expr: - lvalue '=' expr { - AstNode *node = new AstNode(AST_ASSIGN, $1, $3); + lvalue TOK_EQ expr { + AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN, std::move($1), std::move($3))); SET_AST_NODE_LOC(node, @$, @$); - ast_stack.back()->children.push_back(node); }; type_name: TOK_ID // first time seen - | TOK_USER_TYPE { if (isInLocalScope($1)) frontend_verilog_yyerror("Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); } + | TOK_USER_TYPE { if (extra->isInLocalScope($1)) lexer->err("Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); $$ = std::move($1); } ; typedef_decl: - TOK_TYPEDEF typedef_base_type range_or_multirange type_name range_or_multirange ';' { - astbuf1 = $2; - astbuf2 = checkRange(astbuf1, $3); - if (astbuf2) - astbuf1->children.push_back(astbuf2); - - if ($5 != NULL) { - if (!astbuf2 && !astbuf1->is_custom_type) { - addRange(astbuf1, 0, 0, false); - } - rewriteAsMemoryNode(astbuf1, $5); + TOK_TYPEDEF typedef_base_type range_or_multirange type_name range_or_multirange TOK_SEMICOL { + extra->astbuf1 = std::move($2); + extra->astbuf2 = checkRange(extra->astbuf1.get(), std::move($3)); + bool has_a_range = (bool)extra->astbuf2; + if (extra->astbuf2) { + extra->astbuf1->children.push_back(std::move(extra->astbuf2)); } - addTypedefNode($4, astbuf1); } - | TOK_TYPEDEF enum_struct_type type_name ';' { addTypedefNode($3, $2); } + + if ($5 != nullptr) { + if (!has_a_range && !extra->astbuf1->is_custom_type) { + addRange(extra->astbuf1.get(), 0, 0, false); + } + rewriteAsMemoryNode(extra->astbuf1.get(), std::move($5)); + } + extra->addTypedefNode($4, std::move(extra->astbuf1)); } + | TOK_TYPEDEF enum_struct_type type_name TOK_SEMICOL { extra->addTypedefNode($3, std::move($2)); } ; typedef_base_type: hierarchical_type_id { - $$ = new AstNode(AST_WIRE); + $$ = std::make_unique(AST_WIRE); $$->is_logic = true; - addWiretypeNode($1, $$); + extra->addWiretypeNode($1, $$.get()); } | integer_vector_type opt_signedness_default_unsigned { - $$ = new AstNode(AST_WIRE); - if ($1 == TOK_REG) { + $$ = std::make_unique(AST_WIRE); + if ($1 == token::TOK_REG) { $$->is_reg = true; } else { $$->is_logic = true; @@ -2162,7 +2211,7 @@ typedef_base_type: $$->is_signed = $2; } | integer_atom_type opt_signedness_default_signed { - $$ = new AstNode(AST_WIRE); + $$ = std::make_unique(AST_WIRE); $$->is_logic = true; $$->is_signed = $2; $$->range_left = $1 - 1; @@ -2170,27 +2219,25 @@ typedef_base_type: }; enum_struct_type: - enum_type - | struct_type + enum_type { $$ = std::move($1); } + | struct_type { $$ = std::move($1); } ; cell_stmt: attr TOK_ID { - astbuf1 = new AstNode(AST_CELL); - append_attr(astbuf1, $1); - astbuf1->children.push_back(new AstNode(AST_CELLTYPE)); - astbuf1->children[0]->str = *$2; - delete $2; - } cell_parameter_list_opt cell_list ';' { - delete astbuf1; + extra->astbuf1 = std::make_unique(AST_CELL); + append_attr(extra->astbuf1.get(), $1); + extra->astbuf1->children.push_back(std::make_unique(AST_CELLTYPE)); + extra->astbuf1->children[0]->str = *$2; + } cell_parameter_list_opt cell_list TOK_SEMICOL { + (void)extra->astbuf1.reset(); } | attr tok_prim_wrapper delay { - astbuf1 = new AstNode(AST_PRIMITIVE); - astbuf1->str = *$2; - append_attr(astbuf1, $1); - delete $2; - } prim_list ';' { - delete astbuf1; + extra->astbuf1 = std::make_unique(AST_PRIMITIVE); + extra->astbuf1->str = *$2; + append_attr(extra->astbuf1.get(), $1); + } prim_list TOK_SEMICOL { + (void)extra->astbuf1.reset(); }; tok_prim_wrapper: @@ -2203,91 +2250,99 @@ tok_prim_wrapper: cell_list: single_cell | - cell_list ',' single_cell; + cell_list TOK_COMMA single_cell; single_cell: single_cell_no_array | single_cell_arraylist; single_cell_no_array: TOK_ID { - astbuf2 = astbuf1->clone(); - if (astbuf2->type != AST_PRIMITIVE) - astbuf2->str = *$1; - delete $1; - ast_stack.back()->children.push_back(astbuf2); - } '(' cell_port_list ')' { - SET_AST_NODE_LOC(astbuf2, @1, @$); + extra->astbuf2 = extra->astbuf1->clone(); + if (extra->astbuf2->type != AST_PRIMITIVE) + extra->astbuf2->str = *$1; + // TODO optimize again + extra->cell_hack = extra->astbuf2.get(); + extra->ast_stack.back()->children.push_back(std::move(extra->astbuf2)); + } TOK_LPAREN cell_port_list TOK_RPAREN { + log_assert(extra->cell_hack); + SET_AST_NODE_LOC(extra->cell_hack, @1, @$); + extra->cell_hack = nullptr; } single_cell_arraylist: 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 ')'{ - SET_AST_NODE_LOC(astbuf2, @1, @$); + extra->astbuf2 = extra->astbuf1->clone(); + if (extra->astbuf2->type != AST_PRIMITIVE) + extra->astbuf2->str = *$1; + // TODO optimize again + extra->cell_hack = extra->astbuf2.get(); + extra->ast_stack.back()->children.push_back(std::make_unique(AST_CELLARRAY, std::move($2), std::move(extra->astbuf2))); + } TOK_LPAREN cell_port_list TOK_RPAREN{ + log_assert(extra->cell_hack); + SET_AST_NODE_LOC(extra->cell_hack, @1, @$); + extra->cell_hack = nullptr; }; cell_list_no_array: single_cell_no_array | - cell_list_no_array ',' single_cell_no_array; + cell_list_no_array TOK_COMMA single_cell_no_array; prim_list: single_prim | - prim_list ',' single_prim; + prim_list TOK_COMMA single_prim; single_prim: single_cell | /* no name */ { - astbuf2 = astbuf1->clone(); - ast_stack.back()->children.push_back(astbuf2); - } '(' cell_port_list ')' { - SET_AST_NODE_LOC(astbuf2, @1, @$); + extra->astbuf2 = extra->astbuf1->clone(); + log_assert(!extra->cell_hack); + extra->cell_hack = extra->astbuf2.get(); + // TODO optimize again + extra->ast_stack.back()->children.push_back(std::move(extra->astbuf2)); + } TOK_LPAREN cell_port_list TOK_RPAREN { + log_assert(extra->cell_hack); + SET_AST_NODE_LOC(extra->cell_hack, @1, @$); + extra->cell_hack = nullptr; } cell_parameter_list_opt: - '#' '(' cell_parameter_list ')' | %empty; + TOK_HASH TOK_LPAREN cell_parameter_list TOK_RPAREN | %empty; cell_parameter_list: - cell_parameter | cell_parameter_list ',' cell_parameter; + cell_parameter | cell_parameter_list TOK_COMMA cell_parameter; cell_parameter: %empty | expr { - AstNode *node = new AstNode(AST_PARASET); - astbuf1->children.push_back(node); - node->children.push_back($1); + auto node = std::make_unique(AST_PARASET); + node->children.push_back(std::move($1)); + extra->astbuf1->children.push_back(std::move(node)); } | - '.' TOK_ID '(' ')' { - // delete unused TOK_ID - delete $2; + TOK_DOT TOK_ID TOK_LPAREN TOK_RPAREN { + // just ignore empty parameters } | - '.' TOK_ID '(' expr ')' { - AstNode *node = new AstNode(AST_PARASET); + TOK_DOT TOK_ID TOK_LPAREN expr TOK_RPAREN { + auto node = std::make_unique(AST_PARASET); node->str = *$2; - astbuf1->children.push_back(node); - node->children.push_back($4); - delete $2; + node->children.push_back(std::move($4)); + extra->astbuf1->children.push_back(std::move(node)); }; cell_port_list: cell_port_list_rules { // remove empty args from end of list - while (!astbuf2->children.empty()) { - AstNode *node = astbuf2->children.back(); + while (!extra->cell_hack->children.empty()) { + auto& node = extra->cell_hack->children.back(); if (node->type != AST_ARGUMENT) break; if (!node->children.empty()) break; if (!node->str.empty()) break; - astbuf2->children.pop_back(); - delete node; + extra->cell_hack->children.pop_back(); } // check port types bool has_positional_args = false; bool has_named_args = false; - for (auto node : astbuf2->children) { + for (auto& node : extra->cell_hack->children) { if (node->type != AST_ARGUMENT) continue; if (node->str.empty()) has_positional_args = true; @@ -2296,52 +2351,49 @@ cell_port_list: } if (has_positional_args && has_named_args) - frontend_verilog_yyerror("Mix of positional and named cell ports."); + lexer->err("Mix of positional and named cell ports."); }; cell_port_list_rules: - cell_port | cell_port_list_rules ',' cell_port; + cell_port | cell_port_list_rules TOK_COMMA cell_port; cell_port: attr { - AstNode *node = new AstNode(AST_ARGUMENT); - astbuf2->children.push_back(node); + auto node = std::make_unique(AST_ARGUMENT); + extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | attr expr { - AstNode *node = new AstNode(AST_ARGUMENT); - astbuf2->children.push_back(node); - node->children.push_back($2); + auto node = std::make_unique(AST_ARGUMENT); + node->children.push_back(std::move($2)); + extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | - attr '.' TOK_ID '(' expr ')' { - AstNode *node = new AstNode(AST_ARGUMENT); + attr TOK_DOT TOK_ID TOK_LPAREN expr TOK_RPAREN { + auto node = std::make_unique(AST_ARGUMENT); node->str = *$3; - astbuf2->children.push_back(node); - node->children.push_back($5); - delete $3; + node->children.push_back(std::move($5)); + extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | - attr '.' TOK_ID '(' ')' { - AstNode *node = new AstNode(AST_ARGUMENT); + attr TOK_DOT TOK_ID TOK_LPAREN TOK_RPAREN { + auto node = std::make_unique(AST_ARGUMENT); node->str = *$3; - astbuf2->children.push_back(node); - delete $3; + extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | - attr '.' TOK_ID { - AstNode *node = new AstNode(AST_ARGUMENT); + attr TOK_DOT TOK_ID { + auto node = std::make_unique(AST_ARGUMENT); node->str = *$3; - astbuf2->children.push_back(node); - node->children.push_back(new AstNode(AST_IDENTIFIER)); + node->children.push_back(std::make_unique(AST_IDENTIFIER)); node->children.back()->str = *$3; - delete $3; + extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | attr TOK_WILDCARD_CONNECT { - if (!sv_mode) - frontend_verilog_yyerror("Wildcard port connections are only supported in SystemVerilog mode."); - astbuf2->attributes[ID::wildcard_port_conns] = AstNode::mkconst_int(1, false); + if (!mode->sv) + lexer->err("Wildcard port connections are only supported in SystemVerilog mode."); + extra->cell_hack->attributes[ID::wildcard_port_conns] = AstNode::mkconst_int(1, false); free_attr($1); }; @@ -2363,100 +2415,88 @@ always_or_always_ff: always_stmt: attr always_or_always_ff { - AstNode *node = new AstNode(AST_ALWAYS); + AstNode* node = extra->pushChild(std::make_unique(AST_ALWAYS)); append_attr(node, $1); if ($2) node->attributes[ID::always_ff] = AstNode::mkconst_int(1, false); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); } always_cond { - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); + (void)extra->pushChild(std::make_unique(AST_BLOCK)); } behavioral_stmt { - SET_AST_NODE_LOC(ast_stack.back(), @6, @6); - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @6, @6); + extra->ast_stack.pop_back(); - SET_AST_NODE_LOC(ast_stack.back(), @2, @$); - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @$); + extra->ast_stack.pop_back(); SET_RULE_LOC(@$, @2, @$); } | attr always_comb_or_latch { - AstNode *node = new AstNode(AST_ALWAYS); + AstNode* node = extra->pushChild(std::make_unique(AST_ALWAYS)); append_attr(node, $1); if ($2) node->attributes[ID::always_latch] = AstNode::mkconst_int(1, false); else node->attributes[ID::always_comb] = AstNode::mkconst_int(1, false); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); + (void)extra->pushChild(std::make_unique(AST_BLOCK)); } behavioral_stmt { - ast_stack.pop_back(); - ast_stack.pop_back(); + extra->ast_stack.pop_back(); + extra->ast_stack.pop_back(); } | attr TOK_INITIAL { - AstNode *node = new AstNode(AST_INITIAL); + AstNode* node = extra->pushChild(std::make_unique(AST_INITIAL)); append_attr(node, $1); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); + (void)extra->pushChild(std::make_unique(AST_BLOCK)); } behavioral_stmt { - ast_stack.pop_back(); - ast_stack.pop_back(); + extra->ast_stack.pop_back(); + extra->ast_stack.pop_back(); }; always_cond: - '@' '(' always_events ')' | - '@' '(' '*' ')' | - '@' ATTR_BEGIN ')' | - '@' '(' ATTR_END | - '@' '*' | + TOK_AT TOK_LPAREN always_events TOK_RPAREN | + TOK_AT TOK_LPAREN TOK_ASTER TOK_RPAREN | + TOK_AT ATTR_BEGIN TOK_RPAREN | + TOK_AT TOK_LPAREN ATTR_END | + TOK_AT TOK_ASTER | %empty; always_events: always_event | always_events TOK_OR always_event | - always_events ',' always_event; + always_events TOK_COMMA always_event; always_event: TOK_POSEDGE expr { - AstNode *node = new AstNode(AST_POSEDGE); - SET_AST_NODE_LOC(node, @1, @1); - ast_stack.back()->children.push_back(node); - node->children.push_back($2); + auto node = std::make_unique(AST_POSEDGE); + SET_AST_NODE_LOC(node.get(), @1, @1); + node->children.push_back(std::move($2)); + extra->ast_stack.back()->children.push_back(std::move(node)); } | TOK_NEGEDGE expr { - AstNode *node = new AstNode(AST_NEGEDGE); - SET_AST_NODE_LOC(node, @1, @1); - ast_stack.back()->children.push_back(node); - node->children.push_back($2); + auto node = std::make_unique(AST_NEGEDGE); + SET_AST_NODE_LOC(node.get(), @1, @1); + node->children.push_back(std::move($2)); + extra->ast_stack.back()->children.push_back(std::move(node)); } | expr { - AstNode *node = new AstNode(AST_EDGE); - ast_stack.back()->children.push_back(node); - node->children.push_back($1); + auto node = std::make_unique(AST_EDGE); + node->children.push_back(std::move($1)); + extra->ast_stack.back()->children.push_back(std::move(node)); }; opt_label: - ':' TOK_ID { + TOK_COL TOK_ID { $$ = $2; } | %empty { - $$ = NULL; + $$ = nullptr; }; opt_sva_label: - TOK_SVA_LABEL ':' { + TOK_SVA_LABEL TOK_COL { $$ = $1; } | %empty { - $$ = NULL; + $$ = nullptr; }; opt_property: @@ -2472,21 +2512,19 @@ opt_property: modport_stmt: TOK_MODPORT TOK_ID { - AstNode *modport = new AstNode(AST_MODPORT); - ast_stack.back()->children.push_back(modport); - ast_stack.push_back(modport); + AstNode* modport = extra->pushChild(std::make_unique(AST_MODPORT)); modport->str = *$2; - delete $2; + } modport_args_opt { - ast_stack.pop_back(); - log_assert(ast_stack.size() == 2); - } ';' + extra->ast_stack.pop_back(); + log_assert(extra->ast_stack.size() == 2); + } TOK_SEMICOL modport_args_opt: - '(' ')' | '(' modport_args optional_comma ')'; + TOK_LPAREN TOK_RPAREN | TOK_LPAREN modport_args optional_comma TOK_RPAREN; modport_args: - modport_arg | modport_args ',' modport_arg; + modport_arg | modport_args TOK_COMMA modport_arg; modport_arg: modport_type_token modport_member | @@ -2494,222 +2532,174 @@ modport_arg: modport_member: TOK_ID { - AstNode *modport_member = new AstNode(AST_MODPORTMEMBER); - ast_stack.back()->children.push_back(modport_member); + AstNode* modport_member = extra->saveChild(std::make_unique(AST_MODPORTMEMBER)); modport_member->str = *$1; - modport_member->is_input = current_modport_input; - modport_member->is_output = current_modport_output; - delete $1; + modport_member->is_input = extra->current_modport_input; + modport_member->is_output = extra->current_modport_output; + } modport_type_token: - TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;} + TOK_INPUT {extra->current_modport_input = 1; extra->current_modport_output = 0;} | TOK_OUTPUT {extra->current_modport_input = 0; extra->current_modport_output = 1;} assert: - opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' { - if (noassert_mode) { - delete $5; + opt_sva_label TOK_ASSERT opt_property TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + if (mode->noassert) { + } else { - AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5); + AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_ASSUME : AST_ASSERT, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) node->str = *$1; - ast_stack.back()->children.push_back(node); } - if ($1 != nullptr) - delete $1; } | - opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' { - if (noassume_mode) { - delete $5; + opt_sva_label TOK_ASSUME opt_property TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + if (mode->noassume) { } else { - AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5); + AstNode* node = extra->saveChild(std::make_unique(mode->assert_assumes ? AST_ASSERT : AST_ASSUME, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) node->str = *$1; - ast_stack.back()->children.push_back(node); } - if ($1 != nullptr) - delete $1; } | - opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { - if (noassert_mode) { - delete $6; + opt_sva_label TOK_ASSERT opt_property TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { + if (mode->noassert) { } else { - AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6); + AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_FAIR : AST_LIVE, std::move($6))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @7); if ($1 != nullptr) node->str = *$1; - ast_stack.back()->children.push_back(node); } - if ($1 != nullptr) - delete $1; } | - opt_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' { - if (noassume_mode) { - delete $6; + opt_sva_label TOK_ASSUME opt_property TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { + if (mode->noassume) { } else { - AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6); + AstNode* node = extra->saveChild(std::make_unique(mode->assert_assumes ? AST_LIVE : AST_FAIR, std::move($6))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @7); if ($1 != nullptr) node->str = *$1; - ast_stack.back()->children.push_back(node); } - if ($1 != nullptr) - delete $1; } | - opt_sva_label TOK_COVER opt_property '(' expr ')' ';' { - AstNode *node = new AstNode(AST_COVER, $5); + opt_sva_label TOK_COVER opt_property TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(AST_COVER, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) { node->str = *$1; - delete $1; } - ast_stack.back()->children.push_back(node); } | - opt_sva_label TOK_COVER opt_property '(' ')' ';' { - AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); + opt_sva_label TOK_COVER opt_property TOK_LPAREN TOK_RPAREN TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(AST_COVER, AstNode::mkconst_int(1, false))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @5); if ($1 != nullptr) { node->str = *$1; - delete $1; } - ast_stack.back()->children.push_back(node); } | - opt_sva_label TOK_COVER ';' { - AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); + opt_sva_label TOK_COVER TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(AST_COVER, AstNode::mkconst_int(1, false))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @2); if ($1 != nullptr) { node->str = *$1; - delete $1; } - ast_stack.back()->children.push_back(node); } | - opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' { - if (norestrict_mode) { - delete $5; + opt_sva_label TOK_RESTRICT opt_property TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + if (mode->norestrict) { } else { - AstNode *node = new AstNode(AST_ASSUME, $5); + AstNode* node = extra->saveChild(std::make_unique(AST_ASSUME, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) node->str = *$1; - ast_stack.back()->children.push_back(node); } if (!$3) - log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); - if ($1 != nullptr) - delete $1; + log_file_warning(current_filename, @$.begin.line, "SystemVerilog does not allow \"restrict\" without \"property\".\n"); } | - opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' { - if (norestrict_mode) { - delete $6; + opt_sva_label TOK_RESTRICT opt_property TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { + if (mode->norestrict) { } else { - AstNode *node = new AstNode(AST_FAIR, $6); + AstNode* node = extra->saveChild(std::make_unique(AST_FAIR, std::move($6))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @7); if ($1 != nullptr) node->str = *$1; - ast_stack.back()->children.push_back(node); } if (!$3) - log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); - if ($1 != nullptr) - delete $1; + log_file_warning(current_filename, @$.begin.line, "SystemVerilog does not allow \"restrict\" without \"property\".\n"); }; assert_property: - opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { - AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5); + opt_sva_label TOK_ASSERT TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_ASSUME : AST_ASSERT, std::move($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; + extra->ast_stack.back()->children.back()->str = *$1; } } | - opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { - AstNode *node = new AstNode(AST_ASSUME, $5); + opt_sva_label TOK_ASSUME TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(AST_ASSUME, std::move($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; + extra->ast_stack.back()->children.back()->str = *$1; } } | - opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6); + opt_sva_label TOK_ASSERT TOK_PROPERTY TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_FAIR : AST_LIVE, std::move($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; + extra->ast_stack.back()->children.back()->str = *$1; } } | - opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - AstNode *node = new AstNode(AST_FAIR, $6); + opt_sva_label TOK_ASSUME TOK_PROPERTY TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(AST_FAIR, std::move($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; + extra->ast_stack.back()->children.back()->str = *$1; } } | - opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' { - AstNode *node = new AstNode(AST_COVER, $5); + opt_sva_label TOK_COVER TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + AstNode* node = extra->saveChild(std::make_unique(AST_COVER, std::move($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; + extra->ast_stack.back()->children.back()->str = *$1; } } | - opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' { - if (norestrict_mode) { - delete $5; + opt_sva_label TOK_RESTRICT TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { + if (mode->norestrict) { } else { - AstNode *node = new AstNode(AST_ASSUME, $5); + AstNode* node = extra->saveChild(std::make_unique(AST_ASSUME, std::move($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; + extra->ast_stack.back()->children.back()->str = *$1; } } } | - opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - if (norestrict_mode) { - delete $6; + opt_sva_label TOK_RESTRICT TOK_PROPERTY TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { + if (mode->norestrict) { } else { - AstNode *node = new AstNode(AST_FAIR, $6); + AstNode* node = extra->saveChild(std::make_unique(AST_FAIR, std::move($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; + extra->ast_stack.back()->children.back()->str = *$1; } } }; simple_behavioral_stmt: - attr lvalue '=' delay expr { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, $5); - ast_stack.back()->children.push_back(node); + attr lvalue TOK_EQ delay expr { + AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN_EQ, std::move($2), std::move($5))); SET_AST_NODE_LOC(node, @2, @5); append_attr(node, $1); } | attr lvalue attr inc_or_dec_op { - addIncOrDecStmt($1, $2, $3, $4, @1, @4); + extra->addIncOrDecStmt($1, std::move($2), $3, $4, @1, @4); } | attr inc_or_dec_op attr lvalue { - addIncOrDecStmt($1, $4, $3, $2, @1, @4); + extra->addIncOrDecStmt($1, std::move($4), $3, $2, @1, @4); } | attr lvalue OP_LE delay expr { - AstNode *node = new AstNode(AST_ASSIGN_LE, $2, $5); - ast_stack.back()->children.push_back(node); + AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN_LE, std::move($2), std::move($5))); SET_AST_NODE_LOC(node, @2, @5); append_attr(node, $1); } | attr lvalue asgn_binop delay expr { - addAsgnBinopStmt($1, $2, $3, $5, @2, @5); + (void)extra->addAsgnBinopStmt($1, std::move($2), $3, std::move($5), @2, @5); }; asgn_binop: @@ -2733,202 +2723,184 @@ inc_or_dec_op: TOK_DECREMENT { $$ = AST_SUB; } ; for_initialization: - TOK_ID '=' expr { - AstNode *ident = new AstNode(AST_IDENTIFIER); + TOK_ID TOK_EQ expr { + auto ident = std::make_unique(AST_IDENTIFIER); ident->str = *$1; - AstNode *node = new AstNode(AST_ASSIGN_EQ, ident, $3); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @1, @3); - delete $1; + auto node = std::make_unique(AST_ASSIGN_EQ, std::move(ident), std::move($3)); + SET_AST_NODE_LOC(node.get(), @1, @3); + extra->ast_stack.back()->children.push_back(std::move(node)); } | non_io_wire_type range TOK_ID { - frontend_verilog_yyerror("For loop variable declaration is missing initialization!"); + lexer->err("For loop variable declaration is missing initialization!"); } | - non_io_wire_type range TOK_ID '=' expr { - if (!sv_mode) - frontend_verilog_yyerror("For loop inline variable declaration is only supported in SystemVerilog mode!"); + non_io_wire_type range TOK_ID TOK_EQ expr { + if (!mode->sv) + lexer->err("For loop inline variable declaration is only supported in SystemVerilog mode!"); // loop variable declaration - AstNode *wire = $1; - AstNode *range = checkRange(wire, $2); + auto wire = std::move($1); + auto range = checkRange(wire.get(), std::move($2)); + SET_AST_NODE_LOC(wire.get(), @1, @3); + SET_AST_NODE_LOC(range.get(), @2, @2); if (range != nullptr) - wire->children.push_back(range); - SET_AST_NODE_LOC(wire, @1, @3); - SET_AST_NODE_LOC(range, @2, @2); + wire->children.push_back(std::move(range)); - AstNode *ident = new AstNode(AST_IDENTIFIER); + auto ident = std::make_unique(AST_IDENTIFIER); ident->str = *$3; wire->str = *$3; - delete $3; - AstNode *loop = ast_stack.back(); - AstNode *parent = ast_stack.at(ast_stack.size() - 2); - log_assert(parent->children.back() == loop); + AstNode *parent = extra->ast_stack.at(extra->ast_stack.size() - 2); + auto& loop = parent->children.back(); + log_assert(extra->ast_stack.back() == loop.get()); // loop variable initialization - AstNode *asgn = new AstNode(AST_ASSIGN_EQ, ident, $5); - loop->children.push_back(asgn); - SET_AST_NODE_LOC(asgn, @3, @5); - SET_AST_NODE_LOC(ident, @3, @3); + SET_AST_NODE_LOC(ident.get(), @3, @3); + auto asgn = std::make_unique(AST_ASSIGN_EQ, std::move(ident), std::move($5)); + SET_AST_NODE_LOC(asgn.get(), @3, @5); + loop->children.push_back(std::move(asgn)); // inject a wrapping block to declare the loop variable and // contain the current loop - AstNode *wrapper = new AstNode(AST_BLOCK); + auto wrapper = std::make_unique(AST_BLOCK); wrapper->str = "$fordecl_block$" + std::to_string(autoidx++); - wrapper->children.push_back(wire); - wrapper->children.push_back(loop); - parent->children.back() = wrapper; // replaces `loop` + wrapper->children.push_back(std::move(wire)); + wrapper->children.push_back(std::move(loop)); + parent->children.back() = std::move(wrapper); }; // this production creates the obligatory if-else shift/reduce conflict behavioral_stmt: defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl | non_opt_delay behavioral_stmt | - simple_behavioral_stmt ';' | - attr ';' { + simple_behavioral_stmt TOK_SEMICOL | + attr TOK_SEMICOL { free_attr($1); } | attr hierarchical_id { - AstNode *node = new AstNode(AST_TCALL); + AstNode* node = extra->pushChild(std::make_unique(AST_TCALL)); node->str = *$2; - delete $2; - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); append_attr(node, $1); - } opt_arg_list ';'{ - SET_AST_NODE_LOC(ast_stack.back(), @2, @5); - ast_stack.pop_back(); + } opt_arg_list TOK_SEMICOL{ + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @5); + extra->ast_stack.pop_back(); } | attr TOK_MSG_TASKS { - AstNode *node = new AstNode(AST_TCALL); + AstNode* node = extra->pushChild(std::make_unique(AST_TCALL)); node->str = *$2; - delete $2; - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); append_attr(node, $1); - } opt_arg_list ';'{ - SET_AST_NODE_LOC(ast_stack.back(), @2, @5); - ast_stack.pop_back(); + } opt_arg_list TOK_SEMICOL{ + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @5); + extra->ast_stack.pop_back(); } | attr TOK_BEGIN { - enterTypeScope(); + extra->enterTypeScope(); } opt_label { - AstNode *node = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + AstNode* node = extra->pushChild(std::make_unique(AST_BLOCK)); append_attr(node, $1); - if ($4 != NULL) + if ($4 != nullptr) node->str = *$4; } behavioral_stmt_list TOK_END opt_label { - exitTypeScope(); - checkLabelsMatch("Begin label", $4, $8); - AstNode *node = ast_stack.back(); + extra->exitTypeScope(); + checkLabelsMatch(@8, "Begin label", $4, $8); + AstNode *node = extra->ast_stack.back(); // In SystemVerilog, unnamed blocks with block item declarations // create an implicit hierarchy scope - if (sv_mode && node->str.empty()) - for (const AstNode* child : node->children) + if (mode->sv && node->str.empty()) + for (auto& child : node->children) if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || child->type == AST_TYPEDEF) { node->str = "$unnamed_block$" + std::to_string(autoidx++); break; } - SET_AST_NODE_LOC(ast_stack.back(), @2, @8); - delete $4; - delete $8; - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @8); + extra->ast_stack.pop_back(); } | - attr TOK_FOR '(' { - AstNode *node = new AstNode(AST_FOR); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + attr TOK_FOR TOK_LPAREN { + AstNode* node = extra->pushChild(std::make_unique(AST_FOR)); append_attr(node, $1); - } for_initialization ';' expr { - ast_stack.back()->children.push_back($7); - } ';' simple_behavioral_stmt ')' { - AstNode *block = new AstNode(AST_BLOCK); + } for_initialization TOK_SEMICOL expr { + extra->ast_stack.back()->children.push_back(std::move($7)); + } TOK_SEMICOL simple_behavioral_stmt TOK_RPAREN { + AstNode* block = extra->pushChild(std::make_unique(AST_BLOCK)); block->str = "$for_loop$" + std::to_string(autoidx++); - 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(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @13, @13); + extra->ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @13); + extra->ast_stack.pop_back(); } | - attr TOK_WHILE '(' expr ')' { - AstNode *node = new AstNode(AST_WHILE); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + attr TOK_WHILE TOK_LPAREN expr TOK_RPAREN { + AstNode* node = extra->pushChild(std::make_unique(AST_WHILE)); append_attr(node, $1); - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back($4); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); + auto block_owned = std::make_unique(AST_BLOCK); + auto* block = block_owned.get(); + extra->ast_stack.back()->children.push_back(std::move($4)); + extra->ast_stack.back()->children.push_back(std::move(block_owned)); + extra->ast_stack.push_back(block); } behavioral_stmt { - SET_AST_NODE_LOC(ast_stack.back(), @7, @7); - ast_stack.pop_back(); - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @7, @7); + extra->ast_stack.pop_back(); + extra->ast_stack.pop_back(); } | - attr TOK_REPEAT '(' expr ')' { - AstNode *node = new AstNode(AST_REPEAT); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + attr TOK_REPEAT TOK_LPAREN expr TOK_RPAREN { + AstNode* node = extra->pushChild(std::make_unique(AST_REPEAT)); append_attr(node, $1); - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back($4); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); + auto block_owned = std::make_unique(AST_BLOCK); + auto* block = block_owned.get(); + extra->ast_stack.back()->children.push_back(std::move($4)); + extra->ast_stack.back()->children.push_back(std::move(block_owned)); + extra->ast_stack.push_back(block); } behavioral_stmt { - SET_AST_NODE_LOC(ast_stack.back(), @7, @7); - ast_stack.pop_back(); - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @7, @7); + extra->ast_stack.pop_back(); + extra->ast_stack.pop_back(); } | - if_attr TOK_IF '(' expr ')' { - AstNode *node = 0; - AstNode *context = ast_stack.back(); + if_attr TOK_IF TOK_LPAREN expr TOK_RPAREN { + std::unique_ptr node_owned; + AstNode* node = nullptr; + AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) { - AstNode *outer = ast_stack[ast_stack.size() - 2]; + AstNode *outer = extra->ast_stack[extra->ast_stack.size() - 2]; log_assert (outer && outer->type == AST_CASE); if (outer->get_bool_attribute(ID::parallel_case)) { // parallel "else if": append condition to outer "if" node = outer; log_assert (node->children.size()); - delete node->children.back(); node->children.pop_back(); } else if (outer->get_bool_attribute(ID::full_case)) (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); } - AstNode *expr = new AstNode(AST_REDUCE_BOOL, $4); + auto expr = std::make_unique(AST_REDUCE_BOOL, std::move($4)); if (!node) { // not parallel "else if": begin new construction - node = new AstNode(AST_CASE); + node_owned = std::make_unique(AST_CASE); + node = node_owned.get(); append_attr(node, $1); - ast_stack.back()->children.push_back(node); - node->children.push_back(node->get_bool_attribute(ID::parallel_case) ? AstNode::mkconst_int(1, false, 1) : expr); + node->children.push_back(node->get_bool_attribute(ID::parallel_case) ? AstNode::mkconst_int(1, false, 1) : expr->clone()); + extra->ast_stack.back()->children.push_back(std::move(node_owned)); } - AstNode *block = new AstNode(AST_BLOCK); - AstNode *cond = new AstNode(AST_COND, node->get_bool_attribute(ID::parallel_case) ? expr : AstNode::mkconst_int(1, false, 1), block); - SET_AST_NODE_LOC(cond, @4, @4); - node->children.push_back(cond); - ast_stack.push_back(node); - ast_stack.push_back(block); + auto block_owned = std::make_unique(AST_BLOCK); + auto* block = block_owned.get(); + auto cond_owned = std::make_unique(AST_COND, node->get_bool_attribute(ID::parallel_case) ? std::move(expr) : AstNode::mkconst_int(1, false, 1), std::move(block_owned)); + SET_AST_NODE_LOC(cond_owned.get(), @4, @4); + node->children.push_back(std::move(cond_owned)); + extra->ast_stack.push_back(node); + extra->ast_stack.push_back(block); } behavioral_stmt { - SET_AST_NODE_LOC(ast_stack.back(), @7, @7); + SET_AST_NODE_LOC(extra->ast_stack.back(), @7, @7); } optional_else { - ast_stack.pop_back(); - SET_AST_NODE_LOC(ast_stack.back(), @2, @9); - ast_stack.pop_back(); + extra->ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @9); + extra->ast_stack.pop_back(); } | - case_attr case_type '(' expr ')' { - AstNode *node = new AstNode(AST_CASE, $4); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + case_attr case_type TOK_LPAREN expr TOK_RPAREN { + AstNode* node = extra->pushChild(std::make_unique(AST_CASE, std::move($4))); append_attr(node, $1); - SET_AST_NODE_LOC(ast_stack.back(), @4, @4); + SET_AST_NODE_LOC(extra->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(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @9); + extra->case_type_stack.pop_back(); + extra->ast_stack.pop_back(); }; if_attr: @@ -2936,23 +2908,23 @@ if_attr: $$ = $1; } | attr TOK_UNIQUE0 { - AstNode *context = ast_stack.back(); + AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) - frontend_verilog_yyerror("unique0 keyword cannot be used for 'else if' branch."); + lexer->err("unique0 keyword cannot be used for 'else if' branch."); (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); $$ = $1; } | attr TOK_PRIORITY { - AstNode *context = ast_stack.back(); + AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) - frontend_verilog_yyerror("priority keyword cannot be used for 'else if' branch."); + lexer->err("priority keyword cannot be used for 'else if' branch."); (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); $$ = $1; } | attr TOK_UNIQUE { - AstNode *context = ast_stack.back(); + AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) - frontend_verilog_yyerror("unique keyword cannot be used for 'else if' branch."); + lexer->err("unique keyword cannot be used for 'else if' branch."); (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); $$ = $1; @@ -2978,23 +2950,23 @@ case_attr: case_type: TOK_CASE { - case_type_stack.push_back(0); + extra->case_type_stack.push_back(0); } | TOK_CASEX { - case_type_stack.push_back('x'); + extra->case_type_stack.push_back('x'); } | TOK_CASEZ { - case_type_stack.push_back('z'); + extra->case_type_stack.push_back('z'); }; opt_synopsys_attr: opt_synopsys_attr TOK_SYNOPSYS_FULL_CASE { - if (ast_stack.back()->attributes.count(ID::full_case) == 0) - ast_stack.back()->attributes[ID::full_case] = AstNode::mkconst_int(1, false); + if (extra->ast_stack.back()->attributes.count(ID::full_case) == 0) + extra->ast_stack.back()->attributes[ID::full_case] = AstNode::mkconst_int(1, false); } | opt_synopsys_attr TOK_SYNOPSYS_PARALLEL_CASE { - if (ast_stack.back()->attributes.count(ID::parallel_case) == 0) - ast_stack.back()->attributes[ID::parallel_case] = AstNode::mkconst_int(1, false); + if (extra->ast_stack.back()->attributes.count(ID::parallel_case) == 0) + extra->ast_stack.back()->attributes[ID::parallel_case] = AstNode::mkconst_int(1, false); } | %empty; @@ -3004,16 +2976,18 @@ behavioral_stmt_list: optional_else: TOK_ELSE { - AstNode *block = new AstNode(AST_BLOCK); - block->attributes[ID::promoted_if] = AstNode::mkconst_int(1, false ); - AstNode *cond = new AstNode(AST_COND, new AstNode(AST_DEFAULT), block); + extra->ast_stack.pop_back(); + auto block_owned = std::make_unique(AST_BLOCK); + auto* block = block_owned.get(); + block->attributes[ID::promoted_if] = AstNode::mkconst_int(1, false); + AstNode* cond = extra->saveChild( + std::make_unique(AST_COND, + std::make_unique(AST_DEFAULT), + std::move(block_owned))); + extra->ast_stack.push_back(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 { - SET_AST_NODE_LOC(ast_stack.back(), @3, @3); + SET_AST_NODE_LOC(extra->ast_stack.back(), @3, @3); } | %empty %prec FAKE_THEN; @@ -3023,21 +2997,17 @@ case_body: case_item: { - 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); + (void)extra->pushChild(std::make_unique( + extra->case_type_stack.size() && extra->case_type_stack.back() == 'x' ? AST_CONDX : + extra->case_type_stack.size() && extra->case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND)); } case_select { - AstNode *block = new AstNode(AST_BLOCK); - ast_stack.back()->children.push_back(block); - ast_stack.push_back(block); - case_type_stack.push_back(0); + (void)extra->pushChild(std::make_unique(AST_BLOCK)); + extra->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(); + extra->case_type_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @4, @4); + extra->ast_stack.pop_back(); + extra->ast_stack.pop_back(); }; gen_case_body: @@ -3046,87 +3016,78 @@ gen_case_body: gen_case_item: { - 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); + (void)extra->pushChild(std::make_unique( + extra->case_type_stack.size() && extra->case_type_stack.back() == 'x' ? AST_CONDX : + extra->case_type_stack.size() && extra->case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND)); } case_select { - case_type_stack.push_back(0); - SET_AST_NODE_LOC(ast_stack.back(), @2, @2); + extra->case_type_stack.push_back(0); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @2); } gen_stmt_block { - case_type_stack.pop_back(); - ast_stack.pop_back(); + extra->case_type_stack.pop_back(); + extra->ast_stack.pop_back(); }; case_select: - case_expr_list ':' | + case_expr_list TOK_COL | TOK_DEFAULT; case_expr_list: TOK_DEFAULT { - AstNode *node = new AstNode(AST_DEFAULT); + AstNode* node = extra->saveChild(std::make_unique(AST_DEFAULT)); SET_AST_NODE_LOC(node, @1, @1); - ast_stack.back()->children.push_back(node); } | TOK_SVA_LABEL { - AstNode *node = new AstNode(AST_IDENTIFIER); + AstNode* node = extra->pushChild(std::make_unique(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; } | expr { - ast_stack.back()->children.push_back($1); + extra->ast_stack.back()->children.push_back(std::move($1)); } | - case_expr_list ',' expr { - ast_stack.back()->children.push_back($3); + case_expr_list TOK_COMMA expr { + extra->ast_stack.back()->children.push_back(std::move($3)); }; rvalue: - hierarchical_id '[' expr ']' '.' rvalue { - $$ = new AstNode(AST_PREFIX, $3, $6); + hierarchical_id TOK_LBRA expr TOK_RBRA TOK_DOT rvalue { + $$ = std::make_unique(AST_PREFIX, std::move($3), std::move($6)); $$->str = *$1; - SET_AST_NODE_LOC($$, @1, @6); - delete $1; + SET_AST_NODE_LOC($$.get(), @1, @6); } | hierarchical_id range { - $$ = new AstNode(AST_IDENTIFIER, $2); + $$ = std::make_unique(AST_IDENTIFIER, std::move($2)); $$->str = *$1; - SET_AST_NODE_LOC($$, @1, @1); - delete $1; + SET_AST_NODE_LOC($$.get(), @1, @1); if ($2 == nullptr && ($$->str == "\\$initstate" || $$->str == "\\$anyconst" || $$->str == "\\$anyseq" || $$->str == "\\$allconst" || $$->str == "\\$allseq")) $$->type = AST_FCALL; } | hierarchical_id non_opt_multirange { - $$ = new AstNode(AST_IDENTIFIER, $2); + $$ = std::make_unique(AST_IDENTIFIER, std::move($2)); $$->str = *$1; - SET_AST_NODE_LOC($$, @1, @1); - delete $1; + SET_AST_NODE_LOC($$.get(), @1, @1); }; lvalue: rvalue { - $$ = $1; + $$ = std::move($1); } | - '{' lvalue_concat_list '}' { - $$ = $2; + TOK_LCURL lvalue_concat_list TOK_RCURL { + $$ = std::move($2); }; lvalue_concat_list: expr { - $$ = new AstNode(AST_CONCAT); - $$->children.push_back($1); + $$ = std::make_unique(AST_CONCAT); + $$->children.push_back(std::move($1)); } | - expr ',' lvalue_concat_list { - $$ = $3; - $$->children.push_back($1); + expr TOK_COMMA lvalue_concat_list { + $$ = std::move($3); + $$->children.push_back(std::move($1)); }; opt_arg_list: - '(' arg_list optional_comma ')' | + TOK_LPAREN arg_list optional_comma TOK_RPAREN | %empty; arg_list: @@ -3135,11 +3096,11 @@ arg_list: arg_list2: single_arg | - arg_list ',' single_arg; + arg_list TOK_COMMA single_arg; single_arg: expr { - ast_stack.back()->children.push_back($1); + extra->ast_stack.back()->children.push_back(std::move($1)); }; module_gen_body: @@ -3149,111 +3110,92 @@ module_gen_body: gen_stmt_or_module_body_stmt: gen_stmt | module_body_stmt | - attr ';' { + attr TOK_SEMICOL { free_attr($1); }; genvar_identifier: TOK_ID { - $$ = new AstNode(AST_IDENTIFIER); + $$ = std::make_unique(AST_IDENTIFIER); $$->str = *$1; - delete $1; }; genvar_initialization: TOK_GENVAR genvar_identifier { - frontend_verilog_yyerror("Generate for loop variable declaration is missing initialization!"); + lexer->err("Generate for loop variable declaration is missing initialization!"); } | - TOK_GENVAR genvar_identifier '=' expr { - if (!sv_mode) - frontend_verilog_yyerror("Generate for loop inline variable declaration is only supported in SystemVerilog mode!"); - AstNode *node = new AstNode(AST_GENVAR); + TOK_GENVAR genvar_identifier TOK_EQ expr { + if (!mode->sv) + lexer->err("Generate for loop inline variable declaration is only supported in SystemVerilog mode!"); + AstNode* node = extra->saveChild(std::make_unique(AST_GENVAR)); node->is_reg = true; node->is_signed = true; node->range_left = 31; node->range_right = 0; node->str = $2->str; node->children.push_back(checkRange(node, nullptr)); - ast_stack.back()->children.push_back(node); SET_AST_NODE_LOC(node, @1, @4); - node = new AstNode(AST_ASSIGN_EQ, $2, $4); - ast_stack.back()->children.push_back(node); + node = extra->saveChild(std::make_unique(AST_ASSIGN_EQ, std::move($2), std::move($4))); SET_AST_NODE_LOC(node, @1, @4); } | - genvar_identifier '=' expr { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3); - ast_stack.back()->children.push_back(node); + genvar_identifier TOK_EQ expr { + AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN_EQ, std::move($1), std::move($3))); SET_AST_NODE_LOC(node, @1, @3); }; // this production creates the obligatory if-else shift/reduce conflict gen_stmt: - TOK_FOR '(' { - AstNode *node = new AstNode(AST_GENFOR); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - } genvar_initialization ';' expr { - ast_stack.back()->children.push_back($6); - } ';' simple_behavioral_stmt ')' gen_stmt_block { - SET_AST_NODE_LOC(ast_stack.back(), @1, @11); - rewriteGenForDeclInit(ast_stack.back()); - ast_stack.pop_back(); + TOK_FOR TOK_LPAREN { + (void)extra->pushChild(std::make_unique(AST_GENFOR)); + } genvar_initialization TOK_SEMICOL expr { + extra->ast_stack.back()->children.push_back(std::move($6)); + } TOK_SEMICOL simple_behavioral_stmt TOK_RPAREN gen_stmt_block { + SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @11); + extra->rewriteGenForDeclInit(extra->ast_stack.back()); + extra->ast_stack.pop_back(); } | - TOK_IF '(' expr ')' { - AstNode *node = new AstNode(AST_GENIF); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - ast_stack.back()->children.push_back($3); + TOK_IF TOK_LPAREN expr TOK_RPAREN { + (void)extra->pushChild(std::make_unique(AST_GENIF)); + extra->ast_stack.back()->children.push_back(std::move($3)); } gen_stmt_block opt_gen_else { - SET_AST_NODE_LOC(ast_stack.back(), @1, @7); - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @7); + extra->ast_stack.pop_back(); } | - case_type '(' expr ')' { - AstNode *node = new AstNode(AST_GENCASE, $3); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + case_type TOK_LPAREN expr TOK_RPAREN { + (void)extra->pushChild(std::make_unique(AST_GENCASE, std::move($3))); } gen_case_body TOK_ENDCASE { - case_type_stack.pop_back(); - SET_AST_NODE_LOC(ast_stack.back(), @1, @7); - ast_stack.pop_back(); + extra->case_type_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @7); + extra->ast_stack.pop_back(); } | TOK_MSG_TASKS { - AstNode *node = new AstNode(AST_TECALL); + AstNode* node = extra->pushChild(std::make_unique(AST_TECALL)); node->str = *$1; - delete $1; - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); - } opt_arg_list ';'{ - SET_AST_NODE_LOC(ast_stack.back(), @1, @3); - ast_stack.pop_back(); + } opt_arg_list TOK_SEMICOL{ + SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @3); + extra->ast_stack.pop_back(); }; gen_block: TOK_BEGIN { - enterTypeScope(); + extra->enterTypeScope(); } opt_label { - AstNode *node = new AstNode(AST_GENBLOCK); + AstNode* node = extra->pushChild(std::make_unique(AST_GENBLOCK)); node->str = $3 ? *$3 : std::string(); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); } module_gen_body TOK_END opt_label { - exitTypeScope(); - checkLabelsMatch("Begin label", $3, $7); - delete $3; - delete $7; - SET_AST_NODE_LOC(ast_stack.back(), @1, @7); - ast_stack.pop_back(); + extra->exitTypeScope(); + checkLabelsMatch(@7, "Begin label", $3, $7); + SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @7); + extra->ast_stack.pop_back(); }; // result is wrapped in a genblock only if necessary gen_stmt_block: { - AstNode *node = new AstNode(AST_GENBLOCK); - ast_stack.back()->children.push_back(node); - ast_stack.push_back(node); + (void)extra->pushChild(std::make_unique(AST_GENBLOCK)); } gen_stmt_or_module_body_stmt { - SET_AST_NODE_LOC(ast_stack.back(), @2, @2); - ast_stack.pop_back(); + SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @2); + extra->ast_stack.pop_back(); } | gen_block; opt_gen_else: @@ -3261,336 +3203,330 @@ opt_gen_else: expr: basic_expr { - $$ = $1; + $$ = std::move($1); } | - basic_expr '?' attr expr ':' expr { - $$ = new AstNode(AST_TERNARY); - $$->children.push_back($1); - $$->children.push_back($4); - $$->children.push_back($6); - SET_AST_NODE_LOC($$, @1, @$); - append_attr($$, $3); + basic_expr TOK_QUE attr expr TOK_COL expr { + $$ = std::make_unique(AST_TERNARY); + $$->children.push_back(std::move($1)); + $$->children.push_back(std::move($4)); + $$->children.push_back(std::move($6)); + SET_AST_NODE_LOC($$.get(), @1, @$); + append_attr($$.get(), $3); } | inc_or_dec_op attr rvalue { - $$ = addIncOrDecExpr($3, $2, $1, @1, @3, false); + $$ = extra->addIncOrDecExpr(std::move($3), $2, $1, @1, @3, false, mode->sv); } | // TODO: Attributes are allowed in the middle here, but they create some // non-trivial conflicts that don't seem worth solving for now. rvalue inc_or_dec_op { - $$ = addIncOrDecExpr($1, nullptr, $2, @1, @2, true); + $$ = extra->addIncOrDecExpr(std::move($1), nullptr, $2, @1, @2, true, mode->sv); }; basic_expr: rvalue { - $$ = $1; + $$ = std::move($1); } | - '(' expr ')' integral_number { + 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()); - AstNode *bits = $2; - AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); - if (val == NULL) + lexer->err("Cast operation must be applied on sized constants e.g. () , while %s is not a sized constant.", $4->c_str()); + 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()); - $$ = new AstNode(AST_TO_BITS, bits, val); - delete $4; + $$ = std::make_unique(AST_TO_BITS, std::move($2), std::move(val)); } | hierarchical_id integral_number { if ($2->compare(0, 1, "'") != 0) - frontend_verilog_yyerror("Cast operation must be applied on sized constants, e.g. \'d0, while %s is not a sized constant.", $2->c_str()); - AstNode *bits = new AstNode(AST_IDENTIFIER); + lexer->err("Cast operation must be applied on sized constants, e.g. \'d0, while %s is not a sized constant.", $2->c_str()); + auto bits = std::make_unique(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); - SET_AST_NODE_LOC(val, @2, @2); - if (val == NULL) + SET_AST_NODE_LOC(bits.get(), @1, @1); + 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()); - $$ = new AstNode(AST_TO_BITS, bits, val); - delete $1; - delete $2; + $$ = std::make_unique(AST_TO_BITS, std::move(bits), std::move(val)); } | integral_number { - $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); - SET_AST_NODE_LOC($$, @1, @1); - if ($$ == NULL) + 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()); - delete $1; } | TOK_REALVAL { - $$ = new AstNode(AST_REALVALUE); + $$ = std::make_unique(AST_REALVALUE); char *p = (char*)malloc(GetSize(*$1) + 1), *q; for (int i = 0, j = 0; j < GetSize(*$1); j++) if ((*$1)[j] != '_') p[i++] = (*$1)[j], p[i] = 0; $$->realvalue = strtod(p, &q); - SET_AST_NODE_LOC($$, @1, @1); + SET_AST_NODE_LOC($$.get(), @1, @1); log_assert(*q == 0); - delete $1; free(p); } | TOK_STRING { $$ = AstNode::mkconst_str(*$1); - SET_AST_NODE_LOC($$, @1, @1); - delete $1; + SET_AST_NODE_LOC($$.get(), @1, @1); } | hierarchical_id attr { + // super sketchy! Orphaned pointer in non-owning extra->ast_stack AstNode *node = new AstNode(AST_FCALL); node->str = *$1; - delete $1; - ast_stack.push_back(node); + extra->ast_stack.push_back(node); SET_AST_NODE_LOC(node, @1, @1); append_attr(node, $2); - } '(' arg_list optional_comma ')' { - $$ = ast_stack.back(); - ast_stack.pop_back(); + } TOK_LPAREN arg_list optional_comma TOK_RPAREN { + $$.reset(extra->ast_stack.back()); + extra->ast_stack.pop_back(); } | - TOK_TO_SIGNED attr '(' expr ')' { - $$ = new AstNode(AST_TO_SIGNED, $4); - append_attr($$, $2); + TOK_TO_SIGNED attr TOK_LPAREN expr TOK_RPAREN { + $$ = std::make_unique(AST_TO_SIGNED, std::move($4)); + append_attr($$.get(), $2); } | - TOK_TO_UNSIGNED attr '(' expr ')' { - $$ = new AstNode(AST_TO_UNSIGNED, $4); - append_attr($$, $2); + TOK_TO_UNSIGNED attr TOK_LPAREN expr TOK_RPAREN { + $$ = std::make_unique(AST_TO_UNSIGNED, std::move($4)); + append_attr($$.get(), $2); } | - '(' expr ')' { - $$ = $2; + TOK_LPAREN expr TOK_RPAREN { + $$ = std::move($2); } | - '(' expr ':' expr ':' expr ')' { - delete $2; - $$ = $4; - delete $6; + TOK_LPAREN expr TOK_COL expr TOK_COL expr TOK_RPAREN { + $$ = std::move($4); } | - '{' concat_list '}' { - $$ = $2; + TOK_LCURL concat_list TOK_RCURL { + $$ = std::move($2); } | - '{' expr '{' concat_list '}' '}' { - $$ = new AstNode(AST_REPLICATE, $2, $4); + TOK_LCURL expr TOK_LCURL concat_list TOK_RCURL TOK_RCURL { + $$ = std::make_unique(AST_REPLICATE, std::move($2), std::move($4)); } | - '~' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_BIT_NOT, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + TOK_TILDE attr basic_expr %prec UNARY_OPS { + $$ = std::make_unique(AST_BIT_NOT, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); } | - basic_expr '&' attr basic_expr { - $$ = new AstNode(AST_BIT_AND, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_AMP attr basic_expr { + $$ = std::make_unique(AST_BIT_AND, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $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); + $$ = std::make_unique(AST_BIT_NOT, std::make_unique(AST_BIT_AND, std::move($1), std::move($4))); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '|' attr basic_expr { - $$ = new AstNode(AST_BIT_OR, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_PIPE attr basic_expr { + $$ = std::make_unique(AST_BIT_OR, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $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); + $$ = std::make_unique(AST_BIT_NOT, std::make_unique(AST_BIT_OR, std::move($1), std::move($4))); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '^' attr basic_expr { - $$ = new AstNode(AST_BIT_XOR, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_CARET attr basic_expr { + $$ = std::make_unique(AST_BIT_XOR, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_XNOR attr basic_expr { - $$ = new AstNode(AST_BIT_XNOR, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_BIT_XNOR, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - '&' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_AND, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + TOK_AMP attr basic_expr %prec UNARY_OPS { + $$ = std::make_unique(AST_REDUCE_AND, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $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, $$); + $$ = std::make_unique(AST_REDUCE_AND, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); + $$ = std::make_unique(AST_LOGIC_NOT, std::move($$)); } | - '|' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_OR, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + TOK_PIPE attr basic_expr %prec UNARY_OPS { + $$ = std::make_unique(AST_REDUCE_OR, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), std::move($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); + $$ = std::make_unique(AST_REDUCE_OR, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); + $$ = std::make_unique(AST_LOGIC_NOT, std::move($$)); + SET_AST_NODE_LOC($$.get(), @1, @3); } | - '^' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_XOR, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + TOK_CARET attr basic_expr %prec UNARY_OPS { + $$ = std::make_unique(AST_REDUCE_XOR, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); } | OP_XNOR attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_REDUCE_XNOR, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + $$ = std::make_unique(AST_REDUCE_XNOR, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $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); + $$ = std::make_unique(AST_SHIFT_LEFT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $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); + $$ = std::make_unique(AST_SHIFT_RIGHT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $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); + $$ = std::make_unique(AST_SHIFT_SLEFT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $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); + $$ = std::make_unique(AST_SHIFT_SRIGHT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '<' attr basic_expr { - $$ = new AstNode(AST_LT, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_LT attr basic_expr { + $$ = std::make_unique(AST_LT, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_LE attr basic_expr { - $$ = new AstNode(AST_LE, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_LE, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_EQ attr basic_expr { - $$ = new AstNode(AST_EQ, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_EQ, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_NE attr basic_expr { - $$ = new AstNode(AST_NE, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_NE, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_EQX attr basic_expr { - $$ = new AstNode(AST_EQX, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_EQX, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_NEX attr basic_expr { - $$ = new AstNode(AST_NEX, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_NEX, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_GE attr basic_expr { - $$ = new AstNode(AST_GE, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_GE, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '>' attr basic_expr { - $$ = new AstNode(AST_GT, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_GT attr basic_expr { + $$ = std::make_unique(AST_GT, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '+' attr basic_expr { - $$ = new AstNode(AST_ADD, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_PLUS attr basic_expr { + $$ = std::make_unique(AST_ADD, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '-' attr basic_expr { - $$ = new AstNode(AST_SUB, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_MINUS attr basic_expr { + $$ = std::make_unique(AST_SUB, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '*' attr basic_expr { - $$ = new AstNode(AST_MUL, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_ASTER attr basic_expr { + $$ = std::make_unique(AST_MUL, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '/' attr basic_expr { - $$ = new AstNode(AST_DIV, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_SLASH attr basic_expr { + $$ = std::make_unique(AST_DIV, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - basic_expr '%' attr basic_expr { - $$ = new AstNode(AST_MOD, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + basic_expr TOK_PERC attr basic_expr { + $$ = std::make_unique(AST_MOD, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_POW attr basic_expr { - $$ = new AstNode(AST_POW, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_POW, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - '+' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_POS, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + TOK_PLUS attr basic_expr %prec UNARY_OPS { + $$ = std::make_unique(AST_POS, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); } | - '-' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_NEG, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + TOK_MINUS attr basic_expr %prec UNARY_OPS { + $$ = std::make_unique(AST_NEG, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); } | basic_expr OP_LAND attr basic_expr { - $$ = new AstNode(AST_LOGIC_AND, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_LOGIC_AND, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | basic_expr OP_LOR attr basic_expr { - $$ = new AstNode(AST_LOGIC_OR, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); - append_attr($$, $3); + $$ = std::make_unique(AST_LOGIC_OR, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); } | - '!' attr basic_expr %prec UNARY_OPS { - $$ = new AstNode(AST_LOGIC_NOT, $3); - SET_AST_NODE_LOC($$, @1, @3); - append_attr($$, $2); + TOK_EXCL attr basic_expr %prec UNARY_OPS { + $$ = std::make_unique(AST_LOGIC_NOT, std::move($3)); + SET_AST_NODE_LOC($$.get(), @1, @3); + append_attr($$.get(), $2); } | - TOK_SIGNED OP_CAST '(' expr ')' { - if (!sv_mode) - frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); - $$ = new AstNode(AST_TO_SIGNED, $4); - SET_AST_NODE_LOC($$, @1, @4); + TOK_SIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN { + if (!mode->sv) + lexer->err("Static cast is only supported in SystemVerilog mode."); + $$ = std::make_unique(AST_TO_SIGNED, std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); } | - TOK_UNSIGNED OP_CAST '(' expr ')' { - if (!sv_mode) - frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); - $$ = new AstNode(AST_TO_UNSIGNED, $4); - SET_AST_NODE_LOC($$, @1, @4); + TOK_UNSIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN { + if (!mode->sv) + lexer->err("Static cast is only supported in SystemVerilog mode."); + $$ = std::make_unique(AST_TO_UNSIGNED, std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); } | - basic_expr OP_CAST '(' expr ')' { - if (!sv_mode) - frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); - $$ = new AstNode(AST_CAST_SIZE, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); + basic_expr OP_CAST TOK_LPAREN expr TOK_RPAREN { + if (!mode->sv) + lexer->err("Static cast is only supported in SystemVerilog mode."); + $$ = std::make_unique(AST_CAST_SIZE, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); } | - typedef_base_type OP_CAST '(' expr ')' { - if (!sv_mode) - frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); - $$ = new AstNode(AST_CAST_SIZE, $1, $4); - SET_AST_NODE_LOC($$, @1, @4); + typedef_base_type OP_CAST TOK_LPAREN expr TOK_RPAREN { + if (!mode->sv) + lexer->err("Static cast is only supported in SystemVerilog mode."); + $$ = std::make_unique(AST_CAST_SIZE, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); } | - '(' expr '=' expr ')' { - ensureAsgnExprAllowed(); - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, $4); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @2, @4); + TOK_LPAREN expr TOK_EQ expr TOK_RPAREN { + extra->ensureAsgnExprAllowed(@3, mode->sv); $$ = $2->clone(); + auto node = std::make_unique(AST_ASSIGN_EQ, std::move($2), std::move($4)); + SET_AST_NODE_LOC(node.get(), @2, @4); + extra->ast_stack.back()->children.push_back(std::move(node)); } | - '(' expr asgn_binop expr ')' { - ensureAsgnExprAllowed(); - $$ = addAsgnBinopStmt(nullptr, $2, $3, $4, @2, @4)-> clone(); + TOK_LPAREN expr asgn_binop expr TOK_RPAREN { + extra->ensureAsgnExprAllowed(@3, mode->sv); + $$ = extra->addAsgnBinopStmt(nullptr, std::move($2), $3, std::move($4), @2, @4)-> clone(); }; concat_list: expr { - $$ = new AstNode(AST_CONCAT, $1); + $$ = std::make_unique(AST_CONCAT, std::move($1)); } | - expr ',' concat_list { - $$ = $3; - $$->children.push_back($1); + expr TOK_COMMA concat_list { + $$ = std::move($3); + $$->children.push_back(std::move($1)); }; integral_number: @@ -3598,12 +3534,9 @@ integral_number: TOK_UNBASED_UNSIZED_CONSTVAL { $$ = $1; } | TOK_BASE TOK_BASED_CONSTVAL { $1->append(*$2); - $$ = $1; - delete $2; + $$ = std::move($1); } | TOK_CONSTVAL TOK_BASE TOK_BASED_CONSTVAL { $1->append(*$2).append(*$3); - $$ = $1; - delete $2; - delete $3; + $$ = std::move($1); }; diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 646ffcb35..941a7ba3a 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -952,10 +952,6 @@ RTLIL::Design::~Design() delete pr.second; for (auto n : bindings_) delete n; - for (auto n : verilog_packages) - delete n; - for (auto n : verilog_globals) - delete n; #ifdef WITH_PYTHON RTLIL::Design::get_all_designs()->erase(hashidx_); #endif @@ -5710,11 +5706,6 @@ static void sigspec_parse_split(std::vector &tokens, const std::str tokens.push_back(text.substr(start)); } -static int sigspec_parse_get_dummy_line_num() -{ - return 0; -} - bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str) { cover("kernel.rtlil.sigspec.parse"); @@ -5735,12 +5726,11 @@ 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"); - AST::get_line_num = sigspec_parse_get_dummy_line_num; - AST::AstNode *ast = VERILOG_FRONTEND::const2ast(netname); - if (ast == NULL) + VERILOG_FRONTEND::ConstParser p; + auto ast = p.const2ast(netname); + if (ast == nullptr) return false; sig.append(RTLIL::Const(ast->bits)); - delete ast; continue; } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index d53bb3129..e0de79ea9 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1334,7 +1334,7 @@ struct RTLIL::Design dict modules_; std::vector bindings_; - std::vector verilog_packages, verilog_globals; + std::vector> verilog_packages, verilog_globals; std::unique_ptr verilog_defines; std::vector selection_stack; diff --git a/passes/cmds/design.cc b/passes/cmds/design.cc index a2ae45ef3..59cd39c98 100644 --- a/passes/cmds/design.cc +++ b/passes/cmds/design.cc @@ -368,14 +368,8 @@ struct DesignPass : public Pass { if (reset_mode || reset_vlog_mode || !load_name.empty() || push_mode || pop_mode) { - for (auto node : design->verilog_packages) - delete node; design->verilog_packages.clear(); - - for (auto node : design->verilog_globals) - delete node; design->verilog_globals.clear(); - design->verilog_defines->clear(); } diff --git a/passes/memory/memlib.h b/passes/memory/memlib.h index c3f7728f1..43dec7386 100644 --- a/passes/memory/memlib.h +++ b/passes/memory/memlib.h @@ -100,7 +100,7 @@ enum class WrTransKind { struct WrTransDef { WrTransTargetKind target_kind; - int target_group; + int target_group = 0; WrTransKind kind; }; From 4a001694526d5d40a42a3fabd12904b27efbcf5f Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 17 Jun 2025 01:57:51 +0200 Subject: [PATCH 033/176] ast: ownership for string values --- frontends/verilog/verilog_lexer.l | 88 +++++++++++++++--------------- frontends/verilog/verilog_parser.y | 58 +++++++++----------- 2 files changed, 71 insertions(+), 75 deletions(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 0bc192327..24e842691 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -74,12 +74,12 @@ YOSYS_NAMESPACE_END 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(), yylineno); \ - string_t val = new std::string(std::string("\\") + YYText()); \ - return parser::make_TOK_ID(val, out_loc); + string_t val = std::make_unique(std::string("\\") + YYText()); \ + return parser::make_TOK_ID(std::move(val), out_loc); #define NON_KEYWORD() \ - string_t val = new std::string(std::string("\\") + YYText()); \ - return parser::make_TOK_ID(val, out_loc); + string_t val = std::make_unique(std::string("\\") + YYText()); \ + return parser::make_TOK_ID(std::move(val), out_loc); // #define YY_INPUT(buf,result,max_size) \ // result = readsome(*extra->lexin, buf, max_size) @@ -290,8 +290,8 @@ TIME_SCALE_SUFFIX [munpf]?s [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 parser::make_TOK_DEFAULT(out_loc); - string_t val = new std::string(std::string("\\") + YYText()); - return parser::make_TOK_SVA_LABEL(val, out_loc); + string_t val = std::make_unique(std::string("\\") + YYText()); + return parser::make_TOK_SVA_LABEL(std::move(val), out_loc); } "assert" { if (mode->formal) return parser::make_TOK_ASSERT(out_loc); SV_KEYWORD(parser::make_TOK_ASSERT(out_loc)); } @@ -340,35 +340,35 @@ TIME_SCALE_SUFFIX [munpf]?s "packed" { SV_KEYWORD(parser::make_TOK_PACKED(out_loc)); } {UNSIGNED_NUMBER} { - string_t val = new std::string(YYText()); - return parser::make_TOK_CONSTVAL(val, out_loc); + string_t val = std::make_unique(YYText()); + return parser::make_TOK_CONSTVAL(std::move(val), out_loc); } \'[01zxZX] { - string_t val = new std::string(YYText()); - return parser::make_TOK_UNBASED_UNSIZED_CONSTVAL(val, out_loc); + string_t val = std::make_unique(YYText()); + return parser::make_TOK_UNBASED_UNSIZED_CONSTVAL(std::move(val), out_loc); } \'[sS]?[bodhBODH] { BEGIN(BASED_CONST); - string_t val = new std::string(YYText()); - return parser::make_TOK_BASE(val, out_loc); + string_t val = std::make_unique(YYText()); + return parser::make_TOK_BASE(std::move(val), out_loc); } [0-9a-fA-FzxZX?][0-9a-fA-FzxZX?_]* { BEGIN(0); - string_t val = new std::string(YYText()); - return parser::make_TOK_BASED_CONSTVAL(val, out_loc); + string_t val = std::make_unique(YYText()); + return parser::make_TOK_BASED_CONSTVAL(std::move(val), out_loc); } {FIXED_POINT_NUMBER_DEC} { - string_t val = new std::string(YYText()); - return parser::make_TOK_REALVAL(val, out_loc); + string_t val = std::make_unique(YYText()); + return parser::make_TOK_REALVAL(std::move(val), out_loc); } {FIXED_POINT_NUMBER_NO_DEC} { - string_t val = new std::string(YYText()); - return parser::make_TOK_REALVAL(val, out_loc); + string_t val = std::make_unique(YYText()); + return parser::make_TOK_REALVAL(std::move(val), out_loc); } \" { BEGIN(STRING); } @@ -408,33 +408,33 @@ TIME_SCALE_SUFFIX [munpf]?s yystr[j++] = yystr[i++]; } yystr[j] = 0; - string_t val = new std::string(yystr, j); + string_t val = std::make_unique(yystr, j); free(yystr); - return parser::make_TOK_STRING(val, out_loc); + return parser::make_TOK_STRING(std::move(val), out_loc); } and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 { - auto val = new std::string(YYText()); - return parser::make_TOK_PRIMITIVE(val, out_loc); + auto val = std::make_unique(YYText()); + return parser::make_TOK_PRIMITIVE(std::move(val), out_loc); } supply0 { return parser::make_TOK_SUPPLY0(out_loc); } supply1 { return parser::make_TOK_SUPPLY1(out_loc); } "$"(display[bho]?|write[bho]?|strobe|monitor|time|realtime|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) { - auto val = new std::string(YYText()); - return parser::make_TOK_ID(val, out_loc); + auto val = std::make_unique(YYText()); + return parser::make_TOK_ID(std::move(val), out_loc); } "$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) { if (!mode->specify) REJECT; - auto val = new std::string(YYText()); - return parser::make_TOK_ID(val, out_loc); + auto val = std::make_unique(YYText()); + return parser::make_TOK_ID(std::move(val), out_loc); } "$"(info|warning|error|fatal) { - auto val = new std::string(YYText()); - return parser::make_TOK_MSG_TASKS(val, out_loc); + auto val = std::make_unique(YYText()); + return parser::make_TOK_MSG_TASKS(std::move(val), out_loc); } "$signed" { return parser::make_TOK_TO_SIGNED(out_loc); } @@ -445,15 +445,15 @@ supply1 { return parser::make_TOK_SUPPLY1(out_loc); } auto s = std::string("\\") + YYText(); if (extra->pkg_user_types.count(s) > 0) { // package qualified typedefed name - auto val = new std::string(s); - return parser::make_TOK_PKG_USER_TYPE(val, out_loc); + auto val = std::make_unique(s); + return parser::make_TOK_PKG_USER_TYPE(std::move(val), out_loc); } else { // backup before :: just return first part size_t len = strchr(YYText(), ':') - YYText(); yyless(len); - auto val = new std::string(std::string("\\") + YYText()); - return parser::make_TOK_ID(val, out_loc); + auto val = std::make_unique(std::string("\\") + YYText()); + return parser::make_TOK_ID(std::move(val), out_loc); } } @@ -461,18 +461,18 @@ supply1 { return parser::make_TOK_SUPPLY1(out_loc); } auto s = std::string("\\") + YYText(); if (isUserType(extra, s)) { // previously typedefed name - auto val = new std::string(s); - return parser::make_TOK_USER_TYPE(val, out_loc); + auto val = std::make_unique(s); + return parser::make_TOK_USER_TYPE(std::move(val), out_loc); } else { - auto val = new std::string(std::string("\\") + YYText()); - return parser::make_TOK_ID(val, out_loc); + auto val = std::make_unique(std::string("\\") + YYText()); + return parser::make_TOK_ID(std::move(val), out_loc); } } [a-zA-Z_$][a-zA-Z0-9_$\.]* { - auto val = new std::string(std::string("\\") + YYText()); - return parser::make_TOK_ID(val, out_loc); + auto val = std::make_unique(std::string("\\") + YYText()); + return parser::make_TOK_ID(std::move(val), out_loc); } "/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" { @@ -533,8 +533,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { } [a-zA-Z_$][a-zA-Z0-9_$]* { - auto val = new std::string(std::string("\\") + YYText()); - return parser::make_TOK_ID(val, out_loc); + auto val = std::make_unique(std::string("\\") + YYText()); + return parser::make_TOK_ID(std::move(val), out_loc); } [ \t\r\n] /* ignore whitespaces */ @@ -549,8 +549,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { } "\\"[^ \t\r\n]+ { - auto val = new std::string(YYText()); - return parser::make_TOK_ID(val, out_loc); + auto val = std::make_unique(YYText()); + return parser::make_TOK_ID(std::move(val), out_loc); } "(*" { return parser::make_ATTR_BEGIN(out_loc); } @@ -606,8 +606,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { [-+]?[=*]> { if (!mode->specify) REJECT; - auto val = new std::string(YYText()); - return parser::make_TOK_SPECIFY_OPER(val, out_loc); + auto val = std::make_unique(YYText()); + return parser::make_TOK_SPECIFY_OPER(std::move(val), out_loc); } "&&&" { diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 14ea0d615..5ef249a60 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -244,7 +244,7 @@ node->children.push_back(std::move(rangeNode)); } - static void checkLabelsMatch(const frontend_verilog_yy::parser::location_type& loc, const char *element, const std::string *before, const std::string *after) + static void checkLabelsMatch(const frontend_verilog_yy::parser::location_type& loc, const char *element, const std::string* before, const std::string *after) { if (!before && after) err_at_loc(loc, "%s missing where end label (%s) was given.", @@ -271,7 +271,6 @@ node->is_custom_type = true; node->children.push_back(std::make_unique(AST_WIRETYPE)); node->children.back()->str = *name; - delete name; } void ParseState::addTypedefNode(std::string *name, std::unique_ptr node) @@ -287,7 +286,6 @@ auto qname = current_ast_mod->str + "::" + (*name).substr(1); pkg_user_types[qname] = tnode; } - delete name; } void ParseState::enterTypeScope() @@ -479,7 +477,7 @@ specify_triple fall; }; - using string_t = std::string *; + using string_t = std::unique_ptr; using ast_t = std::unique_ptr; using al_t = YOSYS_NAMESPACE_PREFIX dict>*; using specify_target_ptr_t = std::unique_ptr; @@ -688,27 +686,27 @@ attr_assign: hierarchical_id: TOK_ID { - $$ = $1; + $$ = std::move($1); } | hierarchical_id TOK_PACKAGESEP TOK_ID { if ($3->compare(0, 1, "\\") == 0) *$1 += "::" + $3->substr(1); else *$1 += "::" + *$3; - $$ = $1; + $$ = std::move($1); } | hierarchical_id TOK_DOT TOK_ID { if ($3->compare(0, 1, "\\") == 0) *$1 += "." + $3->substr(1); else *$1 += "." + *$3; - $$ = $1; + $$ = std::move($1); }; hierarchical_type_id: - TOK_USER_TYPE - | TOK_PKG_USER_TYPE // package qualified type name - | TOK_LPAREN TOK_USER_TYPE TOK_RPAREN { $$ = $2; } // non-standard grammar + TOK_USER_TYPE {$$ = std::move($1); } + | TOK_PKG_USER_TYPE {$$ = std::move($1); } // package qualified type name + | TOK_LPAREN TOK_USER_TYPE TOK_RPAREN { $$ = std::move($2); } // non-standard grammar ; module: @@ -729,7 +727,7 @@ module: SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @$); extra->ast_stack.pop_back(); log_assert(extra->ast_stack.size() == 1); - checkLabelsMatch(@11, "Module name", $4, $11); + checkLabelsMatch(@11, "Module name", $4.get(), $11.get()); extra->current_ast_mod = nullptr; extra->exitTypeScope(); }; @@ -837,7 +835,7 @@ package: append_attr(mod, $1); } TOK_SEMICOL package_body TOK_ENDPACKAGE opt_label { extra->ast_stack.pop_back(); - checkLabelsMatch(@9, "Package name", $4, $9); + checkLabelsMatch(@9, "Package name", $4.get(), $9.get()); extra->current_ast_mod = nullptr; extra->exitTypeScope(); }; @@ -1054,7 +1052,7 @@ logic_type: extra->astbuf3->is_signed = true; } | hierarchical_type_id { - extra->addWiretypeNode($1, extra->astbuf3.get()); + extra->addWiretypeNode($1.get(), extra->astbuf3.get()); }; integer_atom_type: @@ -1322,7 +1320,7 @@ specify_item: auto en_expr = std::move($1); char specify_edge = $3; auto src_expr = std::move($4); - string *oper = $5; + string *oper = $5.get(); specify_target_ptr_t target = std::move($6); specify_rise_fall_ptr_t timing = std::move($9); @@ -1398,8 +1396,6 @@ specify_item: cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(target->dat))); cell->children.back()->str = "\\DAT"; } - - delete oper; } | TOK_ID TOK_LPAREN specify_edge expr specify_condition TOK_COMMA specify_edge expr specify_condition TOK_COMMA specify_triple specify_opt_triple TOK_RPAREN TOK_SEMICOL { if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" && @@ -1736,7 +1732,7 @@ param_implicit_type: param_signed param_range; param_type: param_integer_type | param_real | param_range_type | param_implicit_type | hierarchical_type_id { - extra->addWiretypeNode($1, extra->astbuf1.get()); + extra->addWiretypeNode($1.get(), extra->astbuf1.get()); }; param_decl: @@ -1993,7 +1989,7 @@ member_type_token: member_type: type_atom type_signing | type_vec type_signing - | hierarchical_type_id { extra->addWiretypeNode($1, extra->astbuf1.get()); } + | hierarchical_type_id { extra->addWiretypeNode($1.get(), extra->astbuf1.get()); } ; struct_var_list: struct_var @@ -2172,8 +2168,8 @@ assign_expr: SET_AST_NODE_LOC(node, @$, @$); }; -type_name: TOK_ID // first time seen - | TOK_USER_TYPE { if (extra->isInLocalScope($1)) lexer->err("Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); $$ = std::move($1); } +type_name: TOK_ID { $$ = std::move($1); } // first time seen + | TOK_USER_TYPE { if (extra->isInLocalScope($1.get())) lexer->err("Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); $$ = std::move($1); } ; typedef_decl: @@ -2191,15 +2187,15 @@ typedef_decl: } rewriteAsMemoryNode(extra->astbuf1.get(), std::move($5)); } - extra->addTypedefNode($4, std::move(extra->astbuf1)); } - | TOK_TYPEDEF enum_struct_type type_name TOK_SEMICOL { extra->addTypedefNode($3, std::move($2)); } + extra->addTypedefNode($4.get(), std::move(extra->astbuf1)); } + | TOK_TYPEDEF enum_struct_type type_name TOK_SEMICOL { extra->addTypedefNode($3.get(), std::move($2)); } ; typedef_base_type: hierarchical_type_id { $$ = std::make_unique(AST_WIRE); $$->is_logic = true; - extra->addWiretypeNode($1, $$.get()); + extra->addWiretypeNode($1.get(), $$.get()); } | integer_vector_type opt_signedness_default_unsigned { $$ = std::make_unique(AST_WIRE); @@ -2242,10 +2238,10 @@ cell_stmt: tok_prim_wrapper: TOK_PRIMITIVE { - $$ = $1; + $$ = std::move($1); } | TOK_OR { - $$ = new std::string("or"); + $$ = std::make_unique("or"); }; cell_list: @@ -2485,7 +2481,7 @@ always_event: opt_label: TOK_COL TOK_ID { - $$ = $2; + $$ = std::move($2); } | %empty { $$ = nullptr; @@ -2493,7 +2489,7 @@ opt_label: opt_sva_label: TOK_SVA_LABEL TOK_COL { - $$ = $1; + $$ = std::move($1); } | %empty { $$ = nullptr; @@ -2801,7 +2797,7 @@ behavioral_stmt: node->str = *$4; } behavioral_stmt_list TOK_END opt_label { extra->exitTypeScope(); - checkLabelsMatch(@8, "Begin label", $4, $8); + checkLabelsMatch(@8, "Begin label", $4.get(), $8.get()); AstNode *node = extra->ast_stack.back(); // In SystemVerilog, unnamed blocks with block item declarations // create an implicit hierarchy scope @@ -3184,7 +3180,7 @@ gen_block: node->str = $3 ? *$3 : std::string(); } module_gen_body TOK_END opt_label { extra->exitTypeScope(); - checkLabelsMatch(@7, "Begin label", $3, $7); + checkLabelsMatch(@7, "Begin label", $3.get(), $7.get()); SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @7); extra->ast_stack.pop_back(); }; @@ -3530,8 +3526,8 @@ concat_list: }; integral_number: - TOK_CONSTVAL { $$ = $1; } | - TOK_UNBASED_UNSIZED_CONSTVAL { $$ = $1; } | + TOK_CONSTVAL { $$ = std::move($1); } | + TOK_UNBASED_UNSIZED_CONSTVAL { $$ = std::move($1); } | TOK_BASE TOK_BASED_CONSTVAL { $1->append(*$2); $$ = std::move($1); From 84f0c5da73fd5ea890b148bdc1b2b3de5980acd6 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 17 Jun 2025 15:25:57 +0200 Subject: [PATCH 034/176] ast: fix new memory safety bugs from rebase --- frontends/ast/genrtlil.cc | 4 ++-- frontends/ast/simplify.cc | 2 +- frontends/verilog/verilog_parser.y | 9 +++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 5139aade2..5b1d20ade 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1613,7 +1613,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; - auto fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? + auto fake_ast = std::make_unique(AST_NONE, clone(), children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : children[0]->children[0]->clone()); fake_ast->children[0]->delete_children(); if (member_node) @@ -1634,7 +1634,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } if (GetSize(shift_val) >= 32) fake_ast->children[1]->is_signed = true; - RTLIL::SigSpec sig = binop2rtlil(fake_ast, ID($shiftx), width, fake_ast->children[0]->genRTLIL(), shift_val); + RTLIL::SigSpec sig = binop2rtlil(fake_ast.get(), ID($shiftx), width, fake_ast->children[0]->genRTLIL(), shift_val); return sig; } else { chunk.width = children[0]->range_left - children[0]->range_right + 1; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 3f7176b20..45a0ab007 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1571,7 +1571,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (children[0]->type == AST_WIRE) { int width = 1; std::unique_ptr node; - AstNode* child = children[0].release(); + AstNode* child = children[0].get(); if (child->children.size() == 0) { // Base type (e.g., int) width = child->range_left - child->range_right +1; diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 5ef249a60..b605271e1 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2855,6 +2855,7 @@ behavioral_stmt: std::unique_ptr node_owned; AstNode* node = nullptr; AstNode *context = extra->ast_stack.back(); + bool patch_block_on_stack = false; if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) { AstNode *outer = extra->ast_stack[extra->ast_stack.size() - 2]; log_assert (outer && outer->type == AST_CASE); @@ -2863,6 +2864,9 @@ behavioral_stmt: node = outer; log_assert (node->children.size()); node->children.pop_back(); + // `context` has been killed as a grandchild of `outer` + // we have to undangle it from the stack + patch_block_on_stack = true; } else if (outer->get_bool_attribute(ID::full_case)) (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); } @@ -2874,12 +2878,17 @@ behavioral_stmt: append_attr(node, $1); node->children.push_back(node->get_bool_attribute(ID::parallel_case) ? AstNode::mkconst_int(1, false, 1) : expr->clone()); extra->ast_stack.back()->children.push_back(std::move(node_owned)); + } else { + free_attr($1); } auto block_owned = std::make_unique(AST_BLOCK); auto* block = block_owned.get(); auto cond_owned = std::make_unique(AST_COND, node->get_bool_attribute(ID::parallel_case) ? std::move(expr) : AstNode::mkconst_int(1, false, 1), std::move(block_owned)); SET_AST_NODE_LOC(cond_owned.get(), @4, @4); node->children.push_back(std::move(cond_owned)); + // Double it and give it to the next person + if (patch_block_on_stack) + extra->ast_stack.back() = block; extra->ast_stack.push_back(node); extra->ast_stack.push_back(block); } behavioral_stmt { From b3bf58896607d16e86cc6228412df8a75ae740dc Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 18 Jun 2025 12:39:32 +0200 Subject: [PATCH 035/176] ast, read_verilog: refactoring --- frontends/ast/genrtlil.cc | 2 -- frontends/ast/simplify.cc | 4 ---- frontends/verilog/Makefile.inc | 3 +++ frontends/verilog/verilog_frontend.cc | 9 --------- frontends/verilog/verilog_frontend.h | 5 ----- frontends/verilog/verilog_lexer.h | 3 ++- frontends/verilog/verilog_parser.y | 11 +++++++++++ 7 files changed, 16 insertions(+), 21 deletions(-) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 5b1d20ade..0c3fc513a 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1339,8 +1339,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // be instantiated for this type of AST node. IdString type_name; - current_filename = filename; - switch (type) { // simply ignore this nodes. diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 45a0ab007..048a15af8 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1038,8 +1038,6 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin return false; } - current_filename = filename; - // we do not look inside a task or function // (but as soon as a task or function is instantiated we process the generated AST as usual) if (type == AST_FUNCTION || type == AST_TASK) { @@ -1906,8 +1904,6 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin current_scope[it->first] = it->second; } - current_filename = filename; - if (type == AST_MODULE || type == AST_INTERFACE) current_scope.clear(); diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 2d26f1930..cc8baf6aa 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -3,6 +3,9 @@ GENFILES += frontends/verilog/verilog_parser.tab.cc GENFILES += frontends/verilog/verilog_parser.tab.hh GENFILES += frontends/verilog/verilog_parser.output GENFILES += frontends/verilog/verilog_lexer.cc +GENFILES += frontends/verilog/location.hh +GENFILES += frontends/verilog/position.hh +GENFILES += frontends/verilog/stack.hh frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y $(Q) mkdir -p $(dir $@) diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index f2a341f54..d4bee02da 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -787,15 +787,6 @@ void VERILOG_FRONTEND::verr_at(std::string filename, int begin_line, char const exit(1); } -[[noreturn]] -void VERILOG_FRONTEND::err_at_loc(parser::location_type loc, char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - verr_at(AST::current_filename, loc.begin.line, fmt, args); - va_end(args); -} - [[noreturn]] void VERILOG_FRONTEND::err_at_ast(AstSrcLocType loc, char const *fmt, ...) { diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index 6426f57d8..29c16c039 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -31,7 +31,6 @@ #include "kernel/yosys.h" #include "frontends/ast/ast.h" -#include "frontends/verilog/location.hh" #if ! defined(yyFlexLexerOnce) #define yyFlexLexer frontend_verilog_yyFlexLexer @@ -66,10 +65,6 @@ namespace VERILOG_FRONTEND }; [[noreturn]] - extern void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap); - [[noreturn]] - extern void err_at_loc(frontend_verilog_yy::location loc, char const *fmt, ...); - [[noreturn]] extern void err_at_ast(AST::AstSrcLocType loc, char const *fmt, ...); }; diff --git a/frontends/verilog/verilog_lexer.h b/frontends/verilog/verilog_lexer.h index 7d73ae193..2c31160dd 100644 --- a/frontends/verilog/verilog_lexer.h +++ b/frontends/verilog/verilog_lexer.h @@ -8,7 +8,8 @@ YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { - // lexer input stream + [[noreturn]] + extern void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap); using parser = frontend_verilog_yy::parser; class VerilogLexer : public frontend_verilog_yyFlexLexer { ParseState* extra; diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index b605271e1..908b3ec41 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -244,6 +244,17 @@ node->children.push_back(std::move(rangeNode)); } + [[noreturn]] + extern void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap); + [[noreturn]] + static void err_at_loc(frontend_verilog_yy::parser::location_type loc, char const *fmt, ...) + { + va_list args; + va_start(args, fmt); + verr_at(AST::current_filename, loc.begin.line, fmt, args); + va_end(args); + } + static void checkLabelsMatch(const frontend_verilog_yy::parser::location_type& loc, const char *element, const std::string* before, const std::string *after) { if (!before && after) From 8bf750ecbb07cc01f27e8633187835a8e2517e82 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 18 Jun 2025 18:05:48 +0200 Subject: [PATCH 036/176] neater errors, lost in the sauce of source --- .../yosys_internals/flow/verilog_frontend.rst | 11 +-- frontends/ast/ast.cc | 50 +++++------ frontends/ast/ast.h | 24 ++--- frontends/ast/dpicall.cc | 12 +-- frontends/ast/genrtlil.cc | 50 +++++------ frontends/ast/simplify.cc | 80 +++++++++-------- frontends/verilog/Makefile.inc | 2 + frontends/verilog/const2ast.cc | 11 +-- frontends/verilog/verilog_frontend.cc | 69 +++++--------- frontends/verilog/verilog_frontend.h | 6 +- frontends/verilog/verilog_lexer.h | 18 ++-- frontends/verilog/verilog_lexer.l | 18 ++-- frontends/verilog/verilog_parser.y | 90 ++++++++----------- 13 files changed, 196 insertions(+), 245 deletions(-) diff --git a/docs/source/yosys_internals/flow/verilog_frontend.rst b/docs/source/yosys_internals/flow/verilog_frontend.rst index b6a7ba8a0..d6bdf6b6d 100644 --- a/docs/source/yosys_internals/flow/verilog_frontend.rst +++ b/docs/source/yosys_internals/flow/verilog_frontend.rst @@ -48,7 +48,7 @@ The lexer does little more than identifying all keywords and literals recognised by the Yosys Verilog frontend. The lexer keeps track of the current location in the Verilog source code using -some global variables. These variables are used by the constructor of AST nodes +some VerilogLexer member variables. These variables are used by the constructor of AST nodes to annotate each node with the source code location it originated from. Finally the lexer identifies and handles special comments such as "``// synopsys @@ -189,10 +189,11 @@ the bison code for parsing multiplications: .. code:: none :number-lines: - basic_expr '*' attr basic_expr { - $$ = new AstNode(AST_MUL, $1, $4); - append_attr($$, $3); - } | + basic_expr TOK_ASTER attr basic_expr { + $$ = std::make_unique(AST_MUL, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); + } | The generated AST data structure is then passed directly to the AST frontend that performs the actual conversion to RTLIL. diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 877c41283..c6305bd09 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -38,8 +38,7 @@ using namespace AST_INTERNAL; // instantiate global variables (public API) namespace AST { - std::string current_filename; - bool sv_mode; + bool sv_mode_but_global_and_used_for_literally_one_condition; unsigned long long astnodes = 0; unsigned long long astnode_count() { return astnodes; } } @@ -201,7 +200,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id) // create new node (AstNode constructor) // (the optional child arguments make it easier to create AST trees) -AstNode::AstNode(AstNodeType type, std::unique_ptr child1, std::unique_ptr child2, std::unique_ptr child3, std::unique_ptr child4) +AstNode::AstNode(AstSrcLocType loc, AstNodeType type, std::unique_ptr child1, std::unique_ptr child2, std::unique_ptr child3, std::unique_ptr child4) { static unsigned int hashidx_count = 123456789; hashidx_count = mkhash_xorshift(hashidx_count); @@ -209,7 +208,7 @@ AstNode::AstNode(AstNodeType type, std::unique_ptr child1, std::unique_ astnodes++; this->type = type; - filename = current_filename; + loc = loc; is_input = false; is_output = false; is_reg = false; @@ -253,7 +252,7 @@ AstNode::AstNode(AstNodeType type, std::unique_ptr child1, std::unique_ // create a (deep recursive) copy of a node std::unique_ptr AstNode::clone() const { - auto that = std::make_unique(this->type); + auto that = std::make_unique(this->location, this->type); cloneInto(*that.get()); return that; } @@ -288,7 +287,6 @@ void AstNode::cloneInto(AstNode &other) const other.id2ast = id2ast; other.basic_prep = basic_prep; other.lookahead = lookahead; - other.filename = filename; other.location = location; other.in_lvalue = in_lvalue; other.in_param = in_param; @@ -843,9 +841,9 @@ bool AstNode::contains(const AstNode *other) const } // create an AST node for a constant (using a 32 bit int as value) -std::unique_ptr AstNode::mkconst_int(uint32_t v, bool is_signed, int width) +std::unique_ptr AstNode::mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width) { - auto node = std::make_unique(AST_CONSTANT); + auto node = std::make_unique(loc, AST_CONSTANT); node->integer = v; node->is_signed = is_signed; for (int i = 0; i < width; i++) { @@ -859,9 +857,9 @@ std::unique_ptr AstNode::mkconst_int(uint32_t v, bool is_signed, int wi } // create an AST node for a constant (using a bit vector as value) -std::unique_ptr AstNode::mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized) +std::unique_ptr AstNode::mkconst_bits(AstSrcLocType loc, const std::vector &v, bool is_signed, bool is_unsized) { - auto node = std::make_unique(AST_CONSTANT); + auto node = std::make_unique(loc, AST_CONSTANT); node->is_signed = is_signed; node->bits = v; for (size_t i = 0; i < 32; i++) { @@ -877,15 +875,15 @@ std::unique_ptr AstNode::mkconst_bits(const std::vector & return node; } -std::unique_ptr AstNode::mkconst_bits(const std::vector &v, bool is_signed) +std::unique_ptr AstNode::mkconst_bits(AstSrcLocType loc, const std::vector &v, bool is_signed) { - return mkconst_bits(v, is_signed, false); + return mkconst_bits(loc, v, is_signed, false); } // create an AST node for a constant (using a string in bit vector form as value) -std::unique_ptr AstNode::mkconst_str(const std::vector &v) +std::unique_ptr AstNode::mkconst_str(AstSrcLocType loc, const std::vector &v) { - auto node = mkconst_str(RTLIL::Const(v).decode_string()); + auto node = mkconst_str(loc, RTLIL::Const(v).decode_string()); while (GetSize(node->bits) < GetSize(v)) node->bits.push_back(RTLIL::State::S0); log_assert(node->bits == v); @@ -893,14 +891,14 @@ std::unique_ptr AstNode::mkconst_str(const std::vector &v } // create an AST node for a constant (using a string as value) -std::unique_ptr AstNode::mkconst_str(const std::string &str) +std::unique_ptr AstNode::mkconst_str(AstSrcLocType loc, const std::string &str) { std::unique_ptr node; // LRM 1364-2005 5.2.3.3 The empty string literal ("") shall be considered // equivalent to the ASCII NUL ("\0") if (str.empty()) { - node = AstNode::mkconst_int(0, false, 8); + node = AstNode::mkconst_int(loc, 0, false, 8); } else { std::vector data; data.reserve(str.size() * 8); @@ -911,7 +909,7 @@ std::unique_ptr AstNode::mkconst_str(const std::string &str) ch = ch >> 1; } } - node = AstNode::mkconst_bits(data, false); + node = AstNode::mkconst_bits(loc, data, false); } node->is_string = true; @@ -920,19 +918,19 @@ std::unique_ptr AstNode::mkconst_str(const std::string &str) } // create a temporary register -std::unique_ptr AstNode::mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed) +std::unique_ptr AstNode::mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed) { - auto wire_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(range_left, true), mkconst_int(range_right, true))); + auto wire_owned = std::make_unique(loc, AST_WIRE, std::make_unique(loc, AST_RANGE, mkconst_int(loc, range_left, true), mkconst_int(loc, range_right, true))); auto* wire = wire_owned.get(); - wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); + wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(location.filename).c_str(), location.first_line, autoidx++); if (nosync) - wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(loc, 1, false)); wire->is_signed = is_signed; wire->is_logic = true; mod->children.push_back(std::move(wire_owned)); while (wire->simplify(true, 1, -1, false)) { } - auto ident = std::make_unique(AST_IDENTIFIER); + auto ident = std::make_unique(loc, AST_IDENTIFIER); ident->str = wire->str; ident->id2ast = wire; @@ -986,7 +984,7 @@ RTLIL::Const AstNode::asParaConst() const { if (type == AST_REALVALUE) { - auto strnode = AstNode::mkconst_str(stringf("%f", realvalue)); + auto strnode = AstNode::mkconst_str(location, stringf("%f", realvalue)); RTLIL::Const val = strnode->asAttrConst(); val.flags |= RTLIL::CONST_FLAG_REAL; return val; @@ -1088,7 +1086,7 @@ RTLIL::Const AstNode::realAsConst(int width) std::string AstNode::loc_string() const { - return stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column); + return stringf("%s:%d.%d-%d.%d", location.filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column); } void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast) @@ -1446,7 +1444,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump if (design->has(child->str)) { RTLIL::Module *existing_mod = design->module(child->str); if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) { - log_file_error(child->filename, child->location.first_line, "Re-definition of module `%s'!\n", child->str.c_str()); + log_file_error(child->location.filename, child->location.first_line, "Re-definition of module `%s'!\n", child->str.c_str()); } else if (nooverwrite) { log("Ignoring re-definition of module `%s' at %s.\n", child->str.c_str(), child->loc_string().c_str()); @@ -1925,7 +1923,7 @@ void AstNode::input_error(const char *format, ...) const { va_list ap; va_start(ap, format); - logv_file_error(filename, location.first_line, format, ap); + logv_file_error(location.filename, location.first_line, format, ap); } YOSYS_NAMESPACE_END diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 72dddab67..ccbce2b1a 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -164,10 +164,11 @@ namespace AST }; struct AstSrcLocType { + std::string filename; unsigned int first_line, last_line; unsigned int first_column, last_column; - AstSrcLocType() : first_line(0), last_line(0), first_column(0), last_column(0) {} - AstSrcLocType(int _first_line, int _first_column, int _last_line, int _last_column) : first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {} + AstSrcLocType() : filename(""), first_line(0), last_line(0), first_column(0), last_column(0) {} + AstSrcLocType(std::string _filename, int _first_line, int _first_column, int _last_line, int _last_column) : filename(_filename), first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {} }; // convert an node type to a string (e.g. for debug output) @@ -224,7 +225,6 @@ namespace AST // this is the original sourcecode location that resulted in this AST node // it is automatically set by the constructor using AST::current_filename and // the AST::get_line_num() callback function. - std::string filename; AstSrcLocType location; // are we embedded in an lvalue, param? @@ -235,7 +235,7 @@ namespace AST bool in_param_from_above; // creating and deleting nodes - AstNode(AstNodeType type = AST_NONE, std::unique_ptr child1 = nullptr, std::unique_ptr child2 = nullptr, std::unique_ptr child3 = nullptr, std::unique_ptr child4 = nullptr); + AstNode(AstSrcLocType loc, AstNodeType type = AST_NONE, std::unique_ptr child1 = nullptr, std::unique_ptr child2 = nullptr, std::unique_ptr child3 = nullptr, std::unique_ptr child4 = nullptr); std::unique_ptr clone() const; void cloneInto(AstNode &other) const; void delete_children(); @@ -323,14 +323,14 @@ namespace AST AstNode operator=(AstNode) = delete; // helper functions for creating AST nodes for constants - static std::unique_ptr mkconst_int(uint32_t v, bool is_signed, int width = 32); - static std::unique_ptr mkconst_bits(const std::vector &v, bool is_signed, bool is_unsized); - static std::unique_ptr mkconst_bits(const std::vector &v, bool is_signed); - static std::unique_ptr mkconst_str(const std::vector &v); - static std::unique_ptr mkconst_str(const std::string &str); + static std::unique_ptr mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width = 32); + static std::unique_ptr mkconst_bits(AstSrcLocType loc, const std::vector &v, bool is_signed, bool is_unsized); + static std::unique_ptr mkconst_bits(AstSrcLocType loc, const std::vector &v, bool is_signed); + static std::unique_ptr mkconst_str(AstSrcLocType loc, const std::vector &v); + static std::unique_ptr mkconst_str(AstSrcLocType loc, const std::string &str); // helper function to create an AST node for a temporary register - std::unique_ptr mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed); + std::unique_ptr mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed); // helper function for creating sign-extended const objects RTLIL::Const bitsAsConst(int width, bool is_signed); @@ -410,7 +410,7 @@ namespace AST // to initialize the filename and linenum properties of new nodes extern std::string current_filename; // also set by the language frontend to control some AST processing - extern bool sv_mode; + extern bool sv_mode_but_global_and_used_for_literally_one_condition; // for stats unsigned long long astnode_count(); @@ -420,7 +420,7 @@ namespace AST void use_internal_line_num(); // call a DPI function - std::unique_ptr dpi_call(const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector> &args); + std::unique_ptr dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector> &args); // Helper functions related to handling SystemVerilog interfaces std::pair split_modport_from_type(std::string name_type); diff --git a/frontends/ast/dpicall.cc b/frontends/ast/dpicall.cc index 4fa375df7..07314e3d7 100644 --- a/frontends/ast/dpicall.cc +++ b/frontends/ast/dpicall.cc @@ -64,7 +64,7 @@ static ffi_fptr resolve_fn (std::string symbol_name) log_error("unable to resolve '%s'.\n", symbol_name.c_str()); } -std::unique_ptr AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector> &args) +std::unique_ptr AST::dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector &argtypes, const std::vector> &args) { std::unique_ptr newNode = nullptr; union value { double f64; float f32; int32_t i32; void *ptr; }; @@ -125,11 +125,11 @@ std::unique_ptr AST::dpi_call(const std::string &rtype, const std: ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values.data()); if (rtype == "real") { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(loc, AST_REALVALUE); newNode->realvalue = value_store[args.size()].f64; log(" return realvalue: %g\n", newNode->asReal(true)); } else if (rtype == "shortreal") { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(loc, AST_REALVALUE); newNode->realvalue = value_store[args.size()].f32; log(" return realvalue: %g\n", newNode->asReal(true)); } else if (rtype == "chandle") { @@ -137,10 +137,10 @@ std::unique_ptr AST::dpi_call(const std::string &rtype, const std: std::vector bits(64); for (int i = 0; i < 64; i++) bits.at(i) = (rawval & (1ULL << i)) ? RTLIL::State::S1 : RTLIL::State::S0; - newNode = AstNode::mkconst_bits(bits, false); + newNode = AstNode::mkconst_bits(loc, bits, false); log(" return chandle: %llx\n", (unsigned long long)newNode->asInt(false)); } else { - newNode = AstNode::mkconst_int(value_store[args.size()].i32, false); + newNode = AstNode::mkconst_int(loc, value_store[args.size()].i32, false); log(" return integer: %lld\n", (long long)newNode->asInt(true)); } @@ -153,7 +153,7 @@ YOSYS_NAMESPACE_END YOSYS_NAMESPACE_BEGIN -AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector&, const std::vector&) +AST::AstNode *AST::dpi_call(AstSrcLocType loc, const std::string&, const std::string &fname, const std::vector&, const std::vector&) { log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str()); } diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 0c3fc513a..9a98cae3b 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -45,7 +45,7 @@ using namespace AST_INTERNAL; // helper function for creating RTLIL code for unary operations static RTLIL::SigSpec uniop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true) { - IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++); + IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, type); set_src_attr(cell, that); @@ -77,7 +77,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s return; } - IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++); + IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, ID($pos)); set_src_attr(cell, that); @@ -104,7 +104,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s // helper function for creating RTLIL code for binary operations static RTLIL::SigSpec binop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) { - IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->filename).c_str(), that->location.first_line, autoidx++); + IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, type); set_src_attr(cell, that); @@ -138,7 +138,7 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const log_assert(cond.size() == 1); std::stringstream sstr; - sstr << "$ternary$" << RTLIL::encode_filename(that->filename) << ":" << that->location.first_line << "$" << (autoidx++); + sstr << "$ternary$" << RTLIL::encode_filename(that->location.filename) << ":" << that->location.first_line << "$" << (autoidx++); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($mux)); set_src_attr(cell, that); @@ -347,7 +347,7 @@ struct AST_INTERNAL::ProcessGenerator LookaheadRewriter la_rewriter(always.get()); // generate process and simple root case - proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(always->filename).c_str(), always->location.first_line, autoidx++)); + proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(always->location.filename).c_str(), always->location.first_line, autoidx++)); set_src_attr(proc, always.get()); for (auto &attr : always->attributes) { if (attr.second->type != AST_CONSTANT) @@ -723,7 +723,7 @@ struct AST_INTERNAL::ProcessGenerator if (ast->str == "$display" || ast->str == "$displayb" || ast->str == "$displayh" || ast->str == "$displayo" || ast->str == "$write" || ast->str == "$writeb" || ast->str == "$writeh" || ast->str == "$writeo") { std::stringstream sstr; - sstr << ast->str << "$" << ast->filename << ":" << ast->location.first_line << "$" << (autoidx++); + sstr << ast->str << "$" << ast->location.filename << ":" << ast->location.first_line << "$" << (autoidx++); Wire *en = current_module->addWire(sstr.str() + "_EN", 1); set_src_attr(en, ast); @@ -766,7 +766,7 @@ struct AST_INTERNAL::ProcessGenerator node->detectSignWidth(width, is_signed, nullptr); VerilogFmtArg arg = {}; - arg.filename = node->filename; + arg.filename = node->location.filename; arg.first_line = node->location.first_line; if (node->type == AST_CONSTANT && node->is_string) { arg.type = VerilogFmtArg::STRING; @@ -793,7 +793,7 @@ struct AST_INTERNAL::ProcessGenerator fmt.append_literal("\n"); fmt.emit_rtlil(cell); } else if (!ast->str.empty()) { - log_file_error(ast->filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str()); + log_file_error(ast->location.filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str()); } break; @@ -813,7 +813,7 @@ struct AST_INTERNAL::ProcessGenerator IdString cellname; if (ast->str.empty()) - cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(ast->filename).c_str(), ast->location.first_line, autoidx++); + cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(ast->location.filename).c_str(), ast->location.first_line, autoidx++); else cellname = ast->str; check_unique_id(current_module, cellname, ast, "procedural assertion"); @@ -843,7 +843,7 @@ struct AST_INTERNAL::ProcessGenerator set_src_attr(cell, ast); for (auto &attr : ast->attributes) { if (attr.second->type != AST_CONSTANT) - log_file_error(ast->filename, ast->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); + log_file_error(ast->location.filename, ast->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } cell->setParam(ID::FLAVOR, flavor); @@ -1504,7 +1504,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } RTLIL::SigSpec sig = realAsConst(width_hint); - log_file_warning(filename, location.first_line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); + log_file_warning(location.filename, location.first_line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); return sig; } @@ -1536,7 +1536,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (dynamic_cast(current_module)) { /* nothing to do here */ } else if (flag_autowire) - log_file_warning(filename, location.first_line, "Identifier `%s' is implicitly declared.\n", str.c_str()); + log_file_warning(location.filename, location.first_line, "Identifier `%s' is implicitly declared.\n", str.c_str()); else input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); } @@ -1641,10 +1641,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk.offset = source_width - (chunk.offset + chunk.width); if (chunk.offset > chunk_left || chunk.offset + chunk.width < chunk_right) { if (chunk.width == 1) - log_file_warning(filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", + log_file_warning(location.filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", str.c_str()); else - log_file_warning(filename, location.first_line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", + log_file_warning(location.filename, location.first_line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width); chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width); } else { @@ -1658,10 +1658,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk.offset += add_undef_bits_lsb; } if (add_undef_bits_lsb) - log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", + log_file_warning(location.filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb); if (add_undef_bits_msb) - log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", + log_file_warning(location.filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb); } } @@ -1935,7 +1935,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_MEMRD: { std::stringstream sstr; - sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($memrd)); set_src_attr(cell, this); @@ -1973,7 +1973,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_MEMINIT: { std::stringstream sstr; - sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); SigSpec en_sig = children[2]->genRTLIL(); @@ -2018,7 +2018,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) IdString cellname; if (str.empty()) - cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); + cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(location.filename).c_str(), location.first_line, autoidx++); else cellname = str; check_unique_id(current_module, cellname, this, "procedural assertion"); @@ -2061,7 +2061,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) new_left.append(left[i]); new_right.append(right[i]); } - log_file_warning(filename, location.first_line, "Ignoring assignment to constant bits:\n" + log_file_warning(location.filename, location.first_line, "Ignoring assignment to constant bits:\n" " old assignment: %s = %s\n new assignment: %s = %s.\n", log_signal(left), log_signal(right), log_signal(new_left), log_signal(new_right)); @@ -2096,7 +2096,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; const AstNode *value = child->children[0].get(); if (value->type == AST_REALVALUE) - log_file_warning(filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n", + log_file_warning(location.filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n", log_id(cell), log_id(paraname), value->realvalue); else if (value->type != AST_CONSTANT) input_error("Parameter %s.%s with non-constant value!\n", @@ -2193,14 +2193,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) int sz = children.size(); if (str == "$info") { if (sz > 0) - log_file_info(filename, location.first_line, "%s.\n", children[0]->str.c_str()); + log_file_info(location.filename, location.first_line, "%s.\n", children[0]->str.c_str()); else - log_file_info(filename, location.first_line, "\n"); + log_file_info(location.filename, location.first_line, "\n"); } else if (str == "$warning") { if (sz > 0) - log_file_warning(filename, location.first_line, "%s.\n", children[0]->str.c_str()); + log_file_warning(location.filename, location.first_line, "%s.\n", children[0]->str.c_str()); else - log_file_warning(filename, location.first_line, "\n"); + log_file_warning(location.filename, location.first_line, "\n"); } else if (str == "$error") { if (sz > 0) input_error("%s.\n", children[0]->str.c_str()); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 048a15af8..374b9c0dc 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -155,7 +155,7 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_ while (node_arg->simplify(true, stage, -1, false)) { } VerilogFmtArg arg = {}; - arg.filename = filename; + arg.filename = location.filename; arg.first_line = location.first_line; if (node_arg->type == AST_CONSTANT && node_arg->is_string) { arg.type = VerilogFmtArg::STRING; @@ -173,10 +173,10 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_ arg.sig = node_arg->bitsAsConst(); arg.signed_ = node_arg->is_signed; } else if (may_fail) { - log_file_info(filename, location.first_line, "Skipping system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); + log_file_info(location.filename, location.first_line, "Skipping system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); return Fmt(); } else { - log_file_error(filename, location.first_line, "Failed to evaluate system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); + log_file_error(location.filename, location.first_line, "Failed to evaluate system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); } args.push_back(arg); } @@ -240,20 +240,20 @@ void AstNode::annotateTypedEnums(AstNode *template_node) RTLIL::Const val = enum_item->children[0]->bitsAsConst(width, is_signed); enum_item_str.append(val.as_string()); //set attribute for available val to enum item name mappings - set_attribute(enum_item_str.c_str(), mkconst_str(enum_item->str)); + set_attribute(enum_item_str.c_str(), mkconst_str(location, enum_item->str)); } } } -static std::unique_ptr make_range(int left, int right, bool is_signed = false) +static std::unique_ptr make_range(AstSrcLocType loc, int left, int right, bool is_signed = false) { // generate a pre-validated range node for a fixed signal range. - auto range = std::make_unique(AST_RANGE); + auto range = std::make_unique(loc, AST_RANGE); range->range_left = left; range->range_right = right; range->range_valid = true; - range->children.push_back(AstNode::mkconst_int(left, true)); - range->children.push_back(AstNode::mkconst_int(right, true)); + range->children.push_back(AstNode::mkconst_int(loc, left, true)); + range->children.push_back(AstNode::mkconst_int(loc, right, true)); range->is_signed = is_signed; return range; } @@ -388,30 +388,32 @@ static int size_packed_struct(AstNode *snode, int base_offset) return width; } -static std::unique_ptr node_int(int ival) +static std::unique_ptr node_int(AstSrcLocType loc, int ival) { - return AstNode::mkconst_int(ival, true); + return AstNode::mkconst_int(loc, ival, true); } static std::unique_ptr multiply_by_const(std::unique_ptr expr_node, int stride) { - return std::make_unique(AST_MUL, std::move(expr_node), node_int(stride)); + auto loc = expr_node->location; + return std::make_unique(loc, AST_MUL, std::move(expr_node), node_int(loc, stride)); } static std::unique_ptr normalize_index(AstNode *expr, AstNode *decl_node, int dimension) { auto new_expr = expr->clone(); + auto loc = expr->location; int offset = decl_node->dimensions[dimension].range_right; if (offset) { - new_expr = std::make_unique(AST_SUB, std::move(new_expr), node_int(offset)); + new_expr = std::make_unique(loc, AST_SUB, std::move(new_expr), node_int(loc, offset)); } // Packed dimensions are normally indexed by lsb, while unpacked dimensions are normally indexed by msb. if ((dimension < decl_node->unpacked_dimensions) ^ decl_node->dimensions[dimension].range_swapped) { // Swap the index if the dimension is declared the "wrong" way. int left = decl_node->dimensions[dimension].range_width - 1; - new_expr = std::make_unique(AST_SUB, node_int(left), std::move(new_expr)); + new_expr = std::make_unique(loc, AST_SUB, node_int(loc, left), std::move(new_expr)); } return new_expr; @@ -433,7 +435,7 @@ static std::unique_ptr index_msb_offset(std::unique_ptr lsb_of std::unique_ptr add_offset; if (rnode->children.size() == 1) { // Index, e.g. s.a[i] - add_offset = node_int(stride - 1); + add_offset = node_int(rnode->location, stride - 1); } else { // rnode->children.size() == 2 @@ -620,7 +622,7 @@ const RTLIL::Module* AstNode::lookup_cell_module() auto reprocess_after = [this] (const std::string &modname) { if (!attributes.count(ID::reprocess_after)) - set_attribute(ID::reprocess_after, AstNode::mkconst_str(modname)); + set_attribute(ID::reprocess_after, AstNode::mkconst_str(location, modname)); }; const AstNode *celltype = nullptr; @@ -929,7 +931,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin #if 0 log("-------------\n"); - log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, filename.c_str(), location.first_line, type2str(type).c_str(), this); + log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, location.filename.c_str(), location.first_line, type2str(type).c_str(), this); log("const_fold=%d, stage=%d, width_hint=%d, sign_hint=%d\n", int(const_fold), int(stage), int(width_hint), int(sign_hint)); // dumpAst(nullptr, "> "); @@ -1020,7 +1022,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (auto &it : node->attributes) if (it.first != ID::mem2reg) reg->set_attribute(it.first, it.second->clone()); - reg->filename = node->filename; + reg->location.filename = node->location.filename; reg->location = node->location; while (reg->simplify(true, 1, -1, false)) { } children.push_back(std::move(reg)); @@ -1049,7 +1051,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" || str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) { - log_file_warning(filename, location.first_line, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str()); + log_file_warning(location.filename, location.first_line, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str()); delete_children(); str = std::string(); } @@ -1059,7 +1061,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin str == "$write" || str == "$writeb" || str == "$writeh" || str == "$writeo")) { if (!current_always) { - log_file_warning(filename, location.first_line, "System task `%s' outside initial or always block is unsupported.\n", str.c_str()); + log_file_warning(location.filename, location.first_line, "System task `%s' outside initial or always block is unsupported.\n", str.c_str()); delete_children(); str = std::string(); } else { @@ -1402,7 +1404,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // create the indirection wire std::stringstream sstr; - sstr << "$indirect$" << ref->name.c_str() << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$indirect$" << ref->name.c_str() << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); std::string tmp_str = sstr.str(); add_wire_for_ref(ref, tmp_str); @@ -2240,7 +2242,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin int width = std::abs(children[1]->range_left - children[1]->range_right) + 1; if (children[0]->type == AST_REALVALUE) { RTLIL::Const constvalue = children[0]->realAsConst(width); - log_file_warning(filename, location.first_line, "converting real value %e to binary %s.\n", + log_file_warning(location.filename, location.first_line, "converting real value %e to binary %s.\n", children[0]->realvalue, log_signal(constvalue)); children[0] = mkconst_bits(constvalue.to_bits(), sign_hint); fixup_hierarchy_flags(); @@ -2382,7 +2384,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin std::swap(data_range_left, data_range_right); std::stringstream sstr; - sstr << "$mem2bits$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$mem2bits$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); std::string wire_id = sstr.str(); auto wire_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); @@ -2602,7 +2604,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (size_t i = 0; i < children.size(); i++) if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF) { - log_assert(!sv_mode); + log_assert(!sv_mode_but_global_and_used_for_literally_one_condition); children[i]->input_error("Local declaration in unnamed block is only supported in SystemVerilog mode!\n"); } } @@ -3139,7 +3141,7 @@ skip_dynamic_range_lvalue_expansion:; auto wire_tmp_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); auto wire_tmp = wire_tmp_owned.get(); - wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); + wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line, autoidx++); current_scope[wire_tmp->str] = wire_tmp; current_ast_mod->children.push_back(std::move(wire_tmp_owned)); wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); @@ -3181,7 +3183,7 @@ skip_dynamic_range_lvalue_expansion:; input_error("Insufficient number of array indices for %s.\n", log_id(str)); std::stringstream sstr; - sstr << "$memwr$" << children[0]->str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$memwr$" << children[0]->str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN"; int mem_width, mem_size, addr_bits; @@ -3452,7 +3454,7 @@ skip_dynamic_range_lvalue_expansion:; auto* reg = reg_owned.get(); current_ast_mod->children.push_back(std::move(reg_owned)); - reg->str = stringf("$past$%s:%d$%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, myidx, i); + reg->str = stringf("$past$%s:%d$%d$%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line, myidx, i); reg->is_reg = true; reg->is_signed = sign_hint; @@ -3828,7 +3830,7 @@ skip_dynamic_range_lvalue_expansion:; input_error("Failed to evaluate DPI function with non-constant argument.\n"); } - newNode = dpi_call(rtype, fname, argtypes, args); + newNode = dpi_call(dpi_decl->location, rtype, fname, argtypes, args); goto apply_newNode; } @@ -3912,7 +3914,7 @@ skip_dynamic_range_lvalue_expansion:; std::stringstream sstr; - sstr << str << "$func$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++) << '.'; + sstr << str << "$func$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++) << '.'; std::string prefix = sstr.str(); auto* decl = current_scope[str]; @@ -4442,7 +4444,7 @@ apply_newNode: // newNode->dumpAst(stderr, "+ "); log_assert(newNode != nullptr); // newNode->null_check(); - newNode->filename = filename; + newNode->location.filename = location.filename; newNode->location = location; newNode->cloneInto(*this); fixup_hierarchy_flags(); @@ -4489,7 +4491,7 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file #else char slash = '/'; #endif - std::string path = filename.substr(0, filename.find_last_of(slash)+1); + std::string path = location.filename.substr(0, location.filename.find_last_of(slash)+1); f.open(path + mem_filename.c_str()); yosys_input_files.insert(path + mem_filename); } else { @@ -4546,7 +4548,7 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file continue; } - VERILOG_FRONTEND::ConstParser p{mem_filename, std::nullopt}; + VERILOG_FRONTEND::ConstParser p{memory->location}; auto value = p.const2ast(stringf("%d'%c", mem_width, is_readmemh ? 'h' : 'b') + token); if (unconditional_init) @@ -4768,7 +4770,7 @@ static void mark_memories_assign_lhs_complex(dict> & if (that->type == AST_IDENTIFIER && that->id2ast && that->id2ast->type == AST_MEMORY) { AstNode *mem = that->id2ast; if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_CMPLX_LHS)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(that->filename).c_str(), that->location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CMPLX_LHS; } } @@ -4796,14 +4798,14 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg // activate mem2reg if this is assigned in an async proc if (flags & AstNode::MEM2REG_FL_ASYNC) { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ASYNC)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ASYNC; } // remember if this is assigned blocking (=) if (type == AST_ASSIGN_EQ) { if (!(proc_flags[mem] & AstNode::MEM2REG_FL_EQ1)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1; } @@ -4820,11 +4822,11 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg // remember where this is if (flags & MEM2REG_FL_INIT) { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_INIT; } else { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ELSE)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ELSE; } } @@ -4841,7 +4843,7 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg // flag if used after blocking assignment (in same proc) if ((proc_flags[mem] & AstNode::MEM2REG_FL_EQ1) && !(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_EQ2)) { - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_EQ2; } } @@ -5027,7 +5029,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, children[0]->children[0]->children[0]->type != AST_CONSTANT) { std::stringstream sstr; - sstr << "$mem2reg_wr$" << children[0]->str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$mem2reg_wr$" << children[0]->str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; int mem_width, mem_size, addr_bits; @@ -5146,7 +5148,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, else { std::stringstream sstr; - sstr << "$mem2reg_rd$" << str << "$" << RTLIL::encode_filename(filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$mem2reg_rd$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; int mem_width, mem_size, addr_bits; diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index cc8baf6aa..338b13e4b 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -13,6 +13,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_frontend.h: frontends/verilog/verilog_parser.tab.hh +frontends/verilog/verilog_error.h: frontends/verilog/verilog_parser.tab.hh frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l frontends/verilog/verilog_parser.tab.cc $(Q) mkdir -p $(dir $@) @@ -24,5 +25,6 @@ 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/verilog_error.o OBJS += frontends/verilog/const2ast.o diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index 9c4a2e76c..cd8f05b9b 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -46,11 +46,8 @@ using namespace VERILOG_FRONTEND; 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 += stringf("%s:%d:", loc.filename, loc.first_line); s += msg; return s; @@ -191,7 +188,7 @@ std::unique_ptr ConstParser::const2ast(std::string code, char case_type ch = ch >> 1; } } - auto ast = AstNode::mkconst_bits(data, false); + auto ast = AstNode::mkconst_bits(loc, data, false); ast->str = code; return ast; } @@ -210,7 +207,7 @@ std::unique_ptr ConstParser::const2ast(std::string code, char case_type my_strtobin(data, str, -1, 10, case_type, false); if (data.back() == State::S1) data.push_back(State::S0); - return AstNode::mkconst_bits(data, true); + return AstNode::mkconst_bits(loc, data, true); } // unsized constant @@ -258,7 +255,7 @@ std::unique_ptr ConstParser::const2ast(std::string code, char case_type if (is_signed && data.back() == State::S1) data.push_back(State::S0); } - return AstNode::mkconst_bits(data, is_signed, is_unsized); + return AstNode::mkconst_bits(loc, data, is_signed, is_unsized); } return NULL; diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index d4bee02da..d05f87aff 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -32,10 +32,12 @@ #include "verilog_frontend.h" #include "verilog_lexer.h" +#include "verilog_error.h" #include "preproc.h" #include "kernel/yosys.h" #include "libs/sha1/sha1.h" #include +#include YOSYS_NAMESPACE_BEGIN using namespace VERILOG_FRONTEND; @@ -47,10 +49,10 @@ static std::list> 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->location.first_line, "Found DPI function %s.\n", node->str.c_str()); - for (auto& child : node->children) - error_on_dpi_function(child.get()); + if (node->type == AST::AST_DPI_FUNCTION) + err_at_ast(node->location, "Found DPI function %s.\n", node->str.c_str()); + for (auto& child : node->children) + error_on_dpi_function(child.get()); } static void add_package_types(dict &user_types, std::vector> &package_list) @@ -69,15 +71,7 @@ static void add_package_types(dict &user_types, std } struct VerilogFrontend : public Frontend { - ParseMode parse_mode; - ParseState parse_state; - VerilogLexer lexer; - frontend_verilog_yy::parser parser; - VerilogFrontend() : Frontend("verilog", "read modules from Verilog file"), - parse_mode(), - parse_state(), - lexer(&parse_state, &parse_mode), - parser(&lexer, &parse_state, &parse_mode) { } + VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -259,6 +253,8 @@ struct VerilogFrontend : public Frontend { bool flag_dump_vlog1 = false; bool flag_dump_vlog2 = false; bool flag_dump_rtlil = false; + bool flag_debug_lexer = false; + bool flag_debug_parser = false; bool flag_nolatches = false; bool flag_nomeminit = false; bool flag_nomem2reg = false; @@ -281,8 +277,8 @@ struct VerilogFrontend : public Frontend { std::list include_dirs; std::list attributes; - lexer.set_debug(false); - parser.set_debug_level(0); + ParseMode parse_mode; + ParseState parse_state; parse_mode.sv = false; parse_mode.formal = false; parse_mode.noassert = false; @@ -340,8 +336,8 @@ struct VerilogFrontend : public Frontend { flag_dump_ast2 = true; flag_dump_vlog1 = true; flag_dump_vlog2 = true; - lexer.set_debug(true); - parser.set_debug_level(1); + flag_debug_lexer = true; + flag_debug_parser = true; continue; } if (arg == "-dump_ast1") { @@ -370,6 +366,8 @@ struct VerilogFrontend : public Frontend { } if (arg == "-yydebug") { flag_yydebug = true; + flag_debug_lexer = true; + flag_debug_parser = true; continue; } if (arg == "-nolatches") { @@ -481,6 +479,11 @@ struct VerilogFrontend : public Frontend { break; } + VerilogLexer lexer(&parse_state, &parse_mode, &filename); + frontend_verilog_yy::parser parser(&lexer, &parse_state, &parse_mode); + lexer.set_debug(flag_debug_lexer); + parser.set_debug_level(flag_debug_parser ? 1 : 0); + if (parse_mode.formal || !flag_nosynthesis) defines_map.add(parse_mode.formal ? "FORMAL" : "SYNTHESIS", "1"); @@ -491,10 +494,10 @@ struct VerilogFrontend : public Frontend { log("Parsing %s%s input from `%s' to AST representation.\n", parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str()); - AST::current_filename = filename; - AST::sv_mode = parse_mode.sv; + AST::sv_mode_but_global_and_used_for_literally_one_condition = parse_mode.sv; - parse_state.current_ast = new AST::AstNode(AST::AST_DESIGN); + AstSrcLocType top_loc = AstSrcLocType ( "read_verilog", 0, 0, 0, 0); + parse_state.current_ast = new AST::AstNode(top_loc, AST::AST_DESIGN); parse_state.lexin = f; std::string code_after_preproc; @@ -522,10 +525,6 @@ struct VerilogFrontend : public Frontend { // add a new empty type map to allow overriding existing global definitions parse_state.user_type_stack.push_back(UserTypeMap()); - parser.~parser(); - lexer.~VerilogLexer(); - new (&lexer) VerilogLexer(&parse_state, &parse_mode); - new (&parser) frontend_verilog_yy::parser(&lexer, &parse_state, &parse_mode); if (flag_yydebug) { lexer.set_debug(true); parser.set_debug_level(1); @@ -537,7 +536,7 @@ struct VerilogFrontend : public Frontend { if (child->type == AST::AST_MODULE) for (auto &attr : attributes) if (child->attributes.count(attr) == 0) - child->attributes[attr] = AST::AstNode::mkconst_int(1, false); + child->attributes[attr] = AST::AstNode::mkconst_int(top_loc, 1, false); } if (flag_nodpi) @@ -776,24 +775,4 @@ struct VerilogFileList : public Pass { #endif -[[noreturn]] -void VERILOG_FRONTEND::verr_at(std::string filename, int begin_line, char const *fmt, va_list ap) -{ - char buffer[1024]; - char *p = buffer; - p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap); - p += snprintf(p, buffer + sizeof(buffer) - p, "\n"); - YOSYS_NAMESPACE_PREFIX log_file_error(filename, begin_line, "%s", buffer); - exit(1); -} - -[[noreturn]] -void VERILOG_FRONTEND::err_at_ast(AstSrcLocType loc, char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - verr_at(AST::current_filename, loc.first_line, fmt, args); - va_end(args); -} - YOSYS_NAMESPACE_END diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index 29c16c039..e97cee4fc 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -39,7 +39,6 @@ #include #include -#include YOSYS_NAMESPACE_BEGIN @@ -47,8 +46,7 @@ namespace VERILOG_FRONTEND { /* Ephemeral context class */ struct ConstParser { - std::optional filename; - std::optional loc; + AST::AstSrcLocType loc; private: std::string fmt_maybe_loc(std::string msg); void log_maybe_loc_error(std::string msg); @@ -64,8 +62,6 @@ namespace VERILOG_FRONTEND std::unique_ptr const2ast(std::string code, char case_type = 0, bool warn_z = false); }; - [[noreturn]] - extern void err_at_ast(AST::AstSrcLocType loc, char const *fmt, ...); }; YOSYS_NAMESPACE_END diff --git a/frontends/verilog/verilog_lexer.h b/frontends/verilog/verilog_lexer.h index 2c31160dd..a4f3d9bfb 100644 --- a/frontends/verilog/verilog_lexer.h +++ b/frontends/verilog/verilog_lexer.h @@ -4,18 +4,20 @@ #include "kernel/yosys.h" #include "frontends/ast/ast.h" #include "frontends/verilog/verilog_parser.tab.hh" +#include YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { - [[noreturn]] - extern void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap); using parser = frontend_verilog_yy::parser; class VerilogLexer : public frontend_verilog_yyFlexLexer { ParseState* extra; ParseMode* mode; public: - VerilogLexer(ParseState* e, ParseMode* m) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) {} + parser::location_type out_loc; // TODO private? + VerilogLexer(ParseState* e, ParseMode* m, std::string* filename) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) { + out_loc.begin.filename = filename; + } ~VerilogLexer() override {} // autogenerated body due to YY_DECL parser::symbol_type nextToken(); @@ -24,19 +26,9 @@ namespace VERILOG_FRONTEND { parser::symbol_type terminate() { return parser::make_FRONTEND_VERILOG_YYEOF(out_loc); } - parser::location_type out_loc; - [[noreturn]] - void err(char const *fmt, ...) - { - va_list args; - va_start(args, fmt); - verr_at(AST::current_filename, yylineno, fmt, args); - } private: std::vector fn_stack; std::vector ln_stack; - parser::location_type real_loc; - parser::location_type old_loc; int LexerInput(char* buf, int max_size) override { return readsome(*extra->lexin, buf, max_size); } diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 24e842691..0e07e9e7b 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -85,17 +85,16 @@ YOSYS_NAMESPACE_END // result = readsome(*extra->lexin, buf, max_size) #define YY_USER_ACTION \ - real_loc.begin = real_loc.end; \ + out_loc.begin = out_loc.end; \ for(int i = 0; YYText()[i] != '\0'; ++i){ \ if(YYText()[i] == '\n') { \ - real_loc.end.line++; \ - real_loc.end.column = 1; \ + out_loc.end.line++; \ + out_loc.end.column = 1; \ } \ else { \ - real_loc.end.column++; \ + out_loc.end.column++; \ } \ - } \ - out_loc = real_loc; + } #define YY_BREAK \ break; @@ -183,7 +182,6 @@ TIME_SCALE_SUFFIX [munpf]?s current_filename = current_filename.substr(0, current_filename.size()-1); yylineno = (0); out_loc.begin.line = out_loc.end.line = 0; - real_loc.begin.line = real_loc.end.line = 0; } "`file_pop"[^\n]*\n { @@ -191,7 +189,6 @@ TIME_SCALE_SUFFIX [munpf]?s fn_stack.pop_back(); yylineno = (ln_stack.back()); out_loc.begin.line = out_loc.end.line = ln_stack.back(); - real_loc.begin.line = real_loc.end.line = ln_stack.back(); ln_stack.pop_back(); } @@ -200,7 +197,6 @@ TIME_SCALE_SUFFIX [munpf]?s while (*p == ' ' || *p == '\t') p++; yylineno = (atoi(p)); out_loc.begin.line = out_loc.end.line = atoi(p); - real_loc.begin.line = real_loc.end.line = atoi(p); while (*p && *p != ' ' && *p != '\t') p++; while (*p == ' ' || *p == '\t') p++; const char *q = *p ? p + 1 : p; @@ -226,14 +222,14 @@ TIME_SCALE_SUFFIX [munpf]?s else if (!strcmp(p, "wire")) extra->default_nettype_wire = true; else - err("Unsupported default nettype: %s", p); + err_at_loc(out_loc, "Unsupported default nettype: %s", p); } "`protect"[^\n]* /* ignore `protect*/ "`endprotect"[^\n]* /* ignore `endprotect*/ "`"[a-zA-Z_$][a-zA-Z0-9_$]* { - err("Unimplemented compiler directive or undefined macro %s.", YYText()); + err_at_loc(out_loc, "Unimplemented compiler directive or undefined macro %s.", YYText()); } "module" { return parser::make_TOK_MODULE(out_loc); } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 908b3ec41..6f3b3baea 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -45,7 +45,7 @@ %code requires { #include "kernel/yosys_common.h" - // #include "frontends/verilog/verilog_lexer.h" + #include "frontends/verilog/verilog_error.h" // start requires YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { @@ -157,8 +157,7 @@ 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}; + ConstParser p{loc}; return p; } static void append_attr(AstNode *ast, dict> *al) @@ -244,17 +243,6 @@ node->children.push_back(std::move(rangeNode)); } - [[noreturn]] - extern void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap); - [[noreturn]] - static void err_at_loc(frontend_verilog_yy::parser::location_type loc, char const *fmt, ...) - { - va_list args; - va_start(args, fmt); - verr_at(AST::current_filename, loc.begin.line, fmt, args); - va_end(args); - } - static void checkLabelsMatch(const frontend_verilog_yy::parser::location_type& loc, const char *element, const std::string* before, const std::string *after) { if (!before && after) @@ -733,7 +721,7 @@ module: append_attr(mod, $1); } module_para_opt module_args_opt TOK_SEMICOL module_body TOK_ENDMODULE opt_label { if (extra->port_stubs.size() != 0) - lexer->err("Missing details for module port `%s'.", + err_at_loc(@7, "Missing details for module port `%s'.", extra->port_stubs.begin()->first.c_str()); SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @$); extra->ast_stack.pop_back(); @@ -787,7 +775,7 @@ module_arg_opt_assignment: extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::move(wire), std::move($2))); } } else - lexer->err("SystemVerilog interface in module port list cannot have a default value."); + err_at_loc(@2, "SystemVerilog interface in module port list cannot have a default value."); } | %empty; @@ -801,7 +789,7 @@ module_arg: extra->ast_stack.back()->children.push_back(std::move(node)); } else { if (extra->port_stubs.count(*$1) != 0) - lexer->err("Duplicate module port `%s'.", $1->c_str()); + err_at_loc(@1, "Duplicate module port `%s'.", $1->c_str()); extra->port_stubs[*$1] = ++extra->port_counter; } } module_arg_opt_assignment | @@ -811,7 +799,7 @@ module_arg: extra->astbuf1->children[0]->str = *$1; } TOK_ID { /* SV interfaces */ if (!mode->sv) - lexer->err("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str()); + err_at_loc(@3, "Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str()); extra->astbuf2 = extra->astbuf1->clone(); // really only needed if multiple instances of same type. extra->astbuf2->str = *$3; extra->astbuf2->port_id = ++extra->port_counter; @@ -826,9 +814,9 @@ module_arg: if (range != nullptr) node->children.push_back(std::move(range)); if (!node->is_input && !node->is_output) - lexer->err("Module port `%s' is neither input nor output.", $4->c_str()); + err_at_loc(@4, "Module port `%s' is neither input nor output.", $4->c_str()); if (node->is_reg && node->is_input && !node->is_output && !mode->sv) - lexer->err("Input port `%s' is declared as register.", $4->c_str()); + err_at_loc(@4, "Input port `%s' is declared as register.", $4->c_str()); append_attr(node.get(), $1); extra->ast_stack.back()->children.push_back(std::move(node)); } module_arg_opt_assignment | @@ -878,7 +866,7 @@ interface: intf->str = *$3; } module_para_opt module_args_opt TOK_SEMICOL interface_body TOK_ENDINTERFACE { if (extra->port_stubs.size() != 0) - lexer->err("Missing details for module port `%s'.", + err_at_loc(@6, "Missing details for module port `%s'.", extra->port_stubs.begin()->first.c_str()); extra->ast_stack.pop_back(); log_assert(extra->ast_stack.size() == 1); @@ -1295,7 +1283,7 @@ task_func_port: extra->astbuf2 = checkRange(extra->astbuf1.get(), std::move($3)); if (!extra->astbuf1->is_input && !extra->astbuf1->is_output) { if (!mode->sv) - lexer->err("task/function argument direction missing"); + err_at_loc(@2, "task/function argument direction missing"); extra->astbuf1->is_input = prev_was_input; extra->astbuf1->is_output = prev_was_output; } @@ -1303,7 +1291,7 @@ task_func_port: { if (!extra->astbuf1) { if (!mode->sv) - lexer->err("task/function argument direction missing"); + err_at_loc(@$, "task/function argument direction missing"); extra->albuf = new dict>; extra->astbuf1 = std::make_unique(AST_WIRE); extra->current_wire_rand = false; @@ -1336,7 +1324,7 @@ specify_item: specify_rise_fall_ptr_t timing = std::move($9); if (specify_edge != 0 && target->dat == nullptr) - lexer->err("Found specify edge but no data spec.\n"); + err_at_loc(@3, "Found specify edge but no data spec.\n"); auto cell_owned = std::make_unique(AST_CELL); auto cell = cell_owned.get(); @@ -1411,7 +1399,7 @@ specify_item: TOK_ID TOK_LPAREN specify_edge expr specify_condition TOK_COMMA specify_edge expr specify_condition TOK_COMMA specify_triple specify_opt_triple TOK_RPAREN TOK_SEMICOL { if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" && *$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange") - lexer->err("Unsupported specify rule type: %s\n", $1->c_str()); + err_at_loc(@1, "Unsupported specify rule type: %s\n", $1->c_str()); auto src_pen = AstNode::mkconst_int($3 != 0, false, 1); auto src_pol = AstNode::mkconst_int($3 == 'p', false, 1); @@ -1777,10 +1765,10 @@ single_param_decl: AstNode *decl = extra->ast_stack.back()->children.back().get(); if (decl->type != AST_PARAMETER) { log_assert(decl->type == AST_LOCALPARAM); - lexer->err("localparam initialization is missing!"); + err_at_loc(@1, "localparam initialization is missing!"); } if (!mode->sv) - lexer->err("Parameter defaults can only be omitted in SystemVerilog mode!"); + err_at_loc(@1, "Parameter defaults can only be omitted in SystemVerilog mode!"); decl->children.erase(decl->children.begin()); }; @@ -1789,7 +1777,7 @@ single_param_decl_ident: std::unique_ptr node_owned; if (extra->astbuf1 == nullptr) { if (!mode->sv) - lexer->err("In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword"); + err_at_loc(@1, "In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword"); node_owned = std::make_unique(AST_PARAMETER); node_owned->children.push_back(AstNode::mkconst_int(0, true)); } else { @@ -1940,7 +1928,7 @@ struct_body: opt_packed TOK_LCURL struct_member_list TOK_RCURL opt_packed: TOK_PACKED opt_signed_struct | - %empty { lexer->err("Only PACKED supported at this time"); }; + %empty { err_at_loc(@$, "Only PACKED supported at this time"); }; opt_signed_struct: TOK_SIGNED { extra->astbuf2->is_signed = true; } @@ -2125,7 +2113,7 @@ wire_name_and_opt_assign: wire_name: TOK_ID range_or_multirange { if (extra->astbuf1 == nullptr) - lexer->err("Internal error - should not happen - no AST_WIRE node."); + err_at_loc(@1, "Internal error - should not happen - no AST_WIRE node."); auto node = extra->astbuf1->clone(); node->str = *$1; append_attr_clone(node.get(), extra->albuf); @@ -2133,7 +2121,7 @@ wire_name: node->children.push_back(extra->astbuf2->clone()); if ($2 != nullptr) { if (node->is_input || node->is_output) - lexer->err("input/output/inout ports cannot have unpacked dimensions."); + err_at_loc(@2, "input/output/inout ports cannot have unpacked dimensions."); if (!extra->astbuf2 && !node->is_custom_type) { addRange(node.get(), 0, 0, false); } @@ -2144,21 +2132,21 @@ wire_name: node->port_id = extra->current_function_or_task_port_id++; } else if (extra->ast_stack.back()->type == AST_GENBLOCK) { if (node->is_input || node->is_output) - lexer->err("Cannot declare module port `%s' within a generate block.", $1->c_str()); + err_at_loc(@1, "Cannot declare module port `%s' within a generate block.", $1->c_str()); } else { if (extra->do_not_require_port_stubs && (node->is_input || node->is_output) && extra->port_stubs.count(*$1) == 0) { extra->port_stubs[*$1] = ++extra->port_counter; } if (extra->port_stubs.count(*$1) != 0) { if (!node->is_input && !node->is_output) - lexer->err("Module port `%s' is neither input nor output.", $1->c_str()); + err_at_loc(@1, "Module port `%s' is neither input nor output.", $1->c_str()); if (node->is_reg && node->is_input && !node->is_output && !mode->sv) - lexer->err("Input port `%s' is declared as register.", $1->c_str()); + err_at_loc(@1, "Input port `%s' is declared as register.", $1->c_str()); node->port_id = extra->port_stubs[*$1]; extra->port_stubs.erase(*$1); } else { if (node->is_input || node->is_output) - lexer->err("Module port `%s' is not declared in module header.", $1->c_str()); + err_at_loc(@1, "Module port `%s' is not declared in module header.", $1->c_str()); } } //FIXME: for some reason, TOK_ID has a location which always points to one column *after* the real last column... @@ -2180,7 +2168,7 @@ assign_expr: }; type_name: TOK_ID { $$ = std::move($1); } // first time seen - | TOK_USER_TYPE { if (extra->isInLocalScope($1.get())) lexer->err("Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); $$ = std::move($1); } + | TOK_USER_TYPE { if (extra->isInLocalScope($1.get())) err_at_loc(@1, "Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); $$ = std::move($1); } ; typedef_decl: @@ -2358,7 +2346,7 @@ cell_port_list: } if (has_positional_args && has_named_args) - lexer->err("Mix of positional and named cell ports."); + err_at_loc(@1, "Mix of positional and named cell ports."); }; cell_port_list_rules: @@ -2399,7 +2387,7 @@ cell_port: } | attr TOK_WILDCARD_CONNECT { if (!mode->sv) - lexer->err("Wildcard port connections are only supported in SystemVerilog mode."); + err_at_loc(@2, "Wildcard port connections are only supported in SystemVerilog mode."); extra->cell_hack->attributes[ID::wildcard_port_conns] = AstNode::mkconst_int(1, false); free_attr($1); }; @@ -2738,11 +2726,11 @@ for_initialization: extra->ast_stack.back()->children.push_back(std::move(node)); } | non_io_wire_type range TOK_ID { - lexer->err("For loop variable declaration is missing initialization!"); + err_at_loc(@3, "For loop variable declaration is missing initialization!"); } | non_io_wire_type range TOK_ID TOK_EQ expr { if (!mode->sv) - lexer->err("For loop inline variable declaration is only supported in SystemVerilog mode!"); + err_at_loc(@4, "For loop inline variable declaration is only supported in SystemVerilog mode!"); // loop variable declaration auto wire = std::move($1); @@ -2926,21 +2914,21 @@ if_attr: attr TOK_UNIQUE0 { AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) - lexer->err("unique0 keyword cannot be used for 'else if' branch."); + err_at_loc(@2, "unique0 keyword cannot be used for 'else if' branch."); (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); $$ = $1; } | attr TOK_PRIORITY { AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) - lexer->err("priority keyword cannot be used for 'else if' branch."); + err_at_loc(@2, "priority keyword cannot be used for 'else if' branch."); (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); $$ = $1; } | attr TOK_UNIQUE { AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) - lexer->err("unique keyword cannot be used for 'else if' branch."); + err_at_loc(@2, "unique keyword cannot be used for 'else if' branch."); (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); $$ = $1; @@ -3138,11 +3126,11 @@ genvar_identifier: genvar_initialization: TOK_GENVAR genvar_identifier { - lexer->err("Generate for loop variable declaration is missing initialization!"); + err_at_loc(@2, "Generate for loop variable declaration is missing initialization!"); } | TOK_GENVAR genvar_identifier TOK_EQ expr { if (!mode->sv) - lexer->err("Generate for loop inline variable declaration is only supported in SystemVerilog mode!"); + err_at_loc(@3, "Generate for loop inline variable declaration is only supported in SystemVerilog mode!"); AstNode* node = extra->saveChild(std::make_unique(AST_GENVAR)); node->is_reg = true; node->is_signed = true; @@ -3244,7 +3232,7 @@ basic_expr: } | TOK_LPAREN expr TOK_RPAREN integral_number { if ($4->compare(0, 1, "'") != 0) - lexer->err("Cast operation must be applied on sized constants e.g. () , while %s is not a sized constant.", $4->c_str()); + err_at_loc(@4, "Cast operation must be applied on sized constants e.g. () , while %s is not a sized constant.", $4->c_str()); 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) @@ -3253,7 +3241,7 @@ basic_expr: } | hierarchical_id integral_number { if ($2->compare(0, 1, "'") != 0) - lexer->err("Cast operation must be applied on sized constants, e.g. \'d0, while %s is not a sized constant.", $2->c_str()); + err_at_loc(@2, "Cast operation must be applied on sized constants, e.g. \'d0, while %s is not a sized constant.", $2->c_str()); auto bits = std::make_unique(AST_IDENTIFIER); bits->str = *$1; SET_AST_NODE_LOC(bits.get(), @1, @1); @@ -3502,25 +3490,25 @@ basic_expr: } | TOK_SIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) - lexer->err("Static cast is only supported in SystemVerilog mode."); + err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); $$ = std::make_unique(AST_TO_SIGNED, std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | TOK_UNSIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) - lexer->err("Static cast is only supported in SystemVerilog mode."); + err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); $$ = std::make_unique(AST_TO_UNSIGNED, std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | basic_expr OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) - lexer->err("Static cast is only supported in SystemVerilog mode."); + err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); $$ = std::make_unique(AST_CAST_SIZE, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | typedef_base_type OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) - lexer->err("Static cast is only supported in SystemVerilog mode."); + err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); $$ = std::make_unique(AST_CAST_SIZE, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | From ecec9a760b8397251e27445c01760b97464956db Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 18 Jun 2025 22:50:46 +0200 Subject: [PATCH 037/176] ast, read_verilog: unify location types, reduce filename copying --- frontends/ast/ast.cc | 37 +- frontends/ast/ast.h | 11 +- frontends/ast/genrtlil.cc | 67 +-- frontends/ast/simplify.cc | 562 +++++++++++----------- frontends/verilog/.gitignore | 2 - frontends/verilog/Makefile.inc | 4 +- frontends/verilog/const2ast.cc | 2 +- frontends/verilog/verilog_frontend.cc | 25 +- frontends/verilog/verilog_lexer.h | 6 +- frontends/verilog/verilog_lexer.l | 38 +- frontends/verilog/verilog_parser.y | 650 +++++++++++++------------- kernel/rtlil.cc | 4 +- 12 files changed, 715 insertions(+), 693 deletions(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index c6305bd09..09989e7ab 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -208,7 +208,7 @@ AstNode::AstNode(AstSrcLocType loc, AstNodeType type, std::unique_ptr c astnodes++; this->type = type; - loc = loc; + location = loc; is_input = false; is_output = false; is_reg = false; @@ -922,7 +922,7 @@ std::unique_ptr AstNode::mktemp_logic(AstSrcLocType loc, const std::str { auto wire_owned = std::make_unique(loc, AST_WIRE, std::make_unique(loc, AST_RANGE, mkconst_int(loc, range_left, true), mkconst_int(loc, range_right, true))); auto* wire = wire_owned.get(); - wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(location.filename).c_str(), location.first_line, autoidx++); + wire->str = stringf("%s%s:%d$%d", name.c_str(), RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, autoidx++); if (nosync) wire->set_attribute(ID::nosync, AstNode::mkconst_int(loc, 1, false)); wire->is_signed = is_signed; @@ -1086,7 +1086,7 @@ RTLIL::Const AstNode::realAsConst(int width) std::string AstNode::loc_string() const { - return stringf("%s:%d.%d-%d.%d", location.filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column); + return stringf("%s:%d.%d-%d.%d", location.begin.filename->c_str(), location.begin.line, location.begin.column, location.end.line, location.end.column); } void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast) @@ -1247,7 +1247,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d ast->children.swap(new_children); if (ast->attributes.count(ID::blackbox) == 0) { - ast->set_attribute(ID::blackbox, AstNode::mkconst_int(1, false)); + ast->set_attribute(ID::blackbox, AstNode::mkconst_int(ast->location, 1, false)); } } @@ -1444,7 +1444,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump if (design->has(child->str)) { RTLIL::Module *existing_mod = design->module(child->str); if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) { - log_file_error(child->location.filename, child->location.first_line, "Re-definition of module `%s'!\n", child->str.c_str()); + log_file_error(*child->location.begin.filename, child->location.begin.line, "Re-definition of module `%s'!\n", child->str.c_str()); } else if (nooverwrite) { log("Ignoring re-definition of module `%s' at %s.\n", child->str.c_str(), child->loc_string().c_str()); @@ -1527,7 +1527,8 @@ AstNode * AST::find_modport(AstNode *intf, std::string name) void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport) { for (auto w : intfmodule->wires()){ - auto wire = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); + auto loc = module_ast->location; + auto wire = std::make_unique(loc, AST_WIRE, std::make_unique(loc, AST_RANGE, AstNode::mkconst_int(loc, w->width -1, true), AstNode::mkconst_int(loc, 0, true))); std::string origname = log_id(w->name); std::string newname = intfname + "." + origname; wire->str = newname; @@ -1584,11 +1585,12 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dictclone(); + auto loc = ast->location; for (auto &intf : local_interfaces) { std::string intfname = intf.first.str(); RTLIL::Module *intfmodule = intf.second; for (auto w : intfmodule->wires()){ - auto wire = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, AstNode::mkconst_int(w->width -1, true), AstNode::mkconst_int(0, true))); + auto wire = std::make_unique(loc, AST_WIRE, std::make_unique(loc, AST_RANGE, AstNode::mkconst_int(loc, w->width -1, true), AstNode::mkconst_int(loc, 0, true))); std::string newname = log_id(w->name); newname = intfname + "." + newname; wire->str = newname; @@ -1616,9 +1618,9 @@ void AstModule::expand_interfaces(RTLIL::Design *design, const dictmodule(interface_type) != nullptr) { // Add a cell to the module corresponding to the interface port such that // it can further propagated down if needed: - auto celltype_for_intf = std::make_unique(AST_CELLTYPE); + auto celltype_for_intf = std::make_unique(loc, AST_CELLTYPE); celltype_for_intf->str = interface_type; - auto cell_for_intf = std::make_unique(AST_CELL, std::move(celltype_for_intf)); + auto cell_for_intf = std::make_unique(loc, AST_CELL, std::move(celltype_for_intf)); cell_for_intf->str = name_port + "_inst_from_top_dummy"; new_ast->children.push_back(std::move(cell_for_intf)); @@ -1825,8 +1827,9 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictclone(); + auto loc = ast->location; if (!new_ast->attributes.count(ID::hdlname)) - new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(stripped_name.substr(1))); + new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(loc, stripped_name.substr(1))); para_counter = 0; for (auto& child : new_ast->children) { @@ -1850,12 +1853,12 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictchildren.insert(child->children.begin(), nullptr); if ((it->second.flags & RTLIL::CONST_FLAG_REAL) != 0) { - child->children[0] = std::make_unique(AST_REALVALUE); + child->children[0] = std::make_unique(loc, AST_REALVALUE); child->children[0]->realvalue = std::stod(it->second.decode_string()); } else if ((it->second.flags & RTLIL::CONST_FLAG_STRING) != 0) - child->children[0] = AstNode::mkconst_str(it->second.decode_string()); + child->children[0] = AstNode::mkconst_str(loc, it->second.decode_string()); else - child->children[0] = AstNode::mkconst_bits(it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0); + child->children[0] = AstNode::mkconst_bits(loc, it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0); rewritten.insert(it->first); } @@ -1863,12 +1866,12 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict(AST_DEFPARAM, std::make_unique(AST_IDENTIFIER)); + auto defparam = std::make_unique(loc, AST_DEFPARAM, std::make_unique(loc, AST_IDENTIFIER)); defparam->children[0]->str = param.first.str(); if ((param.second.flags & RTLIL::CONST_FLAG_STRING) != 0) - defparam->children.push_back(AstNode::mkconst_str(param.second.decode_string())); + defparam->children.push_back(AstNode::mkconst_str(loc, param.second.decode_string())); else - defparam->children.push_back(AstNode::mkconst_bits(param.second.to_bits(), (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0)); + defparam->children.push_back(AstNode::mkconst_bits(loc, param.second.to_bits(), (param.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0)); new_ast->children.push_back(std::move(defparam)); } @@ -1923,7 +1926,7 @@ void AstNode::input_error(const char *format, ...) const { va_list ap; va_start(ap, format); - logv_file_error(location.filename, location.first_line, format, ap); + logv_file_error(*location.begin.filename, location.begin.line, format, ap); } YOSYS_NAMESPACE_END diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index ccbce2b1a..6804c6a30 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -28,6 +28,7 @@ #include "kernel/rtlil.h" #include "kernel/fmt.h" +#include "frontends/verilog/verilog_location.h" #include #include @@ -163,13 +164,7 @@ namespace AST AST_BIND }; - struct AstSrcLocType { - std::string filename; - unsigned int first_line, last_line; - unsigned int first_column, last_column; - AstSrcLocType() : filename(""), first_line(0), last_line(0), first_column(0), last_column(0) {} - AstSrcLocType(std::string _filename, int _first_line, int _first_column, int _last_line, int _last_column) : filename(_filename), first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {} - }; + using AstSrcLocType = location; // convert an node type to a string (e.g. for debug output) std::string type2str(AstNodeType type); @@ -408,7 +403,7 @@ namespace AST // this must be set by the language frontend before parsing the sources // the AstNode constructor then uses current_filename and get_line_num() // to initialize the filename and linenum properties of new nodes - extern std::string current_filename; + // extern std::string current_filename; // also set by the language frontend to control some AST processing extern bool sv_mode_but_global_and_used_for_literally_one_condition; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 9a98cae3b..93731abf0 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -45,7 +45,7 @@ using namespace AST_INTERNAL; // helper function for creating RTLIL code for unary operations static RTLIL::SigSpec uniop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true) { - IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line, autoidx++); + IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, type); set_src_attr(cell, that); @@ -77,7 +77,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s return; } - IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line, autoidx++); + IdString name = stringf("$extend$%s:%d$%d", RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, ID($pos)); set_src_attr(cell, that); @@ -104,7 +104,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s // helper function for creating RTLIL code for binary operations static RTLIL::SigSpec binop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) { - IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line, autoidx++); + IdString name = stringf("%s$%s:%d$%d", type.c_str(), RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, type); set_src_attr(cell, that); @@ -138,7 +138,7 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const log_assert(cond.size() == 1); std::stringstream sstr; - sstr << "$ternary$" << RTLIL::encode_filename(that->location.filename) << ":" << that->location.first_line << "$" << (autoidx++); + sstr << "$ternary$" << RTLIL::encode_filename(*that->location.begin.filename) << ":" << that->location.begin.line << "$" << (autoidx++); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($mux)); set_src_attr(cell, that); @@ -195,12 +195,12 @@ struct AST_INTERNAL::LookaheadRewriter if (node->lookahead) { log_assert(node->type == AST_IDENTIFIER); if (!lookaheadids.count(node->str)) { - auto wire = std::make_unique(AST_WIRE); + auto wire = std::make_unique(node->location, AST_WIRE); for (auto& c : node->id2ast->children) wire->children.push_back(c->clone()); wire->fixup_hierarchy_flags(); wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++); - wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(node->location, 1, false)); wire->is_logic = true; while (wire->simplify(true, 1, -1, false)) { } lookaheadids[node->str] = make_pair(node->id2ast, wire.get()); @@ -271,6 +271,7 @@ struct AST_INTERNAL::LookaheadRewriter // top->dumpVlog(nullptr, "REWRITE-BEFORE> "); AstNode *block = nullptr; + auto loc = top->location; for (auto& c : top->children) if (c->type == AST_BLOCK) { @@ -284,18 +285,18 @@ struct AST_INTERNAL::LookaheadRewriter for (auto it : lookaheadids) { - auto ref_orig = std::make_unique(AST_IDENTIFIER); + auto ref_orig = std::make_unique(loc, AST_IDENTIFIER); ref_orig->str = it.second.first->str; ref_orig->id2ast = it.second.first; ref_orig->was_checked = true; - auto ref_temp = std::make_unique(AST_IDENTIFIER); + auto ref_temp = std::make_unique(loc, AST_IDENTIFIER); ref_temp->str = it.second.second->str; ref_temp->id2ast = it.second.second; ref_temp->was_checked = true; - auto init_assign = std::make_unique(AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone()); - auto final_assign = std::make_unique(AST_ASSIGN_LE, std::move(ref_orig), std::move(ref_temp)); + auto init_assign = std::make_unique(loc, AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone()); + auto final_assign = std::make_unique(loc, AST_ASSIGN_LE, std::move(ref_orig), std::move(ref_temp)); block->children.insert(block->children.begin(), std::move(init_assign)); block->children.push_back(std::move(final_assign)); @@ -347,7 +348,7 @@ struct AST_INTERNAL::ProcessGenerator LookaheadRewriter la_rewriter(always.get()); // generate process and simple root case - proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(always->location.filename).c_str(), always->location.first_line, autoidx++)); + proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(*always->location.begin.filename).c_str(), always->location.begin.line, autoidx++)); set_src_attr(proc, always.get()); for (auto &attr : always->attributes) { if (attr.second->type != AST_CONSTANT) @@ -723,7 +724,7 @@ struct AST_INTERNAL::ProcessGenerator if (ast->str == "$display" || ast->str == "$displayb" || ast->str == "$displayh" || ast->str == "$displayo" || ast->str == "$write" || ast->str == "$writeb" || ast->str == "$writeh" || ast->str == "$writeo") { std::stringstream sstr; - sstr << ast->str << "$" << ast->location.filename << ":" << ast->location.first_line << "$" << (autoidx++); + sstr << ast->str << "$" << ast->location.begin.filename << ":" << ast->location.begin.line << "$" << (autoidx++); Wire *en = current_module->addWire(sstr.str() + "_EN", 1); set_src_attr(en, ast); @@ -766,8 +767,8 @@ struct AST_INTERNAL::ProcessGenerator node->detectSignWidth(width, is_signed, nullptr); VerilogFmtArg arg = {}; - arg.filename = node->location.filename; - arg.first_line = node->location.first_line; + arg.filename = *node->location.begin.filename; + arg.first_line = node->location.begin.line; if (node->type == AST_CONSTANT && node->is_string) { arg.type = VerilogFmtArg::STRING; arg.str = node->bitsAsConst().decode_string(); @@ -793,7 +794,7 @@ struct AST_INTERNAL::ProcessGenerator fmt.append_literal("\n"); fmt.emit_rtlil(cell); } else if (!ast->str.empty()) { - log_file_error(ast->location.filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str()); + log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str()); } break; @@ -813,7 +814,7 @@ struct AST_INTERNAL::ProcessGenerator IdString cellname; if (ast->str.empty()) - cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(ast->location.filename).c_str(), ast->location.first_line, autoidx++); + cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(*ast->location.begin.filename).c_str(), ast->location.begin.line, autoidx++); else cellname = ast->str; check_unique_id(current_module, cellname, ast, "procedural assertion"); @@ -843,7 +844,7 @@ struct AST_INTERNAL::ProcessGenerator set_src_attr(cell, ast); for (auto &attr : ast->attributes) { if (attr.second->type != AST_CONSTANT) - log_file_error(ast->location.filename, ast->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); + log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } cell->setParam(ID::FLAVOR, flavor); @@ -1504,7 +1505,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } RTLIL::SigSpec sig = realAsConst(width_hint); - log_file_warning(location.filename, location.first_line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); + log_file_warning(*location.begin.filename, location.begin.line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); return sig; } @@ -1536,7 +1537,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (dynamic_cast(current_module)) { /* nothing to do here */ } else if (flag_autowire) - log_file_warning(location.filename, location.first_line, "Identifier `%s' is implicitly declared.\n", str.c_str()); + log_file_warning(*location.begin.filename, location.begin.line, "Identifier `%s' is implicitly declared.\n", str.c_str()); else input_error("Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); } @@ -1611,7 +1612,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; - auto fake_ast = std::make_unique(AST_NONE, clone(), children[0]->children.size() >= 2 ? + auto fake_ast = std::make_unique(children[0]->location, AST_NONE, clone(), children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : children[0]->children[0]->clone()); fake_ast->children[0]->delete_children(); if (member_node) @@ -1641,10 +1642,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk.offset = source_width - (chunk.offset + chunk.width); if (chunk.offset > chunk_left || chunk.offset + chunk.width < chunk_right) { if (chunk.width == 1) - log_file_warning(location.filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", + log_file_warning(*location.begin.filename, location.begin.line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", str.c_str()); else - log_file_warning(location.filename, location.first_line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", + log_file_warning(*location.begin.filename, location.begin.line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width); chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width); } else { @@ -1658,10 +1659,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk.offset += add_undef_bits_lsb; } if (add_undef_bits_lsb) - log_file_warning(location.filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", + log_file_warning(*location.begin.filename, location.begin.line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb); if (add_undef_bits_msb) - log_file_warning(location.filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", + log_file_warning(*location.begin.filename, location.begin.line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb); } } @@ -1935,7 +1936,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_MEMRD: { std::stringstream sstr; - sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($memrd)); set_src_attr(cell, this); @@ -1973,7 +1974,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_MEMINIT: { std::stringstream sstr; - sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++); SigSpec en_sig = children[2]->genRTLIL(); @@ -2018,7 +2019,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) IdString cellname; if (str.empty()) - cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(location.filename).c_str(), location.first_line, autoidx++); + cellname = stringf("$%s$%s:%d$%d", flavor.c_str(), RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, autoidx++); else cellname = str; check_unique_id(current_module, cellname, this, "procedural assertion"); @@ -2061,7 +2062,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) new_left.append(left[i]); new_right.append(right[i]); } - log_file_warning(location.filename, location.first_line, "Ignoring assignment to constant bits:\n" + log_file_warning(*location.begin.filename, location.begin.line, "Ignoring assignment to constant bits:\n" " old assignment: %s = %s\n new assignment: %s = %s.\n", log_signal(left), log_signal(right), log_signal(new_left), log_signal(new_right)); @@ -2096,7 +2097,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; const AstNode *value = child->children[0].get(); if (value->type == AST_REALVALUE) - log_file_warning(location.filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n", + log_file_warning(*location.begin.filename, location.begin.line, "Replacing floating point parameter %s.%s = %f with string.\n", log_id(cell), log_id(paraname), value->realvalue); else if (value->type != AST_CONSTANT) input_error("Parameter %s.%s with non-constant value!\n", @@ -2193,14 +2194,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) int sz = children.size(); if (str == "$info") { if (sz > 0) - log_file_info(location.filename, location.first_line, "%s.\n", children[0]->str.c_str()); + log_file_info(*location.begin.filename, location.begin.line, "%s.\n", children[0]->str.c_str()); else - log_file_info(location.filename, location.first_line, "\n"); + log_file_info(*location.begin.filename, location.begin.line, "\n"); } else if (str == "$warning") { if (sz > 0) - log_file_warning(location.filename, location.first_line, "%s.\n", children[0]->str.c_str()); + log_file_warning(*location.begin.filename, location.begin.line, "%s.\n", children[0]->str.c_str()); else - log_file_warning(location.filename, location.first_line, "\n"); + log_file_warning(*location.begin.filename, location.begin.line, "\n"); } else if (str == "$error") { if (sz > 0) input_error("%s.\n", children[0]->str.c_str()); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 374b9c0dc..8cacec275 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -155,8 +155,8 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_ while (node_arg->simplify(true, stage, -1, false)) { } VerilogFmtArg arg = {}; - arg.filename = location.filename; - arg.first_line = location.first_line; + arg.filename = *location.begin.filename; + arg.first_line = location.begin.line; if (node_arg->type == AST_CONSTANT && node_arg->is_string) { arg.type = VerilogFmtArg::STRING; arg.str = node_arg->bitsAsConst().decode_string(); @@ -173,10 +173,10 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_ arg.sig = node_arg->bitsAsConst(); arg.signed_ = node_arg->is_signed; } else if (may_fail) { - log_file_info(location.filename, location.first_line, "Skipping system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); + log_file_info(*location.begin.filename, location.begin.line, "Skipping system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); return Fmt(); } else { - log_file_error(location.filename, location.first_line, "Failed to evaluate system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); + log_file_error(*location.begin.filename, location.begin.line, "Failed to evaluate system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); } args.push_back(arg); } @@ -424,12 +424,13 @@ static std::unique_ptr index_offset(std::unique_ptr offset, As stride /= decl_node->dimensions[dimension].range_width; auto right = normalize_index(rnode->children.back().get(), decl_node, dimension); auto add_offset = stride > 1 ? multiply_by_const(std::move(right), stride) : std::move(right); - return offset ? std::make_unique(AST_ADD, std::move(offset), std::move(add_offset)) : std::move(add_offset); + return offset ? std::make_unique(rnode->location, AST_ADD, std::move(offset), std::move(add_offset)) : std::move(add_offset); } static std::unique_ptr index_msb_offset(std::unique_ptr lsb_offset, AstNode *rnode, AstNode *decl_node, int dimension, int stride) { log_assert(rnode->children.size() <= 2); + auto loc = rnode->location; // Offset to add to LSB std::unique_ptr add_offset; @@ -442,15 +443,15 @@ static std::unique_ptr index_msb_offset(std::unique_ptr lsb_of // Slice, e.g. s.a[i:j] auto left = normalize_index(rnode->children[0].get(), decl_node, dimension); auto right = normalize_index(rnode->children[1].get(), decl_node, dimension); - add_offset = std::make_unique(AST_SUB, std::move(left), std::move(right)); + add_offset = std::make_unique(loc, AST_SUB, std::move(left), std::move(right)); if (stride > 1) { // offset = (msb - lsb + 1)*stride - 1 - auto slice_width = std::make_unique(AST_ADD, std::move(add_offset), node_int(1)); - add_offset = std::make_unique(AST_SUB, multiply_by_const(std::move(slice_width), stride), node_int(1)); + auto slice_width = std::make_unique(loc, AST_ADD, std::move(add_offset), node_int(loc, 1)); + add_offset = std::make_unique(loc, AST_SUB, multiply_by_const(std::move(slice_width), stride), node_int(loc, 1)); } } - return std::make_unique(AST_ADD, std::move(lsb_offset), std::move(add_offset)); + return std::make_unique(loc, AST_ADD, std::move(lsb_offset), std::move(add_offset)); } @@ -461,7 +462,7 @@ std::unique_ptr AstNode::make_index_range(AstNode *decl_node, bool unpa // such as array indexing or slicing if (children.empty()) { // no range operations apply, return the whole width - return make_range(decl_node->range_left - decl_node->range_right, 0); + return make_range(decl_node->location, decl_node->range_left - decl_node->range_right, 0); } log_assert(children.size() == 1); @@ -495,7 +496,7 @@ std::unique_ptr AstNode::make_index_range(AstNode *decl_node, bool unpa input_error("Unsupported range operation for %s\n", str.c_str()); } - std::unique_ptrindex_range = std::make_unique(AST_RANGE); + std::unique_ptr index_range = std::make_unique(rnode->location, AST_RANGE); if (!unpacked_range && (stride > 1 || GetSize(rnode->children) == 2)) { // Calculate MSB offset for the final index / slice of packed dimensions. @@ -537,7 +538,8 @@ static void add_members_to_scope(AstNode *snode, std::string name) std::unique_ptr make_packed_struct(AstNode *template_node, std::string &name, decltype(AstNode::attributes) &attributes) { // create a wire for the packed struct - auto wnode = std::make_unique(AST_WIRE, make_range(template_node->range_left, 0)); + auto loc = template_node->location; + auto wnode = std::make_unique(loc, AST_WIRE, make_range(loc, template_node->range_left, 0)); wnode->str = name; wnode->is_logic = true; wnode->range_valid = true; @@ -557,8 +559,9 @@ std::unique_ptr make_packed_struct(AstNode *template_node, std::string static void prepend_ranges(std::unique_ptr &range, AstNode *range_add) { // Convert range to multirange. + auto loc = range->location; if (range->type == AST_RANGE) - range = std::make_unique(AST_MULTIRANGE, std::move(range)); + range = std::make_unique(loc, AST_MULTIRANGE, std::move(range)); // Add range or ranges. if (range_add->type == AST_RANGE) @@ -693,15 +696,15 @@ static bool contains_unbased_unsized(const AstNode *node) // adds a wire to the current module with the given name that matches the // dimensions of the given wire reference -void add_wire_for_ref(const RTLIL::Wire *ref, const std::string &str) +void add_wire_for_ref(location loc, const RTLIL::Wire *ref, const std::string &str) { - std::unique_ptr left = AstNode::mkconst_int(ref->width - 1 + ref->start_offset, true); - std::unique_ptr right = AstNode::mkconst_int(ref->start_offset, true); + std::unique_ptr left = AstNode::mkconst_int(loc, ref->width - 1 + ref->start_offset, true); + std::unique_ptr right = AstNode::mkconst_int(loc, ref->start_offset, true); if (ref->upto) std::swap(left, right); - std::unique_ptr range = std::make_unique(AST_RANGE, std::move(left), std::move(right)); + std::unique_ptr range = std::make_unique(loc, AST_RANGE, std::move(left), std::move(right)); - std::unique_ptr wire = std::make_unique(AST_WIRE, std::move(range)); + std::unique_ptr wire = std::make_unique(loc, AST_WIRE, std::move(range)); wire->is_signed = ref->is_signed; wire->is_logic = true; wire->str = str; @@ -790,7 +793,7 @@ std::unique_ptr AstNode::clone_at_zero() YS_FALLTHROUGH case AST_MEMRD: detectSignWidth(width_hint, sign_hint); - return mkconst_int(0, sign_hint, width_hint); + return mkconst_int(location, 0, sign_hint, width_hint); default: break; @@ -842,7 +845,7 @@ static void mark_auto_nosync(AstNode *block, const AstNode *wire) { log_assert(block->type == AST_BLOCK); log_assert(wire->type == AST_WIRE); - block->set_attribute(auto_nosync_prefix + wire->str, AstNode::mkconst_int(1, false)); + block->set_attribute(auto_nosync_prefix + wire->str, AstNode::mkconst_int(block->location, 1, false)); } // block names can be prefixed with an explicit scope during elaboration @@ -883,7 +886,7 @@ static void check_auto_nosync(AstNode *node) // mark the wire with `nosync` AstNode *wire = it->second; log_assert(wire->type == AST_WIRE); - wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(wire->location, 1, false)); } // remove the attributes we've "consumed" @@ -931,7 +934,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin #if 0 log("-------------\n"); - log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, location.filename.c_str(), location.first_line, type2str(type).c_str(), this); + log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, location.begin.filename->c_str(), location.begin.line, type2str(type).c_str(), this); log("const_fold=%d, stage=%d, width_hint=%d, sign_hint=%d\n", int(const_fold), int(stage), int(width_hint), int(sign_hint)); // dumpAst(nullptr, "> "); @@ -1013,16 +1016,17 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (node->children[0]->range_swapped) std::swap(data_range_left, data_range_right); + auto loc = node->location; for (int i = 0; i < mem_size; i++) { - auto reg = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, - mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); + auto reg = std::make_unique(loc, AST_WIRE, std::make_unique(loc, AST_RANGE, + mkconst_int(loc, data_range_left, true), mkconst_int(loc, data_range_right, true))); reg->str = stringf("%s[%d]", node->str.c_str(), i); reg->is_reg = true; reg->is_signed = node->is_signed; for (auto &it : node->attributes) if (it.first != ID::mem2reg) reg->set_attribute(it.first, it.second->clone()); - reg->location.filename = node->location.filename; + reg->location.begin.filename = node->location.begin.filename; reg->location = node->location; while (reg->simplify(true, 1, -1, false)) { } children.push_back(std::move(reg)); @@ -1051,7 +1055,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" || str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) { - log_file_warning(location.filename, location.first_line, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str()); + log_file_warning(*location.begin.filename, location.begin.line, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str()); delete_children(); str = std::string(); } @@ -1061,7 +1065,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin str == "$write" || str == "$writeb" || str == "$writeh" || str == "$writeo")) { if (!current_always) { - log_file_warning(location.filename, location.first_line, "System task `%s' outside initial or always block is unsupported.\n", str.c_str()); + log_file_warning(*location.begin.filename, location.begin.line, "System task `%s' outside initial or always block is unsupported.\n", str.c_str()); delete_children(); str = std::string(); } else { @@ -1178,7 +1182,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) { for (auto& c : node->children[0]->children) { if (!c->is_simple_const_expr()) - set_attribute(ID::dynports, AstNode::mkconst_int(1, true)); + set_attribute(ID::dynports, AstNode::mkconst_int(c->location, 1, true)); } } if (this_wire_scope.count(node->str) > 0) { @@ -1404,15 +1408,15 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // create the indirection wire std::stringstream sstr; - sstr << "$indirect$" << ref->name.c_str() << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$indirect$" << ref->name.c_str() << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++); std::string tmp_str = sstr.str(); - add_wire_for_ref(ref, tmp_str); + add_wire_for_ref(location, ref, tmp_str); - auto asgn_owned = std::make_unique(AST_ASSIGN); + auto asgn_owned = std::make_unique(child->location, AST_ASSIGN); auto* asgn = asgn_owned.get(); current_ast_mod->children.push_back(std::move(asgn_owned)); - auto ident = std::make_unique(AST_IDENTIFIER); + auto ident = std::make_unique(child->location, AST_IDENTIFIER); ident->str = tmp_str; child->children[0] = ident->clone(); @@ -1575,7 +1579,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (child->children.size() == 0) { // Base type (e.g., int) width = child->range_left - child->range_right +1; - node = mkconst_int(width, child->is_signed); + node = mkconst_int(child->location, width, child->is_signed); } else { // User defined type log_assert(child->children[0]->type == AST_WIRETYPE); @@ -1598,7 +1602,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (template_node->children.size() > 0 && template_node->children[0]->type == AST_RANGE) width = range_width(this, template_node->children[0].get()); child->delete_children(); - node = mkconst_int(width, true); + node = mkconst_int(child->location, width, true); break; } @@ -1606,7 +1610,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin case AST_UNION: { child->delete_children(); width = size_packed_struct(template_node, 0); - node = mkconst_int(width, false); + node = mkconst_int(child->location, width, false); break; } @@ -1938,7 +1942,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin input_error("Defparam argument `%s . %s` does not match a cell!\n", RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str()); - auto paraset = std::make_unique(AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : nullptr); + auto paraset = std::make_unique(location, AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : nullptr); paraset->str = paramname; AstNode *cell = current_scope.at(modname); @@ -1980,7 +1984,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) { // replace instance with wire representing the packed structure newNode = make_packed_struct(template_node.get(), str, attributes); - newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); + newNode->set_attribute(ID::wiretype, mkconst_str(newNode->location, resolved_type_node->str)); // add original input/output attribute to resolved wire newNode->is_input = this->is_input; newNode->is_output = this->is_output; @@ -1991,7 +1995,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // Prepare replacement node. newNode = template_node->clone(); newNode->str = str; - newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); + newNode->set_attribute(ID::wiretype, mkconst_str(newNode->location, resolved_type_node->str)); newNode->is_input = is_input; newNode->is_output = is_output; newNode->is_wand = is_wand; @@ -2082,7 +2086,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (children[1]->type != AST_CONSTANT) input_error("Right operand of to_bits expression is not constant!\n"); RTLIL::Const new_value = children[1]->bitsAsConst(children[0]->bitsAsConst().as_int(), children[1]->is_signed); - newNode = mkconst_bits(new_value.to_bits(), children[1]->is_signed); + newNode = mkconst_bits(location, new_value.to_bits(), children[1]->is_signed); goto apply_newNode; } @@ -2144,7 +2148,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin range_swapped = force_upto; } if (range_left == range_right && !attributes.count(ID::single_bit_vector)) - set_attribute(ID::single_bit_vector, mkconst_int(1, false)); + set_attribute(ID::single_bit_vector, mkconst_int(location, 1, false)); } } else { if (!range_valid) @@ -2171,7 +2175,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin int left = width - 1, right = 0; if (i) std::swap(left, right); - children[i] = std::make_unique(AST_RANGE, mkconst_int(left, true), mkconst_int(right, true)); + auto loc = children[i]->location; + children[i] = std::make_unique(loc, AST_RANGE, mkconst_int(loc, left, true), mkconst_int(loc, right, true)); fixup_hierarchy_flags(); did_something = true; } else if (children[i]->type == AST_RANGE) { @@ -2242,9 +2247,9 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin int width = std::abs(children[1]->range_left - children[1]->range_right) + 1; if (children[0]->type == AST_REALVALUE) { RTLIL::Const constvalue = children[0]->realAsConst(width); - log_file_warning(location.filename, location.first_line, "converting real value %e to binary %s.\n", + log_file_warning(*location.begin.filename, location.begin.line, "converting real value %e to binary %s.\n", children[0]->realvalue, log_signal(constvalue)); - children[0] = mkconst_bits(constvalue.to_bits(), sign_hint); + children[0] = mkconst_bits(location, constvalue.to_bits(), sign_hint); fixup_hierarchy_flags(); did_something = true; } @@ -2252,7 +2257,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (width != int(children[0]->bits.size())) { RTLIL::SigSpec sig(children[0]->bits); sig.extend_u0(width, children[0]->is_signed); - children[0] = mkconst_bits(sig.as_const().to_bits(), is_signed); + children[0] = mkconst_bits(location, sig.as_const().to_bits(), is_signed); fixup_hierarchy_flags(); } children[0]->is_signed = is_signed; @@ -2264,7 +2269,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } else if (children.size() > 1 && children[1]->type == AST_REALVALUE && children[0]->type == AST_CONSTANT) { double as_realvalue = children[0]->asReal(sign_hint); - children[0] = std::make_unique(AST_REALVALUE); + children[0] = std::make_unique(location, AST_REALVALUE); children[0]->realvalue = as_realvalue; fixup_hierarchy_flags(); did_something = true; @@ -2293,7 +2298,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (found_sname) { // structure member, rewrite this node to reference the packed struct wire auto range = make_index_range(item_node); - newNode = std::make_unique(AST_IDENTIFIER, std::move(range)); + newNode = std::make_unique(location, AST_IDENTIFIER, std::move(range)); newNode->str = sname; // save type and original number of dimensions for $size() etc. newNode->set_attribute(ID::wiretype, item_node->clone()); @@ -2305,7 +2310,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } newNode->basic_prep = true; if (item_node->is_signed) - newNode = std::make_unique(AST_TO_SIGNED, std::move(newNode)); + newNode = std::make_unique(location, AST_TO_SIGNED, std::move(newNode)); goto apply_newNode; } } @@ -2353,7 +2358,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (current_ast_mod == nullptr) { input_error("Identifier `%s' is implicitly declared outside of a module.\n", str.c_str()); } else if (flag_autowire || str == "\\$global_clock") { - auto auto_wire = std::make_unique(AST_AUTOWIRE); + auto auto_wire = std::make_unique(location, AST_AUTOWIRE); auto_wire->str = str; current_scope[str] = auto_wire.get(); current_ast_mod->children.push_back(std::move(auto_wire)); @@ -2384,21 +2389,21 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin std::swap(data_range_left, data_range_right); std::stringstream sstr; - sstr << "$mem2bits$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$mem2bits$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++); std::string wire_id = sstr.str(); - auto wire_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); + auto wire_owned = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, data_range_left, true), mkconst_int(location, data_range_right, true))); auto* wire = wire_owned.get(); current_ast_mod->children.push_back(std::move(wire_owned)); wire->str = wire_id; if (current_block) - wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(location, 1, false)); while (wire->simplify(true, 1, -1, false)) { } auto data = clone(); data->children.pop_back(); - auto assign = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), std::move(data)); + auto assign = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), std::move(data)); assign->children[0]->str = wire_id; assign->children[0]->was_checked = true; @@ -2413,12 +2418,12 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } else { - auto proc = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK)); + auto proc = std::make_unique(location, AST_ALWAYS, std::make_unique(location, AST_BLOCK)); proc->children[0]->children.push_back(std::move(assign)); current_ast_mod->children.push_back(std::move(proc)); } - newNode = std::make_unique(AST_IDENTIFIER, children[1]->clone()); + newNode = std::make_unique(location, AST_IDENTIFIER, children[1]->clone()); newNode->str = wire_id; newNode->integer = integer; // save original number of dimensions for $size() etc. newNode->id2ast = wire; @@ -2508,7 +2513,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } } - varbuf = std::make_unique(AST_LOCALPARAM, std::move(varbuf)); + varbuf = std::make_unique(location, AST_LOCALPARAM, std::move(varbuf)); varbuf->str = init_ast->children[0]->str; AstNode *backup_scope_varbuf = current_scope[varbuf->str]; @@ -2673,7 +2678,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (buf) { if (buf->type != AST_GENBLOCK) - buf = std::make_unique(AST_GENBLOCK, std::move(buf)); + buf = std::make_unique(location, AST_GENBLOCK, std::move(buf)); if (!buf->str.empty()) { buf->expand_genblock(buf->str + "."); @@ -2773,7 +2778,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (!children.at(0)->range_valid) input_error("Non-constant array range on cell array.\n"); - newNode = std::make_unique(AST_GENBLOCK); + newNode = std::make_unique(location, AST_GENBLOCK); int num = max(children.at(0)->range_left, children.at(0)->range_right) - min(children.at(0)->range_left, children.at(0)->range_right) + 1; for (int i = 0; i < num; i++) { @@ -2818,15 +2823,15 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin auto& mux_input = children_list.at(1); if (str == "notif0" || str == "notif1") { - mux_input = std::make_unique(AST_BIT_NOT, std::move(mux_input)); + mux_input = std::make_unique(location, AST_BIT_NOT, std::move(mux_input)); } - auto node = std::make_unique(AST_TERNARY, std::move(children_list.at(2))); + auto node = std::make_unique(location, AST_TERNARY, std::move(children_list.at(2))); if (str == "bufif0") { - node->children.push_back(AstNode::mkconst_bits(z_const, false)); + node->children.push_back(AstNode::mkconst_bits(location, z_const, false)); node->children.push_back(std::move(mux_input)); } else { node->children.push_back(std::move(mux_input)); - node->children.push_back(AstNode::mkconst_bits(z_const, false)); + node->children.push_back(AstNode::mkconst_bits(location, z_const, false)); } str.clear(); @@ -2841,11 +2846,11 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin { auto& input = children_list.back(); if (str == "not") - input = std::make_unique(AST_BIT_NOT, std::move(input)); + input = std::make_unique(location, AST_BIT_NOT, std::move(input)); - newNode = std::make_unique(AST_GENBLOCK); + newNode = std::make_unique(location, AST_GENBLOCK); for (auto it = children_list.begin(); it != std::prev(children_list.end()); it++) { - newNode->children.push_back(std::make_unique(AST_ASSIGN, std::move(*it), input->clone())); + newNode->children.push_back(std::make_unique(location, AST_ASSIGN, std::move(*it), input->clone())); newNode->children.back()->was_checked = true; } @@ -2873,11 +2878,11 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin auto& node = children_list[1]; if (op_type != AST_POS) for (size_t i = 2; i < children_list.size(); i++) { - node = std::make_unique(op_type, std::move(node), std::move(children_list[i])); + node = std::make_unique(location, op_type, std::move(node), std::move(children_list[i])); node->location = location; } if (invert_results) - node = std::make_unique(AST_BIT_NOT, std::move(node)); + node = std::make_unique(location, AST_BIT_NOT, std::move(node)); str.clear(); type = AST_ASSIGN; @@ -3012,13 +3017,13 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin int rvalue_width; bool rvalue_sign; children[1]->detectSignWidth(rvalue_width, rvalue_sign); - auto rvalue = mktemp_logic("$bitselwrite$rvalue$", current_ast_mod, true, rvalue_width - 1, 0, rvalue_sign); + auto rvalue = mktemp_logic(location, "$bitselwrite$rvalue$", current_ast_mod, true, rvalue_width - 1, 0, rvalue_sign); auto* rvalue_leaky = rvalue.get(); log("make 1\n"); - auto case_node_owned = std::make_unique(AST_CASE, std::move(shift_expr)); + auto case_node_owned = std::make_unique(location, AST_CASE, std::move(shift_expr)); auto* case_node = case_node_owned.get(); - newNode = std::make_unique(AST_BLOCK, - std::make_unique(AST_ASSIGN_EQ, std::move(rvalue), children[1]->clone()), + newNode = std::make_unique(location, AST_BLOCK, + std::make_unique(location, AST_ASSIGN_EQ, std::move(rvalue), children[1]->clone()), std::move(case_node_owned)); did_something = true; @@ -3032,14 +3037,14 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (start_bit%bitno_div != 0 || (stride == 0 && start_bit != 0)) continue; - auto cond = std::make_unique(AST_COND, mkconst_int(start_bit, case_sign_hint, max_width)); + auto cond = std::make_unique(location, AST_COND, mkconst_int(location, start_bit, case_sign_hint, max_width)); auto lvalue = children[0]->clone(); lvalue->delete_children(); if (member_node) lvalue->set_attribute(ID::wiretype, member_node->clone()); - lvalue->children.push_back(std::make_unique(AST_RANGE, - mkconst_int(end_bit, true), mkconst_int(start_bit, true))); - cond->children.push_back(std::make_unique(AST_BLOCK, std::make_unique(std::move(type), std::move(lvalue), rvalue_leaky->clone()))); + lvalue->children.push_back(std::make_unique(location, AST_RANGE, + mkconst_int(location, end_bit, true), mkconst_int(location, start_bit, true))); + cond->children.push_back(std::make_unique(location, AST_BLOCK, std::make_unique(location, std::move(type), std::move(lvalue), rvalue_leaky->clone()))); case_node->children.push_back(std::move(cond)); } } else { @@ -3060,50 +3065,50 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin shift_expr->detectSignWidth(shift_width_hint, shift_sign_hint); // All operations are carried out in a new block. - newNode = std::make_unique(AST_BLOCK); + newNode = std::make_unique(location, AST_BLOCK); // Temporary register holding the result of the bit- or part-select position expression. - auto pos = mktemp_logic("$bitselwrite$pos$", current_ast_mod, true, shift_width_hint - 1, 0, shift_sign_hint); + auto pos = mktemp_logic(location, "$bitselwrite$pos$", current_ast_mod, true, shift_width_hint - 1, 0, shift_sign_hint); // Calculate lsb from position. auto shift_val = pos->clone(); - newNode->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::move(pos), std::move(shift_expr))); + newNode->children.push_back(std::make_unique(location, AST_ASSIGN_EQ, std::move(pos), std::move(shift_expr))); // If the expression is signed, we must add an extra bit for possible negation of the most negative number. // If the expression is unsigned, we must add an extra bit for sign. - shift_val = std::make_unique(AST_CAST_SIZE, mkconst_int(shift_width_hint + 1, true), std::move(shift_val)); + shift_val = std::make_unique(location, AST_CAST_SIZE, mkconst_int(location, shift_width_hint + 1, true), std::move(shift_val)); if (!shift_sign_hint) - shift_val = std::make_unique(AST_TO_SIGNED, std::move(shift_val)); + shift_val = std::make_unique(location, AST_TO_SIGNED, std::move(shift_val)); // offset the shift amount by the lower bound of the dimension if (wire_offset != 0) - shift_val = std::make_unique(AST_SUB, std::move(shift_val), mkconst_int(wire_offset, true)); + shift_val = std::make_unique(location, AST_SUB, std::move(shift_val), mkconst_int(location, wire_offset, true)); // reflect the shift amount if the dimension is swapped if (children[0]->id2ast->range_swapped) - shift_val = std::make_unique(AST_SUB, mkconst_int(wire_width - result_width, true), std::move(shift_val)); + shift_val = std::make_unique(location, AST_SUB, mkconst_int(location, wire_width - result_width, true), std::move(shift_val)); // AST_SHIFT uses negative amounts for shifting left - shift_val = std::make_unique(AST_NEG, std::move(shift_val)); + shift_val = std::make_unique(location, AST_NEG, std::move(shift_val)); auto also_shift_val = shift_val->clone(); // dst = (dst & ~(width'1 << lsb)) | unsigned'(width'(src)) << lsb) did_something = true; - auto bitmask = mkconst_bits(std::vector(result_width, State::S1), false); + auto bitmask = mkconst_bits(location, std::vector(result_width, State::S1), false); newNode->children.push_back( - std::make_unique(std::move(type), + std::make_unique(location, std::move(type), std::move(lvalue), - std::make_unique(AST_BIT_OR, - std::make_unique(AST_BIT_AND, + std::make_unique(location, AST_BIT_OR, + std::make_unique(location, AST_BIT_AND, std::move(old_data), - std::make_unique(AST_BIT_NOT, - std::make_unique(AST_SHIFT, + std::make_unique(location, AST_BIT_NOT, + std::make_unique(location, AST_SHIFT, std::move(bitmask), std::move(shift_val)))), - std::make_unique(AST_SHIFT, - std::make_unique(AST_TO_UNSIGNED, - std::make_unique(AST_CAST_SIZE, - mkconst_int(result_width, true), + std::make_unique(location, AST_SHIFT, + std::make_unique(location, AST_TO_UNSIGNED, + std::make_unique(location, AST_CAST_SIZE, + mkconst_int(location, result_width, true), children[1]->clone())), std::move(also_shift_val))))); @@ -3119,7 +3124,7 @@ skip_dynamic_range_lvalue_expansion:; children.size() == 1 && children[0]->type == AST_RANGE && children[0]->children.size() == 1) { if (integer < (unsigned)id2ast->unpacked_dimensions) input_error("Insufficient number of array indices for %s.\n", log_id(str)); - newNode = std::make_unique(AST_MEMRD, children[0]->children[0]->clone()); + newNode = std::make_unique(location, AST_MEMRD, children[0]->children[0]->clone()); newNode->str = str; newNode->id2ast = id2ast; goto apply_newNode; @@ -3137,22 +3142,22 @@ skip_dynamic_range_lvalue_expansion:; if (found_nontrivial_member) { - newNode = std::make_unique(AST_BLOCK); + newNode = std::make_unique(location, AST_BLOCK); - auto wire_tmp_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); + auto wire_tmp_owned = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, width_hint-1, true), mkconst_int(location, 0, true))); auto wire_tmp = wire_tmp_owned.get(); - wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line, autoidx++); + wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, autoidx++); current_scope[wire_tmp->str] = wire_tmp; current_ast_mod->children.push_back(std::move(wire_tmp_owned)); - wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(location, 1, false)); while (wire_tmp->simplify(true, 1, -1, false)) { } wire_tmp->is_logic = true; - auto wire_tmp_id_owned = std::make_unique(AST_IDENTIFIER); + auto wire_tmp_id_owned = std::make_unique(location, AST_IDENTIFIER); auto* wire_tmp_id = wire_tmp_id_owned.get(); wire_tmp_id->str = wire_tmp->str; - newNode->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::move(wire_tmp_id_owned), children[1]->clone())); + newNode->children.push_back(std::make_unique(location, AST_ASSIGN_EQ, std::move(wire_tmp_id_owned), children[1]->clone())); newNode->children.back()->was_checked = true; int cursor = 0; @@ -3163,8 +3168,8 @@ skip_dynamic_range_lvalue_expansion:; child->detectSignWidth(child_width_hint, child_sign_hint); auto rhs = wire_tmp_id->clone(); - rhs->children.push_back(std::make_unique(AST_RANGE, AstNode::mkconst_int(cursor+child_width_hint-1, true), AstNode::mkconst_int(cursor, true))); - newNode->children.push_back(std::make_unique(type, child->clone(), std::move(rhs))); + rhs->children.push_back(std::make_unique(location, AST_RANGE, AstNode::mkconst_int(location, cursor+child_width_hint-1, true), AstNode::mkconst_int(location, cursor, true))); + newNode->children.push_back(std::make_unique(location, type, child->clone(), std::move(rhs))); cursor += child_width_hint; } @@ -3183,15 +3188,15 @@ skip_dynamic_range_lvalue_expansion:; input_error("Insufficient number of array indices for %s.\n", log_id(str)); std::stringstream sstr; - sstr << "$memwr$" << children[0]->str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$memwr$" << children[0]->str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN"; int mem_width, mem_size, addr_bits; bool mem_signed = children[0]->id2ast->is_signed; children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); - newNode = std::make_unique(AST_BLOCK); - auto defNode = std::make_unique(AST_BLOCK); + newNode = std::make_unique(location, AST_BLOCK); + auto defNode = std::make_unique(location, AST_BLOCK); int data_range_left = children[0]->id2ast->children[0]->range_left; int data_range_right = children[0]->id2ast->children[0]->range_right; @@ -3214,7 +3219,7 @@ skip_dynamic_range_lvalue_expansion:; if (children[0]->children[0]->children[0]->isConst()) { node_addr = children[0]->children[0]->children[0]->clone(); } else { - auto wire_addr_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); + auto wire_addr_owned = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, addr_bits-1, true), mkconst_int(location, 0, true))); auto* wire_addr = wire_addr_owned.get(); wire_addr->str = id_addr; wire_addr->was_checked = true; @@ -3222,17 +3227,17 @@ skip_dynamic_range_lvalue_expansion:; current_scope[wire_addr->str] = wire_addr; while (wire_addr->simplify(true, 1, -1, false)) { } - auto assign_addr = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); + auto assign_addr = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), mkconst_bits(location, x_bits_addr, false)); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; defNode->children.push_back(std::move(assign_addr)); - assign_addr = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); + assign_addr = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; newNode->children.push_back(std::move(assign_addr)); - node_addr = std::make_unique(AST_IDENTIFIER); + node_addr = std::make_unique(location, AST_IDENTIFIER); node_addr->str = id_addr; } @@ -3240,7 +3245,7 @@ skip_dynamic_range_lvalue_expansion:; if (children[0]->children.size() == 1 && children[1]->isConst()) { node_data = children[1]->clone(); } else { - auto wire_data_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_data_owned = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, mem_width-1, true), mkconst_int(location, 0, true))); auto* wire_data = wire_data_owned.get(); wire_data->str = id_data; wire_data->was_checked = true; @@ -3249,16 +3254,16 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(std::move(wire_data_owned)); while (wire_data->simplify(true, 1, -1, false)) { } - auto assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); + auto assign_data = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), mkconst_bits(location, x_bits_data, false)); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; defNode->children.push_back(std::move(assign_data)); - node_data = std::make_unique(AST_IDENTIFIER); + node_data = std::make_unique(location, AST_IDENTIFIER); node_data->str = id_data; } - auto wire_en_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_en_owned = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, mem_width-1, true), mkconst_int(location, 0, true))); auto* wire_en = wire_en_owned.get(); wire_en->str = id_en; wire_en->was_checked = true; @@ -3266,12 +3271,12 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(std::move(wire_en_owned)); while (wire_en->simplify(true, 1, -1, false)) { } - auto assign_en_first = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); + auto assign_en_first = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), mkconst_int(location, 0, false, mem_width)); assign_en_first->children[0]->str = id_en; assign_en_first->children[0]->was_checked = true; defNode->children.push_back(std::move(assign_en_first)); - auto node_en = std::make_unique(AST_IDENTIFIER); + auto node_en = std::make_unique(location, AST_IDENTIFIER); node_en->str = id_en; if (!defNode->children.empty()) @@ -3289,14 +3294,14 @@ skip_dynamic_range_lvalue_expansion:; std::vector padding_x(offset, RTLIL::State::Sx); - assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), - std::make_unique(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone())); + assign_data = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), + std::make_unique(location, AST_CONCAT, mkconst_bits(location, padding_x, false), children[1]->clone())); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; for (int i = 0; i < mem_width; i++) set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0; - assign_en = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); + assign_en = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), mkconst_bits(location, set_bits_en, false)); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; } @@ -3315,17 +3320,17 @@ skip_dynamic_range_lvalue_expansion:; offset_ast = the_range->children[0]->clone(); if (mem_data_range_offset) - offset_ast = std::make_unique(AST_SUB, std::move(offset_ast), mkconst_int(mem_data_range_offset, true)); + offset_ast = std::make_unique(location, AST_SUB, std::move(offset_ast), mkconst_int(location, mem_data_range_offset, true)); - assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), - std::make_unique(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone())); + assign_data = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), + std::make_unique(location, AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone())); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; for (int i = 0; i < mem_width; i++) set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0; - assign_en = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), - std::make_unique(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); + assign_en = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), + std::make_unique(location, AST_SHIFT_LEFT, mkconst_bits(location, set_bits_en, false), offset_ast->clone())); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; } @@ -3333,12 +3338,12 @@ skip_dynamic_range_lvalue_expansion:; else { if (!(children[0]->children.size() == 1 && children[1]->isConst())) { - assign_data = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), children[1]->clone()); + assign_data = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), children[1]->clone()); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; } - assign_en = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); + assign_en = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), mkconst_bits(location, set_bits_en, false)); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; } @@ -3349,21 +3354,21 @@ skip_dynamic_range_lvalue_expansion:; std::unique_ptr wrnode; if (current_always->type == AST_INITIAL) - wrnode = std::make_unique(AST_MEMINIT, std::move(node_addr), std::move(node_data), std::move(node_en), mkconst_int(1, false)); + wrnode = std::make_unique(location, AST_MEMINIT, std::move(node_addr), std::move(node_data), std::move(node_en), mkconst_int(location, 1, false)); else - wrnode = std::make_unique(AST_MEMWR, std::move(node_addr), std::move(node_data), std::move(node_en)); + wrnode = std::make_unique(location, AST_MEMWR, std::move(node_addr), std::move(node_data), std::move(node_en)); wrnode->str = children[0]->str; wrnode->id2ast = children[0]->id2ast; wrnode->location = location; if (wrnode->type == AST_MEMWR) { int portid = current_memwr_count[wrnode->str]++; - wrnode->children.push_back(mkconst_int(portid, false)); + wrnode->children.push_back(mkconst_int(location, portid, false)); std::vector priority_mask; for (int i = 0; i < portid; i++) { bool has_prio = current_memwr_visible[wrnode->str].count(i); priority_mask.push_back(State(has_prio)); } - wrnode->children.push_back(mkconst_bits(priority_mask, false)); + wrnode->children.push_back(mkconst_bits(location, priority_mask, false)); current_memwr_visible[wrnode->str].insert(portid); current_always->children.push_back(std::move(wrnode)); } else { @@ -3371,7 +3376,7 @@ skip_dynamic_range_lvalue_expansion:; } if (newNode->children.empty()) { - newNode = std::make_unique(); + newNode = std::make_unique(location); } goto apply_newNode; } @@ -3385,13 +3390,13 @@ skip_dynamic_range_lvalue_expansion:; { int myidx = autoidx++; - auto wire_owned = std::make_unique(AST_WIRE); + auto wire_owned = std::make_unique(location, AST_WIRE); auto* wire = wire_owned.get(); current_ast_mod->children.push_back(std::move(wire_owned)); wire->str = stringf("$initstate$%d_wire", myidx); while (wire->simplify(true, 1, -1, false)) { } - auto cell = std::make_unique(AST_CELL, std::make_unique(AST_CELLTYPE), std::make_unique(AST_ARGUMENT, std::make_unique(AST_IDENTIFIER))); + auto cell = std::make_unique(location, AST_CELL, std::make_unique(location, AST_CELLTYPE), std::make_unique(location, AST_ARGUMENT, std::make_unique(location, AST_IDENTIFIER))); cell->str = stringf("$initstate$%d", myidx); cell->children[0]->str = "$initstate"; cell->children[1]->str = "\\Y"; @@ -3400,7 +3405,7 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(std::move(cell)); while (cell->simplify(true, 1, -1, false)) { } - newNode = std::make_unique(AST_IDENTIFIER); + newNode = std::make_unique(location, AST_IDENTIFIER); newNode->str = wire->str; newNode->id2ast = wire; goto apply_newNode; @@ -3449,19 +3454,19 @@ skip_dynamic_range_lvalue_expansion:; for (int i = 0; i < num_steps; i++) { - auto reg_owned = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, - mkconst_int(width_hint-1, true), mkconst_int(0, true))); + auto reg_owned = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, + mkconst_int(location, width_hint-1, true), mkconst_int(location, 0, true))); auto* reg = reg_owned.get(); current_ast_mod->children.push_back(std::move(reg_owned)); - reg->str = stringf("$past$%s:%d$%d$%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line, myidx, i); + reg->str = stringf("$past$%s:%d$%d$%d", RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line, myidx, i); reg->is_reg = true; reg->is_signed = sign_hint; while (reg->simplify(true, 1, -1, false)) { } - auto regid = std::make_unique(AST_IDENTIFIER); + auto regid = std::make_unique(location, AST_IDENTIFIER); regid->str = reg->str; regid->id2ast = reg; regid->was_checked = true; @@ -3471,16 +3476,16 @@ skip_dynamic_range_lvalue_expansion:; if (outreg == nullptr) { rhs = children.at(0)->clone(); } else { - rhs = std::make_unique(AST_IDENTIFIER); + rhs = std::make_unique(location, AST_IDENTIFIER); rhs->str = outreg->str; rhs->id2ast = outreg; } - block->children.push_back(std::make_unique(AST_ASSIGN_LE, std::move(regid), std::move(rhs))); + block->children.push_back(std::make_unique(location, AST_ASSIGN_LE, std::move(regid), std::move(rhs))); outreg = reg; } - newNode = std::make_unique(AST_IDENTIFIER); + newNode = std::make_unique(location, AST_IDENTIFIER); newNode->str = outreg->str; newNode->id2ast = outreg; goto apply_newNode; @@ -3501,20 +3506,20 @@ skip_dynamic_range_lvalue_expansion:; past->str = "\\$past"; if (str == "\\$stable") - newNode = std::make_unique(AST_EQ, std::move(past), std::move(present)); + newNode = std::make_unique(location, AST_EQ, std::move(past), std::move(present)); else if (str == "\\$changed") - newNode = std::make_unique(AST_NE, std::move(past), std::move(present)); + newNode = std::make_unique(location, AST_NE, std::move(past), std::move(present)); else if (str == "\\$rose") - newNode = std::make_unique(AST_LOGIC_AND, - std::make_unique(AST_LOGIC_NOT, std::make_unique(AST_BIT_AND, std::move(past), mkconst_int(1,false))), - std::make_unique(AST_BIT_AND, std::move(present), mkconst_int(1,false))); + newNode = std::make_unique(location, AST_LOGIC_AND, + std::make_unique(location, AST_LOGIC_NOT, std::make_unique(location, AST_BIT_AND, std::move(past), mkconst_int(location, 1, false))), + std::make_unique(location, AST_BIT_AND, std::move(present), mkconst_int(location, 1, false))); else if (str == "\\$fell") - newNode = std::make_unique(AST_LOGIC_AND, - std::make_unique(AST_BIT_AND, std::move(past), mkconst_int(1,false)), - std::make_unique(AST_LOGIC_NOT, std::make_unique(AST_BIT_AND, std::move(present), mkconst_int(1,false)))); + newNode = std::make_unique(location, AST_LOGIC_AND, + std::make_unique(location, AST_BIT_AND, std::move(past), mkconst_int(location, 1, false)), + std::make_unique(location, AST_LOGIC_NOT, std::make_unique(location, AST_BIT_AND, std::move(present), mkconst_int(location, 1, false)))); else log_abort(); @@ -3548,7 +3553,7 @@ skip_dynamic_range_lvalue_expansion:; if (arg_value.at(i) == RTLIL::State::S1) result = i + 1; - newNode = mkconst_int(result, true); + newNode = mkconst_int(location, result, true); goto apply_newNode; } @@ -3639,7 +3644,7 @@ skip_dynamic_range_lvalue_expansion:; else { // str == "\\$bits" result = width * mem_depth; } - newNode = mkconst_int(result, true); + newNode = mkconst_int(location, result, true); goto apply_newNode; } @@ -3685,9 +3690,9 @@ skip_dynamic_range_lvalue_expansion:; } if (str == "\\$rtoi") { - newNode = AstNode::mkconst_int(x, true); + newNode = AstNode::mkconst_int(location, x, true); } else { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(location, AST_REALVALUE); if (str == "\\$ln") newNode->realvalue = ::log(x); else if (str == "\\$log10") newNode->realvalue = ::log10(x); else if (str == "\\$exp") newNode->realvalue = ::exp(x); @@ -3717,7 +3722,7 @@ skip_dynamic_range_lvalue_expansion:; if (str == "\\$sformatf") { Fmt fmt = processFormat(stage, /*sformat_like=*/true); - newNode = AstNode::mkconst_str(fmt.render()); + newNode = AstNode::mkconst_str(location, fmt.render()); goto apply_newNode; } @@ -3745,24 +3750,24 @@ skip_dynamic_range_lvalue_expansion:; auto& exp = children[0]; exp->detectSignWidth(exp_width, exp_sign, nullptr); - newNode = mkconst_int(0, false); + newNode = mkconst_int(location, 0, false); for (int i = 0; i < exp_width; i++) { // Generate nodes for: exp << i >> ($size(exp) - 1) // ^^ ^^ - auto lsh_node = std::make_unique(AST_SHIFT_LEFT, exp->clone(), mkconst_int(i, false)); - auto rsh_node = std::make_unique(AST_SHIFT_RIGHT, std::move(lsh_node), mkconst_int(exp_width - 1, false)); + auto lsh_node = std::make_unique(location, AST_SHIFT_LEFT, exp->clone(), mkconst_int(location, i, false)); + auto rsh_node = std::make_unique(location, AST_SHIFT_RIGHT, std::move(lsh_node), mkconst_int(location, exp_width - 1, false)); std::unique_ptr or_node = nullptr; for (RTLIL::State control_bit : control_bits) { // Generate node for: (exp << i >> ($size(exp) - 1)) === control_bit // ^^^ - auto eq_node = std::make_unique(AST_EQX, rsh_node->clone(), mkconst_bits({control_bit}, false)); + auto eq_node = std::make_unique(location, AST_EQX, rsh_node->clone(), mkconst_bits(location, {control_bit}, false)); // Or the result for each checked bit value if (or_node) - or_node = std::make_unique(AST_LOGIC_OR, std::move(or_node), std::move(eq_node)); + or_node = std::make_unique(location, AST_LOGIC_OR, std::move(or_node), std::move(eq_node)); else or_node = std::move(eq_node); } @@ -3772,7 +3777,7 @@ skip_dynamic_range_lvalue_expansion:; log_assert(or_node != nullptr); // Generate node for adding with result of previous bit - newNode = std::make_unique(AST_ADD, std::move(newNode), std::move(or_node)); + newNode = std::make_unique(location, AST_ADD, std::move(newNode), std::move(or_node)); } goto apply_newNode; @@ -3787,18 +3792,18 @@ skip_dynamic_range_lvalue_expansion:; countbits->str = "\\$countbits"; if (str == "\\$countones") { - countbits->children.push_back(mkconst_bits({RTLIL::State::S1}, false)); + countbits->children.push_back(mkconst_bits(location, {RTLIL::State::S1}, false)); newNode = std::move(countbits); } else if (str == "\\$isunknown") { - countbits->children.push_back(mkconst_bits({RTLIL::Sx}, false)); - countbits->children.push_back(mkconst_bits({RTLIL::Sz}, false)); - newNode = std::make_unique(AST_GT, std::move(countbits), mkconst_int(0, false)); + countbits->children.push_back(mkconst_bits(location, {RTLIL::Sx}, false)); + countbits->children.push_back(mkconst_bits(location, {RTLIL::Sz}, false)); + newNode = std::make_unique(location, AST_GT, std::move(countbits), mkconst_int(location, 0, false)); } else if (str == "\\$onehot") { - countbits->children.push_back(mkconst_bits({RTLIL::State::S1}, false)); - newNode = std::make_unique(AST_EQ, std::move(countbits), mkconst_int(1, false)); + countbits->children.push_back(mkconst_bits(location, {RTLIL::State::S1}, false)); + newNode = std::make_unique(location, AST_EQ, std::move(countbits), mkconst_int(location, 1, false)); } else if (str == "\\$onehot0") { - countbits->children.push_back(mkconst_bits({RTLIL::State::S1}, false)); - newNode = std::make_unique(AST_LE, std::move(countbits), mkconst_int(1, false)); + countbits->children.push_back(mkconst_bits(location, {RTLIL::State::S1}, false)); + newNode = std::make_unique(location, AST_LE, std::move(countbits), mkconst_int(location, 1, false)); } else { log_abort(); } @@ -3914,7 +3919,7 @@ skip_dynamic_range_lvalue_expansion:; std::stringstream sstr; - sstr << str << "$func$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++) << '.'; + sstr << str << "$func$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++) << '.'; std::string prefix = sstr.str(); auto* decl = current_scope[str]; @@ -3977,11 +3982,11 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(std::move(wire)); while (wire_leaky->simplify(true, 1, -1, false)) { } - auto lvalue = std::make_unique(AST_IDENTIFIER); + auto lvalue = std::make_unique(location, AST_IDENTIFIER); lvalue->str = wire_leaky->str; - auto always = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK, - std::make_unique(AST_ASSIGN_EQ, std::move(lvalue), clone()))); + auto always = std::make_unique(location, AST_ALWAYS, std::make_unique(location, AST_BLOCK, + std::make_unique(location, AST_ASSIGN_EQ, std::move(lvalue), clone()))); always->children[0]->children[0]->was_checked = true; current_ast_mod->children.push_back(std::move(always)); @@ -4001,14 +4006,14 @@ skip_dynamic_range_lvalue_expansion:; } else celltype = RTLIL::escape_id(celltype); - auto cell = std::make_unique(AST_CELL, std::make_unique(AST_CELLTYPE)); + auto cell = std::make_unique(location, AST_CELL, std::make_unique(location, AST_CELLTYPE)); cell->str = prefix.substr(0, GetSize(prefix)-1); cell->children[0]->str = celltype; for (auto& attr : decl->attributes) if (attr.first.str().rfind("\\via_celltype_defparam_", 0) == 0) { - auto cell_arg = std::make_unique(AST_PARASET, attr.second->clone()); + auto cell_arg = std::make_unique(location, AST_PARASET, attr.second->clone()); cell_arg->str = RTLIL::escape_id(attr.first.substr(strlen("\\via_celltype_defparam_"))); cell->children.push_back(std::move(cell_arg)); } @@ -4023,15 +4028,15 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(std::move(wire)); while (wire->simplify(true, 1, -1, false)) { } - auto wire_id = std::make_unique(AST_IDENTIFIER); + auto wire_id = std::make_unique(location, AST_IDENTIFIER); wire_id->str = wire->str; if ((child->is_input || child->is_output) && arg_count < children.size()) { auto arg = children[arg_count++]->clone(); auto assign = child->is_input ? - std::make_unique(AST_ASSIGN_EQ, wire_id->clone(), std::move(arg)) : - std::make_unique(AST_ASSIGN_EQ, std::move(arg), wire_id->clone()); + std::make_unique(location, AST_ASSIGN_EQ, wire_id->clone(), std::move(arg)) : + std::make_unique(location, AST_ASSIGN_EQ, std::move(arg), wire_id->clone()); assign->children[0]->was_checked = true; for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { @@ -4042,7 +4047,7 @@ skip_dynamic_range_lvalue_expansion:; } } - auto cell_arg = std::make_unique(AST_ARGUMENT, std::move(wire_id)); + auto cell_arg = std::make_unique(location, AST_ARGUMENT, std::move(wire_id)); cell_arg->str = child->str == str ? outport : child->str; cell->children.push_back(std::move(cell_arg)); } @@ -4083,7 +4088,7 @@ skip_dynamic_range_lvalue_expansion:; wire->is_input = false; wire->is_output = false; wire->is_reg = true; - wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(location, 1, false)); if (child->type == AST_ENUM_ITEM) wire->set_attribute(ID::enum_base_type, std::move(child->attributes[ID::enum_base_type])); @@ -4114,10 +4119,10 @@ skip_dynamic_range_lvalue_expansion:; break; } if (!uses_explicit_size) { - auto range = std::make_unique(); + auto range = std::make_unique(location); range->type = AST_RANGE; - range->children.push_back(mkconst_int(0, true)); - range->children.push_back(mkconst_int(0, true)); + range->children.push_back(mkconst_int(location, 0, true)); + range->children.push_back(mkconst_int(location, 0, true)); wire->children.push_back(std::move(range)); } } @@ -4127,16 +4132,16 @@ skip_dynamic_range_lvalue_expansion:; continue; } - auto wire_id = std::make_unique(AST_IDENTIFIER); + auto wire_id = std::make_unique(location, AST_IDENTIFIER); wire_id->str = wire->str; if (child->is_input) { - auto assign = std::make_unique(AST_ASSIGN_EQ, wire_id->clone(), arg->clone()); + auto assign = std::make_unique(location, AST_ASSIGN_EQ, wire_id->clone(), arg->clone()); assign->children[0]->was_checked = true; new_stmts.push_back(std::move(assign)); } if (child->is_output) { - auto assign = std::make_unique(AST_ASSIGN_EQ, arg->clone(), wire_id->clone()); + auto assign = std::make_unique(location, AST_ASSIGN_EQ, arg->clone(), wire_id->clone()); assign->children[0]->was_checked = true; output_assignments.push_back(std::move(assign)); } @@ -4207,7 +4212,7 @@ replace_fcall_later:; else data.push_back(RTLIL::State::Sx); } - newNode = mkconst_bits(data, false); + newNode = mkconst_bits(location, data, false); } else if (children.size() == 0) newNode = current_scope[str]->children[0]->clone(); @@ -4219,14 +4224,14 @@ replace_fcall_later:; case AST_BIT_NOT: if (children[0]->type == AST_CONSTANT) { RTLIL::Const y = RTLIL::const_not(children[0]->bitsAsConst(width_hint, sign_hint), dummy_arg, sign_hint, false, width_hint); - newNode = mkconst_bits(y.to_bits(), sign_hint); + newNode = mkconst_bits(location, y.to_bits(), sign_hint); } break; case AST_TO_SIGNED: case AST_TO_UNSIGNED: if (children[0]->type == AST_CONSTANT) { RTLIL::Const y = children[0]->bitsAsConst(width_hint, sign_hint); - newNode = mkconst_bits(y.to_bits(), type == AST_TO_SIGNED); + newNode = mkconst_bits(location, y.to_bits(), type == AST_TO_SIGNED); } break; if (0) { case AST_BIT_AND: const_func = RTLIL::const_and; } @@ -4236,7 +4241,7 @@ replace_fcall_later:; if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), children[1]->bitsAsConst(width_hint, sign_hint), sign_hint, sign_hint, width_hint); - newNode = mkconst_bits(y.to_bits(), sign_hint); + newNode = mkconst_bits(location, y.to_bits(), sign_hint); } break; if (0) { case AST_REDUCE_AND: const_func = RTLIL::const_reduce_and; } @@ -4246,16 +4251,16 @@ replace_fcall_later:; if (0) { case AST_REDUCE_BOOL: const_func = RTLIL::const_reduce_bool; } if (children[0]->type == AST_CONSTANT) { RTLIL::Const y = const_func(RTLIL::Const(children[0]->bits), dummy_arg, false, false, -1); - newNode = mkconst_bits(y.to_bits(), false); + newNode = mkconst_bits(location, y.to_bits(), false); } break; case AST_LOGIC_NOT: if (children[0]->type == AST_CONSTANT) { RTLIL::Const y = RTLIL::const_logic_not(RTLIL::Const(children[0]->bits), dummy_arg, children[0]->is_signed, false, -1); - newNode = mkconst_bits(y.to_bits(), false); + newNode = mkconst_bits(location, y.to_bits(), false); } else if (children[0]->isConst()) { - newNode = mkconst_int(children[0]->asReal(sign_hint) == 0, false, 1); + newNode = mkconst_int(location, children[0]->asReal(sign_hint) == 0, false, 1); } break; if (0) { case AST_LOGIC_AND: const_func = RTLIL::const_logic_and; } @@ -4263,13 +4268,13 @@ replace_fcall_later:; if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { RTLIL::Const y = const_func(RTLIL::Const(children[0]->bits), RTLIL::Const(children[1]->bits), children[0]->is_signed, children[1]->is_signed, -1); - newNode = mkconst_bits(y.to_bits(), false); + newNode = mkconst_bits(location, y.to_bits(), false); } else if (children[0]->isConst() && children[1]->isConst()) { if (type == AST_LOGIC_AND) - newNode = mkconst_int((children[0]->asReal(sign_hint) != 0) && (children[1]->asReal(sign_hint) != 0), false, 1); + newNode = mkconst_int(location, (children[0]->asReal(sign_hint) != 0) && (children[1]->asReal(sign_hint) != 0), false, 1); else - newNode = mkconst_int((children[0]->asReal(sign_hint) != 0) || (children[1]->asReal(sign_hint) != 0), false, 1); + newNode = mkconst_int(location, (children[0]->asReal(sign_hint) != 0) || (children[1]->asReal(sign_hint) != 0), false, 1); } break; if (0) { case AST_SHIFT_LEFT: const_func = RTLIL::const_shl; } @@ -4280,10 +4285,10 @@ replace_fcall_later:; if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), RTLIL::Const(children[1]->bits), sign_hint, type == AST_POW ? children[1]->is_signed : false, width_hint); - newNode = mkconst_bits(y.to_bits(), sign_hint); + newNode = mkconst_bits(location, y.to_bits(), sign_hint); } else if (type == AST_POW && children[0]->isConst() && children[1]->isConst()) { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(location, AST_REALVALUE); newNode->realvalue = pow(children[0]->asReal(sign_hint), children[1]->asReal(sign_hint)); } break; @@ -4300,19 +4305,19 @@ replace_fcall_later:; bool cmp_signed = children[0]->is_signed && children[1]->is_signed; RTLIL::Const y = const_func(children[0]->bitsAsConst(cmp_width, cmp_signed), children[1]->bitsAsConst(cmp_width, cmp_signed), cmp_signed, cmp_signed, 1); - newNode = mkconst_bits(y.to_bits(), false); + newNode = mkconst_bits(location, y.to_bits(), false); } else if (children[0]->isConst() && children[1]->isConst()) { bool cmp_signed = (children[0]->type == AST_REALVALUE || children[0]->is_signed) && (children[1]->type == AST_REALVALUE || children[1]->is_signed); switch (type) { - case AST_LT: newNode = mkconst_int(children[0]->asReal(cmp_signed) < children[1]->asReal(cmp_signed), false, 1); break; - case AST_LE: newNode = mkconst_int(children[0]->asReal(cmp_signed) <= children[1]->asReal(cmp_signed), false, 1); break; - case AST_EQ: newNode = mkconst_int(children[0]->asReal(cmp_signed) == children[1]->asReal(cmp_signed), false, 1); break; - case AST_NE: newNode = mkconst_int(children[0]->asReal(cmp_signed) != children[1]->asReal(cmp_signed), false, 1); break; - case AST_EQX: newNode = mkconst_int(children[0]->asReal(cmp_signed) == children[1]->asReal(cmp_signed), false, 1); break; - case AST_NEX: newNode = mkconst_int(children[0]->asReal(cmp_signed) != children[1]->asReal(cmp_signed), false, 1); break; - case AST_GE: newNode = mkconst_int(children[0]->asReal(cmp_signed) >= children[1]->asReal(cmp_signed), false, 1); break; - case AST_GT: newNode = mkconst_int(children[0]->asReal(cmp_signed) > children[1]->asReal(cmp_signed), false, 1); break; + case AST_LT: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) < children[1]->asReal(cmp_signed), false, 1); break; + case AST_LE: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) <= children[1]->asReal(cmp_signed), false, 1); break; + case AST_EQ: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) == children[1]->asReal(cmp_signed), false, 1); break; + case AST_NE: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) != children[1]->asReal(cmp_signed), false, 1); break; + case AST_EQX: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) == children[1]->asReal(cmp_signed), false, 1); break; + case AST_NEX: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) != children[1]->asReal(cmp_signed), false, 1); break; + case AST_GE: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) >= children[1]->asReal(cmp_signed), false, 1); break; + case AST_GT: newNode = mkconst_int(location, children[0]->asReal(cmp_signed) > children[1]->asReal(cmp_signed), false, 1); break; default: log_abort(); } } @@ -4325,10 +4330,10 @@ replace_fcall_later:; if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), children[1]->bitsAsConst(width_hint, sign_hint), sign_hint, sign_hint, width_hint); - newNode = mkconst_bits(y.to_bits(), sign_hint); + newNode = mkconst_bits(location, y.to_bits(), sign_hint); } else if (children[0]->isConst() && children[1]->isConst()) { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(location, AST_REALVALUE); switch (type) { case AST_ADD: newNode->realvalue = children[0]->asReal(sign_hint) + children[1]->asReal(sign_hint); break; case AST_SUB: newNode->realvalue = children[0]->asReal(sign_hint) - children[1]->asReal(sign_hint); break; @@ -4344,10 +4349,10 @@ replace_fcall_later:; if (0) { case AST_NEG: const_func = RTLIL::const_neg; } if (children[0]->type == AST_CONSTANT) { RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), dummy_arg, sign_hint, false, width_hint); - newNode = mkconst_bits(y.to_bits(), sign_hint); + newNode = mkconst_bits(location, y.to_bits(), sign_hint); } else if (children[0]->isConst()) { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(location, AST_REALVALUE); if (type == AST_NEG) newNode->realvalue = -children[0]->asReal(sign_hint); else @@ -4367,15 +4372,15 @@ replace_fcall_later:; bool other_sign_hint = sign_hint, other_real = false; not_choice->detectSignWidth(other_width_hint, other_sign_hint, &other_real); if (other_real) { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(location, AST_REALVALUE); choice->detectSignWidth(width_hint, sign_hint); newNode->realvalue = choice->asReal(sign_hint); } else { RTLIL::Const y = choice->bitsAsConst(width_hint, sign_hint); if (choice->is_string && y.size() % 8 == 0 && sign_hint == false) - newNode = mkconst_str(y.to_bits()); + newNode = mkconst_str(location, y.to_bits()); else - newNode = mkconst_bits(y.to_bits(), sign_hint); + newNode = mkconst_bits(location, y.to_bits(), sign_hint); } } else if (choice->isConst()) { @@ -4388,9 +4393,9 @@ replace_fcall_later:; for (auto i = 0; i < a.size(); i++) if (a[i] != b[i]) a.bits()[i] = RTLIL::State::Sx; - newNode = mkconst_bits(a.to_bits(), sign_hint); + newNode = mkconst_bits(location, a.to_bits(), sign_hint); } else if (children[1]->isConst() && children[2]->isConst()) { - newNode = std::make_unique(AST_REALVALUE); + newNode = std::make_unique(location, AST_REALVALUE); if (children[1]->asReal(sign_hint) == children[2]->asReal(sign_hint)) newNode->realvalue = children[1]->asReal(sign_hint); else @@ -4409,7 +4414,7 @@ replace_fcall_later:; val = children[1]->bitsAsUnsizedConst(width); else val = children[1]->bitsAsConst(width); - newNode = mkconst_bits(val.to_bits(), children[1]->is_signed); + newNode = mkconst_bits(location, val.to_bits(), children[1]->is_signed); } break; case AST_CONCAT: @@ -4421,14 +4426,14 @@ replace_fcall_later:; string_op = false; tmp_bits.insert(tmp_bits.end(), (*it)->bits.begin(), (*it)->bits.end()); } - newNode = string_op ? mkconst_str(tmp_bits) : mkconst_bits(tmp_bits, false); + newNode = string_op ? mkconst_str(location, tmp_bits) : mkconst_bits(location, tmp_bits, false); break; case AST_REPLICATE: if (children.at(0)->type != AST_CONSTANT || children.at(1)->type != AST_CONSTANT) goto not_const; for (int i = 0; i < children[0]->bitsAsConst().as_int(); i++) tmp_bits.insert(tmp_bits.end(), children.at(1)->bits.begin(), children.at(1)->bits.end()); - newNode = children.at(1)->is_string ? mkconst_str(tmp_bits) : mkconst_bits(tmp_bits, false); + newNode = children.at(1)->is_string ? mkconst_str(location, tmp_bits) : mkconst_bits(location, tmp_bits, false); break; default: not_const: @@ -4444,7 +4449,7 @@ apply_newNode: // newNode->dumpAst(stderr, "+ "); log_assert(newNode != nullptr); // newNode->null_check(); - newNode->location.filename = location.filename; + newNode->location.begin.filename = location.begin.filename; newNode->location = location; newNode->cloneInto(*this); fixup_hierarchy_flags(); @@ -4472,7 +4477,7 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file int mem_width, mem_size, addr_bits; memory->meminfo(mem_width, mem_size, addr_bits); - auto block = std::make_unique(AST_BLOCK); + auto block = std::make_unique(location, AST_BLOCK); AstNode* meminit = nullptr; int next_meminit_cursor=0; @@ -4491,7 +4496,7 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file #else char slash = '/'; #endif - std::string path = location.filename.substr(0, location.filename.find_last_of(slash)+1); + std::string path = location.begin.filename->substr(0, location.begin.filename->find_last_of(slash)+1); f.open(path + mem_filename.c_str()); yosys_input_files.insert(path + mem_filename); } else { @@ -4556,15 +4561,15 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file if (meminit == nullptr || cursor != next_meminit_cursor) { if (meminit != nullptr) { - meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false); - meminit->children[3] = AstNode::mkconst_int(meminit_size, false); + meminit->children[1] = AstNode::mkconst_bits(location, meminit_bits, false); + meminit->children[3] = AstNode::mkconst_int(location, meminit_size, false); } - auto meminit_owned = std::make_unique(AST_MEMINIT); + auto meminit_owned = std::make_unique(location, AST_MEMINIT); meminit = meminit_owned.get(); - meminit->children.push_back(AstNode::mkconst_int(cursor, false)); + meminit->children.push_back(AstNode::mkconst_int(location, cursor, false)); meminit->children.push_back(nullptr); - meminit->children.push_back(AstNode::mkconst_bits(en_bits, false)); + meminit->children.push_back(AstNode::mkconst_bits(location, en_bits, false)); meminit->children.push_back(nullptr); meminit->str = memory->str; meminit->id2ast = memory; @@ -4581,7 +4586,13 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file } else { - block->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER, std::make_unique(AST_RANGE, AstNode::mkconst_int(cursor, false))), std::move(value))); + block->children.push_back( + std::make_unique(location, + AST_ASSIGN_EQ, std::make_unique(location, + AST_IDENTIFIER, std::make_unique(location, + AST_RANGE, AstNode::mkconst_int(location, + cursor, false))), + std::move(value))); block->children.back()->children[0]->str = memory->str; block->children.back()->children[0]->id2ast = memory; block->children.back()->children[0]->was_checked = true; @@ -4597,8 +4608,8 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file } if (meminit != nullptr) { - meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false); - meminit->children[3] = AstNode::mkconst_int(meminit_size, false); + meminit->children[1] = AstNode::mkconst_bits(location, meminit_bits, false); + meminit->children[3] = AstNode::mkconst_int(location, meminit_size, false); } return block; @@ -4770,7 +4781,7 @@ static void mark_memories_assign_lhs_complex(dict> & if (that->type == AST_IDENTIFIER && that->id2ast && that->id2ast->type == AST_MEMORY) { AstNode *mem = that->id2ast; if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_CMPLX_LHS)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(that->location.filename).c_str(), that->location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(*that->location.begin.filename).c_str(), that->location.begin.line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CMPLX_LHS; } } @@ -4798,14 +4809,14 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg // activate mem2reg if this is assigned in an async proc if (flags & AstNode::MEM2REG_FL_ASYNC) { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ASYNC)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ASYNC; } // remember if this is assigned blocking (=) if (type == AST_ASSIGN_EQ) { if (!(proc_flags[mem] & AstNode::MEM2REG_FL_EQ1)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line)); proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1; } @@ -4822,11 +4833,11 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg // remember where this is if (flags & MEM2REG_FL_INIT) { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_INIT; } else { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ELSE)) - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ELSE; } } @@ -4843,7 +4854,7 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg // flag if used after blocking assignment (in same proc) if ((proc_flags[mem] & AstNode::MEM2REG_FL_EQ1) && !(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_EQ2)) { - mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(location.filename).c_str(), location.first_line)); + mem2reg_places[mem].insert(stringf("%s:%d", RTLIL::encode_filename(*location.begin.filename).c_str(), location.begin.line)); mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_EQ2; } } @@ -4960,7 +4971,9 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, if (length != 0) { - auto block_owned = std::make_unique(AST_INITIAL, std::make_unique(AST_BLOCK)); + auto block_owned = std::make_unique(location, + AST_INITIAL, std::make_unique(location, + AST_BLOCK)); auto block = block_owned.get(); mod->children.push_back(std::move(block_owned)); block = block->children[0].get(); @@ -4977,7 +4990,9 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, while (epos < wordsz && en[epos] == State::S1) epos++; int clen = epos - pos; - auto range = std::make_unique(AST_RANGE, AstNode::mkconst_int(cursor+i, false)); + auto range = std::make_unique(location, + AST_RANGE, AstNode::mkconst_int(location, + cursor+i, false)); if (pos != 0 || epos != wordsz) { int left; int right; @@ -4989,20 +5004,29 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, right = mrange->range_right + pos; left = mrange->range_right + epos - 1; } - range = std::make_unique(AST_MULTIRANGE, std::move(range), std::make_unique(AST_RANGE, AstNode::mkconst_int(left, true), AstNode::mkconst_int(right, true))); + range = std::make_unique(location, + AST_MULTIRANGE, std::move(range), std::make_unique(location, + AST_RANGE, + AstNode::mkconst_int(location, left, true), + AstNode::mkconst_int(location, right, true))); } - auto target = std::make_unique(AST_IDENTIFIER, std::move(range)); + auto target = std::make_unique(location, AST_IDENTIFIER, std::move(range)); target->str = str; target->id2ast = id2ast; target->was_checked = true; - block->children.push_back(std::make_unique(AST_ASSIGN_EQ, std::move(target), mkconst_bits(data.extract(i*wordsz + pos, clen).to_bits(), false))); + block->children.push_back(std::make_unique(location, + AST_ASSIGN_EQ, + std::move(target), + mkconst_bits(location, + data.extract(i*wordsz + pos, clen).to_bits(), + false))); pos = epos; } } } } - auto newNode = std::make_unique(AST_NONE); + auto newNode = std::make_unique(location, AST_NONE); newNode->cloneInto(*this); did_something = true; } @@ -5010,7 +5034,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, if (type == AST_ASSIGN && block == nullptr && children[0]->mem2reg_check(mem2reg_set)) { if (async_block == nullptr) { - auto async_block_owned = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK)); + auto async_block_owned = std::make_unique(location, AST_ALWAYS, std::make_unique(location, AST_BLOCK)); async_block = async_block_owned.get(); mod->children.push_back(std::move(async_block_owned)); } @@ -5020,7 +5044,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, newNode->children[0]->was_checked = true; async_block->children[0]->children.push_back(std::move(newNode)); - newNode = std::make_unique(AST_NONE); + newNode = std::make_unique(location, AST_NONE); newNode->cloneInto(*this); did_something = true; } @@ -5029,27 +5053,27 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, children[0]->children[0]->children[0]->type != AST_CONSTANT) { std::stringstream sstr; - sstr << "$mem2reg_wr$" << children[0]->str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$mem2reg_wr$" << children[0]->str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; int mem_width, mem_size, addr_bits; bool mem_signed = children[0]->id2ast->is_signed; children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); - auto wire_addr = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); + auto wire_addr = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, addr_bits-1, true), mkconst_int(location, 0, true))); wire_addr->str = id_addr; wire_addr->is_reg = true; wire_addr->was_checked = true; - wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(location, 1, false)); while (wire_addr->simplify(true, 1, -1, false)) { } mod->children.push_back(std::move(wire_addr)); - auto wire_data = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_data = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, mem_width-1, true), mkconst_int(location, 0, true))); wire_data->str = id_data; wire_data->is_reg = true; wire_data->was_checked = true; wire_data->is_signed = mem_signed; - wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(location, 1, false)); while (wire_data->simplify(true, 1, -1, false)) { } mod->children.push_back(std::move(wire_data)); @@ -5059,18 +5083,18 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, assign_idx++; log_assert(assign_idx < block->children.size()); - auto assign_addr = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); + auto assign_addr = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; block->children.insert(block->children.begin()+assign_idx+1, std::move(assign_addr)); - auto case_node = std::make_unique(AST_CASE, std::make_unique(AST_IDENTIFIER)); + auto case_node = std::make_unique(location, AST_CASE, std::make_unique(location, AST_IDENTIFIER)); case_node->children[0]->str = id_addr; for (int i = 0; i < mem_size; i++) { if (children[0]->children[0]->children[0]->type == AST_CONSTANT && int(children[0]->children[0]->children[0]->integer) != i) continue; - auto cond_node = std::make_unique(AST_COND, AstNode::mkconst_int(i, false, addr_bits), std::make_unique(AST_BLOCK)); - auto assign_reg = std::make_unique(type, std::make_unique(AST_IDENTIFIER), std::make_unique(AST_IDENTIFIER)); + auto cond_node = std::make_unique(location, AST_COND, AstNode::mkconst_int(location, i, false, addr_bits), std::make_unique(location, AST_BLOCK)); + auto assign_reg = std::make_unique(location, type, std::make_unique(location, AST_IDENTIFIER), std::make_unique(location, AST_IDENTIFIER)); if (children[0]->children.size() == 2) assign_reg->children[0]->children.push_back(children[0]->children[1]->clone()); assign_reg->children[0]->str = stringf("%s[%d]", children[0]->str.c_str(), i); @@ -5141,51 +5165,51 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, std::vector x_bits; for (int i = 0; i < width; i++) x_bits.push_back(RTLIL::State::Sx); - std::unique_ptr constant = AstNode::mkconst_bits(x_bits, false); + std::unique_ptr constant = AstNode::mkconst_bits(location, x_bits, false); constant->cloneInto(*this); } } else { std::stringstream sstr; - sstr << "$mem2reg_rd$" << str << "$" << RTLIL::encode_filename(location.filename) << ":" << location.first_line << "$" << (autoidx++); + sstr << "$mem2reg_rd$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; int mem_width, mem_size, addr_bits; bool mem_signed = id2ast->is_signed; id2ast->meminfo(mem_width, mem_size, addr_bits); - auto wire_addr = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); + auto wire_addr = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, addr_bits-1, true), mkconst_int(location, 0, true))); wire_addr->str = id_addr; wire_addr->is_reg = true; wire_addr->was_checked = true; if (block) - wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(location, 1, false)); while (wire_addr->simplify(true, 1, -1, false)) { } mod->children.push_back(std::move(wire_addr)); - auto wire_data = std::make_unique(AST_WIRE, std::make_unique(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + auto wire_data = std::make_unique(location, AST_WIRE, std::make_unique(location, AST_RANGE, mkconst_int(location, mem_width-1, true), mkconst_int(location, 0, true))); wire_data->str = id_data; wire_data->is_reg = true; wire_data->was_checked = true; wire_data->is_signed = mem_signed; if (block) - wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); + wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(location, 1, false)); while (wire_data->simplify(true, 1, -1, false)) { } mod->children.push_back(std::move(wire_data)); - auto assign_addr = std::make_unique(block ? AST_ASSIGN_EQ : AST_ASSIGN, std::make_unique(AST_IDENTIFIER), children[0]->children[0]->clone()); + auto assign_addr = std::make_unique(location, block ? AST_ASSIGN_EQ : AST_ASSIGN, std::make_unique(location, AST_IDENTIFIER), children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; - auto case_node = std::make_unique(AST_CASE, std::make_unique(AST_IDENTIFIER)); + auto case_node = std::make_unique(location, AST_CASE, std::make_unique(location, AST_IDENTIFIER)); case_node->children[0]->str = id_addr; for (int i = 0; i < mem_size; i++) { if (children[0]->children[0]->type == AST_CONSTANT && int(children[0]->children[0]->integer) != i) continue; - auto cond_node = std::make_unique(AST_COND, AstNode::mkconst_int(i, false, addr_bits), std::make_unique(AST_BLOCK)); - auto assign_reg = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), std::make_unique(AST_IDENTIFIER)); + auto cond_node = std::make_unique(location, AST_COND, AstNode::mkconst_int(location, i, false, addr_bits), std::make_unique(location, AST_BLOCK)); + auto assign_reg = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), std::make_unique(location, AST_IDENTIFIER)); assign_reg->children[0]->str = id_data; assign_reg->children[0]->was_checked = true; assign_reg->children[1]->str = stringf("%s[%d]", str.c_str(), i); @@ -5197,8 +5221,8 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, for (int i = 0; i < mem_width; i++) x_bits.push_back(RTLIL::State::Sx); - auto cond_node = std::make_unique(AST_COND, std::make_unique(AST_DEFAULT), std::make_unique(AST_BLOCK)); - auto assign_reg = std::make_unique(AST_ASSIGN_EQ, std::make_unique(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false)); + auto cond_node = std::make_unique(location, AST_COND, std::make_unique(location, AST_DEFAULT), std::make_unique(location, AST_BLOCK)); + auto assign_reg = std::make_unique(location, AST_ASSIGN_EQ, std::make_unique(location, AST_IDENTIFIER), AstNode::mkconst_bits(location, x_bits, false)); assign_reg->children[0]->str = id_data; assign_reg->children[0]->was_checked = true; cond_node->children[1]->children.push_back(std::move(assign_reg)); @@ -5218,7 +5242,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, } else { - auto proc = std::make_unique(AST_ALWAYS, std::make_unique(AST_BLOCK, std::move(case_node))); + auto proc = std::make_unique(location, AST_ALWAYS, std::make_unique(location, AST_BLOCK, std::move(case_node))); mod->children.push_back(std::move(proc)); mod->children.push_back(std::move(assign_addr)); mod->fixup_hierarchy_flags(); @@ -5373,7 +5397,7 @@ bool AstNode::replace_variables(std::map &varia offset = -offset; std::vector &var_bits = variables.at(str).val.bits(); std::vector new_bits(var_bits.begin() + offset, var_bits.begin() + offset + width); - auto newNode = mkconst_bits(new_bits, variables.at(str).is_signed); + auto newNode = mkconst_bits(location, new_bits, variables.at(str).is_signed); newNode->cloneInto(*this); return true; } @@ -5389,7 +5413,7 @@ std::unique_ptr AstNode::eval_const_function(AstNode *fcall, bool must_ { std::map backup_scope = current_scope; std::map variables; - auto block = std::make_unique(AST_BLOCK); + auto block = std::make_unique(location, AST_BLOCK); std::unique_ptr result = nullptr; size_t argidx = 0; @@ -5614,7 +5638,7 @@ std::unique_ptr AstNode::eval_const_function(AstNode *fcall, bool must_ if (!cond->replace_variables(variables, fcall, must_succeed)) goto finished; - cond = std::make_unique(AST_EQ, expr->clone(), std::move(cond)); + cond = std::make_unique(location, AST_EQ, expr->clone(), std::move(cond)); cond->set_in_param_flag(true); while (cond->simplify(true, 1, -1, false)) { } @@ -5666,7 +5690,7 @@ std::unique_ptr AstNode::eval_const_function(AstNode *fcall, bool must_ log_abort(); } - result = AstNode::mkconst_bits(variables.at(str).val.to_bits(), variables.at(str).is_signed); + result = AstNode::mkconst_bits(location, variables.at(str).val.to_bits(), variables.at(str).is_signed); finished: current_scope = backup_scope; @@ -5682,12 +5706,12 @@ void AstNode::allocateDefaultEnumValues() int last_enum_int = -1; for (auto& node : children) { log_assert(node->type==AST_ENUM_ITEM); - node->set_attribute(ID::enum_base_type, mkconst_str(str)); + node->set_attribute(ID::enum_base_type, mkconst_str(node->location, str)); for (size_t i = 0; i < node->children.size(); i++) { switch (node->children[i]->type) { case AST_NONE: // replace with auto-incremented constant - node->children[i] = AstNode::mkconst_int(++last_enum_int, true); + node->children[i] = AstNode::mkconst_int(node->location, ++last_enum_int, true); break; case AST_CONSTANT: // explicit constant (or folded expression) diff --git a/frontends/verilog/.gitignore b/frontends/verilog/.gitignore index a6d4c8b86..cb6775cbc 100644 --- a/frontends/verilog/.gitignore +++ b/frontends/verilog/.gitignore @@ -2,6 +2,4 @@ verilog_lexer.cc verilog_parser.output verilog_parser.tab.cc verilog_parser.tab.hh -position.hh -location.hh stack.hh diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 338b13e4b..a563c899c 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -3,11 +3,9 @@ GENFILES += frontends/verilog/verilog_parser.tab.cc GENFILES += frontends/verilog/verilog_parser.tab.hh GENFILES += frontends/verilog/verilog_parser.output GENFILES += frontends/verilog/verilog_lexer.cc -GENFILES += frontends/verilog/location.hh -GENFILES += frontends/verilog/position.hh GENFILES += frontends/verilog/stack.hh -frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y +frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y frontends/verilog/verilog_location.h $(Q) mkdir -p $(dir $@) $(P) $(BISON) -Wall -Werror -o $@ -d -r all -b frontends/verilog/verilog_parser $< diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index cd8f05b9b..5d906cb0f 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -47,7 +47,7 @@ using namespace VERILOG_FRONTEND; std::string ConstParser::fmt_maybe_loc(std::string msg) { std::string s; - s += stringf("%s:%d:", loc.filename, loc.first_line); + s += stringf("%s:%d:", loc.begin.filename->c_str(), loc.begin.line); s += msg; return s; diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index d05f87aff..733ec8ba7 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -33,6 +33,7 @@ #include "verilog_frontend.h" #include "verilog_lexer.h" #include "verilog_error.h" +#include "verilog_location.h" #include "preproc.h" #include "kernel/yosys.h" #include "libs/sha1/sha1.h" @@ -277,8 +278,8 @@ struct VerilogFrontend : public Frontend { std::list include_dirs; std::list attributes; - ParseMode parse_mode; - ParseState parse_state; + ParseMode parse_mode = {}; + ParseState parse_state = {}; parse_mode.sv = false; parse_mode.formal = false; parse_mode.noassert = false; @@ -479,11 +480,6 @@ struct VerilogFrontend : public Frontend { break; } - VerilogLexer lexer(&parse_state, &parse_mode, &filename); - frontend_verilog_yy::parser parser(&lexer, &parse_state, &parse_mode); - lexer.set_debug(flag_debug_lexer); - parser.set_debug_level(flag_debug_parser ? 1 : 0); - if (parse_mode.formal || !flag_nosynthesis) defines_map.add(parse_mode.formal ? "FORMAL" : "SYNTHESIS", "1"); @@ -495,13 +491,9 @@ struct VerilogFrontend : public Frontend { parse_mode.formal ? "formal " : "", parse_mode.sv ? "SystemVerilog" : "Verilog", filename.c_str()); AST::sv_mode_but_global_and_used_for_literally_one_condition = parse_mode.sv; - - AstSrcLocType top_loc = AstSrcLocType ( "read_verilog", 0, 0, 0, 0); - parse_state.current_ast = new AST::AstNode(top_loc, AST::AST_DESIGN); - - parse_state.lexin = f; std::string code_after_preproc; + parse_state.lexin = f; if (!flag_nopp) { code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, *design->verilog_defines, include_dirs, parse_state, parse_mode); if (flag_ppdump) @@ -509,6 +501,15 @@ struct VerilogFrontend : public Frontend { parse_state.lexin = new std::istringstream(code_after_preproc); } + auto filename_shared = std::make_shared(filename); + auto top_loc = location(); + top_loc.begin.filename = filename_shared; + parse_state.current_ast = new AST::AstNode(top_loc, AST::AST_DESIGN); + VerilogLexer lexer(&parse_state, &parse_mode, filename_shared); + frontend_verilog_yy::parser parser(&lexer, &parse_state, &parse_mode); + lexer.set_debug(flag_debug_lexer); + parser.set_debug_level(flag_debug_parser ? 1 : 0); + // make package typedefs available to parser add_package_types(parse_state.pkg_user_types, design->verilog_packages); diff --git a/frontends/verilog/verilog_lexer.h b/frontends/verilog/verilog_lexer.h index a4f3d9bfb..b7885181c 100644 --- a/frontends/verilog/verilog_lexer.h +++ b/frontends/verilog/verilog_lexer.h @@ -5,6 +5,7 @@ #include "frontends/ast/ast.h" #include "frontends/verilog/verilog_parser.tab.hh" #include +#include YOSYS_NAMESPACE_BEGIN @@ -15,7 +16,7 @@ namespace VERILOG_FRONTEND { ParseMode* mode; public: parser::location_type out_loc; // TODO private? - VerilogLexer(ParseState* e, ParseMode* m, std::string* filename) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) { + VerilogLexer(ParseState* e, ParseMode* m, std::shared_ptr filename) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) { out_loc.begin.filename = filename; } ~VerilogLexer() override {} @@ -27,7 +28,8 @@ namespace VERILOG_FRONTEND { return parser::make_FRONTEND_VERILOG_YYEOF(out_loc); } private: - std::vector fn_stack; + std::shared_ptr current_filename; + std::vector> fn_stack; std::vector ln_stack; int LexerInput(char* buf, int max_size) override { return readsome(*extra->lexin, buf, max_size); diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 0e07e9e7b..84d5ce880 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -50,8 +50,10 @@ #include "frontends/verilog/verilog_lexer.h" #include "frontends/ast/ast.h" +#include "frontends/verilog/verilog_location.h" #include "kernel/log.h" #include +#include USING_YOSYS_NAMESPACE using namespace AST; @@ -73,7 +75,7 @@ YOSYS_NAMESPACE_END if (mode->sv) 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(), yylineno); \ + current_filename->c_str(), yylineno); \ string_t val = std::make_unique(std::string("\\") + YYText()); \ return parser::make_TOK_ID(std::move(val), out_loc); @@ -85,16 +87,17 @@ YOSYS_NAMESPACE_END // result = readsome(*extra->lexin, buf, max_size) #define YY_USER_ACTION \ - out_loc.begin = out_loc.end; \ - for(int i = 0; YYText()[i] != '\0'; ++i){ \ - if(YYText()[i] == '\n') { \ - out_loc.end.line++; \ - out_loc.end.column = 1; \ - } \ - else { \ - out_loc.end.column++; \ - } \ - } + out_loc.step(); \ + for(int i = 0; YYText()[i] != '\0'; ++i){ \ + if(YYText()[i] == '\n') { \ + out_loc.lines(); \ + } \ + else { \ + out_loc.columns(); \ + } \ + } \ + out_loc.begin.filename = current_filename; \ + out_loc.end.filename = current_filename; #define YY_BREAK \ break; @@ -175,11 +178,12 @@ TIME_SCALE_SUFFIX [munpf]?s "`file_push "[^\n]* { fn_stack.push_back(current_filename); ln_stack.push_back(yylineno); - 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); + std::string filename = YYText()+11; + if (!filename.empty() && filename.front() == '"') + filename = filename.substr(1); + if (!filename.empty() && filename.back() == '"') + filename = filename.substr(0, filename.size()-1); + current_filename = std::make_shared(filename); yylineno = (0); out_loc.begin.line = out_loc.end.line = 0; } @@ -201,7 +205,7 @@ TIME_SCALE_SUFFIX [munpf]?s while (*p == ' ' || *p == '\t') p++; const char *q = *p ? p + 1 : p; while (*q && *q != '"') q++; - current_filename = std::string(p).substr(1, q-p-1); + current_filename = std::make_shared(std::string(p).substr(1, q-p-1)); } "`file_notfound "[^\n]* { diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 6f3b3baea..743061ae5 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -38,14 +38,17 @@ %define api.value.type variant %define api.prefix {frontend_verilog_yy} %define api.token.constructor +%define api.location.type {location} %param { YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::VerilogLexer* lexer } %parse-param { YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::ParseState* extra } %parse-param { YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::ParseMode* mode } + %code requires { #include "kernel/yosys_common.h" #include "frontends/verilog/verilog_error.h" + #include "frontends/verilog/verilog_location.h" // start requires YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { @@ -101,10 +104,10 @@ const AstNode *addIncOrDecStmt(dict> *stmt_attr, std::unique_ptr lhs, dict> *op_attr, AST::AstNodeType op, - parser::location_type begin, parser::location_type end); - std::unique_ptr addIncOrDecExpr(std::unique_ptr lhs, dict> *attr, AST::AstNodeType op, parser::location_type begin, parser::location_type end, bool undo, bool sv_mode); + parser::location_type loc); + std::unique_ptr addIncOrDecExpr(std::unique_ptr lhs, dict> *attr, AST::AstNodeType op, parser::location_type loc, bool undo, bool sv_mode); // add a binary operator assignment statement, e.g., a += b - std::unique_ptr addAsgnBinopStmt(dict> *attr, std::unique_ptr eq_lhs, AST::AstNodeType op, std::unique_ptr rhs, parser::location_type begin, parser::location_type end); + std::unique_ptr addAsgnBinopStmt(dict> *attr, std::unique_ptr eq_lhs, AST::AstNodeType op, std::unique_ptr rhs); }; struct ParseMode { bool noassert = false; @@ -140,13 +143,7 @@ return lexer->nextToken(); } - #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_AST_NODE_LOC(WHICH, BEGIN, END) (WHICH)->location = location_range(BEGIN, END) #define SET_RULE_LOC(LHS, BEGIN, END) \ do { (LHS).begin = BEGIN.begin; \ @@ -154,10 +151,13 @@ YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { + + static location location_range(location begin, location end) { + return location(begin.begin, end.end); + } + static ConstParser make_ConstParser_here(parser::location_type flex_loc) { - AstSrcLocType loc; - SET_LOC(loc, flex_loc, flex_loc); - ConstParser p{loc}; + ConstParser p{flex_loc}; return p; } static void append_attr(AstNode *ast, dict> *al) @@ -180,18 +180,18 @@ delete al; } - static std::unique_ptr makeRange(int msb = 31, int lsb = 0, bool isSigned = true) + static std::unique_ptr makeRange(parser::location_type loc, int msb = 31, int lsb = 0, bool isSigned = true) { - auto range = std::make_unique(AST_RANGE); - range->children.push_back(AstNode::mkconst_int(msb, true)); - range->children.push_back(AstNode::mkconst_int(lsb, true)); + auto range = std::make_unique(loc, AST_RANGE); + range->children.push_back(AstNode::mkconst_int(loc, msb, true)); + range->children.push_back(AstNode::mkconst_int(loc, 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); + auto range = makeRange(parent->location, msb, lsb, isSigned); parent->children.push_back(std::move(range)); } @@ -203,7 +203,7 @@ err_at_ast(type_node->location, "integer/genvar types cannot have packed dimensions."); } else { - range_node = makeRange(type_node->range_left, type_node->range_right, false); + range_node = makeRange(type_node->location, type_node->range_left, type_node->range_right, false); } } @@ -227,8 +227,8 @@ { if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) { // SV array size [n], rewrite as [0:n-1] - rangeNode->children.push_back(std::make_unique(AST_SUB, std::move(rangeNode->children[0]), AstNode::mkconst_int(1, true))); - rangeNode->children[0] = AstNode::mkconst_int(0, false); + rangeNode->children.push_back(std::make_unique(rangeNode->location, AST_SUB, std::move(rangeNode->children[0]), AstNode::mkconst_int(rangeNode->location, 1, true))); + rangeNode->children[0] = AstNode::mkconst_int(rangeNode->location, 0, false); } } @@ -268,14 +268,14 @@ { log_assert(node); node->is_custom_type = true; - node->children.push_back(std::make_unique(AST_WIRETYPE)); + node->children.push_back(std::make_unique(node->location, AST_WIRETYPE)); node->children.back()->str = *name; } void ParseState::addTypedefNode(std::string *name, std::unique_ptr node) { log_assert((bool)node); - AstNode* tnode = saveChild(std::make_unique(AST_TYPEDEF, std::move(node))); + AstNode* tnode = saveChild(std::make_unique(node->location, AST_TYPEDEF, std::move(node))); log_assert((bool)name); tnode->str = *name; auto &user_types = user_type_stack.back(); @@ -342,9 +342,9 @@ // create a new localparam with old name so that the items in the loop // can simply use the old name and shadow it as necessary - auto indirect = std::make_unique(AST_LOCALPARAM); + auto indirect = std::make_unique(loop->location, AST_LOCALPARAM); indirect->str = old_str; - auto ident = std::make_unique(AST_IDENTIFIER); + auto ident = std::make_unique(loop->location, AST_IDENTIFIER); ident->str = new_str; indirect->children.push_back(std::move(ident)); @@ -376,54 +376,48 @@ const AstNode *ParseState::addIncOrDecStmt(dict> *stmt_attr, std::unique_ptr lhs, dict> *op_attr, AST::AstNodeType op, - frontend_verilog_yy::location begin, frontend_verilog_yy::location end) + location loc) { - auto one = AstNode::mkconst_int(1, true); - auto rhs = std::make_unique(op, lhs->clone(), std::move(one)); + auto one = AstNode::mkconst_int(loc, 1, true); + auto rhs = std::make_unique(loc, op, lhs->clone(), std::move(one)); if (op_attr != nullptr) append_attr(rhs.get(), op_attr); - auto stmt_owned = std::make_unique(AST_ASSIGN_EQ, std::move(lhs), std::move(rhs)); + auto stmt_owned = std::make_unique(loc, AST_ASSIGN_EQ, std::move(lhs), std::move(rhs)); auto* stmt = stmt_owned.get(); ast_stack.back()->children.push_back(std::move(stmt_owned)); - SET_AST_NODE_LOC(stmt, begin, end); if (stmt_attr != nullptr) append_attr(stmt, stmt_attr); return stmt; } // create a pre/post-increment/decrement expression, and add the corresponding statement - std::unique_ptr ParseState::addIncOrDecExpr(std::unique_ptr lhs, dict> *attr, AST::AstNodeType op, frontend_verilog_yy::location begin, frontend_verilog_yy::location end, bool undo, bool sv_mode) + std::unique_ptr ParseState::addIncOrDecExpr(std::unique_ptr lhs, dict> *attr, AST::AstNodeType op, location loc, bool undo, bool sv_mode) { - ensureAsgnExprAllowed(begin, sv_mode); - const AstNode *stmt = addIncOrDecStmt(nullptr, std::move(lhs), attr, op, begin, end); + ensureAsgnExprAllowed(loc, sv_mode); + const AstNode *stmt = addIncOrDecStmt(nullptr, std::move(lhs), attr, op, loc); log_assert(stmt->type == AST_ASSIGN_EQ); auto expr = stmt->children[0]->clone(); if (undo) { - auto one = AstNode::mkconst_int(1, false, 1); - auto minus_one = std::make_unique(AST_NEG, std::move(one)); - expr = std::make_unique(op, std::move(expr), std::move(minus_one)); + auto one = AstNode::mkconst_int(loc, 1, false, 1); + auto minus_one = std::make_unique(loc, AST_NEG, std::move(one)); + expr = std::make_unique(loc, op, std::move(expr), std::move(minus_one)); } - SET_AST_NODE_LOC(expr.get(), begin, end); return expr; } // add a binary operator assignment statement, e.g., a += b - std::unique_ptr ParseState::addAsgnBinopStmt(dict> *attr, std::unique_ptr eq_lhs, AST::AstNodeType op, std::unique_ptr rhs, frontend_verilog_yy::location begin, frontend_verilog_yy::location end) + std::unique_ptr ParseState::addAsgnBinopStmt(dict> *attr, std::unique_ptr eq_lhs, AST::AstNodeType op, std::unique_ptr rhs) { - SET_AST_NODE_LOC(rhs.get(), end, end); + location loc = location_range(eq_lhs->location, rhs->location); if (op == AST_SHIFT_LEFT || op == AST_SHIFT_RIGHT || op == AST_SHIFT_SLEFT || op == AST_SHIFT_SRIGHT) { - rhs = std::make_unique(AST_TO_UNSIGNED, std::move(rhs)); - SET_AST_NODE_LOC(rhs.get(), end, end); + rhs = std::make_unique(rhs->location, AST_TO_UNSIGNED, std::move(rhs)); } auto binop_lhs = eq_lhs->clone(); - auto eq_rhs_owned = std::make_unique(op, std::move(binop_lhs), std::move(rhs)); - auto* eq_rhs = eq_rhs_owned.get(); + auto eq_rhs_owned = std::make_unique(loc, op, std::move(binop_lhs), std::move(rhs)); auto ret_lhs = eq_lhs->clone(); - auto stmt_owned = std::make_unique(AST_ASSIGN_EQ, std::move(eq_lhs), std::move(eq_rhs_owned)); + auto stmt_owned = std::make_unique(loc, AST_ASSIGN_EQ, std::move(eq_lhs), std::move(eq_rhs_owned)); auto* stmt = stmt_owned.get(); - SET_AST_NODE_LOC(eq_rhs, begin, end); - SET_AST_NODE_LOC(stmt, begin, end); ast_stack.back()->children.push_back(std::move(stmt_owned)); if (attr != nullptr) append_attr(stmt, attr); @@ -677,7 +671,7 @@ attr_list: attr_assign: hierarchical_id { - (*extra->attr_list)[*$1] = AstNode::mkconst_int(1, false); + (*extra->attr_list)[*$1] = AstNode::mkconst_int(@1, 1, false); } | hierarchical_id TOK_EQ expr { (*extra->attr_list)[*$1] = std::move($3); @@ -713,7 +707,7 @@ module: extra->enterTypeScope(); } TOK_ID { extra->do_not_require_port_stubs = false; - AstNode* mod = extra->pushChild(std::make_unique(AST_MODULE)); + AstNode* mod = extra->pushChild(std::make_unique(@$, AST_MODULE)); extra->current_ast_mod = mod; extra->port_stubs.clear(); extra->port_counter = 0; @@ -740,13 +734,13 @@ module_para_list: single_module_para: %empty | attr TOK_PARAMETER { - extra->astbuf1 = std::make_unique(AST_PARAMETER); - extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + extra->astbuf1 = std::make_unique(@$, AST_PARAMETER); + extra->astbuf1->children.push_back(AstNode::mkconst_int(@2, 0, true)); append_attr(extra->astbuf1.get(), $1); } param_type single_param_decl | attr TOK_LOCALPARAM { - extra->astbuf1 = std::make_unique(AST_LOCALPARAM); - extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + extra->astbuf1 = std::make_unique(@$, AST_LOCALPARAM); + extra->astbuf1->children.push_back(AstNode::mkconst_int(@2, 0, true)); append_attr(extra->astbuf1.get(), $1); } param_type single_param_decl | single_param_decl; @@ -767,12 +761,12 @@ module_arg_opt_assignment: auto& n = extra->ast_stack.back()->children.back(); n->attributes[ID::defaultvalue] = std::move($2); } else { - auto wire = std::make_unique(AST_IDENTIFIER); + auto wire = std::make_unique(@$, AST_IDENTIFIER); wire->str = extra->ast_stack.back()->children.back()->str; if (extra->ast_stack.back()->children.back()->is_reg || extra->ast_stack.back()->children.back()->is_logic) - extra->ast_stack.back()->children.push_back(std::make_unique(AST_INITIAL, std::make_unique(AST_BLOCK, std::make_unique(AST_ASSIGN_LE, std::move(wire), std::move($2))))); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_INITIAL, std::make_unique(@$, AST_BLOCK, std::make_unique(@$, AST_ASSIGN_LE, std::move(wire), std::move($2))))); else - extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::move(wire), std::move($2))); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_ASSIGN, std::move(wire), std::move($2))); } } else err_at_loc(@2, "SystemVerilog interface in module port list cannot have a default value."); @@ -794,8 +788,8 @@ module_arg: } } module_arg_opt_assignment | TOK_ID { - extra->astbuf1 = std::make_unique(AST_INTERFACEPORT); - extra->astbuf1->children.push_back(std::make_unique(AST_INTERFACEPORTTYPE)); + extra->astbuf1 = std::make_unique(@$, AST_INTERFACEPORT); + extra->astbuf1->children.push_back(std::make_unique(@$, AST_INTERFACEPORTTYPE)); extra->astbuf1->children[0]->str = *$1; } TOK_ID { /* SV interfaces */ if (!mode->sv) @@ -828,7 +822,7 @@ package: attr TOK_PACKAGE { extra->enterTypeScope(); } TOK_ID { - AstNode* mod = extra->pushChild(std::make_unique(AST_PACKAGE)); + AstNode* mod = extra->pushChild(std::make_unique(@$, AST_PACKAGE)); extra->current_ast_mod = mod; mod->str = *$4; append_attr(mod, $1); @@ -859,7 +853,7 @@ interface: extra->enterTypeScope(); } TOK_ID { extra->do_not_require_port_stubs = false; - AstNode* intf = extra->pushChild(std::make_unique(AST_INTERFACE)); + AstNode* intf = extra->pushChild(std::make_unique(@$, AST_INTERFACE)); extra->current_ast_mod = intf; extra->port_stubs.clear(); extra->port_counter = 0; @@ -883,7 +877,7 @@ interface_body_stmt: bind_directive: TOK_BIND { - (void)extra->pushChild(std::make_unique(AST_BIND)); + (void)extra->pushChild(std::make_unique(@$, AST_BIND)); } bind_target { // bind_target should have added at least one child @@ -892,8 +886,8 @@ bind_directive: TOK_ID { // The single_cell parser in cell_list_no_array uses extra->astbuf1 as // a sort of template for constructing cells. - extra->astbuf1 = std::make_unique(AST_CELL); - extra->astbuf1->children.push_back(std::make_unique(AST_CELLTYPE)); + extra->astbuf1 = std::make_unique(@$, AST_CELL); + extra->astbuf1->children.push_back(std::make_unique(@$, AST_CELLTYPE)); extra->astbuf1->children[0]->str = *$5; } cell_parameter_list_opt cell_list_no_array TOK_SEMICOL { @@ -932,7 +926,7 @@ bind_target_instance_list: // the bind node where we should add it. bind_target_instance: hierarchical_id { - auto node = std::make_unique(AST_IDENTIFIER); + auto node = std::make_unique(@$, AST_IDENTIFIER); node->str = *$1; extra->ast_stack.back()->children.push_back(std::move(node)); }; @@ -956,12 +950,12 @@ delay: non_opt_delay | %empty; io_wire_type: - { extra->astbuf3 = std::make_unique(AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; } + { extra->astbuf3 = std::make_unique(@$, AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; } wire_type_token_io wire_type_const_rand opt_wire_type_token wire_type_signedness { $$ = std::move(extra->astbuf3); SET_RULE_LOC(@$, @2, @$); }; non_io_wire_type: - { extra->astbuf3 = std::make_unique(AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; } + { extra->astbuf3 = std::make_unique(@$, AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; } wire_type_const_rand wire_type_token wire_type_signedness { $$ = std::move(extra->astbuf3); SET_RULE_LOC(@$, @2, @$); }; @@ -1067,30 +1061,30 @@ integer_vector_type: non_opt_range: TOK_LBRA expr TOK_COL expr TOK_RBRA { - $$ = std::make_unique(AST_RANGE); + $$ = std::make_unique(@$, AST_RANGE); $$->children.push_back(std::move($2)); $$->children.push_back(std::move($4)); } | TOK_LBRA expr TOK_POS_INDEXED expr TOK_RBRA { - $$ = std::make_unique(AST_RANGE); - auto expr = std::make_unique(AST_SELFSZ, std::move($2)); - $$->children.push_back(std::make_unique(AST_SUB, std::make_unique(AST_ADD, expr->clone(), std::move($4)), AstNode::mkconst_int(1, true))); - $$->children.push_back(std::make_unique(AST_ADD, std::move(expr), AstNode::mkconst_int(0, true))); + $$ = std::make_unique(@$, AST_RANGE); + auto expr = std::make_unique(@$, AST_SELFSZ, std::move($2)); + $$->children.push_back(std::make_unique(@$, AST_SUB, std::make_unique(@$, AST_ADD, expr->clone(), std::move($4)), AstNode::mkconst_int(@$, 1, true))); + $$->children.push_back(std::make_unique(@$, AST_ADD, std::move(expr), AstNode::mkconst_int(@$, 0, true))); } | TOK_LBRA expr TOK_NEG_INDEXED expr TOK_RBRA { - $$ = std::make_unique(AST_RANGE); - auto expr = std::make_unique(AST_SELFSZ, std::move($2)); - $$->children.push_back(std::make_unique(AST_ADD, expr->clone(), AstNode::mkconst_int(0, true))); - $$->children.push_back(std::make_unique(AST_SUB, std::make_unique(AST_ADD, std::move(expr), AstNode::mkconst_int(1, true)), std::move($4))); + $$ = std::make_unique(@$, AST_RANGE); + auto expr = std::make_unique(@$, AST_SELFSZ, std::move($2)); + $$->children.push_back(std::make_unique(@$, AST_ADD, expr->clone(), AstNode::mkconst_int(@$, 0, true))); + $$->children.push_back(std::make_unique(@$, AST_SUB, std::make_unique(@$, AST_ADD, std::move(expr), AstNode::mkconst_int(@$, 1, true)), std::move($4))); } | TOK_LBRA expr TOK_RBRA { - $$ = std::make_unique(AST_RANGE); + $$ = std::make_unique(@$, AST_RANGE); $$->children.push_back(std::move($2)); }; non_opt_multirange: non_opt_range non_opt_range { - $$ = std::make_unique(AST_MULTIRANGE, std::move($1), std::move($2)); + $$ = std::make_unique(@$, AST_MULTIRANGE, std::move($1), std::move($2)); } | non_opt_multirange non_opt_range { $$ = std::move($1); @@ -1124,7 +1118,7 @@ module_body_stmt: checker_decl: TOK_CHECKER TOK_ID TOK_SEMICOL { - AstNode* node = extra->pushChild(std::make_unique(AST_GENBLOCK)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_GENBLOCK)); node->str = *$2; } module_body TOK_ENDCHECKER { extra->ast_stack.pop_back(); @@ -1132,28 +1126,28 @@ checker_decl: task_func_decl: attr TOK_DPI_FUNCTION TOK_ID TOK_ID { - extra->current_function_or_task = extra->saveChild(std::make_unique(AST_DPI_FUNCTION, AstNode::mkconst_str(*$3), AstNode::mkconst_str(*$4))); + extra->current_function_or_task = extra->saveChild(std::make_unique(@$, AST_DPI_FUNCTION, AstNode::mkconst_str(@3, *$3), AstNode::mkconst_str(@4, *$4))); extra->current_function_or_task->str = *$4; append_attr(extra->current_function_or_task, $1); } opt_dpi_function_args TOK_SEMICOL { extra->current_function_or_task = nullptr; } | attr TOK_DPI_FUNCTION TOK_ID TOK_EQ TOK_ID TOK_ID { - extra->current_function_or_task = extra->saveChild(std::make_unique(AST_DPI_FUNCTION, AstNode::mkconst_str(*$5), AstNode::mkconst_str(*$3))); + extra->current_function_or_task = extra->saveChild(std::make_unique(@$, AST_DPI_FUNCTION, AstNode::mkconst_str(@5, *$5), AstNode::mkconst_str(@3, *$3))); extra->current_function_or_task->str = *$6; append_attr(extra->current_function_or_task, $1); } opt_dpi_function_args TOK_SEMICOL { extra->current_function_or_task = nullptr; } | attr TOK_DPI_FUNCTION TOK_ID TOK_COL TOK_ID TOK_EQ TOK_ID TOK_ID { - extra->current_function_or_task = extra->saveChild(std::make_unique(AST_DPI_FUNCTION, AstNode::mkconst_str(*$7), AstNode::mkconst_str(*$3 + ":" + RTLIL::unescape_id(*$5)))); + extra->current_function_or_task = extra->saveChild(std::make_unique(@$, AST_DPI_FUNCTION, AstNode::mkconst_str(@7, *$7), AstNode::mkconst_str(location_range(@3, @5), *$3 + ":" + RTLIL::unescape_id(*$5)))); extra->current_function_or_task->str = *$8; append_attr(extra->current_function_or_task, $1); } opt_dpi_function_args TOK_SEMICOL { extra->current_function_or_task = nullptr; } | attr TOK_TASK opt_automatic TOK_ID { - extra->current_function_or_task = extra->pushChild(std::make_unique(AST_TASK)); + extra->current_function_or_task = extra->pushChild(std::make_unique(@$, AST_TASK)); extra->current_function_or_task->str = *$4; append_attr(extra->current_function_or_task, $1); extra->current_function_or_task_port_id = 1; @@ -1167,7 +1161,7 @@ task_func_decl: // inlined, but ignores signals read only in tasks. This only matters // for event based simulation, and for synthesis we can treat a void // function like a task. - extra->current_function_or_task = extra->pushChild(std::make_unique(AST_TASK)); + extra->current_function_or_task = extra->pushChild(std::make_unique(@$, AST_TASK)); extra->current_function_or_task->str = *$5; append_attr(extra->current_function_or_task, $1); extra->current_function_or_task_port_id = 1; @@ -1176,10 +1170,10 @@ task_func_decl: extra->ast_stack.pop_back(); } | attr TOK_FUNCTION opt_automatic func_return_type TOK_ID { - extra->current_function_or_task = extra->pushChild(std::make_unique(AST_FUNCTION)); + extra->current_function_or_task = extra->pushChild(std::make_unique(@$, AST_FUNCTION)); extra->current_function_or_task->str = *$5; append_attr(extra->current_function_or_task, $1); - auto outreg = std::make_unique(AST_WIRE); + auto outreg = std::make_unique(@$, AST_WIRE); outreg->str = *$5; outreg->is_signed = false; outreg->is_reg = true; @@ -1198,18 +1192,18 @@ task_func_decl: func_return_type: hierarchical_type_id { - $$ = std::make_unique(AST_WIRETYPE); + $$ = std::make_unique(@$, AST_WIRETYPE); $$->str = *$1; } | opt_type_vec opt_signedness_default_unsigned { - $$ = makeRange(0, 0, $2); + $$ = makeRange(@$, 0, 0, $2); } | opt_type_vec opt_signedness_default_unsigned non_opt_range { $$ = std::move($3); $$->is_signed = $2; } | integer_atom_type opt_signedness_default_signed { - $$ = makeRange($1 - 1, 0, $2); + $$ = makeRange(@$, $1 - 1, 0, $2); }; opt_type_vec: @@ -1231,10 +1225,10 @@ opt_signedness_default_unsigned: dpi_function_arg: TOK_ID TOK_ID { - extra->current_function_or_task->children.push_back(AstNode::mkconst_str(*$1)); + extra->current_function_or_task->children.push_back(AstNode::mkconst_str(@1, *$1)); } | TOK_ID { - extra->current_function_or_task->children.push_back(AstNode::mkconst_str(*$1)); + extra->current_function_or_task->children.push_back(AstNode::mkconst_str(@1, *$1)); }; opt_dpi_function_args: @@ -1293,7 +1287,7 @@ task_func_port: if (!mode->sv) err_at_loc(@$, "task/function argument direction missing"); extra->albuf = new dict>; - extra->astbuf1 = std::make_unique(AST_WIRE); + extra->astbuf1 = std::make_unique(@$, AST_WIRE); extra->current_wire_rand = false; extra->current_wire_const = false; extra->astbuf1->is_input = true; @@ -1326,11 +1320,11 @@ specify_item: if (specify_edge != 0 && target->dat == nullptr) err_at_loc(@3, "Found specify edge but no data spec.\n"); - auto cell_owned = std::make_unique(AST_CELL); + auto cell_owned = std::make_unique(@$, AST_CELL); auto cell = cell_owned.get(); extra->ast_stack.back()->children.push_back(std::move(cell_owned)); cell->str = stringf("$specify$%d", autoidx++); - cell->children.push_back(std::make_unique(AST_CELLTYPE)); + cell->children.push_back(std::make_unique(@$, AST_CELLTYPE)); cell->children.back()->str = target->dat ? "$specify3" : "$specify2"; SET_AST_NODE_LOC(cell, en_expr.get() ? @1 : @2, @10); @@ -1342,57 +1336,57 @@ specify_item: oper_type = oper->at(1); } - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1))); + cell->children.push_back(std::make_unique(@5, AST_PARASET, AstNode::mkconst_int(@5, oper_type == '*', false, 1))); cell->children.back()->str = "\\FULL"; - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1))); + cell->children.push_back(std::make_unique(@5, AST_PARASET, AstNode::mkconst_int(@5, oper_polarity != 0, false, 1))); cell->children.back()->str = "\\SRC_DST_PEN"; - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1))); + cell->children.push_back(std::make_unique(@5, AST_PARASET, AstNode::mkconst_int(@5, oper_polarity == '+', false, 1))); cell->children.back()->str = "\\SRC_DST_POL"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->rise.t_min))); + cell->children.push_back(std::make_unique(@9, AST_PARASET, std::move(timing->rise.t_min))); cell->children.back()->str = "\\T_RISE_MIN"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->rise.t_avg))); + cell->children.push_back(std::make_unique(@9, AST_PARASET, std::move(timing->rise.t_avg))); cell->children.back()->str = "\\T_RISE_TYP"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->rise.t_max))); + cell->children.push_back(std::make_unique(@9, AST_PARASET, std::move(timing->rise.t_max))); cell->children.back()->str = "\\T_RISE_MAX"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->fall.t_min))); + cell->children.push_back(std::make_unique(@9, AST_PARASET, std::move(timing->fall.t_min))); cell->children.back()->str = "\\T_FALL_MIN"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->fall.t_avg))); + cell->children.push_back(std::make_unique(@9, AST_PARASET, std::move(timing->fall.t_avg))); cell->children.back()->str = "\\T_FALL_TYP"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(timing->fall.t_max))); + cell->children.push_back(std::make_unique(@9, AST_PARASET, std::move(timing->fall.t_max))); cell->children.back()->str = "\\T_FALL_MAX"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, en_expr ? std::move(en_expr) : AstNode::mkconst_int(1, false, 1))); + cell->children.push_back(std::make_unique(@1, AST_ARGUMENT, en_expr ? std::move(en_expr) : AstNode::mkconst_int(@1, 1, false, 1))); cell->children.back()->str = "\\EN"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(src_expr))); + cell->children.push_back(std::make_unique(@4, AST_ARGUMENT, std::move(src_expr))); cell->children.back()->str = "\\SRC"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(target->dst))); + cell->children.push_back(std::make_unique(@6, AST_ARGUMENT, std::move(target->dst))); cell->children.back()->str = "\\DST"; if (target->dat) { - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1))); + cell->children.push_back(std::make_unique(@3, AST_PARASET, AstNode::mkconst_int(@3, specify_edge != 0, false, 1))); cell->children.back()->str = "\\EDGE_EN"; - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1))); + cell->children.push_back(std::make_unique(@3, AST_PARASET, AstNode::mkconst_int(@3, specify_edge == 'p', false, 1))); cell->children.back()->str = "\\EDGE_POL"; - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1))); + cell->children.push_back(std::make_unique(@6, AST_PARASET, AstNode::mkconst_int(@6, target->polarity_op != 0, false, 1))); cell->children.back()->str = "\\DAT_DST_PEN"; - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1))); + cell->children.push_back(std::make_unique(@6, AST_PARASET, AstNode::mkconst_int(@6, target->polarity_op == '+', false, 1))); cell->children.back()->str = "\\DAT_DST_POL"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(target->dat))); + cell->children.push_back(std::make_unique(@6, AST_ARGUMENT, std::move(target->dat))); cell->children.back()->str = "\\DAT"; } } | @@ -1401,68 +1395,68 @@ specify_item: *$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange") err_at_loc(@1, "Unsupported specify rule type: %s\n", $1->c_str()); - auto src_pen = AstNode::mkconst_int($3 != 0, false, 1); - auto src_pol = AstNode::mkconst_int($3 == 'p', false, 1); - auto src_expr = std::move($4), src_en = $5 ? std::move($5) : AstNode::mkconst_int(1, false, 1); + auto src_pen = AstNode::mkconst_int(@3, $3 != 0, false, 1); + auto src_pol = AstNode::mkconst_int(@3, $3 == 'p', false, 1); + auto src_expr = std::move($4), src_en = $5 ? std::move($5) : AstNode::mkconst_int(@5, 1, false, 1); - auto dst_pen = AstNode::mkconst_int($7 != 0, false, 1); - auto dst_pol = AstNode::mkconst_int($7 == 'p', false, 1); - auto dst_expr = std::move($8), dst_en = $9 ? std::move($9) : AstNode::mkconst_int(1, false, 1); + auto dst_pen = AstNode::mkconst_int(@7, $7 != 0, false, 1); + auto dst_pol = AstNode::mkconst_int(@7, $7 == 'p', false, 1); + auto dst_expr = std::move($8), dst_en = $9 ? std::move($9) : AstNode::mkconst_int(@5, 1, false, 1); specify_triple_ptr_t limit = std::move($11); specify_triple_ptr_t limit2 = std::move($12); - auto cell_owned = std::make_unique(AST_CELL); + auto cell_owned = std::make_unique(@$, AST_CELL); auto cell = cell_owned.get(); extra->ast_stack.back()->children.push_back(std::move(cell_owned)); cell->str = stringf("$specify$%d", autoidx++); - cell->children.push_back(std::make_unique(AST_CELLTYPE)); + cell->children.push_back(std::make_unique(@$, AST_CELLTYPE)); cell->children.back()->str = "$specrule"; SET_AST_NODE_LOC(cell, @1, @14); - cell->children.push_back(std::make_unique(AST_PARASET, AstNode::mkconst_str(*$1))); + cell->children.push_back(std::make_unique(@1, AST_PARASET, AstNode::mkconst_str(@1, *$1))); cell->children.back()->str = "\\TYPE"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(limit->t_min))); + cell->children.push_back(std::make_unique(@11, AST_PARASET, std::move(limit->t_min))); cell->children.back()->str = "\\T_LIMIT_MIN"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(limit->t_avg))); + cell->children.push_back(std::make_unique(@11, AST_PARASET, std::move(limit->t_avg))); cell->children.back()->str = "\\T_LIMIT_TYP"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(limit->t_max))); + cell->children.push_back(std::make_unique(@11, AST_PARASET, std::move(limit->t_max))); cell->children.back()->str = "\\T_LIMIT_MAX"; - cell->children.push_back(std::make_unique(AST_PARASET, limit2 ? std::move(limit2->t_min) : AstNode::mkconst_int(0, true))); + cell->children.push_back(std::make_unique(@12, AST_PARASET, limit2 ? std::move(limit2->t_min) : AstNode::mkconst_int(@12, 0, true))); cell->children.back()->str = "\\T_LIMIT2_MIN"; - cell->children.push_back(std::make_unique(AST_PARASET, limit2 ? std::move(limit2->t_avg) : AstNode::mkconst_int(0, true))); + cell->children.push_back(std::make_unique(@12, AST_PARASET, limit2 ? std::move(limit2->t_avg) : AstNode::mkconst_int(@12, 0, true))); cell->children.back()->str = "\\T_LIMIT2_TYP"; - cell->children.push_back(std::make_unique(AST_PARASET, limit2 ? std::move(limit2->t_max) : AstNode::mkconst_int(0, true))); + cell->children.push_back(std::make_unique(@12, AST_PARASET, limit2 ? std::move(limit2->t_max) : AstNode::mkconst_int(@12, 0, true))); cell->children.back()->str = "\\T_LIMIT2_MAX"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(src_pen))); + cell->children.push_back(std::make_unique(@3, AST_PARASET, std::move(src_pen))); cell->children.back()->str = "\\SRC_PEN"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(src_pol))); + cell->children.push_back(std::make_unique(@3, AST_PARASET, std::move(src_pol))); cell->children.back()->str = "\\SRC_POL"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(dst_pen))); + cell->children.push_back(std::make_unique(@3, AST_PARASET, std::move(dst_pen))); cell->children.back()->str = "\\DST_PEN"; - cell->children.push_back(std::make_unique(AST_PARASET, std::move(dst_pol))); + cell->children.push_back(std::make_unique(@7, AST_PARASET, std::move(dst_pol))); cell->children.back()->str = "\\DST_POL"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(src_en))); + cell->children.push_back(std::make_unique(@5, AST_ARGUMENT, std::move(src_en))); cell->children.back()->str = "\\SRC_EN"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(src_expr))); + cell->children.push_back(std::make_unique(@4, AST_ARGUMENT, std::move(src_expr))); cell->children.back()->str = "\\SRC"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(dst_en))); + cell->children.push_back(std::make_unique(@9, AST_ARGUMENT, std::move(dst_en))); cell->children.back()->str = "\\DST_EN"; - cell->children.push_back(std::make_unique(AST_ARGUMENT, std::move(dst_expr))); + cell->children.push_back(std::make_unique(@8, AST_ARGUMENT, std::move(dst_expr))); cell->children.back()->str = "\\DST"; }; @@ -1538,19 +1532,19 @@ specify_rise_fall: $$ = std::make_unique(); $$->rise = std::move(*$2); $$->fall = std::move(*$4); - log_file_warning(current_filename, @$.begin.line, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + err_at_loc(@$, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } | TOK_LPAREN specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_RPAREN { $$ = std::make_unique(); $$->rise = std::move(*$2); $$->fall = std::move(*$4); - log_file_warning(current_filename, @$.begin.line, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + err_at_loc(@$, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } | TOK_LPAREN specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_RPAREN { $$ = std::make_unique(); $$->rise = std::move(*$2); $$->fall = std::move(*$4); - log_file_warning(current_filename, @$.begin.line, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + err_at_loc(@$, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } specify_triple: @@ -1708,7 +1702,7 @@ param_integer: param_real: TOK_REAL { - extra->astbuf1->children.push_back(std::make_unique(AST_REALVALUE)); + extra->astbuf1->children.push_back(std::make_unique(@$, AST_REALVALUE)); }; param_range: @@ -1736,8 +1730,8 @@ param_type: param_decl: attr TOK_PARAMETER { - extra->astbuf1 = std::make_unique(AST_PARAMETER); - extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + extra->astbuf1 = std::make_unique(@$, AST_PARAMETER); + extra->astbuf1->children.push_back(AstNode::mkconst_int(@$, 0, true)); append_attr(extra->astbuf1.get(), $1); } param_type param_decl_list TOK_SEMICOL { (void)extra->astbuf1.reset(); @@ -1745,8 +1739,8 @@ param_decl: localparam_decl: attr TOK_LOCALPARAM { - extra->astbuf1 = std::make_unique(AST_LOCALPARAM); - extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + extra->astbuf1 = std::make_unique(@$, AST_LOCALPARAM); + extra->astbuf1->children.push_back(AstNode::mkconst_int(@$, 0, true)); append_attr(extra->astbuf1.get(), $1); } param_type param_decl_list TOK_SEMICOL { (void)extra->astbuf1.reset(); @@ -1778,8 +1772,8 @@ single_param_decl_ident: if (extra->astbuf1 == nullptr) { if (!mode->sv) err_at_loc(@1, "In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword"); - node_owned = std::make_unique(AST_PARAMETER); - node_owned->children.push_back(AstNode::mkconst_int(0, true)); + node_owned = std::make_unique(@$, AST_PARAMETER); + node_owned->children.push_back(AstNode::mkconst_int(@$, 0, true)); } else { node_owned = extra->astbuf1->clone(); } @@ -1797,7 +1791,7 @@ defparam_decl_list: single_defparam_decl: range rvalue TOK_EQ expr { - auto node = std::make_unique(AST_DEFPARAM); + auto node = std::make_unique(@$, AST_DEFPARAM); node->children.push_back(std::move($2)); node->children.push_back(std::move($4)); if ($1 != nullptr) @@ -1812,15 +1806,15 @@ single_defparam_decl: enum_type: TOK_ENUM { static int enum_count; // create parent node for the enum - extra->astbuf2 = std::make_unique(AST_ENUM); + extra->astbuf2 = std::make_unique(@$, AST_ENUM); extra->astbuf2->str = std::string("$enum"); extra->astbuf2->str += std::to_string(enum_count++); log_assert(!extra->cell_hack); extra->cell_hack = extra->astbuf2.get(); extra->ast_stack.back()->children.push_back(std::move(extra->astbuf2)); // create the template for the names - extra->astbuf1 = std::make_unique(AST_ENUM_ITEM); - extra->astbuf1->children.push_back(AstNode::mkconst_int(0, true)); + extra->astbuf1 = std::make_unique(@$, AST_ENUM_ITEM); + extra->astbuf1->children.push_back(AstNode::mkconst_int(@$, 0, true)); } enum_base_type TOK_LCURL enum_name_list optional_comma TOK_RCURL { // create template for the enum vars log_assert(extra->cell_hack); @@ -1828,7 +1822,7 @@ enum_type: TOK_ENUM { auto* tnode = tnode_owned.get(); extra->astbuf1 = std::move(tnode_owned); tnode->type = AST_WIRE; - tnode->attributes[ID::enum_type] = AstNode::mkconst_str(extra->cell_hack->str); + tnode->attributes[ID::enum_type] = AstNode::mkconst_str(@$, extra->cell_hack->str); extra->cell_hack = nullptr; // drop constant but keep any range tnode->children.erase(tnode->children.begin()); @@ -1869,7 +1863,7 @@ enum_name_decl: auto node = extra->astbuf1->clone(); node->str = *$1; SET_AST_NODE_LOC(node.get(), @1, @1); - node->children[0] = $2 ? std::move($2) : std::make_unique(AST_NONE); + node->children[0] = $2 ? std::move($2) : std::make_unique(@$, AST_NONE); extra->cell_hack->children.push_back(std::move(node)); } ; @@ -1919,8 +1913,8 @@ struct_type: ; struct_union: - TOK_STRUCT { $$ = std::make_unique(AST_STRUCT); } - | TOK_UNION { $$ = std::make_unique(AST_UNION); } + TOK_STRUCT { $$ = std::make_unique(@$, AST_STRUCT); } + | TOK_UNION { $$ = std::make_unique(@$, AST_UNION); } ; struct_body: opt_packed TOK_LCURL struct_member_list TOK_RCURL @@ -1962,7 +1956,7 @@ member_name: TOK_ID { } ; -struct_member_type: { extra->astbuf1 = std::make_unique(AST_STRUCT_ITEM); } member_type_token +struct_member_type: { extra->astbuf1 = std::make_unique(@$, AST_STRUCT_ITEM); } member_type_token ; member_type_token: @@ -2019,17 +2013,17 @@ wire_decl: free_attr(extra->albuf); } TOK_SEMICOL | attr TOK_SUPPLY0 TOK_ID { - extra->ast_stack.back()->children.push_back(std::make_unique(AST_WIRE)); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_WIRE)); extra->ast_stack.back()->children.back()->str = *$3; append_attr(extra->ast_stack.back()->children.back().get(), $1); - extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::make_unique(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1))); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_ASSIGN, std::make_unique(@$, AST_IDENTIFIER), AstNode::mkconst_int(@$, 0, false, 1))); extra->ast_stack.back()->children.back()->children[0]->str = *$3; } opt_supply_wires TOK_SEMICOL | attr TOK_SUPPLY1 TOK_ID { - extra->ast_stack.back()->children.push_back(std::make_unique(AST_WIRE)); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_WIRE)); extra->ast_stack.back()->children.back()->str = *$3; append_attr(extra->ast_stack.back()->children.back().get(), $1); - extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::make_unique(AST_IDENTIFIER), AstNode::mkconst_int(1, false, 1))); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_ASSIGN, std::make_unique(@$, AST_IDENTIFIER), AstNode::mkconst_int(@$, 1, false, 1))); extra->ast_stack.back()->children.back()->children[0]->str = *$3; } opt_supply_wires TOK_SEMICOL; @@ -2070,8 +2064,8 @@ wire_name_and_opt_assign: attr_allseq = true; } if (extra->current_wire_rand || attr_anyconst || attr_anyseq || attr_allconst || attr_allseq) { - auto wire = std::make_unique(AST_IDENTIFIER); - auto fcall = std::make_unique(AST_FCALL); + auto wire = std::make_unique(@$, AST_IDENTIFIER); + auto fcall = std::make_unique(@$, AST_FCALL); wire->str = extra->ast_stack.back()->children.back()->str; fcall->str = extra->current_wire_const ? "\\$anyconst" : "\\$anyseq"; if (attr_anyconst) @@ -2082,28 +2076,28 @@ wire_name_and_opt_assign: fcall->str = "\\$allconst"; if (attr_allseq) fcall->str = "\\$allseq"; - fcall->attributes[ID::reg] = AstNode::mkconst_str(RTLIL::unescape_id(wire->str)); - extra->ast_stack.back()->children.push_back(std::make_unique(AST_ASSIGN, std::move(wire), std::move(fcall))); + fcall->attributes[ID::reg] = AstNode::mkconst_str(@$, RTLIL::unescape_id(wire->str)); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_ASSIGN, std::move(wire), std::move(fcall))); } } | wire_name TOK_EQ expr { - auto wire = std::make_unique(AST_IDENTIFIER); + auto wire = std::make_unique(@$, AST_IDENTIFIER); wire->str = extra->ast_stack.back()->children.back()->str; if (extra->astbuf1->is_input) { extra->astbuf1->attributes[ID::defaultvalue] = std::move($3); } else if (extra->astbuf1->is_reg || extra->astbuf1->is_logic){ - auto assign = std::make_unique(AST_ASSIGN_LE, std::move(wire), std::move($3)); + auto assign = std::make_unique(@$, AST_ASSIGN_LE, std::move(wire), std::move($3)); SET_AST_NODE_LOC(assign.get(), @1, @3); - auto block = std::make_unique(AST_BLOCK, std::move(assign)); + auto block = std::make_unique(@$, AST_BLOCK, std::move(assign)); SET_AST_NODE_LOC(block.get(), @1, @3); - auto init = std::make_unique(AST_INITIAL, std::move(block)); + auto init = std::make_unique(@$, AST_INITIAL, std::move(block)); SET_AST_NODE_LOC(init.get(), @1, @3); extra->ast_stack.back()->children.push_back(std::move(init)); } else { - auto assign = std::make_unique(AST_ASSIGN, std::move(wire), std::move($3)); + auto assign = std::make_unique(@$, AST_ASSIGN, std::move(wire), std::move($3)); SET_AST_NODE_LOC(assign.get(), @1, @3); extra->ast_stack.back()->children.push_back(std::move(assign)); } @@ -2163,7 +2157,7 @@ assign_expr_list: assign_expr: lvalue TOK_EQ expr { - AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN, std::move($1), std::move($3))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_ASSIGN, std::move($1), std::move($3))); SET_AST_NODE_LOC(node, @$, @$); }; @@ -2192,12 +2186,12 @@ typedef_decl: typedef_base_type: hierarchical_type_id { - $$ = std::make_unique(AST_WIRE); + $$ = std::make_unique(@$, AST_WIRE); $$->is_logic = true; extra->addWiretypeNode($1.get(), $$.get()); } | integer_vector_type opt_signedness_default_unsigned { - $$ = std::make_unique(AST_WIRE); + $$ = std::make_unique(@$, AST_WIRE); if ($1 == token::TOK_REG) { $$->is_reg = true; } else { @@ -2206,7 +2200,7 @@ typedef_base_type: $$->is_signed = $2; } | integer_atom_type opt_signedness_default_signed { - $$ = std::make_unique(AST_WIRE); + $$ = std::make_unique(@$, AST_WIRE); $$->is_logic = true; $$->is_signed = $2; $$->range_left = $1 - 1; @@ -2220,15 +2214,15 @@ enum_struct_type: cell_stmt: attr TOK_ID { - extra->astbuf1 = std::make_unique(AST_CELL); + extra->astbuf1 = std::make_unique(@$, AST_CELL); append_attr(extra->astbuf1.get(), $1); - extra->astbuf1->children.push_back(std::make_unique(AST_CELLTYPE)); + extra->astbuf1->children.push_back(std::make_unique(@$, AST_CELLTYPE)); extra->astbuf1->children[0]->str = *$2; } cell_parameter_list_opt cell_list TOK_SEMICOL { (void)extra->astbuf1.reset(); } | attr tok_prim_wrapper delay { - extra->astbuf1 = std::make_unique(AST_PRIMITIVE); + extra->astbuf1 = std::make_unique(@$, AST_PRIMITIVE); extra->astbuf1->str = *$2; append_attr(extra->astbuf1.get(), $1); } prim_list TOK_SEMICOL { @@ -2271,7 +2265,7 @@ single_cell_arraylist: extra->astbuf2->str = *$1; // TODO optimize again extra->cell_hack = extra->astbuf2.get(); - extra->ast_stack.back()->children.push_back(std::make_unique(AST_CELLARRAY, std::move($2), std::move(extra->astbuf2))); + extra->ast_stack.back()->children.push_back(std::make_unique(@$, AST_CELLARRAY, std::move($2), std::move(extra->astbuf2))); } TOK_LPAREN cell_port_list TOK_RPAREN{ log_assert(extra->cell_hack); SET_AST_NODE_LOC(extra->cell_hack, @1, @$); @@ -2309,7 +2303,7 @@ cell_parameter_list: cell_parameter: %empty | expr { - auto node = std::make_unique(AST_PARASET); + auto node = std::make_unique(@$, AST_PARASET); node->children.push_back(std::move($1)); extra->astbuf1->children.push_back(std::move(node)); } | @@ -2317,7 +2311,7 @@ cell_parameter: // just ignore empty parameters } | TOK_DOT TOK_ID TOK_LPAREN expr TOK_RPAREN { - auto node = std::make_unique(AST_PARASET); + auto node = std::make_unique(@$, AST_PARASET); node->str = *$2; node->children.push_back(std::move($4)); extra->astbuf1->children.push_back(std::move(node)); @@ -2354,33 +2348,33 @@ cell_port_list_rules: cell_port: attr { - auto node = std::make_unique(AST_ARGUMENT); + auto node = std::make_unique(@$, AST_ARGUMENT); extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | attr expr { - auto node = std::make_unique(AST_ARGUMENT); + auto node = std::make_unique(@$, AST_ARGUMENT); node->children.push_back(std::move($2)); extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | attr TOK_DOT TOK_ID TOK_LPAREN expr TOK_RPAREN { - auto node = std::make_unique(AST_ARGUMENT); + auto node = std::make_unique(@$, AST_ARGUMENT); node->str = *$3; node->children.push_back(std::move($5)); extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | attr TOK_DOT TOK_ID TOK_LPAREN TOK_RPAREN { - auto node = std::make_unique(AST_ARGUMENT); + auto node = std::make_unique(@$, AST_ARGUMENT); node->str = *$3; extra->cell_hack->children.push_back(std::move(node)); free_attr($1); } | attr TOK_DOT TOK_ID { - auto node = std::make_unique(AST_ARGUMENT); + auto node = std::make_unique(@$, AST_ARGUMENT); node->str = *$3; - node->children.push_back(std::make_unique(AST_IDENTIFIER)); + node->children.push_back(std::make_unique(@$, AST_IDENTIFIER)); node->children.back()->str = *$3; extra->cell_hack->children.push_back(std::move(node)); free_attr($1); @@ -2388,7 +2382,7 @@ cell_port: attr TOK_WILDCARD_CONNECT { if (!mode->sv) err_at_loc(@2, "Wildcard port connections are only supported in SystemVerilog mode."); - extra->cell_hack->attributes[ID::wildcard_port_conns] = AstNode::mkconst_int(1, false); + extra->cell_hack->attributes[ID::wildcard_port_conns] = AstNode::mkconst_int(@2, 1, false); free_attr($1); }; @@ -2410,12 +2404,12 @@ always_or_always_ff: always_stmt: attr always_or_always_ff { - AstNode* node = extra->pushChild(std::make_unique(AST_ALWAYS)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_ALWAYS)); append_attr(node, $1); if ($2) - node->attributes[ID::always_ff] = AstNode::mkconst_int(1, false); + node->attributes[ID::always_ff] = AstNode::mkconst_int(@2, 1, false); } always_cond { - (void)extra->pushChild(std::make_unique(AST_BLOCK)); + (void)extra->pushChild(std::make_unique(@$, AST_BLOCK)); } behavioral_stmt { SET_AST_NODE_LOC(extra->ast_stack.back(), @6, @6); extra->ast_stack.pop_back(); @@ -2426,21 +2420,21 @@ always_stmt: SET_RULE_LOC(@$, @2, @$); } | attr always_comb_or_latch { - AstNode* node = extra->pushChild(std::make_unique(AST_ALWAYS)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_ALWAYS)); append_attr(node, $1); if ($2) - node->attributes[ID::always_latch] = AstNode::mkconst_int(1, false); + node->attributes[ID::always_latch] = AstNode::mkconst_int(@2, 1, false); else - node->attributes[ID::always_comb] = AstNode::mkconst_int(1, false); - (void)extra->pushChild(std::make_unique(AST_BLOCK)); + node->attributes[ID::always_comb] = AstNode::mkconst_int(@2, 1, false); + (void)extra->pushChild(std::make_unique(@$, AST_BLOCK)); } behavioral_stmt { extra->ast_stack.pop_back(); extra->ast_stack.pop_back(); } | attr TOK_INITIAL { - AstNode* node = extra->pushChild(std::make_unique(AST_INITIAL)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_INITIAL)); append_attr(node, $1); - (void)extra->pushChild(std::make_unique(AST_BLOCK)); + (void)extra->pushChild(std::make_unique(@$, AST_BLOCK)); } behavioral_stmt { extra->ast_stack.pop_back(); extra->ast_stack.pop_back(); @@ -2461,19 +2455,19 @@ always_events: always_event: TOK_POSEDGE expr { - auto node = std::make_unique(AST_POSEDGE); + auto node = std::make_unique(@$, AST_POSEDGE); SET_AST_NODE_LOC(node.get(), @1, @1); node->children.push_back(std::move($2)); extra->ast_stack.back()->children.push_back(std::move(node)); } | TOK_NEGEDGE expr { - auto node = std::make_unique(AST_NEGEDGE); + auto node = std::make_unique(@$, AST_NEGEDGE); SET_AST_NODE_LOC(node.get(), @1, @1); node->children.push_back(std::move($2)); extra->ast_stack.back()->children.push_back(std::move(node)); } | expr { - auto node = std::make_unique(AST_EDGE); + auto node = std::make_unique(@$, AST_EDGE); node->children.push_back(std::move($1)); extra->ast_stack.back()->children.push_back(std::move(node)); }; @@ -2507,7 +2501,7 @@ opt_property: modport_stmt: TOK_MODPORT TOK_ID { - AstNode* modport = extra->pushChild(std::make_unique(AST_MODPORT)); + AstNode* modport = extra->pushChild(std::make_unique(@$, AST_MODPORT)); modport->str = *$2; } modport_args_opt { @@ -2527,7 +2521,7 @@ modport_arg: modport_member: TOK_ID { - AstNode* modport_member = extra->saveChild(std::make_unique(AST_MODPORTMEMBER)); + AstNode* modport_member = extra->saveChild(std::make_unique(@$, AST_MODPORTMEMBER)); modport_member->str = *$1; modport_member->is_input = extra->current_modport_input; modport_member->is_output = extra->current_modport_output; @@ -2542,7 +2536,7 @@ assert: if (mode->noassert) { } else { - AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_ASSUME : AST_ASSERT, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, mode->assume_asserts ? AST_ASSUME : AST_ASSERT, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) node->str = *$1; @@ -2551,7 +2545,7 @@ assert: opt_sva_label TOK_ASSUME opt_property TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { if (mode->noassume) { } else { - AstNode* node = extra->saveChild(std::make_unique(mode->assert_assumes ? AST_ASSERT : AST_ASSUME, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, mode->assert_assumes ? AST_ASSERT : AST_ASSUME, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) node->str = *$1; @@ -2560,7 +2554,7 @@ assert: opt_sva_label TOK_ASSERT opt_property TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { if (mode->noassert) { } else { - AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_FAIR : AST_LIVE, std::move($6))); + AstNode* node = extra->saveChild(std::make_unique(@$, mode->assume_asserts ? AST_FAIR : AST_LIVE, std::move($6))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @7); if ($1 != nullptr) node->str = *$1; @@ -2569,28 +2563,28 @@ assert: opt_sva_label TOK_ASSUME opt_property TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { if (mode->noassume) { } else { - AstNode* node = extra->saveChild(std::make_unique(mode->assert_assumes ? AST_LIVE : AST_FAIR, std::move($6))); + AstNode* node = extra->saveChild(std::make_unique(@$, mode->assert_assumes ? AST_LIVE : AST_FAIR, std::move($6))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @7); if ($1 != nullptr) node->str = *$1; } } | opt_sva_label TOK_COVER opt_property TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(AST_COVER, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_COVER, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) { node->str = *$1; } } | opt_sva_label TOK_COVER opt_property TOK_LPAREN TOK_RPAREN TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(AST_COVER, AstNode::mkconst_int(1, false))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_COVER, AstNode::mkconst_int(@$, 1, false))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @5); if ($1 != nullptr) { node->str = *$1; } } | opt_sva_label TOK_COVER TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(AST_COVER, AstNode::mkconst_int(1, false))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_COVER, AstNode::mkconst_int(@$, 1, false))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @2); if ($1 != nullptr) { node->str = *$1; @@ -2599,57 +2593,57 @@ assert: opt_sva_label TOK_RESTRICT opt_property TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { if (mode->norestrict) { } else { - AstNode* node = extra->saveChild(std::make_unique(AST_ASSUME, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_ASSUME, std::move($5))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6); if ($1 != nullptr) node->str = *$1; } if (!$3) - log_file_warning(current_filename, @$.begin.line, "SystemVerilog does not allow \"restrict\" without \"property\".\n"); + err_at_loc(@$, "SystemVerilog does not allow \"restrict\" without \"property\".\n"); } | opt_sva_label TOK_RESTRICT opt_property TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { if (mode->norestrict) { } else { - AstNode* node = extra->saveChild(std::make_unique(AST_FAIR, std::move($6))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_FAIR, std::move($6))); SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @7); if ($1 != nullptr) node->str = *$1; } if (!$3) - log_file_warning(current_filename, @$.begin.line, "SystemVerilog does not allow \"restrict\" without \"property\".\n"); + err_at_loc(@$, "SystemVerilog does not allow \"restrict\" without \"property\".\n"); }; assert_property: opt_sva_label TOK_ASSERT TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_ASSUME : AST_ASSERT, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, mode->assume_asserts ? AST_ASSUME : AST_ASSERT, std::move($5))); SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) { extra->ast_stack.back()->children.back()->str = *$1; } } | opt_sva_label TOK_ASSUME TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(AST_ASSUME, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_ASSUME, std::move($5))); SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) { extra->ast_stack.back()->children.back()->str = *$1; } } | opt_sva_label TOK_ASSERT TOK_PROPERTY TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(mode->assume_asserts ? AST_FAIR : AST_LIVE, std::move($6))); + AstNode* node = extra->saveChild(std::make_unique(@$, mode->assume_asserts ? AST_FAIR : AST_LIVE, std::move($6))); SET_AST_NODE_LOC(node, @1, @7); if ($1 != nullptr) { extra->ast_stack.back()->children.back()->str = *$1; } } | opt_sva_label TOK_ASSUME TOK_PROPERTY TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(AST_FAIR, std::move($6))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_FAIR, std::move($6))); SET_AST_NODE_LOC(node, @1, @7); if ($1 != nullptr) { extra->ast_stack.back()->children.back()->str = *$1; } } | opt_sva_label TOK_COVER TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { - AstNode* node = extra->saveChild(std::make_unique(AST_COVER, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_COVER, std::move($5))); SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) { extra->ast_stack.back()->children.back()->str = *$1; @@ -2658,7 +2652,7 @@ assert_property: opt_sva_label TOK_RESTRICT TOK_PROPERTY TOK_LPAREN expr TOK_RPAREN TOK_SEMICOL { if (mode->norestrict) { } else { - AstNode* node = extra->saveChild(std::make_unique(AST_ASSUME, std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_ASSUME, std::move($5))); SET_AST_NODE_LOC(node, @1, @6); if ($1 != nullptr) { extra->ast_stack.back()->children.back()->str = *$1; @@ -2668,7 +2662,7 @@ assert_property: opt_sva_label TOK_RESTRICT TOK_PROPERTY TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { if (mode->norestrict) { } else { - AstNode* node = extra->saveChild(std::make_unique(AST_FAIR, std::move($6))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_FAIR, std::move($6))); SET_AST_NODE_LOC(node, @1, @7); if ($1 != nullptr) { extra->ast_stack.back()->children.back()->str = *$1; @@ -2678,23 +2672,23 @@ assert_property: simple_behavioral_stmt: attr lvalue TOK_EQ delay expr { - AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN_EQ, std::move($2), std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_ASSIGN_EQ, std::move($2), std::move($5))); SET_AST_NODE_LOC(node, @2, @5); append_attr(node, $1); } | attr lvalue attr inc_or_dec_op { - extra->addIncOrDecStmt($1, std::move($2), $3, $4, @1, @4); + extra->addIncOrDecStmt($1, std::move($2), $3, $4, location_range(@1, @4)); } | attr inc_or_dec_op attr lvalue { - extra->addIncOrDecStmt($1, std::move($4), $3, $2, @1, @4); + extra->addIncOrDecStmt($1, std::move($4), $3, $2, location_range(@1, @4)); } | attr lvalue OP_LE delay expr { - AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN_LE, std::move($2), std::move($5))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_ASSIGN_LE, std::move($2), std::move($5))); SET_AST_NODE_LOC(node, @2, @5); append_attr(node, $1); } | attr lvalue asgn_binop delay expr { - (void)extra->addAsgnBinopStmt($1, std::move($2), $3, std::move($5), @2, @5); + (void)extra->addAsgnBinopStmt($1, std::move($2), $3, std::move($5)); }; asgn_binop: @@ -2719,9 +2713,9 @@ inc_or_dec_op: for_initialization: TOK_ID TOK_EQ expr { - auto ident = std::make_unique(AST_IDENTIFIER); + auto ident = std::make_unique(@$, AST_IDENTIFIER); ident->str = *$1; - auto node = std::make_unique(AST_ASSIGN_EQ, std::move(ident), std::move($3)); + auto node = std::make_unique(@$, AST_ASSIGN_EQ, std::move(ident), std::move($3)); SET_AST_NODE_LOC(node.get(), @1, @3); extra->ast_stack.back()->children.push_back(std::move(node)); } | @@ -2740,7 +2734,7 @@ for_initialization: if (range != nullptr) wire->children.push_back(std::move(range)); - auto ident = std::make_unique(AST_IDENTIFIER); + auto ident = std::make_unique(@$, AST_IDENTIFIER); ident->str = *$3; wire->str = *$3; @@ -2750,13 +2744,13 @@ for_initialization: // loop variable initialization SET_AST_NODE_LOC(ident.get(), @3, @3); - auto asgn = std::make_unique(AST_ASSIGN_EQ, std::move(ident), std::move($5)); + auto asgn = std::make_unique(@$, AST_ASSIGN_EQ, std::move(ident), std::move($5)); SET_AST_NODE_LOC(asgn.get(), @3, @5); loop->children.push_back(std::move(asgn)); // inject a wrapping block to declare the loop variable and // contain the current loop - auto wrapper = std::make_unique(AST_BLOCK); + auto wrapper = std::make_unique(@$, AST_BLOCK); wrapper->str = "$fordecl_block$" + std::to_string(autoidx++); wrapper->children.push_back(std::move(wire)); wrapper->children.push_back(std::move(loop)); @@ -2772,7 +2766,7 @@ behavioral_stmt: free_attr($1); } | attr hierarchical_id { - AstNode* node = extra->pushChild(std::make_unique(AST_TCALL)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_TCALL)); node->str = *$2; append_attr(node, $1); } opt_arg_list TOK_SEMICOL{ @@ -2780,7 +2774,7 @@ behavioral_stmt: extra->ast_stack.pop_back(); } | attr TOK_MSG_TASKS { - AstNode* node = extra->pushChild(std::make_unique(AST_TCALL)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_TCALL)); node->str = *$2; append_attr(node, $1); } opt_arg_list TOK_SEMICOL{ @@ -2790,7 +2784,7 @@ behavioral_stmt: attr TOK_BEGIN { extra->enterTypeScope(); } opt_label { - AstNode* node = extra->pushChild(std::make_unique(AST_BLOCK)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_BLOCK)); append_attr(node, $1); if ($4 != nullptr) node->str = *$4; @@ -2811,12 +2805,12 @@ behavioral_stmt: extra->ast_stack.pop_back(); } | attr TOK_FOR TOK_LPAREN { - AstNode* node = extra->pushChild(std::make_unique(AST_FOR)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_FOR)); append_attr(node, $1); } for_initialization TOK_SEMICOL expr { extra->ast_stack.back()->children.push_back(std::move($7)); } TOK_SEMICOL simple_behavioral_stmt TOK_RPAREN { - AstNode* block = extra->pushChild(std::make_unique(AST_BLOCK)); + AstNode* block = extra->pushChild(std::make_unique(@$, AST_BLOCK)); block->str = "$for_loop$" + std::to_string(autoidx++); } behavioral_stmt { SET_AST_NODE_LOC(extra->ast_stack.back(), @13, @13); @@ -2825,9 +2819,9 @@ behavioral_stmt: extra->ast_stack.pop_back(); } | attr TOK_WHILE TOK_LPAREN expr TOK_RPAREN { - AstNode* node = extra->pushChild(std::make_unique(AST_WHILE)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_WHILE)); append_attr(node, $1); - auto block_owned = std::make_unique(AST_BLOCK); + auto block_owned = std::make_unique(@$, AST_BLOCK); auto* block = block_owned.get(); extra->ast_stack.back()->children.push_back(std::move($4)); extra->ast_stack.back()->children.push_back(std::move(block_owned)); @@ -2838,9 +2832,9 @@ behavioral_stmt: extra->ast_stack.pop_back(); } | attr TOK_REPEAT TOK_LPAREN expr TOK_RPAREN { - AstNode* node = extra->pushChild(std::make_unique(AST_REPEAT)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_REPEAT)); append_attr(node, $1); - auto block_owned = std::make_unique(AST_BLOCK); + auto block_owned = std::make_unique(@$, AST_BLOCK); auto* block = block_owned.get(); extra->ast_stack.back()->children.push_back(std::move($4)); extra->ast_stack.back()->children.push_back(std::move(block_owned)); @@ -2867,22 +2861,22 @@ behavioral_stmt: // we have to undangle it from the stack patch_block_on_stack = true; } else if (outer->get_bool_attribute(ID::full_case)) - (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); + (*$1)[ID::full_case] = AstNode::mkconst_int(@$, 1, false); } - auto expr = std::make_unique(AST_REDUCE_BOOL, std::move($4)); + auto expr = std::make_unique(@$, AST_REDUCE_BOOL, std::move($4)); if (!node) { // not parallel "else if": begin new construction - node_owned = std::make_unique(AST_CASE); + node_owned = std::make_unique(@$, AST_CASE); node = node_owned.get(); append_attr(node, $1); - node->children.push_back(node->get_bool_attribute(ID::parallel_case) ? AstNode::mkconst_int(1, false, 1) : expr->clone()); + node->children.push_back(node->get_bool_attribute(ID::parallel_case) ? AstNode::mkconst_int(@$, 1, false, 1) : expr->clone()); extra->ast_stack.back()->children.push_back(std::move(node_owned)); } else { free_attr($1); } - auto block_owned = std::make_unique(AST_BLOCK); + auto block_owned = std::make_unique(@$, AST_BLOCK); auto* block = block_owned.get(); - auto cond_owned = std::make_unique(AST_COND, node->get_bool_attribute(ID::parallel_case) ? std::move(expr) : AstNode::mkconst_int(1, false, 1), std::move(block_owned)); + auto cond_owned = std::make_unique(@$, AST_COND, node->get_bool_attribute(ID::parallel_case) ? std::move(expr) : AstNode::mkconst_int(@$, 1, false, 1), std::move(block_owned)); SET_AST_NODE_LOC(cond_owned.get(), @4, @4); node->children.push_back(std::move(cond_owned)); // Double it and give it to the next person @@ -2898,7 +2892,7 @@ behavioral_stmt: extra->ast_stack.pop_back(); } | case_attr case_type TOK_LPAREN expr TOK_RPAREN { - AstNode* node = extra->pushChild(std::make_unique(AST_CASE, std::move($4))); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_CASE, std::move($4))); append_attr(node, $1); SET_AST_NODE_LOC(extra->ast_stack.back(), @4, @4); } opt_synopsys_attr case_body TOK_ENDCASE { @@ -2915,22 +2909,22 @@ if_attr: AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) err_at_loc(@2, "unique0 keyword cannot be used for 'else if' branch."); - (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); + (*$1)[ID::parallel_case] = AstNode::mkconst_int(@$, 1, false); $$ = $1; } | attr TOK_PRIORITY { AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) err_at_loc(@2, "priority keyword cannot be used for 'else if' branch."); - (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); + (*$1)[ID::full_case] = AstNode::mkconst_int(@$, 1, false); $$ = $1; } | attr TOK_UNIQUE { AstNode *context = extra->ast_stack.back(); if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) err_at_loc(@2, "unique keyword cannot be used for 'else if' branch."); - (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); - (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); + (*$1)[ID::full_case] = AstNode::mkconst_int(@$, 1, false); + (*$1)[ID::parallel_case] = AstNode::mkconst_int(@$, 1, false); $$ = $1; }; @@ -2939,16 +2933,16 @@ case_attr: $$ = $1; } | attr TOK_UNIQUE0 { - (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); + (*$1)[ID::parallel_case] = AstNode::mkconst_int(@$, 1, false); $$ = $1; } | attr TOK_PRIORITY { - (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); + (*$1)[ID::full_case] = AstNode::mkconst_int(@$, 1, false); $$ = $1; } | attr TOK_UNIQUE { - (*$1)[ID::full_case] = AstNode::mkconst_int(1, false); - (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); + (*$1)[ID::full_case] = AstNode::mkconst_int(@$, 1, false); + (*$1)[ID::parallel_case] = AstNode::mkconst_int(@$, 1, false); $$ = $1; }; @@ -2966,11 +2960,11 @@ case_type: opt_synopsys_attr: opt_synopsys_attr TOK_SYNOPSYS_FULL_CASE { if (extra->ast_stack.back()->attributes.count(ID::full_case) == 0) - extra->ast_stack.back()->attributes[ID::full_case] = AstNode::mkconst_int(1, false); + extra->ast_stack.back()->attributes[ID::full_case] = AstNode::mkconst_int(@$, 1, false); } | opt_synopsys_attr TOK_SYNOPSYS_PARALLEL_CASE { if (extra->ast_stack.back()->attributes.count(ID::parallel_case) == 0) - extra->ast_stack.back()->attributes[ID::parallel_case] = AstNode::mkconst_int(1, false); + extra->ast_stack.back()->attributes[ID::parallel_case] = AstNode::mkconst_int(@$, 1, false); } | %empty; @@ -2981,12 +2975,12 @@ behavioral_stmt_list: optional_else: TOK_ELSE { extra->ast_stack.pop_back(); - auto block_owned = std::make_unique(AST_BLOCK); + auto block_owned = std::make_unique(@$, AST_BLOCK); auto* block = block_owned.get(); - block->attributes[ID::promoted_if] = AstNode::mkconst_int(1, false); + block->attributes[ID::promoted_if] = AstNode::mkconst_int(@$, 1, false); AstNode* cond = extra->saveChild( - std::make_unique(AST_COND, - std::make_unique(AST_DEFAULT), + std::make_unique(@$, AST_COND, + std::make_unique(@$, AST_DEFAULT), std::move(block_owned))); extra->ast_stack.push_back(block); SET_AST_NODE_LOC(cond, @1, @1); @@ -3002,10 +2996,11 @@ case_body: case_item: { (void)extra->pushChild(std::make_unique( + @$, extra->case_type_stack.size() && extra->case_type_stack.back() == 'x' ? AST_CONDX : extra->case_type_stack.size() && extra->case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND)); } case_select { - (void)extra->pushChild(std::make_unique(AST_BLOCK)); + (void)extra->pushChild(std::make_unique(@$, AST_BLOCK)); extra->case_type_stack.push_back(0); } behavioral_stmt { extra->case_type_stack.pop_back(); @@ -3021,6 +3016,7 @@ gen_case_body: gen_case_item: { (void)extra->pushChild(std::make_unique( + @$, extra->case_type_stack.size() && extra->case_type_stack.back() == 'x' ? AST_CONDX : extra->case_type_stack.size() && extra->case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND)); } case_select { @@ -3037,11 +3033,11 @@ case_select: case_expr_list: TOK_DEFAULT { - AstNode* node = extra->saveChild(std::make_unique(AST_DEFAULT)); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_DEFAULT)); SET_AST_NODE_LOC(node, @1, @1); } | TOK_SVA_LABEL { - AstNode* node = extra->pushChild(std::make_unique(AST_IDENTIFIER)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_IDENTIFIER)); SET_AST_NODE_LOC(node, @1, @1); } | expr { @@ -3053,12 +3049,12 @@ case_expr_list: rvalue: hierarchical_id TOK_LBRA expr TOK_RBRA TOK_DOT rvalue { - $$ = std::make_unique(AST_PREFIX, std::move($3), std::move($6)); + $$ = std::make_unique(@$, AST_PREFIX, std::move($3), std::move($6)); $$->str = *$1; SET_AST_NODE_LOC($$.get(), @1, @6); } | hierarchical_id range { - $$ = std::make_unique(AST_IDENTIFIER, std::move($2)); + $$ = std::make_unique(@$, AST_IDENTIFIER, std::move($2)); $$->str = *$1; SET_AST_NODE_LOC($$.get(), @1, @1); if ($2 == nullptr && ($$->str == "\\$initstate" || @@ -3067,7 +3063,7 @@ rvalue: $$->type = AST_FCALL; } | hierarchical_id non_opt_multirange { - $$ = std::make_unique(AST_IDENTIFIER, std::move($2)); + $$ = std::make_unique(@$, AST_IDENTIFIER, std::move($2)); $$->str = *$1; SET_AST_NODE_LOC($$.get(), @1, @1); }; @@ -3082,7 +3078,7 @@ lvalue: lvalue_concat_list: expr { - $$ = std::make_unique(AST_CONCAT); + $$ = std::make_unique(@$, AST_CONCAT); $$->children.push_back(std::move($1)); } | expr TOK_COMMA lvalue_concat_list { @@ -3120,7 +3116,7 @@ gen_stmt_or_module_body_stmt: genvar_identifier: TOK_ID { - $$ = std::make_unique(AST_IDENTIFIER); + $$ = std::make_unique(@$, AST_IDENTIFIER); $$->str = *$1; }; @@ -3131,7 +3127,7 @@ genvar_initialization: TOK_GENVAR genvar_identifier TOK_EQ expr { if (!mode->sv) err_at_loc(@3, "Generate for loop inline variable declaration is only supported in SystemVerilog mode!"); - AstNode* node = extra->saveChild(std::make_unique(AST_GENVAR)); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_GENVAR)); node->is_reg = true; node->is_signed = true; node->range_left = 31; @@ -3139,18 +3135,18 @@ genvar_initialization: node->str = $2->str; node->children.push_back(checkRange(node, nullptr)); SET_AST_NODE_LOC(node, @1, @4); - node = extra->saveChild(std::make_unique(AST_ASSIGN_EQ, std::move($2), std::move($4))); + node = extra->saveChild(std::make_unique(@$, AST_ASSIGN_EQ, std::move($2), std::move($4))); SET_AST_NODE_LOC(node, @1, @4); } | genvar_identifier TOK_EQ expr { - AstNode* node = extra->saveChild(std::make_unique(AST_ASSIGN_EQ, std::move($1), std::move($3))); + AstNode* node = extra->saveChild(std::make_unique(@$, AST_ASSIGN_EQ, std::move($1), std::move($3))); SET_AST_NODE_LOC(node, @1, @3); }; // this production creates the obligatory if-else shift/reduce conflict gen_stmt: TOK_FOR TOK_LPAREN { - (void)extra->pushChild(std::make_unique(AST_GENFOR)); + (void)extra->pushChild(std::make_unique(@$, AST_GENFOR)); } genvar_initialization TOK_SEMICOL expr { extra->ast_stack.back()->children.push_back(std::move($6)); } TOK_SEMICOL simple_behavioral_stmt TOK_RPAREN gen_stmt_block { @@ -3159,21 +3155,21 @@ gen_stmt: extra->ast_stack.pop_back(); } | TOK_IF TOK_LPAREN expr TOK_RPAREN { - (void)extra->pushChild(std::make_unique(AST_GENIF)); + (void)extra->pushChild(std::make_unique(@$, AST_GENIF)); extra->ast_stack.back()->children.push_back(std::move($3)); } gen_stmt_block opt_gen_else { SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @7); extra->ast_stack.pop_back(); } | case_type TOK_LPAREN expr TOK_RPAREN { - (void)extra->pushChild(std::make_unique(AST_GENCASE, std::move($3))); + (void)extra->pushChild(std::make_unique(@$, AST_GENCASE, std::move($3))); } gen_case_body TOK_ENDCASE { extra->case_type_stack.pop_back(); SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @7); extra->ast_stack.pop_back(); } | TOK_MSG_TASKS { - AstNode* node = extra->pushChild(std::make_unique(AST_TECALL)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_TECALL)); node->str = *$1; } opt_arg_list TOK_SEMICOL{ SET_AST_NODE_LOC(extra->ast_stack.back(), @1, @3); @@ -3184,7 +3180,7 @@ gen_block: TOK_BEGIN { extra->enterTypeScope(); } opt_label { - AstNode* node = extra->pushChild(std::make_unique(AST_GENBLOCK)); + AstNode* node = extra->pushChild(std::make_unique(@$, AST_GENBLOCK)); node->str = $3 ? *$3 : std::string(); } module_gen_body TOK_END opt_label { extra->exitTypeScope(); @@ -3196,7 +3192,7 @@ gen_block: // result is wrapped in a genblock only if necessary gen_stmt_block: { - (void)extra->pushChild(std::make_unique(AST_GENBLOCK)); + (void)extra->pushChild(std::make_unique(@$, AST_GENBLOCK)); } gen_stmt_or_module_body_stmt { SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @2); extra->ast_stack.pop_back(); @@ -3210,7 +3206,7 @@ expr: $$ = std::move($1); } | basic_expr TOK_QUE attr expr TOK_COL expr { - $$ = std::make_unique(AST_TERNARY); + $$ = std::make_unique(@$, AST_TERNARY); $$->children.push_back(std::move($1)); $$->children.push_back(std::move($4)); $$->children.push_back(std::move($6)); @@ -3218,12 +3214,12 @@ expr: append_attr($$.get(), $3); } | inc_or_dec_op attr rvalue { - $$ = extra->addIncOrDecExpr(std::move($3), $2, $1, @1, @3, false, mode->sv); + $$ = extra->addIncOrDecExpr(std::move($3), $2, $1, location_range(@1, @3), false, mode->sv); } | // TODO: Attributes are allowed in the middle here, but they create some // non-trivial conflicts that don't seem worth solving for now. rvalue inc_or_dec_op { - $$ = extra->addIncOrDecExpr(std::move($1), nullptr, $2, @1, @2, true, mode->sv); + $$ = extra->addIncOrDecExpr(std::move($1), nullptr, $2, location_range(@1, @2), true, mode->sv); }; basic_expr: @@ -3237,12 +3233,12 @@ basic_expr: 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)); + $$ = std::make_unique(@$, AST_TO_BITS, std::move($2), std::move(val)); } | hierarchical_id integral_number { if ($2->compare(0, 1, "'") != 0) err_at_loc(@2, "Cast operation must be applied on sized constants, e.g. \'d0, while %s is not a sized constant.", $2->c_str()); - auto bits = std::make_unique(AST_IDENTIFIER); + auto bits = std::make_unique(@$, AST_IDENTIFIER); bits->str = *$1; SET_AST_NODE_LOC(bits.get(), @1, @1); auto p = make_ConstParser_here(@2); @@ -3250,7 +3246,7 @@ basic_expr: 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)); + $$ = std::make_unique(@$, AST_TO_BITS, std::move(bits), std::move(val)); } | integral_number { auto p = make_ConstParser_here(@1); @@ -3260,7 +3256,7 @@ basic_expr: log_error("Value conversion failed: `%s'\n", $1->c_str()); } | TOK_REALVAL { - $$ = std::make_unique(AST_REALVALUE); + $$ = std::make_unique(@$, AST_REALVALUE); char *p = (char*)malloc(GetSize(*$1) + 1), *q; for (int i = 0, j = 0; j < GetSize(*$1); j++) if ((*$1)[j] != '_') @@ -3271,12 +3267,12 @@ basic_expr: free(p); } | TOK_STRING { - $$ = AstNode::mkconst_str(*$1); + $$ = AstNode::mkconst_str(@1, *$1); SET_AST_NODE_LOC($$.get(), @1, @1); } | hierarchical_id attr { // super sketchy! Orphaned pointer in non-owning extra->ast_stack - AstNode *node = new AstNode(AST_FCALL); + AstNode *node = new AstNode(@1, AST_FCALL); node->str = *$1; extra->ast_stack.push_back(node); SET_AST_NODE_LOC(node, @1, @1); @@ -3286,11 +3282,11 @@ basic_expr: extra->ast_stack.pop_back(); } | TOK_TO_SIGNED attr TOK_LPAREN expr TOK_RPAREN { - $$ = std::make_unique(AST_TO_SIGNED, std::move($4)); + $$ = std::make_unique(@$, AST_TO_SIGNED, std::move($4)); append_attr($$.get(), $2); } | TOK_TO_UNSIGNED attr TOK_LPAREN expr TOK_RPAREN { - $$ = std::make_unique(AST_TO_UNSIGNED, std::move($4)); + $$ = std::make_unique(@$, AST_TO_UNSIGNED, std::move($4)); append_attr($$.get(), $2); } | TOK_LPAREN expr TOK_RPAREN { @@ -3303,230 +3299,230 @@ basic_expr: $$ = std::move($2); } | TOK_LCURL expr TOK_LCURL concat_list TOK_RCURL TOK_RCURL { - $$ = std::make_unique(AST_REPLICATE, std::move($2), std::move($4)); + $$ = std::make_unique(@$, AST_REPLICATE, std::move($2), std::move($4)); } | TOK_TILDE attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_BIT_NOT, std::move($3)); + $$ = std::make_unique(@$, AST_BIT_NOT, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); } | basic_expr TOK_AMP attr basic_expr { - $$ = std::make_unique(AST_BIT_AND, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_BIT_AND, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_NAND attr basic_expr { - $$ = std::make_unique(AST_BIT_NOT, std::make_unique(AST_BIT_AND, std::move($1), std::move($4))); + $$ = std::make_unique(@$, AST_BIT_NOT, std::make_unique(@$, AST_BIT_AND, std::move($1), std::move($4))); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_PIPE attr basic_expr { - $$ = std::make_unique(AST_BIT_OR, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_BIT_OR, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_NOR attr basic_expr { - $$ = std::make_unique(AST_BIT_NOT, std::make_unique(AST_BIT_OR, std::move($1), std::move($4))); + $$ = std::make_unique(@$, AST_BIT_NOT, std::make_unique(@$, AST_BIT_OR, std::move($1), std::move($4))); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_CARET attr basic_expr { - $$ = std::make_unique(AST_BIT_XOR, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_BIT_XOR, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_XNOR attr basic_expr { - $$ = std::make_unique(AST_BIT_XNOR, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_BIT_XNOR, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | TOK_AMP attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_REDUCE_AND, std::move($3)); + $$ = std::make_unique(@$, AST_REDUCE_AND, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); } | OP_NAND attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_REDUCE_AND, std::move($3)); + $$ = std::make_unique(@$, AST_REDUCE_AND, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); - $$ = std::make_unique(AST_LOGIC_NOT, std::move($$)); + $$ = std::make_unique(@$, AST_LOGIC_NOT, std::move($$)); } | TOK_PIPE attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_REDUCE_OR, std::move($3)); + $$ = std::make_unique(@$, AST_REDUCE_OR, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), std::move($2)); } | OP_NOR attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_REDUCE_OR, std::move($3)); + $$ = std::make_unique(@$, AST_REDUCE_OR, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); - $$ = std::make_unique(AST_LOGIC_NOT, std::move($$)); + $$ = std::make_unique(@$, AST_LOGIC_NOT, std::move($$)); SET_AST_NODE_LOC($$.get(), @1, @3); } | TOK_CARET attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_REDUCE_XOR, std::move($3)); + $$ = std::make_unique(@$, AST_REDUCE_XOR, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); } | OP_XNOR attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_REDUCE_XNOR, std::move($3)); + $$ = std::make_unique(@$, AST_REDUCE_XNOR, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); } | basic_expr OP_SHL attr basic_expr { - $$ = std::make_unique(AST_SHIFT_LEFT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + $$ = std::make_unique(@$, AST_SHIFT_LEFT, std::move($1), std::make_unique(@$, AST_TO_UNSIGNED, std::move($4))); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_SHR attr basic_expr { - $$ = std::make_unique(AST_SHIFT_RIGHT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + $$ = std::make_unique(@$, AST_SHIFT_RIGHT, std::move($1), std::make_unique(@$, AST_TO_UNSIGNED, std::move($4))); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_SSHL attr basic_expr { - $$ = std::make_unique(AST_SHIFT_SLEFT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + $$ = std::make_unique(@$, AST_SHIFT_SLEFT, std::move($1), std::make_unique(@$, AST_TO_UNSIGNED, std::move($4))); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_SSHR attr basic_expr { - $$ = std::make_unique(AST_SHIFT_SRIGHT, std::move($1), std::make_unique(AST_TO_UNSIGNED, std::move($4))); + $$ = std::make_unique(@$, AST_SHIFT_SRIGHT, std::move($1), std::make_unique(@$, AST_TO_UNSIGNED, std::move($4))); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_LT attr basic_expr { - $$ = std::make_unique(AST_LT, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_LT, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_LE attr basic_expr { - $$ = std::make_unique(AST_LE, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_LE, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_EQ attr basic_expr { - $$ = std::make_unique(AST_EQ, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_EQ, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_NE attr basic_expr { - $$ = std::make_unique(AST_NE, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_NE, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_EQX attr basic_expr { - $$ = std::make_unique(AST_EQX, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_EQX, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_NEX attr basic_expr { - $$ = std::make_unique(AST_NEX, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_NEX, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_GE attr basic_expr { - $$ = std::make_unique(AST_GE, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_GE, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_GT attr basic_expr { - $$ = std::make_unique(AST_GT, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_GT, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_PLUS attr basic_expr { - $$ = std::make_unique(AST_ADD, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_ADD, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_MINUS attr basic_expr { - $$ = std::make_unique(AST_SUB, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_SUB, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_ASTER attr basic_expr { - $$ = std::make_unique(AST_MUL, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_MUL, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_SLASH attr basic_expr { - $$ = std::make_unique(AST_DIV, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_DIV, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr TOK_PERC attr basic_expr { - $$ = std::make_unique(AST_MOD, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_MOD, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_POW attr basic_expr { - $$ = std::make_unique(AST_POW, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_POW, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | TOK_PLUS attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_POS, std::move($3)); + $$ = std::make_unique(@$, AST_POS, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); } | TOK_MINUS attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_NEG, std::move($3)); + $$ = std::make_unique(@$, AST_NEG, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); } | basic_expr OP_LAND attr basic_expr { - $$ = std::make_unique(AST_LOGIC_AND, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_LOGIC_AND, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | basic_expr OP_LOR attr basic_expr { - $$ = std::make_unique(AST_LOGIC_OR, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_LOGIC_OR, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); append_attr($$.get(), $3); } | TOK_EXCL attr basic_expr %prec UNARY_OPS { - $$ = std::make_unique(AST_LOGIC_NOT, std::move($3)); + $$ = std::make_unique(@$, AST_LOGIC_NOT, std::move($3)); SET_AST_NODE_LOC($$.get(), @1, @3); append_attr($$.get(), $2); } | TOK_SIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); - $$ = std::make_unique(AST_TO_SIGNED, std::move($4)); + $$ = std::make_unique(@$, AST_TO_SIGNED, std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | TOK_UNSIGNED OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); - $$ = std::make_unique(AST_TO_UNSIGNED, std::move($4)); + $$ = std::make_unique(@$, AST_TO_UNSIGNED, std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | basic_expr OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); - $$ = std::make_unique(AST_CAST_SIZE, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_CAST_SIZE, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | typedef_base_type OP_CAST TOK_LPAREN expr TOK_RPAREN { if (!mode->sv) err_at_loc(@2, "Static cast is only supported in SystemVerilog mode."); - $$ = std::make_unique(AST_CAST_SIZE, std::move($1), std::move($4)); + $$ = std::make_unique(@$, AST_CAST_SIZE, std::move($1), std::move($4)); SET_AST_NODE_LOC($$.get(), @1, @4); } | TOK_LPAREN expr TOK_EQ expr TOK_RPAREN { extra->ensureAsgnExprAllowed(@3, mode->sv); $$ = $2->clone(); - auto node = std::make_unique(AST_ASSIGN_EQ, std::move($2), std::move($4)); + auto node = std::make_unique(@$, AST_ASSIGN_EQ, std::move($2), std::move($4)); SET_AST_NODE_LOC(node.get(), @2, @4); extra->ast_stack.back()->children.push_back(std::move(node)); } | TOK_LPAREN expr asgn_binop expr TOK_RPAREN { extra->ensureAsgnExprAllowed(@3, mode->sv); - $$ = extra->addAsgnBinopStmt(nullptr, std::move($2), $3, std::move($4), @2, @4)-> clone(); + $$ = extra->addAsgnBinopStmt(nullptr, std::move($2), $3, std::move($4))-> clone(); }; concat_list: expr { - $$ = std::make_unique(AST_CONCAT, std::move($1)); + $$ = std::make_unique(@$, AST_CONCAT, std::move($1)); } | expr TOK_COMMA concat_list { $$ = std::move($3); diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 941a7ba3a..fd67b7404 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5710,7 +5710,7 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri { cover("kernel.rtlil.sigspec.parse"); - AST::current_filename = "input"; + // AST::current_filename = "input"; std::vector tokens; sigspec_parse_split(tokens, str, ','); @@ -5726,7 +5726,7 @@ 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"); - VERILOG_FRONTEND::ConstParser p; + VERILOG_FRONTEND::ConstParser p{location()}; auto ast = p.const2ast(netname); if (ast == nullptr) return false; From 87352f97b22da3bd184b0502e2d68a607e3cc8fe Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 24 Jun 2025 22:14:30 +0200 Subject: [PATCH 038/176] fixup! ast, read_verilog: unify location types, reduce filename copying --- frontends/verilog/verilog_error.cc | 54 ++++++++++++++++ frontends/verilog/verilog_error.h | 25 ++++++++ frontends/verilog/verilog_location.h | 96 ++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 frontends/verilog/verilog_error.cc create mode 100644 frontends/verilog/verilog_error.h create mode 100644 frontends/verilog/verilog_location.h diff --git a/frontends/verilog/verilog_error.cc b/frontends/verilog/verilog_error.cc new file mode 100644 index 000000000..410a13580 --- /dev/null +++ b/frontends/verilog/verilog_error.cc @@ -0,0 +1,54 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * + * 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 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * --- + * + */ + +#include "kernel/yosys_common.h" +#include "frontends/verilog/verilog_error.h" +#include "frontends/verilog/verilog_location.h" + +USING_YOSYS_NAMESPACE + +[[noreturn]] +static void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap) +{ + char buffer[1024]; + char *p = buffer; + p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap); + p += snprintf(p, buffer + sizeof(buffer) - p, "\n"); + YOSYS_NAMESPACE_PREFIX log_file_error(filename, begin_line, "%s", buffer); + exit(1); +} + +void VERILOG_FRONTEND::err_at_ast(AST::AstSrcLocType loc, char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + verr_at(*loc.begin.filename, loc.begin.line, fmt, args); + va_end(args); +} + +[[noreturn]] +void VERILOG_FRONTEND::err_at_loc(location loc, char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + verr_at(loc.begin.filename ? *(loc.begin.filename) : "UNKNOWN", loc.begin.line, fmt, args); +} + diff --git a/frontends/verilog/verilog_error.h b/frontends/verilog/verilog_error.h new file mode 100644 index 000000000..4cb65164b --- /dev/null +++ b/frontends/verilog/verilog_error.h @@ -0,0 +1,25 @@ +#ifndef VERILOG_ERROR_H +#define VERILOG_ERROR_H + +#include "kernel/yosys_common.h" +#include "frontends/ast/ast.h" +#include "frontends/verilog/verilog_location.h" + +#if ! defined(yyFlexLexerOnce) +#define yyFlexLexer frontend_verilog_yyFlexLexer +#include +#endif + +YOSYS_NAMESPACE_BEGIN + +namespace VERILOG_FRONTEND +{ + [[noreturn]] + void err_at_ast(AST::AstSrcLocType loc, char const *fmt, ...); + [[noreturn]] + void err_at_loc(location loc, char const *fmt, ...); +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/frontends/verilog/verilog_location.h b/frontends/verilog/verilog_location.h new file mode 100644 index 000000000..d2ef8e94c --- /dev/null +++ b/frontends/verilog/verilog_location.h @@ -0,0 +1,96 @@ +#ifndef VERILOG_LOCATION_H +#define VERILOG_LOCATION_H + +#include +#include +#include +#include + +/** + * Provide frontend-wide location tracking like what bison generates + * but using shared_ptr for filename + */ + +struct position { + std::shared_ptr filename; + int line; + int column; + + position(std::shared_ptr filename, int line = 1, int column = 1) + : filename(filename), line(line), column(column) {} + position() = default; + position(const position& other) = default; + position& operator=(const position& other) = default; + + void advance() { ++column; } + void columns(int count = 1) { + column += count; + } + + void lines(int count = 1) { + line += count; + column = 1; + } + std::string to_string() const { + std::ostringstream oss; + if (filename && !filename->empty()) { + oss << *filename << ":"; + } + oss << line << ":" << column; + return oss.str(); + } +}; + +struct location { + position begin; + position end; + + location() = default; + location(const position& b, const position& e) + : begin(b), end(e) {} + location(const location& other) = default; + location& operator=(const location& other) = default; + + void step() { begin = end; } + + void columns(int count = 1) { + end.columns(count); + } + + void lines(int count = 1) { + end.lines(count); + } + std::string to_string() const { + std::ostringstream oss; + bool same_file = (!begin.filename && !end.filename) || + (begin.filename && end.filename && + *begin.filename == *end.filename); + + if (same_file) { + if (begin.filename && !begin.filename->empty()) + oss << *begin.filename << ":"; + + if (begin.line == end.line) { + if (begin.column == end.column) { + oss << begin.line << ":" << begin.column; + } else { + oss << begin.line << ":" << begin.column + << "-" << end.column; + } + } else { + oss << begin.line << ":" << begin.column + << "-" << end.line << ":" << end.column; + } + } else { + oss << begin.to_string() << "-" << end.to_string(); + } + + return oss.str(); + } +}; + +static inline std::ostream& operator<<(std::ostream& os, const location& loc) { + return os << loc.to_string(); +} + +#endif From 27899180a339dc0d0f88a26439d6776fbf02f73d Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 24 Jun 2025 22:45:59 +0200 Subject: [PATCH 039/176] fixup! fixup! ast, read_verilog: unify location types, reduce filename copying --- frontends/verilog/verilog_frontend.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index e97cee4fc..eabc0d46b 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -32,11 +32,6 @@ #include "kernel/yosys.h" #include "frontends/ast/ast.h" -#if ! defined(yyFlexLexerOnce) -#define yyFlexLexer frontend_verilog_yyFlexLexer -#include -#endif - #include #include From 2b7b09b81adf0e1989f6f117cd5a9e30122636ee Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 25 Jun 2025 10:23:44 +1200 Subject: [PATCH 040/176] Add libfl-dev Should fix the missing `` error. --- .github/actions/setup-build-env/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index dfdcd88c0..059287a63 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -8,7 +8,7 @@ runs: shell: bash run: | sudo apt-get update - sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev + sudo apt-get install gperf build-essential bison flex libfl-dev libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev - name: Install macOS Dependencies if: runner.os == 'macOS' From 8e89eab9a280cd3c179d3cc0a8d43e8113efc3db Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 25 Jun 2025 10:38:07 +1200 Subject: [PATCH 041/176] preproc depends on parser --- frontends/verilog/Makefile.inc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index a563c899c..838ee8c58 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -13,6 +13,8 @@ frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc frontends/verilog/verilog_frontend.h: frontends/verilog/verilog_parser.tab.hh frontends/verilog/verilog_error.h: frontends/verilog/verilog_parser.tab.hh +frontends/verilog/preproc.o: frontends/verilog/verilog_parser.tab.hh + 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 $< From 69f2f3ca8122e1111953c72875ed5f17d8e8920e Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 25 Jun 2025 10:39:50 +1200 Subject: [PATCH 042/176] docs/verilog_frontend.rst: Fix indentation --- .../source/yosys_internals/flow/verilog_frontend.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/yosys_internals/flow/verilog_frontend.rst b/docs/source/yosys_internals/flow/verilog_frontend.rst index d6bdf6b6d..2a26daec3 100644 --- a/docs/source/yosys_internals/flow/verilog_frontend.rst +++ b/docs/source/yosys_internals/flow/verilog_frontend.rst @@ -187,13 +187,13 @@ simplifies the creation of AST nodes for simple expressions a bit. For example the bison code for parsing multiplications: .. code:: none - :number-lines: + :number-lines: - basic_expr TOK_ASTER attr basic_expr { - $$ = std::make_unique(AST_MUL, std::move($1), std::move($4)); - SET_AST_NODE_LOC($$.get(), @1, @4); - append_attr($$.get(), $3); - } | + basic_expr TOK_ASTER attr basic_expr { + $$ = std::make_unique(AST_MUL, std::move($1), std::move($4)); + SET_AST_NODE_LOC($$.get(), @1, @4); + append_attr($$.get(), $3); + } | The generated AST data structure is then passed directly to the AST frontend that performs the actual conversion to RTLIL. From d2573f168d0e94b12a17841935200847bcbae63d Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 25 Jun 2025 11:25:39 +1200 Subject: [PATCH 043/176] preproc.cc: Use full path for generated file Fixes out-of-tree builds. --- frontends/verilog/preproc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index d07e39189..b83fad7c3 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -34,7 +34,7 @@ #include "preproc.h" #include "verilog_frontend.h" -#include "verilog_parser.tab.hh" +#include "frontends/verilog/verilog_parser.tab.hh" #include "kernel/log.h" #include #include From f4016d96ccc74fc4e792b112656d1c84a8087e42 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 25 Jun 2025 11:32:46 +1200 Subject: [PATCH 044/176] Makefile: Add flex lib/include for brew --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 512c1410d..b0f565338 100644 --- a/Makefile +++ b/Makefile @@ -132,8 +132,8 @@ ifeq ($(ENABLE_PYOSYS),1) CXXFLAGS += -I$(BREW_PREFIX)/boost/include LINKFLAGS += -L$(BREW_PREFIX)/boost/lib -L$(BREW_PREFIX)/boost-python3/lib endif -CXXFLAGS += -I$(BREW_PREFIX)/readline/include -LINKFLAGS += -L$(BREW_PREFIX)/readline/lib +CXXFLAGS += -I$(BREW_PREFIX)/readline/include -I$(BREW_PREFIX)/flex/include +LINKFLAGS += -L$(BREW_PREFIX)/readline/lib -L$(BREW_PREFIX)/flex/lib PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH) PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH) export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH) From 0f7080ebf8cbccbbf8cd2a183498d7abf3849a42 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 25 Jun 2025 11:37:40 +1200 Subject: [PATCH 045/176] dpicall.cc: Fix sans-plugin function call --- frontends/ast/dpicall.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/ast/dpicall.cc b/frontends/ast/dpicall.cc index 07314e3d7..d76318739 100644 --- a/frontends/ast/dpicall.cc +++ b/frontends/ast/dpicall.cc @@ -153,7 +153,7 @@ YOSYS_NAMESPACE_END YOSYS_NAMESPACE_BEGIN -AST::AstNode *AST::dpi_call(AstSrcLocType loc, const std::string&, const std::string &fname, const std::vector&, const std::vector&) +std::unique_ptr AST::dpi_call(AstSrcLocType, const std::string&, const std::string &fname, const std::vector&, const std::vector>&) { log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str()); } From e6e680cd62cc75be9c6e1a7439473956bafdfd23 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 9 Jul 2025 14:34:03 +0200 Subject: [PATCH 046/176] readme, verilog_parser: bison 3.8 and ubuntu 22.04 example --- README.md | 2 +- frontends/verilog/verilog_parser.y | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e5b8d1072..96fd54a52 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make. TCL, readline and libffi are optional (see ``ENABLE_*`` settings in Makefile). Xdot (graphviz) is used by the ``show`` command in yosys to display schematics. -For example on Ubuntu Linux 16.04 LTS the following commands will install all +For example on Ubuntu Linux 22.04 LTS the following commands will install all prerequisites for building yosys: $ sudo apt-get install build-essential clang lld bison flex \ diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 743061ae5..8192c0eb4 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -33,7 +33,7 @@ * */ -%require "3.0" +%require "3.8" %language "c++" %define api.value.type variant %define api.prefix {frontend_verilog_yy} From 42b5c14e359d538e5b3b7f0f6d9547abc6d536a6 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 9 Jul 2025 15:24:34 +0200 Subject: [PATCH 047/176] read_verilog, ast: use unified locations in errors and simplify dependencies --- frontends/verilog/.gitignore | 1 - frontends/verilog/Makefile.inc | 6 ++---- frontends/verilog/verilog_error.cc | 14 ++++++-------- frontends/verilog/verilog_error.h | 7 ------- frontends/verilog/verilog_frontend.cc | 2 +- frontends/verilog/verilog_lexer.h | 5 +++++ frontends/verilog/verilog_parser.y | 4 ++-- 7 files changed, 16 insertions(+), 23 deletions(-) diff --git a/frontends/verilog/.gitignore b/frontends/verilog/.gitignore index cb6775cbc..aadbcdcdd 100644 --- a/frontends/verilog/.gitignore +++ b/frontends/verilog/.gitignore @@ -2,4 +2,3 @@ verilog_lexer.cc verilog_parser.output verilog_parser.tab.cc verilog_parser.tab.hh -stack.hh diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 838ee8c58..67e8074bf 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -3,18 +3,16 @@ GENFILES += frontends/verilog/verilog_parser.tab.cc GENFILES += frontends/verilog/verilog_parser.tab.hh GENFILES += frontends/verilog/verilog_parser.output GENFILES += frontends/verilog/verilog_lexer.cc -GENFILES += frontends/verilog/stack.hh -frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y frontends/verilog/verilog_location.h +frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y $(Q) mkdir -p $(dir $@) $(P) $(BISON) -Wall -Werror -o $@ -d -r all -b frontends/verilog/verilog_parser $< frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc -frontends/verilog/verilog_frontend.h: frontends/verilog/verilog_parser.tab.hh -frontends/verilog/verilog_error.h: frontends/verilog/verilog_parser.tab.hh frontends/verilog/preproc.o: frontends/verilog/verilog_parser.tab.hh +frontends/verilog/verilog_lexer.h: frontends/verilog/verilog_parser.tab.hh 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_error.cc b/frontends/verilog/verilog_error.cc index 410a13580..4adfaafa6 100644 --- a/frontends/verilog/verilog_error.cc +++ b/frontends/verilog/verilog_error.cc @@ -25,6 +25,12 @@ USING_YOSYS_NAMESPACE +/** + * Legacy behavior is to only track lines. Now we have columns too, but we don't + * report them in errors. + * TODO: report columns, too + */ + [[noreturn]] static void verr_at(std::string filename, int begin_line, char const *fmt, va_list ap) { @@ -36,14 +42,6 @@ static void verr_at(std::string filename, int begin_line, char const *fmt, va_li exit(1); } -void VERILOG_FRONTEND::err_at_ast(AST::AstSrcLocType loc, char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - verr_at(*loc.begin.filename, loc.begin.line, fmt, args); - va_end(args); -} - [[noreturn]] void VERILOG_FRONTEND::err_at_loc(location loc, char const *fmt, ...) { diff --git a/frontends/verilog/verilog_error.h b/frontends/verilog/verilog_error.h index 4cb65164b..2eeb4538e 100644 --- a/frontends/verilog/verilog_error.h +++ b/frontends/verilog/verilog_error.h @@ -5,17 +5,10 @@ #include "frontends/ast/ast.h" #include "frontends/verilog/verilog_location.h" -#if ! defined(yyFlexLexerOnce) -#define yyFlexLexer frontend_verilog_yyFlexLexer -#include -#endif - YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { - [[noreturn]] - void err_at_ast(AST::AstSrcLocType loc, char const *fmt, ...); [[noreturn]] void err_at_loc(location loc, char const *fmt, ...); }; diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 733ec8ba7..e7d34dac5 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -51,7 +51,7 @@ static std::list> verilog_defaults_stack; static void error_on_dpi_function(AST::AstNode *node) { if (node->type == AST::AST_DPI_FUNCTION) - err_at_ast(node->location, "Found DPI function %s.\n", node->str.c_str()); + err_at_loc(node->location, "Found DPI function %s.\n", node->str.c_str()); for (auto& child : node->children) error_on_dpi_function(child.get()); } diff --git a/frontends/verilog/verilog_lexer.h b/frontends/verilog/verilog_lexer.h index b7885181c..fe56b27d2 100644 --- a/frontends/verilog/verilog_lexer.h +++ b/frontends/verilog/verilog_lexer.h @@ -7,6 +7,11 @@ #include #include +#if ! defined(yyFlexLexerOnce) +#define yyFlexLexer frontend_verilog_yyFlexLexer +#include +#endif + YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 8192c0eb4..5f77e712f 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -200,7 +200,7 @@ if (type_node->range_left >= 0 && type_node->range_right >= 0) { // type already restricts the range if (range_node) { - err_at_ast(type_node->location, "integer/genvar types cannot have packed dimensions."); + err_at_loc(type_node->location, "integer/genvar types cannot have packed dimensions."); } else { range_node = makeRange(type_node->location, type_node->range_left, type_node->range_right, false); @@ -217,7 +217,7 @@ } } if (!valid) - err_at_ast(type_node->location, "wire/reg/logic packed dimension must be of the form [:]"); + err_at_loc(type_node->location, "wire/reg/logic packed dimension must be of the form [:]"); } return range_node; From 0a5aa4c78b6417c7cbd9e31564aadc8ffcf5a438 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 9 Jul 2025 16:11:10 +0200 Subject: [PATCH 048/176] docs: fix verilog frontend internals --- .../yosys_internals/flow/verilog_frontend.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/source/yosys_internals/flow/verilog_frontend.rst b/docs/source/yosys_internals/flow/verilog_frontend.rst index 2a26daec3..8381641b3 100644 --- a/docs/source/yosys_internals/flow/verilog_frontend.rst +++ b/docs/source/yosys_internals/flow/verilog_frontend.rst @@ -47,9 +47,9 @@ be found in :file:`frontends/verilog/verilog_lexer.l` in the Yosys source tree. The lexer does little more than identifying all keywords and literals recognised by the Yosys Verilog frontend. -The lexer keeps track of the current location in the Verilog source code using -some VerilogLexer member variables. These variables are used by the constructor of AST nodes -to annotate each node with the source code location it originated from. +The lexer keeps track of the current location in the Verilog source code with +a ``VerilogLexer::out_loc`` and uses it to construct parser-defined +symbol objects. Finally the lexer identifies and handles special comments such as "``// synopsys translate_off``" and "``// synopsys full_case``". (It is recommended to use @@ -178,11 +178,11 @@ properties: - | Source code location | Each ``AST::AstNode`` is automatically annotated with the current source - code location by the ``AST::AstNode`` constructor. It is stored in the - ``std::string filename`` and ``int linenum`` member variables. + code location by the ``AST::AstNode`` constructor. The ``location`` type + is a manual reimplementation of the bison-provided location type. This + type is defined at ``frontends/verilog/verilog_location.h``. -The ``AST::AstNode`` constructor can be called with up to two child nodes that -are automatically added to the list of child nodes for the new object. This +The ``AST::AstNode`` constructor can be called with up to 4 child nodes. This simplifies the creation of AST nodes for simple expressions a bit. For example the bison code for parsing multiplications: @@ -205,7 +205,7 @@ tree respectively. Transforming AST to RTLIL ------------------------- -The AST Frontend converts a set of modules in AST representation to modules in +The AST frontend converts a set of modules in AST representation to modules in RTLIL representation and adds them to the current design. This is done in two steps: simplification and RTLIL generation. From 105a3cd32d548e04089ac4cf1ec5449b3f25d0e3 Mon Sep 17 00:00:00 2001 From: garytwong Date: Thu, 19 Jun 2025 16:41:18 +0000 Subject: [PATCH 049/176] verilog: fix string literal regular expression (#5187) * verilog: fix string literal regular expression. A backslash was improperly quoted, causing string literal matching to fail when the final token before a closing quote was an escaped backslash. * verilog: add regression test for string literal regex bug. Test for bug triggered by escaped backslash immediately before closing quote (introduced in ca7d94af and fixed by 40aa7eaf). --- frontends/verilog/verilog_lexer.l | 2 +- tests/verilog/bug5160.v | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 tests/verilog/bug5160.v diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 84d5ce880..ee4611ceb 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -372,7 +372,7 @@ TIME_SCALE_SUFFIX [munpf]?s } \" { BEGIN(STRING); } -([^\"]|\\.)+ { yymore(); } +([^\\"]|\\.)+ { yymore(); } \" { BEGIN(0); char *yystr = strdup(YYText()); diff --git a/tests/verilog/bug5160.v b/tests/verilog/bug5160.v new file mode 100644 index 000000000..5b141a360 --- /dev/null +++ b/tests/verilog/bug5160.v @@ -0,0 +1,5 @@ +// Regression test for bug mentioned in #5160: +// https://github.com/YosysHQ/yosys/pull/5160#issuecomment-2983643084 +module top; + initial $display( "\\" ); +endmodule From 4ffd05af6fdf7c90ce544ded320822765a561465 Mon Sep 17 00:00:00 2001 From: Gary Wong Date: Thu, 3 Jul 2025 20:51:12 -0600 Subject: [PATCH 050/176] verilog: add support for SystemVerilog string literals. Differences are new escape sequences (including escaped newline continuations and hex escapes) and triple-quoted literals. --- docs/source/using_yosys/verilog.rst | 3 + frontends/verilog/verilog_lexer.l | 167 +++++++++++++----- tests/verilog/bug5160.v | 5 - tests/verilog/string-literals.ys | 257 ++++++++++++++++++++++++++++ 4 files changed, 385 insertions(+), 47 deletions(-) delete mode 100644 tests/verilog/bug5160.v create mode 100644 tests/verilog/string-literals.ys diff --git a/docs/source/using_yosys/verilog.rst b/docs/source/using_yosys/verilog.rst index eb18cb699..92f223e49 100644 --- a/docs/source/using_yosys/verilog.rst +++ b/docs/source/using_yosys/verilog.rst @@ -379,3 +379,6 @@ from SystemVerilog: will process conditionals using these keywords by annotating their representation with the appropriate ``full_case`` and/or ``parallel_case`` attributes, which are described above.) + +- SystemVerilog string literals are supported (triple-quoted strings and + escape sequences such as line continuations and hex escapes). diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index ee4611ceb..d6918d19c 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -154,11 +154,132 @@ parser::symbol_type char_tok(char c, parser::location_type loc) { return parser::make_ch_t(c, loc); } } +static bool is_hex_dig(char c, int *val, parser::location_type loc) +{ + if ('0' <= c && c <= '9') { + *val = c - '0'; + return true; + } else if ('a' <= c && c <= 'f') { + *val = c - 'a' + 0xA; + return true; + } else if ('A' <= c && c <= 'F') { + *val = c - 'A' + 0xA; + return true; + } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { + log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "'%c' not a valid digit in hex escape sequence.\n", c); + *val = 0; // not semantically valid in hex escape... + return true; // ...but still processed as part of hex token + } + + return false; +} + +static bool is_oct_dig(char c, int *val, parser::location_type loc) +{ + if ('0' <= c && c <= '7') { + *val = c - '0'; + return true; + } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { + log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "'%c' not a valid digit in octal escape sequence.\n", c); + *val = 0; // not semantically valid in octal escape... + return true; // ...but still processed as part of octal token + } + + return false; +} + +static parser::symbol_type process_str(char *str, int len, bool triple, parser::location_type loc) +{ + char *in, *out; // Overwrite input buffer: flex manual states "Actions + // are free to modify 'yytext' except for lengthening it". + + for (in = str, out = str; in < str + len; in++) + switch (*in) { + case '\n': + case '\r': + if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r')) + in++; + if (!triple) + log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "Multi-line string literals should be triple-quoted or escaped.\n"); + *out++ = '\n'; + break; + case '\\': + in++; + log_assert(in < str + len); + switch (*in) { + case 'a': + *out++ = '\a'; + break; + case 'f': + *out++ = '\f'; + break; + case 'n': + *out++ = '\n'; + break; + case 'r': /* not part of IEEE-1800 2023, but seems + like a good idea to support it anyway */ + *out++ = '\r'; + break; + case 't': + *out++ = '\t'; + break; + case 'v': + *out++ = '\v'; + break; + case 'x': + int val; + if (in + 1 < str + len && is_hex_dig(in[1], &val, loc)) { + *out = val; + in++; + if (in + 1 < str + len && is_hex_dig(in[1], &val, loc)) { + *out = *out * 0x10 + val; + in++; + } + out++; + } else + log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "ignoring invalid hex escape.\n"); + break; + case '\\': + *out++ = '\\'; + break; + case '"': + *out++ = '"'; + break; + case '\n': + case '\r': + if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r')) + in++; + break; + default: + if ('0' <= *in && *in <= '7') { + int val; + + *out = *in - '0'; + if (in + 1 < str + len && is_oct_dig(in[1], &val, loc)) { + *out = *out * 010 + val; + in++; + if (in + 1 < str + len && is_oct_dig(in[1], &val, loc)) { + if (*out >= 040) + log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "octal escape exceeds \\377\n"); + *out = *out * 010 + val; + in++; + } + } + out++; + } else + *out++ = *in; + } + break; + default: + *out++ = *in; + } + + return parser::make_TOK_STRING(std::make_unique(str, out - str), loc); +} %} %x COMMENT -%x STRING %x SYNOPSYS_TRANSLATE_OFF %x SYNOPSYS_FLAGS %x IMPORT_DPI @@ -371,47 +492,9 @@ TIME_SCALE_SUFFIX [munpf]?s return parser::make_TOK_REALVAL(std::move(val), out_loc); } -\" { BEGIN(STRING); } -([^\\"]|\\.)+ { yymore(); } -\" { - BEGIN(0); - char *yystr = strdup(YYText()); - yystr[strlen(YYText()) - 1] = 0; - int i = 0, j = 0; - while (yystr[i]) { - if (yystr[i] == '\\' && yystr[i + 1]) { - i++; - if (yystr[i] == 'a') - yystr[i] = '\a'; - else if (yystr[i] == 'f') - yystr[i] = '\f'; - else if (yystr[i] == 'n') - yystr[i] = '\n'; - else if (yystr[i] == 'r') - yystr[i] = '\r'; - else if (yystr[i] == 't') - yystr[i] = '\t'; - else if (yystr[i] == 'v') - yystr[i] = '\v'; - else if ('0' <= yystr[i] && yystr[i] <= '7') { - yystr[i] = yystr[i] - '0'; - if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { - yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; - i++; - } - if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { - yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; - i++; - } - } - } - yystr[j++] = yystr[i++]; - } - yystr[j] = 0; - string_t val = std::make_unique(yystr, j); - free(yystr); - return parser::make_TOK_STRING(std::move(val), out_loc); -} +\"([^\\"]|\\.|\\\n)*\" { return process_str(yytext + 1, yyleng - 2, false, out_loc); } + +\"{3}(\"{0,2}([^\\"]|\\.|\\\n))*\"{3} { return process_str(yytext + 3, yyleng - 6, true, out_loc); } and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 { auto val = std::make_unique(YYText()); diff --git a/tests/verilog/bug5160.v b/tests/verilog/bug5160.v deleted file mode 100644 index 5b141a360..000000000 --- a/tests/verilog/bug5160.v +++ /dev/null @@ -1,5 +0,0 @@ -// Regression test for bug mentioned in #5160: -// https://github.com/YosysHQ/yosys/pull/5160#issuecomment-2983643084 -module top; - initial $display( "\\" ); -endmodule diff --git a/tests/verilog/string-literals.ys b/tests/verilog/string-literals.ys new file mode 100644 index 000000000..a0f0f0460 --- /dev/null +++ b/tests/verilog/string-literals.ys @@ -0,0 +1,257 @@ +# Test valid escape sequences yield correct results: +logger -expect-no-warnings +read_verilog << EOF +module top; + wire[7:0] sp = "\ "; + wire[7:0] spval = 32; + wire[7:0] ex = "\!"; + wire[7:0] exval = 33; + wire[7:0] dq = "\""; + wire[7:0] dqval = 34; + wire[7:0] ha = "\#"; + wire[7:0] haval = 35; + wire[7:0] do = "\$"; + wire[7:0] doval = 36; + wire[7:0] pc = "\%"; + wire[7:0] pcval = 37; + wire[7:0] am = "\&"; + wire[7:0] amval = 38; + wire[7:0] sq = "\'"; + wire[7:0] sqval = 39; + wire[7:0] op = "\("; + wire[7:0] opval = 40; + wire[7:0] cp = "\)"; + wire[7:0] cpval = 41; + wire[7:0] as = "\*"; + wire[7:0] asval = 42; + wire[7:0] pl = "\+"; + wire[7:0] plval = 43; + wire[7:0] co = "\,"; + wire[7:0] coval = 44; + wire[7:0] mi = "\-"; + wire[7:0] mival = 45; + wire[7:0] do = "\."; + wire[7:0] doval = 46; + wire[7:0] sl = "\/"; + wire[7:0] slval = 47; + + wire[7:0] dig0 = "\012"; + wire[7:0] dig0val = 10; + wire[7:0] dig8 = "\8"; // not octal, a literal '8' + wire[7:0] dig8val = 56; + wire[7:0] dig9 = "\9"; // not octal, a literal '9' + wire[7:0] dig9val = 57; + + wire[7:0] cl = "\:"; + wire[7:0] clval = 58; + wire[7:0] sc = "\;"; + wire[7:0] scval = 59; + wire[7:0] lt = "\<"; + wire[7:0] ltval = 60; + wire[7:0] eq = "\="; + wire[7:0] eqval = 61; + wire[7:0] gt = "\>"; + wire[7:0] gtval = 62; + wire[7:0] qu = "\?"; + wire[7:0] quval = 63; + wire[7:0] at = "\@"; + wire[7:0] atval = 64; + + wire[7:0] A = "\A"; + wire[7:0] Aval = 65; // etc. etc. + + wire[7:0] os = "\["; + wire[7:0] osval = 91; + wire[7:0] bs = "\\"; + wire[7:0] bsval = 92; + wire[7:0] cs = "\]"; + wire[7:0] csval = 93; + wire[7:0] ca = "\^"; + wire[7:0] caval = 94; + wire[7:0] us = "\_"; + wire[7:0] usval = 95; + wire[7:0] bq = "\`"; + wire[7:0] bqval = 96; + + wire[7:0] a = "\a"; // alert, ASCII BEL=7 + wire[7:0] aval = 7; + wire[7:0] b = "\b"; + wire[7:0] bval = 98; + wire[7:0] c = "\c"; + wire[7:0] cval = 99; + wire[7:0] d = "\d"; + wire[7:0] dval = 100; + wire[7:0] e = "\e"; + wire[7:0] eval = 101; + wire[7:0] f = "\f"; // form feed, ASCII FF=12 + wire[7:0] fval = 12; + wire[7:0] g = "\g"; + wire[7:0] gval = 103; + wire[7:0] h = "\h"; + wire[7:0] hval = 104; + wire[7:0] i = "\i"; + wire[7:0] ival = 105; + wire[7:0] j = "\j"; + wire[7:0] jval = 106; + wire[7:0] k = "\k"; + wire[7:0] kval = 107; + wire[7:0] l = "\l"; + wire[7:0] lval = 108; + wire[7:0] m = "\m"; + wire[7:0] mval = 109; + wire[7:0] n = "\n"; // new line, ASCII LF=10 + wire[7:0] nval = 10; + wire[7:0] o = "\o"; + wire[7:0] oval = 111; + wire[7:0] p = "\p"; + wire[7:0] pval = 112; + wire[7:0] q = "\q"; + wire[7:0] qval = 113; + wire[7:0] r = "\r"; // carriage return, ASCII CR=13, not IEEE 1800-2023 + wire[7:0] rval = 13; + wire[7:0] s = "\s"; + wire[7:0] sval = 115; + wire[7:0] t = "\t"; // tab, ASCII HT=9 + wire[7:0] tval = 9; + wire[7:0] u = "\u"; + wire[7:0] uval = 117; + wire[7:0] v = "\v"; // vertical tab, ASCII VT=11 + wire[7:0] vval = 11; + wire[7:0] w = "\w"; + wire[7:0] wval = 119; + wire[7:0] x = "\x2A"; // hex escape + wire[7:0] xval = 42; + wire[7:0] y = "\y"; + wire[7:0] yval = 121; + wire[7:0] z = "\z"; + wire[7:0] zval = 122; + + wire[7:0] ob = "\{"; + wire[7:0] obval = 123; + wire[7:0] vb = "\|"; + wire[7:0] vbval = 124; + wire[7:0] cb = "\}"; + wire[7:0] cbval = 125; + wire[7:0] ti = "\~"; + wire[7:0] tival = 126; +endmodule +EOF +sat -prove sp spval -prove ex exval -prove dq dqval -prove ha haval -prove do doval -prove pc pcval -prove am amval -prove sq sqval -prove op opval -prove cp cpval -prove as asval -prove pl plval -prove co coval -prove mi mival -prove do doval -prove sl slval -verify +sat -prove dig0 dig0val -prove dig8 dig8val -prove dig9 dig9val -verify +sat -prove cl clval -prove sc scval -prove lt ltval -prove eq eqval -prove gt gtval -prove qu quval -prove at atval -prove A Aval -verify +sat -prove os osval -prove bs bsval -prove cs csval -prove ca caval -prove us usval -prove bq bqval -verify +sat -prove a aval -prove b bval -prove c cval -prove d dval -prove e eval -prove f fval -prove g gval -prove h hval -prove i ival -prove j jval -prove k kval -prove l lval -prove m mval -prove n nval -prove o oval -prove p pval -prove q qval -prove r rval -prove s sval -prove t tval -prove u uval -prove v vval -prove w wval -prove x xval -prove y yval -prove z zval -verify +sat -prove ob obval -prove vb vbval -prove cb cbval -prove ti tival -verify +logger -check-expected +design -reset + +# Test octal escape out of range. +logger -expect warning "octal escape exceeds \\377" 1 +read_verilog << EOF +module top; + wire[7:0] x = "\400"; +endmodule +EOF +logger -check-expected +design -reset + +# Test invalid octal digit. +logger -expect warning "'\?' not a valid digit in octal escape sequence" 1 +read_verilog << EOF +module top; + wire[7:0] x = "\0?"; +endmodule +EOF +logger -check-expected +design -reset + +# Test invalid hex digit. +logger -expect warning "'X' not a valid digit in hex escape sequence" 1 +read_verilog << EOF +module top; + wire[7:0] x = "\x0X"; +endmodule +EOF +logger -check-expected +design -reset + +# Test hex escape with no hex digits at all. +logger -expect warning "ignoring invalid hex escape" 1 +read_verilog << EOF +module top; + wire[7:0] x = "\xy"; +endmodule +EOF +logger -check-expected +design -reset + +# Test hex escape interrupted by end of string. +logger -expect warning "ignoring invalid hex escape" 1 +read_verilog << EOF +module top; + wire[7:0] x = "\x"; +endmodule +EOF +logger -check-expected +design -reset + +# Test multi-line string. +logger -expect warning "Multi-line string literals should be triple-quoted or escaped" 1 +read_verilog << EOF +module top; + wire[31:0] x = "A +BC"; + wire[31:0] xval = 32'h410A4243; +endmodule +EOF +logger -check-expected +design -reset + +# Test multi-line triple-quoted string. +logger -expect-no-warnings +read_verilog << EOF +module top; + wire[31:0] x = """A +BC"""; + wire[31:0] xval = 32'h410A4243; +endmodule +EOF +logger -check-expected +sat -prove x xval -verify +design -reset + +# Test escaped multi-line string. +logger -expect-no-warnings +read_verilog << EOF +module top; + wire[31:0] x = "AB\ +CD"; + wire[31:0] xval = 32'h41424344; +endmodule +EOF +logger -check-expected +sat -prove x xval -verify +design -reset + +# Test octal escape with surrounding data. +logger -expect-no-warnings +read_verilog << EOF +module top; + wire[31:0] x = "AB\234C"; + wire[31:0] xval = 32'h41429C43; +endmodule +EOF +logger -check-expected +sat -prove x xval -verify +design -reset + +# Test hex escape with surrounding data. +logger -expect-no-warnings +read_verilog << EOF +module top; + wire[31:0] x = "A\xBCDE"; + wire[31:0] xval = 32'h41BC4445; +endmodule +EOF +logger -check-expected +sat -prove x xval -verify From 85b5a7d08b9afbf7a944ab512a755323423924c0 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 10 Jul 2025 23:59:54 +0200 Subject: [PATCH 051/176] verilog: fix build dependency graph --- frontends/verilog/Makefile.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 67e8074bf..3f937f3c2 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -10,6 +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_frontend.o: frontends/verilog/verilog_parser.tab.hh frontends/verilog/preproc.o: frontends/verilog/verilog_parser.tab.hh frontends/verilog/verilog_lexer.h: frontends/verilog/verilog_parser.tab.hh From f3ebf0557e0c00a252e4cfbddc36e6911355a35a Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 14 Jul 2025 21:45:41 +0200 Subject: [PATCH 052/176] CI: sneak FlexLexer.h into the WASI sysroot --- .github/workflows/extra-builds.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 8d64b2e0e..36215454f 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -72,6 +72,7 @@ jobs: cat > build/Makefile.conf < Date: Mon, 14 Jul 2025 22:14:11 +0200 Subject: [PATCH 053/176] CI: bump flex and bison on Windows --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d81e340aa..502200e0d 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -79,7 +79,7 @@ jobs: - if: ${{ matrix.os.family == 'windows' }} name: "[Windows] Flex/Bison" run: | - choco install winflexbison3 + choco install winflexbison3 --source https://github.com/lexxmark/winflexbison/releases/download/v2.5.25/win_flex_bison-2.5.25.zip - if: ${{ matrix.os.family == 'macos' && matrix.os.archs == 'arm64' }} name: "[macOS/arm64] Install Python 3.8 (see: https://cibuildwheel.pypa.io/en/stable/faq/#macos-building-cpython-38-wheels-on-arm64)" uses: actions/setup-python@v5 From 0ce51029f6d6745529b2f8cfb80f909c76546fda Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 14 Jul 2025 22:16:46 +0200 Subject: [PATCH 054/176] fixup! CI: sneak FlexLexer.h into the WASI sysroot --- .github/workflows/extra-builds.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 36215454f..8959103ca 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -67,12 +67,12 @@ jobs: WASI_SDK=wasi-sdk-19.0 WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi + ln -s /usr/include/FlexLexer.h ${WASI_SDK}/share/wasi-sysroot/include/ mkdir -p build cat > build/Makefile.conf < Date: Thu, 17 Jul 2025 12:03:39 +0000 Subject: [PATCH 055/176] CI: install flex for WASI builds. --- .github/workflows/extra-builds.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 8959103ca..1891a4cc3 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -33,13 +33,13 @@ jobs: with: name: vcxsrc path: yosys-win32-vcxsrc-latest.zip - + vs-build: name: Visual Studio build runs-on: windows-latest needs: [vs-prep, pre_job] if: needs.pre_job.outputs.should_skip != 'true' - steps: + steps: - uses: actions/download-artifact@v4 with: name: vcxsrc @@ -67,11 +67,21 @@ jobs: WASI_SDK=wasi-sdk-19.0 WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi - ln -s /usr/include/FlexLexer.h ${WASI_SDK}/share/wasi-sysroot/include/ + + FLEX_VER=2.6.4 + FLEX=flex-${FLEX_VER} + FLEX_URL=https://github.com/westes/flex/releases/download/v${FLEX_VER}/${FLEX}.tar.gz + if ! [ -d ${FLEX} ]; then curl -L ${FLEX_URL} | tar xzf -; fi + + mkdir -p flex-build + (cd flex-build && + ../${FLEX}/configure --prefix=$(pwd)/../flex-prefix && + make && + make install) mkdir -p build cat > build/Makefile.conf < Date: Thu, 17 Jul 2025 12:15:47 +0000 Subject: [PATCH 056/176] CI: fix typo --- .github/workflows/extra-builds.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 1891a4cc3..8c8b892d0 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -81,7 +81,7 @@ jobs: mkdir -p build cat > build/Makefile.conf < Date: Wed, 16 Jul 2025 11:52:46 +1200 Subject: [PATCH 057/176] Sneak FlexLexer.h into VS build --- .github/workflows/extra-builds.yml | 1 + misc/create_vcxsrc.sh | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 8c8b892d0..458eb76a6 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -27,6 +27,7 @@ jobs: with: submodules: true persist-credentials: false + - run: sudo apt-get install libfl-dev - name: Build run: make vcxsrc YOSYS_VER=latest - uses: actions/upload-artifact@v4 diff --git a/misc/create_vcxsrc.sh b/misc/create_vcxsrc.sh index d7b516fd6..31bea8a36 100644 --- a/misc/create_vcxsrc.sh +++ b/misc/create_vcxsrc.sh @@ -20,6 +20,13 @@ mv zlib-1.2.11/* "$vcxsrc"/yosys/libs/zlib/. rm -rf zlib-1.2.11 pushd "$vcxsrc"/yosys ls libs/zlib/*.c | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' >> ../../srcfiles.txt + +if [ -f "/usr/include/FlexLexer.h" ] ; then + mkdir -p libs/flex + cp /usr/include/FlexLexer.h libs/flex/FlexLexer.h + ls libs/flex/*.h >> ../../srcfiles.txt +fi + popd { n=$(grep -B999 '' "$vcxsrc"/YosysVS/YosysVS.vcxproj | wc -l) From 1a63dd56bd649c4863427832e772ffa262709359 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 16 Jul 2025 13:48:31 +1200 Subject: [PATCH 058/176] Add flex lib to vcxsrc include dirs --- misc/create_vcxsrc.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/misc/create_vcxsrc.sh b/misc/create_vcxsrc.sh index 31bea8a36..d6800d15e 100644 --- a/misc/create_vcxsrc.sh +++ b/misc/create_vcxsrc.sh @@ -38,6 +38,9 @@ popd } > "$vcxsrc"/YosysVS/YosysVS.vcxproj.new sed -i 's,,\n stdcpp17\n /Zc:__cplusplus %(AdditionalOptions),g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new +if [ -f "/usr/include/FlexLexer.h" ] ; then + sed -i 's,,;..\\yosys\\libs\\flex,g' "$vcxsrc"/YosysVS/YosysVS.vcxproj.new +fi mv "$vcxsrc"/YosysVS/YosysVS.vcxproj.new "$vcxsrc"/YosysVS/YosysVS.vcxproj mkdir -p "$vcxsrc"/yosys From aedc237c7a4586a180672c953d339f0026452a60 Mon Sep 17 00:00:00 2001 From: Emil J Date: Sat, 19 Jul 2025 22:21:17 +0200 Subject: [PATCH 059/176] rtlil: remove comment Co-authored-by: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> --- kernel/rtlil.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index fd67b7404..1b133d9c1 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5710,7 +5710,6 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri { cover("kernel.rtlil.sigspec.parse"); - // AST::current_filename = "input"; std::vector tokens; sigspec_parse_split(tokens, str, ','); From cbccc01d38969e88ea4f6ce894bb88e4f1876075 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Sat, 19 Jul 2025 22:39:55 +0200 Subject: [PATCH 060/176] Revert "CI: bump flex and bison on Windows" This reverts commit efbc138ced04e2fc9cff67b8ca7a862cdd7b4278. --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 502200e0d..d81e340aa 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -79,7 +79,7 @@ jobs: - if: ${{ matrix.os.family == 'windows' }} name: "[Windows] Flex/Bison" run: | - choco install winflexbison3 --source https://github.com/lexxmark/winflexbison/releases/download/v2.5.25/win_flex_bison-2.5.25.zip + choco install winflexbison3 - if: ${{ matrix.os.family == 'macos' && matrix.os.archs == 'arm64' }} name: "[macOS/arm64] Install Python 3.8 (see: https://cibuildwheel.pypa.io/en/stable/faq/#macos-building-cpython-38-wheels-on-arm64)" uses: actions/setup-python@v5 From deedfbefe267adcfbfea483933aa3210e69402c1 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Sat, 19 Jul 2025 22:40:45 +0200 Subject: [PATCH 061/176] fixup! readme, verilog_parser: bison 3.8 and ubuntu 22.04 example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 96fd54a52..6118d6079 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ Xdot (graphviz) is used by the ``show`` command in yosys to display schematics. For example on Ubuntu Linux 22.04 LTS the following commands will install all prerequisites for building yosys: - $ sudo apt-get install build-essential clang lld bison flex \ + $ sudo apt-get install build-essential clang lld bison flex libfl-dev \ libreadline-dev gawk tcl-dev libffi-dev git \ graphviz xdot pkg-config python3 libboost-system-dev \ libboost-python-dev libboost-filesystem-dev zlib1g-dev From abb8b8d28b42d057c9cef3dc318e6f93d89f387b Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Sat, 19 Jul 2025 22:45:19 +0200 Subject: [PATCH 062/176] preproc: formatting --- frontends/verilog/preproc.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontends/verilog/preproc.h b/frontends/verilog/preproc.h index 51562787a..fd2e99f3d 100644 --- a/frontends/verilog/preproc.h +++ b/frontends/verilog/preproc.h @@ -73,12 +73,12 @@ struct define_map_t; std::string frontend_verilog_preproc(std::istream &f, - std::string filename, - const define_map_t &pre_defines, - define_map_t &global_defines_cache, - const std::list &include_dirs, - VERILOG_FRONTEND::ParseState &parse_state, - VERILOG_FRONTEND::ParseMode &parse_mode); + std::string filename, + const define_map_t &pre_defines, + define_map_t &global_defines_cache, + const std::list &include_dirs, + VERILOG_FRONTEND::ParseState &parse_state, + VERILOG_FRONTEND::ParseMode &parse_mode); YOSYS_NAMESPACE_END From 39c5c256c03682ad506fe48bc5b915c9c59f22fa Mon Sep 17 00:00:00 2001 From: Emil J Date: Sat, 19 Jul 2025 22:46:17 +0200 Subject: [PATCH 063/176] verilog_lexer: remove comment Co-authored-by: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> --- frontends/verilog/verilog_lexer.l | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index d6918d19c..7b42970c4 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -83,8 +83,6 @@ YOSYS_NAMESPACE_END string_t val = std::make_unique(std::string("\\") + YYText()); \ return parser::make_TOK_ID(std::move(val), out_loc); -// #define YY_INPUT(buf,result,max_size) \ -// result = readsome(*extra->lexin, buf, max_size) #define YY_USER_ACTION \ out_loc.step(); \ From ae65b4fc84951de9f9e13c3c64d666045ad96525 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Sat, 19 Jul 2025 22:53:02 +0200 Subject: [PATCH 064/176] verilog_lexer: fix fallthrough warning --- frontends/verilog/verilog_lexer.l | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 7b42970c4..893db9aae 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -67,7 +67,7 @@ YOSYS_NAMESPACE_BEGIN #define YY_DECL parser::symbol_type VerilogLexer::nextToken() #undef yyterminate -#define yyterminate() terminate() +#define yyterminate() return terminate() YOSYS_NAMESPACE_END From 9a10f4c02f61d5dbe49597bfd13bb6981d47775b Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Sat, 19 Jul 2025 22:56:48 +0200 Subject: [PATCH 065/176] verilog_lexer, verilog_parser: remove comment --- frontends/verilog/verilog_lexer.l | 2 -- frontends/verilog/verilog_parser.y | 9 --------- 2 files changed, 11 deletions(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 893db9aae..8280c0067 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -59,8 +59,6 @@ USING_YOSYS_NAMESPACE using namespace AST; using namespace VERILOG_FRONTEND; using parser = frontend_verilog_yy::parser; -//#define YYSTYPE FRONTEND_VERILOG_YYSTYPE -//#define YYLTYPE FRONTEND_VERILOG_YYLTYPE YOSYS_NAMESPACE_BEGIN #undef YY_DECL diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 5f77e712f..c59144bd0 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -49,7 +49,6 @@ #include "kernel/yosys_common.h" #include "frontends/verilog/verilog_error.h" #include "frontends/verilog/verilog_location.h" - // start requires YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { struct ParseState; @@ -57,11 +56,9 @@ class VerilogLexer; }; YOSYS_NAMESPACE_END - // end requires } %code provides { - // start provides USING_YOSYS_NAMESPACE; using namespace AST; using namespace VERILOG_FRONTEND; @@ -70,7 +67,6 @@ namespace VERILOG_FRONTEND { typedef std::map UserTypeMap; struct ParseState { - // TODO initialization? int port_counter; dict port_stubs; dict> *attr_list, default_attr_list; @@ -122,11 +118,9 @@ }; }; YOSYS_NAMESPACE_END - // end provides } %code { - // start unqual #include #include #include @@ -430,11 +424,9 @@ { err_at_loc(loc, "%s", msg.c_str()); } - // end unqual } %code requires { - // start requires #include #include #include @@ -480,7 +472,6 @@ using ch_t = char; using integer_t = int; using ast_node_type_t = YOSYS_NAMESPACE_PREFIX AST::AstNodeType; - // end requires } %token string_t "string" From 5b62616b63b93a78d260896df65e27054df18ac7 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Sat, 19 Jul 2025 22:57:53 +0200 Subject: [PATCH 066/176] preproc: formatting --- frontends/verilog/preproc.cc | 4 ++-- frontends/verilog/preproc.h | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index b83fad7c3..6dff1b6fc 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -751,8 +751,8 @@ frontend_verilog_preproc(std::istream &f, const define_map_t &pre_defines, define_map_t &global_defines_cache, const std::list &include_dirs, - ParseState &parse_state, - ParseMode &parse_mode) + ParseState &parse_state, + ParseMode &parse_mode) { define_map_t defines; defines.merge(pre_defines); diff --git a/frontends/verilog/preproc.h b/frontends/verilog/preproc.h index fd2e99f3d..8333f7661 100644 --- a/frontends/verilog/preproc.h +++ b/frontends/verilog/preproc.h @@ -73,12 +73,12 @@ struct define_map_t; std::string frontend_verilog_preproc(std::istream &f, - std::string filename, - const define_map_t &pre_defines, - define_map_t &global_defines_cache, - const std::list &include_dirs, - VERILOG_FRONTEND::ParseState &parse_state, - VERILOG_FRONTEND::ParseMode &parse_mode); + std::string filename, + const define_map_t &pre_defines, + define_map_t &global_defines_cache, + const std::list &include_dirs, + VERILOG_FRONTEND::ParseState &parse_state, + VERILOG_FRONTEND::ParseMode &parse_mode); YOSYS_NAMESPACE_END From 720f33271d505b6f0d4d7d9c25d9dca8da60c2b7 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 8 Aug 2025 14:00:53 +1200 Subject: [PATCH 067/176] docs: Update ubuntu apt-get Also mention CXXSTD fix for cygwin. --- docs/source/getting_started/installation.rst | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/source/getting_started/installation.rst b/docs/source/getting_started/installation.rst index fe96b2314..0ac85d199 100644 --- a/docs/source/getting_started/installation.rst +++ b/docs/source/getting_started/installation.rst @@ -88,18 +88,18 @@ Build prerequisites ^^^^^^^^^^^^^^^^^^^ A C++ compiler with C++17 support is required as well as some standard tools -such as GNU Flex, GNU Bison, Make and Python. Some additional tools: readline, -libffi, Tcl and zlib; are optional but enabled by default (see +such as GNU Flex, GNU Bison (>=3.8), Make, and Python (>=3.11). Some additional +tools: readline, libffi, Tcl and zlib; are optional but enabled by default (see :makevar:`ENABLE_*` settings in Makefile). Graphviz and Xdot are used by the `show` command to display schematics. -Installing all prerequisites for Ubuntu 20.04: +Installing all prerequisites for Ubuntu 22.04: .. code:: console - sudo apt-get install gperf build-essential bison flex \ - libreadline-dev gawk tcl-dev libffi-dev git graphviz \ - xdot pkg-config python3 libboost-system-dev \ + sudo apt-get install gperf build-essential clang lld bison flex libfl-dev \ + libreadline-dev gawk tcl-dev libffi-dev git \ + graphviz xdot pkg-config python3 libboost-system-dev \ libboost-python-dev libboost-filesystem-dev zlib1g-dev Installing all prerequisites for macOS 13 (with Homebrew): @@ -137,8 +137,9 @@ For Cygwin use the following command to install all prerequisites, or select the minimum required version of Python is 3.11. This means that Cygwin is not compatible with many of the Python-based frontends. While this does not currently prevent Yosys itself from working, no guarantees are made for - continued support. It is instead recommended to use Windows Subsystem for - Linux (WSL) and follow the instructions for Ubuntu. + continued support. You may also need to specify `CXXSTD=gnu++17` to resolve + missing `strdup` function when using gcc. It is instead recommended to use + Windows Subsystem for Linux (WSL) and follow the instructions for Ubuntu. .. For MSYS2 (MINGW64): From 9b882c32c1a34e02171949cce838813643f0440f Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 8 Aug 2025 17:10:16 +1200 Subject: [PATCH 068/176] frontends/ast: More usage of auto For consistency. --- frontends/ast/genrtlil.cc | 6 +++--- frontends/ast/simplify.cc | 28 ++++++++++++++-------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 93731abf0..0002f6308 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -2086,7 +2086,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) cell->set_bool_attribute(ID::module_not_derived); for (auto it = children.begin(); it != children.end(); it++) { - AstNode *child = it->get(); + auto* child = it->get(); if (child->type == AST_CELLTYPE) { cell->type = child->str; if (flag_icells && cell->type.begins_with("\\$")) @@ -2095,7 +2095,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } if (child->type == AST_PARASET) { IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; - const AstNode *value = child->children[0].get(); + const auto* value = child->children[0].get(); if (value->type == AST_REALVALUE) log_file_warning(*location.begin.filename, location.begin.line, "Replacing floating point parameter %s.%s = %f with string.\n", log_id(cell), log_id(paraname), value->realvalue); @@ -2108,7 +2108,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (child->type == AST_ARGUMENT) { RTLIL::SigSpec sig; if (child->children.size() > 0) { - AstNode *arg = child->children[0].get(); + auto* arg = child->children[0].get(); int local_width_hint = -1; bool local_sign_hint = false; // don't inadvertently attempt to detect the width of interfaces diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 8cacec275..0a43955a2 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -698,13 +698,13 @@ static bool contains_unbased_unsized(const AstNode *node) // dimensions of the given wire reference void add_wire_for_ref(location loc, const RTLIL::Wire *ref, const std::string &str) { - std::unique_ptr left = AstNode::mkconst_int(loc, ref->width - 1 + ref->start_offset, true); - std::unique_ptr right = AstNode::mkconst_int(loc, ref->start_offset, true); + auto left = AstNode::mkconst_int(loc, ref->width - 1 + ref->start_offset, true); + auto right = AstNode::mkconst_int(loc, ref->start_offset, true); if (ref->upto) std::swap(left, right); - std::unique_ptr range = std::make_unique(loc, AST_RANGE, std::move(left), std::move(right)); + auto range = std::make_unique(loc, AST_RANGE, std::move(left), std::move(right)); - std::unique_ptr wire = std::make_unique(loc, AST_WIRE, std::move(range)); + auto wire = std::make_unique(loc, AST_WIRE, std::move(range)); wire->is_signed = ref->is_signed; wire->is_logic = true; wire->str = str; @@ -821,8 +821,8 @@ static bool try_determine_range_width(AstNode *range, int &result_width) return true; } - std::unique_ptr left_at_zero_ast = range->children[0]->clone_at_zero(); - std::unique_ptr right_at_zero_ast = range->children[1]->clone_at_zero(); + auto left_at_zero_ast = range->children[0]->clone_at_zero(); + auto right_at_zero_ast = range->children[1]->clone_at_zero(); while (left_at_zero_ast->simplify(true, 1, -1, false)) {} while (right_at_zero_ast->simplify(true, 1, -1, false)) {} @@ -1575,7 +1575,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (children[0]->type == AST_WIRE) { int width = 1; std::unique_ptr node; - AstNode* child = children[0].get(); + auto* child = children[0].get(); if (child->children.size() == 0) { // Base type (e.g., int) width = child->range_left - child->range_right +1; @@ -1591,7 +1591,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (resolved_type_node->type != AST_TYPEDEF) input_error("`%s' does not name a type\n", type_name.c_str()); log_assert(resolved_type_node->children.size() == 1); - AstNode *template_node = resolved_type_node->children[0].get(); + auto* template_node = resolved_type_node->children[0].get(); // Ensure typedef itself is fully simplified while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; @@ -2048,7 +2048,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // Pretend it's just a wire in order to resolve the type in the code block above. AstNodeType param_type = type; type = AST_WIRE; - std::unique_ptr expr = std::move(children.front()); + auto expr = std::move(children.front()); children.erase(children.begin()); while (is_custom_type && simplify(const_fold, stage, width_hint, sign_hint)) {}; type = param_type; @@ -2130,13 +2130,13 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin range_right = children[0]->range_right; bool force_upto = false, force_downto = false; if (attributes.count(ID::force_upto)) { - AstNode *val = attributes[ID::force_upto].get(); + auto* val = attributes[ID::force_upto].get(); if (val->type != AST_CONSTANT) input_error("Attribute `force_upto' with non-constant value!\n"); force_upto = val->asAttrConst().as_bool(); } if (attributes.count(ID::force_downto)) { - AstNode *val = attributes[ID::force_downto].get(); + auto* val = attributes[ID::force_downto].get(); if (val->type != AST_CONSTANT) input_error("Attribute `force_downto' with non-constant value!\n"); force_downto = val->asAttrConst().as_bool(); @@ -3307,7 +3307,7 @@ skip_dynamic_range_lvalue_expansion:; } else { - std::unique_ptr& the_range = children[0]->children[1]; + auto& the_range = children[0]->children[1]; std::unique_ptr offset_ast; int width; @@ -5165,7 +5165,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, std::vector x_bits; for (int i = 0; i < width; i++) x_bits.push_back(RTLIL::State::Sx); - std::unique_ptr constant = AstNode::mkconst_bits(location, x_bits, false); + auto constant = AstNode::mkconst_bits(location, x_bits, false); constant->cloneInto(*this); } } @@ -5427,7 +5427,7 @@ std::unique_ptr AstNode::eval_const_function(AstNode *fcall, bool must_ while (!block->children.empty()) { // log("%zu left in block %p\n", block->children.size(), block.get()); - std::unique_ptr& stmt = block->children.front(); + auto& stmt = block->children.front(); #if 0 log("-----------------------------------\n"); From d3e33a3be52cdf7d603886d652f596ead6b8c95b Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 8 Aug 2025 17:14:31 +1200 Subject: [PATCH 069/176] simplify.cc: Drop unused debug prints At least the ones added by this PR. There are some unused debug prints that are *changed* by this PR, but I've left them. --- frontends/ast/simplify.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 0a43955a2..dc2ae1b31 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -5426,7 +5426,6 @@ std::unique_ptr AstNode::eval_const_function(AstNode *fcall, bool must_ while (!block->children.empty()) { - // log("%zu left in block %p\n", block->children.size(), block.get()); auto& stmt = block->children.front(); #if 0 @@ -5435,8 +5434,6 @@ std::unique_ptr AstNode::eval_const_function(AstNode *fcall, bool must_ log("%20s %40s\n", it.first.c_str(), log_signal(it.second.val)); stmt->dumpAst(nullptr, "stmt> "); #endif - // log("A\n"); - // log("%s\n", type2str(stmt->type).c_str()); if (stmt->type == AST_WIRE) { while (stmt->simplify(true, 1, -1, false)) { } From 97bc0088d824486ad1f4bb9ee647f3519cf02a3f Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 8 Aug 2025 12:31:13 +0200 Subject: [PATCH 070/176] simplify: std::gcd --- frontends/ast/simplify.cc | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index dc2ae1b31..d4191cef7 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -36,25 +36,13 @@ #include #include #include -// For std::gcd in C++17 -// #include +#include YOSYS_NAMESPACE_BEGIN using namespace AST; using namespace AST_INTERNAL; -// gcd computed by Euclidian division. -// To be replaced by C++17 std::gcd -template I gcd(I a, I b) { - while (b != 0) { - I tmp = b; - b = a%b; - a = tmp; - } - return std::abs(a); -} - void AstNode::set_in_lvalue_flag(bool flag, bool no_descend) { if (flag != in_lvalue_from_above) { @@ -3001,9 +2989,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // // long long is at least 64 bits in C++11 long long shift_mod = 1ll << (max_width - case_sign_hint); - // std::gcd requires C++17 - // bitno_div = std::gcd(stride, shift_mod); - bitno_div = gcd((long long)stride, shift_mod); + bitno_div = std::gcd((long long)stride, shift_mod); } } } From 25d2a8ce3a96a6e7f25fd883d846ea9b360c1eae Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 8 Aug 2025 12:31:40 +0200 Subject: [PATCH 071/176] simplify: simplify --- frontends/ast/genrtlil.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 0002f6308..b53fa7a44 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -2180,14 +2180,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // use ProcessGenerator for always blocks case AST_ALWAYS: { - auto always = this->clone(); - ProcessGenerator generator(std::move(always)); + ProcessGenerator generator(this->clone()); ignoreThisSignalsInInitial.append(generator.outputSignals); } break; case AST_INITIAL: { auto always = this->clone(); - ProcessGenerator generator(std::move(always), ignoreThisSignalsInInitial); + ProcessGenerator generator(this->clone(), ignoreThisSignalsInInitial); } break; case AST_TECALL: { From 646c45e6b89da4d2fc5d4f933b18962f3ad82af8 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 8 Aug 2025 12:32:43 +0200 Subject: [PATCH 072/176] ast: remove null_check as dead code --- frontends/ast/ast.h | 1 - frontends/ast/simplify.cc | 12 ------------ 2 files changed, 13 deletions(-) diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 6804c6a30..4baa2a3f6 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -260,7 +260,6 @@ namespace AST // simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc. // it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL() bool simplify(bool const_fold, int stage, int width_hint, bool sign_hint); - void null_check(); void replace_result_wire_name_in_function(const std::string &from, const std::string &to); std::unique_ptr readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init); void expand_genblock(const std::string &prefix); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index d4191cef7..e6954dbb9 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -888,16 +888,6 @@ static void check_auto_nosync(AstNode *node) check_auto_nosync(child.get()); } -void AstNode::null_check() -{ - for (auto& child : children) { - // if (!child) - // VALGRIND_PRINTF_BACKTRACE("null child"); - log_assert((bool) child); - child->null_check(); - } -} - // convert the AST into a simpler AST that has all parameters substituted by their // values, unrolled for-loops, expanded generate blocks, etc. when this function // is done with an AST it can be converted into RTLIL using genRTLIL(). @@ -906,7 +896,6 @@ void AstNode::null_check() // nodes that link to a different node using names and lexical scoping. bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hint) { - // null_check(); static int recursion_counter = 0; static bool deep_recursion_warning = false; @@ -4434,7 +4423,6 @@ apply_newNode: // dumpAst(stderr, "- "); // newNode->dumpAst(stderr, "+ "); log_assert(newNode != nullptr); - // newNode->null_check(); newNode->location.begin.filename = location.begin.filename; newNode->location = location; newNode->cloneInto(*this); From 740ed3fc1cf2dfc3a5dcfe01b23f5b049a4310a1 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 8 Aug 2025 13:00:39 +0200 Subject: [PATCH 073/176] ast: refactor --- frontends/ast/ast.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 09989e7ab..aba0ef5dd 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -191,11 +191,11 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id) if (attributes.count(id) == 0) return false; - AstNode& attr = *(attributes.at(id)); - if (attr.type != AST_CONSTANT) - attr.input_error("Attribute `%s' with non-constant value!\n", id.c_str()); + auto& attr = attributes.at(id); + if (attr->type != AST_CONSTANT) + attr->input_error("Attribute `%s' with non-constant value!\n", id.c_str()); - return attr.integer != 0; + return attr->integer != 0; } // create new node (AstNode constructor) @@ -1094,7 +1094,7 @@ void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast) obj->attributes[ID::src] = ast->loc_string(); } -static bool param_has_no_default(const std::unique_ptr ¶m) { +static bool param_has_no_default(const AstNode* param) { const auto &children = param->children; log_assert(param->type == AST_PARAMETER); log_assert(children.size() <= 2); @@ -1142,7 +1142,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d if (!defer) { for (auto& node : ast->children) - if (node->type == AST_PARAMETER && param_has_no_default(node)) + if (node->type == AST_PARAMETER && param_has_no_default(node.get())) node->input_error("Parameter `%s' has no default value and has not been overridden!\n", node->str.c_str()); bool blackbox_module = flag_lib; @@ -1430,7 +1430,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump bool defer_local = defer; if (!defer_local) for (const auto& node : child->children) - if (node->type == AST_PARAMETER && param_has_no_default(node)) + if (node->type == AST_PARAMETER && param_has_no_default(node.get())) { log("Deferring `%s' because it contains parameter(s) without defaults.\n", child->str.c_str()); defer_local = true; @@ -1850,7 +1850,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictchildren.insert(child->children.begin(), nullptr); if ((it->second.flags & RTLIL::CONST_FLAG_REAL) != 0) { child->children[0] = std::make_unique(loc, AST_REALVALUE); From df8422d24467743fec8d0ee40970d2a874a9e8dd Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 8 Aug 2025 13:00:51 +0200 Subject: [PATCH 074/176] verilog_lexer: refactor --- frontends/verilog/verilog_lexer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_lexer.h b/frontends/verilog/verilog_lexer.h index fe56b27d2..363c17b76 100644 --- a/frontends/verilog/verilog_lexer.h +++ b/frontends/verilog/verilog_lexer.h @@ -19,8 +19,8 @@ namespace VERILOG_FRONTEND { class VerilogLexer : public frontend_verilog_yyFlexLexer { ParseState* extra; ParseMode* mode; + parser::location_type out_loc; public: - parser::location_type out_loc; // TODO private? VerilogLexer(ParseState* e, ParseMode* m, std::shared_ptr filename) : frontend_verilog_yyFlexLexer(e->lexin), extra(e), mode(m) { out_loc.begin.filename = filename; } From 5195f812574fbc419a7556cb609d9be8e8ddbb17 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 8 Aug 2025 16:15:20 +0200 Subject: [PATCH 075/176] ast: fix import node --- frontends/ast/simplify.cc | 16 +++++++--------- frontends/verilog/verilog_parser.y | 7 +++---- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index e6954dbb9..c651553c4 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1089,7 +1089,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin // Process package imports after clearing the scope but before processing module declarations for (size_t i = 0; i < children.size(); i++) { - AstNode *child = children[i]; + AstNode *child = children[i].get(); if (child->type == AST_IMPORT) { // Find the package in the design AstNode *package_node = nullptr; @@ -1099,7 +1099,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin for (auto &design_child : current_ast->children) { if (design_child->type == AST_PACKAGE) { if (design_child->str == child->str) { - package_node = design_child; + package_node = design_child.get(); break; } } @@ -1115,7 +1115,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin package_name = package_name.substr(1); } if (package_name == child->str || design_package->str == child->str) { - package_node = design_package; + package_node = design_package.get(); break; } } @@ -1123,30 +1123,28 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin if (package_node) { // Import all names from the package into current scope - for (auto &pkg_child : package_node->children) { + for (auto& pkg_child : package_node->children) { if (pkg_child->type == AST_PARAMETER || pkg_child->type == AST_LOCALPARAM || pkg_child->type == AST_TYPEDEF || pkg_child->type == AST_FUNCTION || pkg_child->type == AST_TASK || pkg_child->type == AST_ENUM) { - current_scope[pkg_child->str] = pkg_child; + current_scope[pkg_child->str] = pkg_child.get(); } if (pkg_child->type == AST_ENUM) { - for (auto enode : pkg_child->children) { + for (auto& enode : pkg_child->children) { log_assert(enode->type==AST_ENUM_ITEM); if (current_scope.count(enode->str) == 0) - current_scope[enode->str] = enode; + current_scope[enode->str] = enode.get(); else input_error("enum item %s already exists in current scope\n", enode->str.c_str()); } } } // Remove the import node since it's been processed - delete child; children.erase(children.begin() + i); i--; // Adjust index since we removed an element } else { // If we can't find the package, just remove the import node to avoid errors later log_warning("Package `%s' not found for import, removing import statement\n", child->str.c_str()); - delete child; children.erase(children.begin() + i); i--; // Adjust index since we removed an element } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index c59144bd0..6762ada9e 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -831,12 +831,11 @@ package_body_stmt: typedef_decl | localparam_decl | param_decl | task_func_decl; import_stmt: - TOK_IMPORT hierarchical_id TOK_PACKAGESEP '*' ';' { + TOK_IMPORT hierarchical_id TOK_PACKAGESEP TOK_ASTER TOK_SEMICOL { // Create an import node to track package imports - AstNode *import_node = new AstNode(AST_IMPORT); + auto import_node = std::make_unique(@$, AST_IMPORT); import_node->str = *$2; - ast_stack.back()->children.push_back(import_node); - delete $2; + extra->ast_stack.back()->children.push_back(std::move(import_node)); }; interface: From 99ab73424d07ab36ad210f514cf6b44f45431f5b Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 8 Aug 2025 16:22:54 +0200 Subject: [PATCH 076/176] verilog_location: rename location to Location to avoid conflict with Pass::location --- frontends/ast/ast.h | 2 +- frontends/ast/simplify.cc | 2 +- frontends/verilog/verilog_error.cc | 2 +- frontends/verilog/verilog_error.h | 2 +- frontends/verilog/verilog_frontend.cc | 2 +- frontends/verilog/verilog_location.h | 26 +++++++++++++------------- frontends/verilog/verilog_parser.y | 22 +++++++++------------- kernel/rtlil.cc | 2 +- 8 files changed, 28 insertions(+), 32 deletions(-) diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 4baa2a3f6..fdf4d1ec9 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -164,7 +164,7 @@ namespace AST AST_BIND }; - using AstSrcLocType = location; + using AstSrcLocType = Location; // convert an node type to a string (e.g. for debug output) std::string type2str(AstNodeType type); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index c651553c4..c25d0183f 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -684,7 +684,7 @@ static bool contains_unbased_unsized(const AstNode *node) // adds a wire to the current module with the given name that matches the // dimensions of the given wire reference -void add_wire_for_ref(location loc, const RTLIL::Wire *ref, const std::string &str) +void add_wire_for_ref(Location loc, const RTLIL::Wire *ref, const std::string &str) { auto left = AstNode::mkconst_int(loc, ref->width - 1 + ref->start_offset, true); auto right = AstNode::mkconst_int(loc, ref->start_offset, true); diff --git a/frontends/verilog/verilog_error.cc b/frontends/verilog/verilog_error.cc index 4adfaafa6..19e634b5d 100644 --- a/frontends/verilog/verilog_error.cc +++ b/frontends/verilog/verilog_error.cc @@ -43,7 +43,7 @@ static void verr_at(std::string filename, int begin_line, char const *fmt, va_li } [[noreturn]] -void VERILOG_FRONTEND::err_at_loc(location loc, char const *fmt, ...) +void VERILOG_FRONTEND::err_at_loc(Location loc, char const *fmt, ...) { va_list args; va_start(args, fmt); diff --git a/frontends/verilog/verilog_error.h b/frontends/verilog/verilog_error.h index 2eeb4538e..07198a2ba 100644 --- a/frontends/verilog/verilog_error.h +++ b/frontends/verilog/verilog_error.h @@ -10,7 +10,7 @@ YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { [[noreturn]] - void err_at_loc(location loc, char const *fmt, ...); + void err_at_loc(Location loc, char const *fmt, ...); }; YOSYS_NAMESPACE_END diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index e7d34dac5..4b4f7ad8d 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -502,7 +502,7 @@ struct VerilogFrontend : public Frontend { } auto filename_shared = std::make_shared(filename); - auto top_loc = location(); + auto top_loc = Location(); top_loc.begin.filename = filename_shared; parse_state.current_ast = new AST::AstNode(top_loc, AST::AST_DESIGN); VerilogLexer lexer(&parse_state, &parse_mode, filename_shared); diff --git a/frontends/verilog/verilog_location.h b/frontends/verilog/verilog_location.h index d2ef8e94c..9b530fbeb 100644 --- a/frontends/verilog/verilog_location.h +++ b/frontends/verilog/verilog_location.h @@ -11,16 +11,16 @@ * but using shared_ptr for filename */ -struct position { +struct Position { std::shared_ptr filename; int line; int column; - position(std::shared_ptr filename, int line = 1, int column = 1) + Position(std::shared_ptr filename, int line = 1, int column = 1) : filename(filename), line(line), column(column) {} - position() = default; - position(const position& other) = default; - position& operator=(const position& other) = default; + Position() = default; + Position(const Position& other) = default; + Position& operator=(const Position& other) = default; void advance() { ++column; } void columns(int count = 1) { @@ -41,15 +41,15 @@ struct position { } }; -struct location { - position begin; - position end; +struct Location { + Position begin; + Position end; - location() = default; - location(const position& b, const position& e) + Location() = default; + Location(const Position& b, const Position& e) : begin(b), end(e) {} - location(const location& other) = default; - location& operator=(const location& other) = default; + Location(const Location& other) = default; + Location& operator=(const Location& other) = default; void step() { begin = end; } @@ -89,7 +89,7 @@ struct location { } }; -static inline std::ostream& operator<<(std::ostream& os, const location& loc) { +static inline std::ostream& operator<<(std::ostream& os, const Location& loc) { return os << loc.to_string(); } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 6762ada9e..46dfeedd0 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -38,7 +38,7 @@ %define api.value.type variant %define api.prefix {frontend_verilog_yy} %define api.token.constructor -%define api.location.type {location} +%define api.location.type {Location} %param { YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::VerilogLexer* lexer } %parse-param { YOSYS_NAMESPACE_PREFIX VERILOG_FRONTEND::ParseState* extra } @@ -146,14 +146,10 @@ YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { - static location location_range(location begin, location end) { - return location(begin.begin, end.end); + static Location location_range(Location begin, Location end) { + return Location(begin.begin, end.end); } - static ConstParser make_ConstParser_here(parser::location_type flex_loc) { - ConstParser p{flex_loc}; - return p; - } static void append_attr(AstNode *ast, dict> *al) { for (auto &it : *al) { @@ -370,7 +366,7 @@ const AstNode *ParseState::addIncOrDecStmt(dict> *stmt_attr, std::unique_ptr lhs, dict> *op_attr, AST::AstNodeType op, - location loc) + Location loc) { auto one = AstNode::mkconst_int(loc, 1, true); auto rhs = std::make_unique(loc, op, lhs->clone(), std::move(one)); @@ -385,7 +381,7 @@ } // create a pre/post-increment/decrement expression, and add the corresponding statement - std::unique_ptr ParseState::addIncOrDecExpr(std::unique_ptr lhs, dict> *attr, AST::AstNodeType op, location loc, bool undo, bool sv_mode) + std::unique_ptr ParseState::addIncOrDecExpr(std::unique_ptr lhs, dict> *attr, AST::AstNodeType op, Location loc, bool undo, bool sv_mode) { ensureAsgnExprAllowed(loc, sv_mode); const AstNode *stmt = addIncOrDecStmt(nullptr, std::move(lhs), attr, op, loc); @@ -402,7 +398,7 @@ // add a binary operator assignment statement, e.g., a += b std::unique_ptr ParseState::addAsgnBinopStmt(dict> *attr, std::unique_ptr eq_lhs, AST::AstNodeType op, std::unique_ptr rhs) { - location loc = location_range(eq_lhs->location, rhs->location); + Location loc = location_range(eq_lhs->location, rhs->location); if (op == AST_SHIFT_LEFT || op == AST_SHIFT_RIGHT || op == AST_SHIFT_SLEFT || op == AST_SHIFT_SRIGHT) { rhs = std::make_unique(rhs->location, AST_TO_UNSIGNED, std::move(rhs)); @@ -3219,7 +3215,7 @@ basic_expr: TOK_LPAREN expr TOK_RPAREN integral_number { if ($4->compare(0, 1, "'") != 0) err_at_loc(@4, "Cast operation must be applied on sized constants e.g. () , while %s is not a sized constant.", $4->c_str()); - auto p = make_ConstParser_here(@4); + ConstParser p{@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()); @@ -3231,7 +3227,7 @@ basic_expr: auto bits = std::make_unique(@$, AST_IDENTIFIER); bits->str = *$1; SET_AST_NODE_LOC(bits.get(), @1, @1); - auto p = make_ConstParser_here(@2); + ConstParser p{@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) @@ -3239,7 +3235,7 @@ basic_expr: $$ = std::make_unique(@$, AST_TO_BITS, std::move(bits), std::move(val)); } | integral_number { - auto p = make_ConstParser_here(@1); + ConstParser p{@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) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 1b133d9c1..5899328ef 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5725,7 +5725,7 @@ 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"); - VERILOG_FRONTEND::ConstParser p{location()}; + VERILOG_FRONTEND::ConstParser p{Location()}; auto ast = p.const2ast(netname); if (ast == nullptr) return false; From 642e041f771dc09eb58c9991ee2860c46df8cb32 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 8 Aug 2025 16:32:51 +0200 Subject: [PATCH 077/176] const2ast: fix for consistency with previous diagnostics behavior --- frontends/verilog/const2ast.cc | 13 ++----------- frontends/verilog/verilog_frontend.h | 1 - 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index 5d906cb0f..9b197b356 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -44,21 +44,12 @@ YOSYS_NAMESPACE_BEGIN using namespace AST; using namespace VERILOG_FRONTEND; -std::string ConstParser::fmt_maybe_loc(std::string msg) { - std::string s; - - s += stringf("%s:%d:", loc.begin.filename->c_str(), loc.begin.line); - - s += msg; - return s; -} - void ConstParser::log_maybe_loc_error(std::string msg) { - log_error("%s", fmt_maybe_loc(msg).c_str()); + log_file_error(*loc.begin.filename, loc.begin.line, "%s", msg.c_str()); } void ConstParser::log_maybe_loc_warn(std::string msg) { - log_warning("%s", fmt_maybe_loc(msg).c_str()); + log_file_warning(*loc.begin.filename, loc.begin.line, "%s", msg.c_str()); } // divide an arbitrary length decimal number by two and return the rest diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index eabc0d46b..83c0e37a1 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -43,7 +43,6 @@ namespace VERILOG_FRONTEND struct ConstParser { AST::AstSrcLocType 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 From 481ecb51a724410012dac05e9005c674a580f23d Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 12 Aug 2025 10:57:58 +1200 Subject: [PATCH 078/176] test_cell: Disable $macc testing Needs updating to `$macc_v2`. --- passes/tests/test_cell.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index b6385766c..227d39139 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -939,7 +939,7 @@ struct TestCellPass : public Pass { cell_types[ID($sop)] = "*"; cell_types[ID($alu)] = "ABSY"; cell_types[ID($lcu)] = "*"; - cell_types[ID($macc)] = "*"; + // cell_types[ID($macc)] = "*"; cell_types[ID($fa)] = "*"; for (; argidx < GetSize(args); argidx++) From 22aa9fba3b864efb159e18ccfa9b48331cbde68f Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 12 Aug 2025 10:57:58 +1200 Subject: [PATCH 079/176] test_cell: Support more cell types Still unsupported: - wide muxes (`$_MUX16_` and friends) Partially supported types have comments in `test_cell.cc`. Fix `CellTypes::eval() for `$_NMUX_`. Fix `RTLIL::Cell::fixup_parameters()` for $concat, $bwmux and $bweqx. --- kernel/celltypes.h | 2 + kernel/rtlil.cc | 6 +- passes/tests/test_cell.cc | 162 +++++++++++++++++++++++++++++++++++--- 3 files changed, 157 insertions(+), 13 deletions(-) diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 0ce5db54d..9aeba6797 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -507,6 +507,8 @@ struct CellTypes { if (cell->type.in(ID($mux), ID($_MUX_))) return const_mux(arg1, arg2, arg3); + if (cell->type == ID($_NMUX_)) + return eval_not(const_mux(arg1, arg2, arg3)); if (cell->type == ID($bwmux)) return const_bwmux(arg1, arg2, arg3); if (cell->type == ID($pmux)) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 646ffcb35..b0ce13ea4 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4287,9 +4287,9 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) type.begins_with("$verific$") || type.begins_with("$array:") || type.begins_with("$extern:")) return; - if (type == ID($buf) || type == ID($mux) || type == ID($pmux) || type == ID($bmux)) { + if (type == ID($buf) || type == ID($mux) || type == ID($pmux) || type == ID($bmux) || type == ID($bwmux) || type == ID($bweqx)) { parameters[ID::WIDTH] = GetSize(connections_[ID::Y]); - if (type != ID($buf) && type != ID($mux)) + if (type.in(ID($pmux), ID($bmux))) parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]); check(); return; @@ -4344,7 +4344,7 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) parameters[ID::B_WIDTH] = GetSize(connections_[ID::B]); } - if (connections_.count(ID::Y)) + if (connections_.count(ID::Y) && type != ID($concat)) parameters[ID::Y_WIDTH] = GetSize(connections_[ID::Y]); if (connections_.count(ID::Q)) diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index 227d39139..ab4fd2c9f 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -71,6 +71,29 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce cell->setPort(ID::Y, wire); } + if (cell_type.in(ID($_MUX_), ID($_NMUX_))) + { + wire = module->addWire(ID::A); + wire->width = 1; + wire->port_input = true; + cell->setPort(ID::A, wire); + + wire = module->addWire(ID::B); + wire->width = 1; + wire->port_input = true; + cell->setPort(ID::B, wire); + + wire = module->addWire(ID::S); + wire->width = 1; + wire->port_input = true; + cell->setPort(ID::S, wire); + + wire = module->addWire(ID::Y); + wire->width = 1; + wire->port_output = true; + cell->setPort(ID::Y, wire); + } + if (cell_type == ID($bmux)) { int width = 1 + xorshift32(8 * bloat_factor); @@ -273,14 +296,19 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce if (cell_type_flags.find('A') != std::string::npos) { wire = module->addWire(ID::A); - wire->width = 1 + xorshift32(8 * bloat_factor); + if (cell_type_flags.find('b') != std::string::npos) + wire->width = 1; + else + wire->width = 1 + xorshift32(8 * bloat_factor); wire->port_input = true; cell->setPort(ID::A, wire); } if (cell_type_flags.find('B') != std::string::npos) { wire = module->addWire(ID::B); - if (cell_type_flags.find('h') != std::string::npos) + if (cell_type_flags.find('b') != std::string::npos) + wire->width = 1; + else if (cell_type_flags.find('h') != std::string::npos) wire->width = 1 + xorshift32(6 * bloat_factor); else wire->width = 1 + xorshift32(8 * bloat_factor); @@ -288,6 +316,26 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce cell->setPort(ID::B, wire); } + if (cell_type_flags.find('C') != std::string::npos) { + wire = module->addWire(ID::C); + if (cell_type_flags.find('b') != std::string::npos) + wire->width = 1; + else + wire->width = 1 + xorshift32(8 * bloat_factor); + wire->port_input = true; + cell->setPort(ID::C, wire); + } + + if (cell_type_flags.find('D') != std::string::npos) { + wire = module->addWire(ID::D); + if (cell_type_flags.find('b') != std::string::npos) + wire->width = 1; + else + wire->width = 1 + xorshift32(8 * bloat_factor); + wire->port_input = true; + cell->setPort(ID::D, wire); + } + if (cell_type_flags.find('S') != std::string::npos && xorshift32(2)) { if (cell_type_flags.find('A') != std::string::npos) cell->parameters[ID::A_SIGNED] = true; @@ -304,7 +352,10 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce if (cell_type_flags.find('Y') != std::string::npos) { wire = module->addWire(ID::Y); - wire->width = 1 + xorshift32(8 * bloat_factor); + if (cell_type_flags.find('b') != std::string::npos) + wire->width = 1; + else + wire->width = 1 + xorshift32(8 * bloat_factor); wire->port_output = true; cell->setPort(ID::Y, wire); } @@ -345,6 +396,58 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce cell->setPort(ID::CO, wire); } + if (cell_type == ID($slice)) + { + int a_size = GetSize(cell->getPort(ID::A)); + int y_size = 1; + if (a_size > 1) + y_size += (xorshift32(8 * bloat_factor) % (a_size - 1)); + wire = module->addWire(ID::Y); + wire->width = y_size; + wire->port_output = true; + cell->setPort(ID::Y, wire); + if (a_size > y_size) + cell->setParam(ID::OFFSET, (xorshift32(8 * bloat_factor) % (a_size - y_size))); + else + cell->setParam(ID::OFFSET, 0); + } + + if (cell_type == ID($concat)) + { + wire = module->addWire(ID::Y); + wire->width = GetSize(cell->getPort(ID::A)) + GetSize(cell->getPort(ID::B)); + wire->port_output = true; + cell->setPort(ID::Y, wire); + } + + if (cell_type == ID($buf)) + { + wire = module->addWire(ID::Y); + wire->width = GetSize(cell->getPort(ID::A)); + wire->port_output = true; + cell->setPort(ID::Y, wire); + } + + if (cell_type.in(ID($bwmux), ID($bweqx))) + { + int a_size = GetSize(cell->getPort(ID::A)); + wire = module->addWire(ID::B); + wire->width = a_size; + wire->port_output = true; + cell->setPort(ID::B, wire); + if (cell_type == ID($bwmux)) + { + wire = module->addWire(ID::S); + wire->width = a_size; + wire->port_output = true; + cell->setPort(ID::S, wire); + } + wire = module->addWire(ID::Y); + wire->width = a_size; + wire->port_output = true; + cell->setPort(ID::Y, wire); + } + if (constmode) { auto conn_list = cell->connections(); @@ -884,6 +987,9 @@ struct TestCellPass : public Pass { cell_types[ID($not)] = "ASY"; cell_types[ID($pos)] = "ASY"; cell_types[ID($neg)] = "ASY"; + // $buf is unsupported with techmap -assert + if (techmap_cmd.compare("techmap -assert") != 0) + cell_types[ID($buf)] = "A"; cell_types[ID($and)] = "ABSY"; cell_types[ID($or)] = "ABSY"; @@ -907,8 +1013,16 @@ struct TestCellPass : public Pass { cell_types[ID($le)] = "ABSY"; cell_types[ID($eq)] = "ABSY"; cell_types[ID($ne)] = "ABSY"; - // cell_types[ID($eqx)] = "ABSY"; - // cell_types[ID($nex)] = "ABSY"; + // $eqx, $nex, and $bweqx don't work in sat, and are unsupported with + // 'techmap -assert' + if (nosat && techmap_cmd.compare("techmap -assert") != 0) + { + cell_types[ID($eqx)] = "ABSY"; + cell_types[ID($nex)] = "ABSY"; + } + // $bweqx is additionally unsupported by ConstEval + if (nosat && techmap_cmd.compare("techmap -assert") != 0 && noeval) + cell_types[ID($bweqx)] = "A"; cell_types[ID($ge)] = "ABSY"; cell_types[ID($gt)] = "ABSY"; @@ -919,7 +1033,10 @@ struct TestCellPass : public Pass { cell_types[ID($mod)] = "ABSY"; cell_types[ID($divfloor)] = "ABSY"; cell_types[ID($modfloor)] = "ABSY"; - // cell_types[ID($pow)] = "ABsY"; + // $pow doesnt work in sat, not supported with 'techmap -assert', and only + // only partially supported with '-simlib' + if (nosat && techmap_cmd.compare("aigmap") == 0) + cell_types[ID($pow)] = "ABsY"; cell_types[ID($logic_not)] = "ASY"; cell_types[ID($logic_and)] = "ABSY"; @@ -928,20 +1045,45 @@ struct TestCellPass : public Pass { cell_types[ID($mux)] = "*"; cell_types[ID($bmux)] = "*"; cell_types[ID($demux)] = "*"; - if (edges) { + // $pmux doesn't work in sat, and is not supported with 'techmap -assert' + if (nosat && techmap_cmd.compare("aigmap") == 0) cell_types[ID($pmux)] = "*"; - } + // $bwmux is not supported by ConstEval + if (noeval) + cell_types[ID($bwmux)] = "A"; - // cell_types[ID($slice)] = "A"; - // cell_types[ID($concat)] = "A"; + cell_types[ID($slice)] = "A"; + cell_types[ID($concat)] = "AB"; cell_types[ID($lut)] = "*"; cell_types[ID($sop)] = "*"; cell_types[ID($alu)] = "ABSY"; cell_types[ID($lcu)] = "*"; + // create_gold_module() needs updating for $macc_v2 // cell_types[ID($macc)] = "*"; cell_types[ID($fa)] = "*"; + cell_types[ID($_BUF_)] = "AYb"; + cell_types[ID($_NOT_)] = "AYb"; + cell_types[ID($_AND_)] = "ABYb"; + cell_types[ID($_NAND_)] = "ABYb"; + cell_types[ID($_OR_)] = "ABYb"; + cell_types[ID($_NOR_)] = "ABYb"; + cell_types[ID($_XOR_)] = "ABYb"; + cell_types[ID($_XNOR_)] = "ABYb"; + cell_types[ID($_ANDNOT_)] = "ABYb"; + cell_types[ID($_ORNOT_)] = "ABYb"; + cell_types[ID($_MUX_)] = "*"; + cell_types[ID($_NMUX_)] = "*"; + // wide $_MUX_ cells are not yet implemented + // cell_types[ID($_MUX4_)] = "*"; + // cell_types[ID($_MUX8_)] = "*"; + // cell_types[ID($_MUX16_)] = "*"; + cell_types[ID($_AOI3_)] = "ABCYb"; + cell_types[ID($_OAI3_)] = "ABCYb"; + cell_types[ID($_AOI4_)] = "ABCDYb"; + cell_types[ID($_OAI4_)] = "ABCDYb"; + for (; argidx < GetSize(args); argidx++) { if (args[argidx].rfind("-", 0) == 0) From 014eadd8b95945738a03d1872d68c783e8e14ec8 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 12 Aug 2025 10:57:58 +1200 Subject: [PATCH 080/176] test_cell: Fix $bweqx --- passes/tests/test_cell.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index ab4fd2c9f..37c82397b 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -433,13 +433,13 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce int a_size = GetSize(cell->getPort(ID::A)); wire = module->addWire(ID::B); wire->width = a_size; - wire->port_output = true; + wire->port_input = true; cell->setPort(ID::B, wire); if (cell_type == ID($bwmux)) { wire = module->addWire(ID::S); wire->width = a_size; - wire->port_output = true; + wire->port_input = true; cell->setPort(ID::S, wire); } wire = module->addWire(ID::Y); @@ -1019,10 +1019,8 @@ struct TestCellPass : public Pass { { cell_types[ID($eqx)] = "ABSY"; cell_types[ID($nex)] = "ABSY"; - } - // $bweqx is additionally unsupported by ConstEval - if (nosat && techmap_cmd.compare("techmap -assert") != 0 && noeval) cell_types[ID($bweqx)] = "A"; + } cell_types[ID($ge)] = "ABSY"; cell_types[ID($gt)] = "ABSY"; From db4ffaffd2d2f94e1c76d64e08118c2ec2287845 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 12 Aug 2025 10:57:58 +1200 Subject: [PATCH 081/176] consteval: Fix $bwmux handling If the cell type has a S signal and hasn't already been handled, use `CellTypes::eval(cell, A, B, S)`. --- kernel/consteval.h | 6 +++++- passes/tests/test_cell.cc | 4 +--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/kernel/consteval.h b/kernel/consteval.h index 844120ef0..adcf86f8a 100644 --- a/kernel/consteval.h +++ b/kernel/consteval.h @@ -349,7 +349,11 @@ struct ConstEval return false; bool eval_err = false; - RTLIL::Const eval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_c.as_const(), sig_d.as_const(), &eval_err); + RTLIL::Const eval_ret; + if (sig_s.size() > 0 && eval(sig_s, undef, cell)) { + eval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_s.as_const(), &eval_err); + } else + eval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_c.as_const(), sig_d.as_const(), &eval_err); if (eval_err) return false; diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index 37c82397b..83ef1a66e 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -1046,9 +1046,7 @@ struct TestCellPass : public Pass { // $pmux doesn't work in sat, and is not supported with 'techmap -assert' if (nosat && techmap_cmd.compare("aigmap") == 0) cell_types[ID($pmux)] = "*"; - // $bwmux is not supported by ConstEval - if (noeval) - cell_types[ID($bwmux)] = "A"; + cell_types[ID($bwmux)] = "A"; cell_types[ID($slice)] = "A"; cell_types[ID($concat)] = "AB"; From c5897144334cb9ae94f96bf567e7bc4a811c141a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 12 Aug 2025 10:57:59 +1200 Subject: [PATCH 082/176] test_cell: Update to $macc_v2 --- passes/tests/test_cell.cc | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index 83ef1a66e..dd8db2dd1 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -190,7 +190,7 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce cell->setPort(ID::CO, wire); } - if (cell_type == ID($macc)) + if (cell_type == ID($macc_v2)) { Macc macc; int width = 1 + xorshift32(8 * bloat_factor); @@ -224,6 +224,7 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce this_term.do_subtract = xorshift32(2) == 1; macc.terms.push_back(this_term); } + // Macc::to_cell sets the input ports macc.to_cell(cell); @@ -231,12 +232,6 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce wire->width = width; wire->port_output = true; cell->setPort(ID::Y, wire); - - // override the B input (macc helpers always sets an empty vector) - wire = module->addWire(ID::B); - wire->width = xorshift32(mulbits_a ? xorshift32(4)+1 : xorshift32(16)+1); - wire->port_input = true; - cell->setPort(ID::B, wire); } if (cell_type == ID($lut)) @@ -1055,8 +1050,7 @@ struct TestCellPass : public Pass { cell_types[ID($sop)] = "*"; cell_types[ID($alu)] = "ABSY"; cell_types[ID($lcu)] = "*"; - // create_gold_module() needs updating for $macc_v2 - // cell_types[ID($macc)] = "*"; + cell_types[ID($macc_v2)] = "*"; cell_types[ID($fa)] = "*"; cell_types[ID($_BUF_)] = "AYb"; From 20c2d2a6f3992c8f1fb18dde920397c8ef4da691 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 12 Aug 2025 10:57:59 +1200 Subject: [PATCH 083/176] test_cell: Add comment on $pmux `-simlib` also doesn't work. --- passes/tests/test_cell.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index dd8db2dd1..4285611f7 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -1038,7 +1038,8 @@ struct TestCellPass : public Pass { cell_types[ID($mux)] = "*"; cell_types[ID($bmux)] = "*"; cell_types[ID($demux)] = "*"; - // $pmux doesn't work in sat, and is not supported with 'techmap -assert' + // $pmux doesn't work in sat, and is not supported with 'techmap -assert' or + // '-simlib' if (nosat && techmap_cmd.compare("aigmap") == 0) cell_types[ID($pmux)] = "*"; cell_types[ID($bwmux)] = "A"; From 1afe8d9f4d95cdfee032371b6fa0e5d99c6e7c3f Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 12 Aug 2025 10:57:59 +1200 Subject: [PATCH 084/176] celltypes: Comment pointing to ConstEval `CellTypes::eval()` is more generic but also more limited. `ConstEval::eval()` requires more setup (both in code and at runtime) but has more complete support. --- kernel/celltypes.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 9aeba6797..11640c25f 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -334,6 +334,7 @@ struct CellTypes return v; } + // Consider using the ConstEval struct instead if you need named ports and/or multiple outputs static RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len, bool *errp = nullptr) { if (type == ID($sshr) && !signed1) @@ -416,6 +417,7 @@ struct CellTypes log_abort(); } + // Consider using the ConstEval struct instead if you need named ports and/or multiple outputs static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool *errp = nullptr) { if (cell->type == ID($slice)) { @@ -503,6 +505,7 @@ struct CellTypes return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len, errp); } + // Consider using the ConstEval struct instead if you need named ports and/or multiple outputs static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, bool *errp = nullptr) { if (cell->type.in(ID($mux), ID($_MUX_))) @@ -522,6 +525,7 @@ struct CellTypes return eval(cell, arg1, arg2, errp); } + // Consider using the ConstEval struct instead if you need named ports and/or multiple outputs static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4, bool *errp = nullptr) { if (cell->type == ID($_AOI4_)) From ba01f7c64f06db0542b3316878aa9873a82c9ef9 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 12 Aug 2025 10:57:59 +1200 Subject: [PATCH 085/176] ci: Run test_cell Includes special cases for partially supported cells. --- .github/workflows/test-build.yml | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index bdd290189..9115a19e7 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -161,6 +161,40 @@ jobs: run: | find tests/**/*.err -print -exec cat {} \; + test-cells: + name: Run test_cell + runs-on: ubuntu-latest + needs: [build-yosys, pre_job] + if: needs.pre_job.outputs.should_skip != 'true' + env: + CC: clang + steps: + - name: Checkout Yosys + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Setup environment + uses: ./.github/actions/setup-build-env + + - name: Download build artifact + uses: actions/download-artifact@v4 + with: + name: build-ubuntu-latest + + - name: Uncompress build + shell: bash + run: + tar -xvf build.tar + + - name: test_cell + shell: bash + run: | + ./yosys -p 'test_cell all' + ./yosys -p 'test_cell -nosat -aigmap $pow $pmux' + ./yosys -p 'test_cell -nosat -aigmap $eqx $nex $bweqx' + ./yosys -p 'test_cell -aigmap $buf' + test-docs: name: Run docs tests runs-on: ${{ matrix.os }} From c630f995d5974184b2e28cbb6798f52da5c91c11 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 12 Aug 2025 11:17:00 +1200 Subject: [PATCH 086/176] ci: Reduce test_cell count and use a seed --- .github/workflows/test-build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 9115a19e7..886b23d36 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -190,10 +190,10 @@ jobs: - name: test_cell shell: bash run: | - ./yosys -p 'test_cell all' - ./yosys -p 'test_cell -nosat -aigmap $pow $pmux' - ./yosys -p 'test_cell -nosat -aigmap $eqx $nex $bweqx' - ./yosys -p 'test_cell -aigmap $buf' + ./yosys -p 'test_cell -n 20 -s 1 all' + ./yosys -p 'test_cell -n 20 -s 1 -nosat -aigmap $pow $pmux' + ./yosys -p 'test_cell -n 20 -s 1 -nosat -aigmap $eqx $nex $bweqx' + ./yosys -p 'test_cell -n 20 -s 1 -aigmap $buf' test-docs: name: Run docs tests From 73403ad8304ec5a94e7effa6f10bb35a0d167dd9 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 12 Aug 2025 12:05:23 +1200 Subject: [PATCH 087/176] ci: Adjust workflow triggers for tests In light of problems with concurrent skipping, disable it. Instead, limit the `push` trigger to just main, and enable `workflow_dispatch` for manual triggering. Don't cancel builds from main if a new commit is pushed. --- .github/workflows/extra-builds.yml | 16 ++++++++++++---- .github/workflows/test-build.yml | 23 ++++++++++++++++------- .github/workflows/test-compile.yml | 16 ++++++++++++---- .github/workflows/test-verific.yml | 16 ++++++++++++---- 4 files changed, 52 insertions(+), 19 deletions(-) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 8d64b2e0e..944bb9e09 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -1,6 +1,14 @@ name: Test extra build flows -on: [push, pull_request] +on: + # always test main + push: + branches: + - main + # test PRs + pull_request: + # allow triggering tests, ignores skip check + workflow_dispatch: jobs: pre_job: @@ -11,11 +19,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: + # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - cancel_others: 'true' - # only run on push *or* pull_request, not both - concurrent_skipping: 'same_content_newer' + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} vs-prep: name: Prepare Visual Studio build diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index bdd290189..4cfd64da3 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -1,6 +1,14 @@ name: Build and run tests -on: [push, pull_request] +on: + # always test main + push: + branches: + - main + # test PRs + pull_request: + # allow triggering tests, ignores skip check + workflow_dispatch: jobs: pre_job: @@ -11,11 +19,12 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: + # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - cancel_others: 'true' - # only run on push *or* pull_request, not both - concurrent_skipping: 'same_content_newer' + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} + pre_docs_job: runs-on: ubuntu-latest outputs: @@ -24,11 +33,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: + # don't run on readme changes paths_ignore: '["**/README.md"]' # cancel previous builds if a new commit is pushed - cancel_others: 'true' - # only run on push *or* pull_request, not both - concurrent_skipping: 'same_content_newer' + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} build-yosys: name: Reusable build diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index 7a706e69a..f208b911a 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -1,6 +1,14 @@ name: Compiler testing -on: [push, pull_request] +on: + # always test main + push: + branches: + - main + # test PRs + pull_request: + # allow triggering tests, ignores skip check + workflow_dispatch: jobs: pre_job: @@ -11,11 +19,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: + # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - cancel_others: 'true' - # only run on push *or* pull_request, not both - concurrent_skipping: 'same_content_newer' + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} test-compile: runs-on: ${{ matrix.os }} diff --git a/.github/workflows/test-verific.yml b/.github/workflows/test-verific.yml index 013c9f8ca..9af07b920 100644 --- a/.github/workflows/test-verific.yml +++ b/.github/workflows/test-verific.yml @@ -1,6 +1,14 @@ name: Build and run tests with Verific (Linux) -on: [push, pull_request] +on: + # always test main + push: + branches: + - main + # test PRs + pull_request: + # allow triggering tests, ignores skip check + workflow_dispatch: jobs: pre-job: @@ -11,11 +19,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: + # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - cancel_others: 'true' - # only run on push *or* pull_request, not both - concurrent_skipping: 'same_content_newer' + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} test-verific: needs: pre-job From 0f8c040371e7f1c8c10859e77882bdea0f7bfab9 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 12 Aug 2025 12:21:50 +1200 Subject: [PATCH 088/176] ci: Move SAN into a separate workflow --- .github/workflows/test-build.yml | 13 +--- .github/workflows/test-sanitizers.yml | 105 ++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/test-sanitizers.yml diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 4cfd64da3..b62973414 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -42,6 +42,7 @@ jobs: build-yosys: name: Reusable build runs-on: ${{ matrix.os }} + # pre_job is a subset of pre_docs_job, so we can always build for pre_docs_job needs: pre_docs_job if: needs.pre_docs_job.outputs.should_skip != 'true' env: @@ -49,7 +50,6 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] - sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -67,7 +67,6 @@ jobs: mkdir build cd build make -f ../Makefile config-$CC - echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf make -f ../Makefile -j$procs ENABLE_LTO=1 - name: Log yosys-config output @@ -83,7 +82,7 @@ jobs: - name: Store build artifact uses: actions/upload-artifact@v4 with: - name: build-${{ matrix.os }}-${{ matrix.sanitizer }} + name: build-${{ matrix.os }} path: build.tar retention-days: 1 @@ -94,12 +93,9 @@ jobs: if: needs.pre_job.outputs.should_skip != 'true' env: CC: clang - ASAN_OPTIONS: halt_on_error=1 - UBSAN_OPTIONS: halt_on_error=1 strategy: matrix: os: [ubuntu-latest, macos-latest] - sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -148,7 +144,7 @@ jobs: - name: Download build artifact uses: actions/download-artifact@v4 with: - name: build-${{ matrix.os }}-${{ matrix.sanitizer }} + name: build-${{ matrix.os }} - name: Uncompress build shell: bash @@ -180,7 +176,6 @@ jobs: strategy: matrix: os: [ubuntu-latest] - sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -194,7 +189,7 @@ jobs: - name: Download build artifact uses: actions/download-artifact@v4 with: - name: build-${{ matrix.os }}-${{ matrix.sanitizer }} + name: build-${{ matrix.os }} - name: Uncompress build shell: bash diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml new file mode 100644 index 000000000..fb76d1266 --- /dev/null +++ b/.github/workflows/test-sanitizers.yml @@ -0,0 +1,105 @@ +name: Check clang sanitizers + +on: + # always test main + push: + branches: + - main + # ignore PRs due to time needed + # allow triggering tests, ignores skip check + workflow_dispatch: + +jobs: + pre_job: + runs-on: ubuntu-latest + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5 + with: + # don't run on documentation changes + paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' + + run_san: + name: Build and run tests + runs-on: ${{ matrix.os }} + needs: pre_job + if: needs.pre_job.outputs.should_skip != 'true' + env: + CC: clang + ASAN_OPTIONS: halt_on_error=1 + UBSAN_OPTIONS: halt_on_error=1 + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + sanitizer: ['undefined,address'] + fail-fast: false + steps: + - name: Checkout Yosys + uses: actions/checkout@v4 + with: + submodules: true + persist-credentials: false + + - name: Setup environment + uses: ./.github/actions/setup-build-env + + - name: Build + shell: bash + run: | + mkdir build + cd build + make -f ../Makefile config-$CC + echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf + make -f ../Makefile -j$procs ENABLE_LTO=1 + + - name: Log yosys-config output + run: | + ./yosys-config || true + + - name: Get iverilog + shell: bash + run: | + git clone https://github.com/steveicarus/iverilog.git + cd iverilog + echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_ENV + + - name: Get vcd2fst + shell: bash + run: | + git clone https://github.com/mmicko/libwave.git + mkdir -p ${{ github.workspace }}/.local/ + cd libwave + cmake . -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/.local + make -j$procs + make install + + - name: Cache iverilog + id: cache-iverilog + uses: actions/cache@v4 + with: + path: .local/ + key: ${{ matrix.os }}-${IVERILOG_GIT} + + - name: Build iverilog + if: steps.cache-iverilog.outputs.cache-hit != 'true' + shell: bash + run: | + mkdir -p ${{ github.workspace }}/.local/ + cd iverilog + autoconf + CC=gcc CXX=g++ ./configure --prefix=${{ github.workspace }}/.local + make -j$procs + make install + + - name: Run tests + shell: bash + run: | + make -j$procs test TARGETS= EXTRA_TARGETS= CONFIG=$CC + + - name: Report errors + if: ${{ failure() }} + shell: bash + run: | + find tests/**/*.err -print -exec cat {} \; From 1e6e25c81f0d12b3906473ffd39c2fb5cc1c00b4 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 12 Aug 2025 12:43:14 +1200 Subject: [PATCH 089/176] ci: Use correct build artifact --- .github/workflows/test-build.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 886b23d36..f9574594a 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -163,11 +163,15 @@ jobs: test-cells: name: Run test_cell - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} needs: [build-yosys, pre_job] if: needs.pre_job.outputs.should_skip != 'true' env: CC: clang + strategy: + matrix: + os: [ubuntu-latest] + sanitizer: [undefined] steps: - name: Checkout Yosys uses: actions/checkout@v4 @@ -180,7 +184,7 @@ jobs: - name: Download build artifact uses: actions/download-artifact@v4 with: - name: build-ubuntu-latest + name: build-${{ matrix.os }}-${{ matrix.sanitizer }} - name: Uncompress build shell: bash From a0dde68487da600c569c0b61b684dc845fd5c554 Mon Sep 17 00:00:00 2001 From: clemens Date: Tue, 15 Apr 2025 09:39:49 +0200 Subject: [PATCH 090/176] Improve STAT --- passes/cmds/stat.cc | 617 +++++++++++++++++++++++++++++++++----------- 1 file changed, 472 insertions(+), 145 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index af7023bdd..0d19849c3 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -19,13 +19,14 @@ #include -#include "kernel/yosys.h" #include "kernel/celltypes.h" -#include "passes/techmap/libparse.h" #include "kernel/cost.h" #include "kernel/gzip.h" +#include "kernel/yosys.h" #include "libs/json11/json11.hpp" #include "kernel/log_help.h" +#include "passes/techmap/libparse.h" +#include USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -35,137 +36,225 @@ struct cell_area_t { bool is_sequential; }; -struct statdata_t -{ - #define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) X(num_pub_wires) X(num_pub_wire_bits) \ - X(num_ports) X(num_port_bits) X(num_memories) X(num_memory_bits) X(num_cells) \ - X(num_processes) +struct statdata_t { +#define STAT_INT_MEMBERS \ + X(num_wires) \ + X(num_wire_bits) \ + X(num_pub_wires) X(num_pub_wire_bits) X(num_ports) X(num_port_bits) X(num_memories) X(num_memory_bits) X(num_cells) X(num_processes) - #define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area) X(sequential_area) +#define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area) X(sequential_area) - #define X(_name) unsigned int _name; +#define X(_name) unsigned int _name; STAT_INT_MEMBERS - #undef X +#undef X +#define X(_name) unsigned int local_##_name; + STAT_INT_MEMBERS +#undef X double area = 0; double sequential_area = 0; + double local_area = 0; + double local_sequential_area = 0; + double submodule_area = 0; + int num_submodules = 0; + std::map num_submodules_by_type; + std::map submodules_area_by_type; + + std::map local_num_cells_by_type; + std::map local_area_cells_by_type; + std::map local_seq_area_cells_by_type; string tech; std::map num_cells_by_type; + std::map area_cells_by_type; + std::map seq_area_cells_by_type; std::set unknown_cell_area; statdata_t operator+(const statdata_t &other) const { statdata_t sum = other; - #define X(_name) sum._name += _name; +#define X(_name) sum._name += _name; STAT_NUMERIC_MEMBERS - #undef X +#undef X for (auto &it : num_cells_by_type) sum.num_cells_by_type[it.first] += it.second; return sum; } - statdata_t operator*(unsigned int other) const { statdata_t sum = *this; - #define X(_name) sum._name *= other; +#define X(_name) sum._name *= other; STAT_NUMERIC_MEMBERS - #undef X +#undef X for (auto &it : sum.num_cells_by_type) it.second *= other; return sum; } + statdata_t add(const statdata_t &other) + { +#define X(_name) _name += other._name; + STAT_NUMERIC_MEMBERS +#undef X + for (auto &it : other.num_cells_by_type) { + if (num_cells_by_type.count(it.first)) + num_cells_by_type[it.first] += it.second; + else + num_cells_by_type[it.first] = it.second; + } + for (auto &it : other.submodules_area_by_type) { + if (submodules_area_by_type.count(it.first)) + submodules_area_by_type[it.first] += it.second; + else + submodules_area_by_type[it.first] = it.second; + } + for (auto &it : other.area_cells_by_type) { + if (area_cells_by_type.count(it.first)) + area_cells_by_type[it.first] += it.second; + else + area_cells_by_type[it.first] = it.second; + } + for (auto &it : other.seq_area_cells_by_type) { + if (seq_area_cells_by_type.count(it.first)) + seq_area_cells_by_type[it.first] += it.second; + else + seq_area_cells_by_type[it.first] = it.second; + } + unknown_cell_area.insert(other.unknown_cell_area.begin(), other.unknown_cell_area.end()); + return *this; + } statdata_t() { - #define X(_name) _name = 0; +#define X(_name) _name = 0; STAT_NUMERIC_MEMBERS - #undef X +#undef X } - statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict &cell_area, string techname) + statdata_t(cell_area_t &cell_data, string techname) + { + tech = techname; + area = cell_data.area; + if (cell_data.is_sequential) { + sequential_area = cell_data.area; + } + } + + statdata_t(const RTLIL::Design *design, const RTLIL::Module *mod, bool width_mode, dict &cell_area, string techname) { tech = techname; - #define X(_name) _name = 0; +#define X(_name) _name = 0; STAT_NUMERIC_MEMBERS - #undef X +#undef X +#define X(_name) local_##_name = 0; + STAT_NUMERIC_MEMBERS +#undef X + // additional_cell_area - for (auto wire : mod->selected_wires()) - { + for (auto wire : mod->selected_wires()) { if (wire->port_input || wire->port_output) { num_ports++; + local_num_ports++; num_port_bits += wire->width; + local_num_port_bits += wire->width; } if (wire->name.isPublic()) { num_pub_wires++; + local_num_pub_wires++; num_pub_wire_bits += wire->width; + local_num_pub_wire_bits += wire->width; } num_wires++; + local_num_wires++; num_wire_bits += wire->width; + local_num_wire_bits += wire->width; } for (auto &it : mod->memories) { if (!design->selected(mod, it.second)) continue; num_memories++; + local_num_memories++; num_memory_bits += it.second->width * it.second->size; + local_num_memory_bits += it.second->width * it.second->size; } - - for (auto cell : mod->selected_cells()) - { + for (auto cell : mod->selected_cells()) { RTLIL::IdString cell_type = cell->type; - - if (width_mode) - { - if (cell_type.in(ID($not), ID($pos), ID($neg), - ID($logic_not), ID($logic_and), ID($logic_or), - ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), - ID($lut), ID($and), ID($or), ID($xor), ID($xnor), - ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), - ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), - ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow), ID($alu))) { + if (width_mode) { + if (cell_type.in(ID($not), ID($pos), ID($neg), ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_and), + ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($lut), ID($and), ID($or), + ID($xor), ID($xnor), ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), ID($lt), + ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), ID($add), ID($sub), ID($mul), + ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow), ID($alu))) { int width_a = cell->hasPort(ID::A) ? GetSize(cell->getPort(ID::A)) : 0; int width_b = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : 0; int width_y = cell->hasPort(ID::Y) ? GetSize(cell->getPort(ID::Y)) : 0; cell_type = stringf("%s_%d", cell_type.c_str(), max({width_a, width_b, width_y})); - } - else if (cell_type.in(ID($mux), ID($pmux))) + } else if (cell_type.in(ID($mux))) cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y))); - else if (cell_type == ID($bmux)) - cell_type = stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y)), GetSize(cell->getPort(ID::S))); + else if (cell_type.in(ID($bmux), ID($pmux))) + cell_type = + stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y)), GetSize(cell->getPort(ID::S))); else if (cell_type == ID($demux)) - cell_type = stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::S))); - else if (cell_type.in( - ID($sr), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), - ID($adff), ID($adffe), ID($sdff), ID($sdffe), ID($sdffce), - ID($aldff), ID($aldffe), ID($dlatch), ID($adlatch), ID($dlatchsr))) + cell_type = + stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::S))); + else if (cell_type.in(ID($sr), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), + ID($sdff), ID($sdffe), ID($sdffce), ID($aldff), ID($aldffe), ID($dlatch), ID($adlatch), + ID($dlatchsr))) cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Q))); } if (!cell_area.empty()) { + if (cell_area.count(cell_type)) { cell_area_t cell_data = cell_area.at(cell_type); if (cell_data.is_sequential) { sequential_area += cell_data.area; + local_sequential_area += cell_data.area; } area += cell_data.area; - } - else { - unknown_cell_area.insert(cell_type); - } - } + num_cells++; + num_cells_by_type[cell_type]++; + area_cells_by_type[cell_type] += cell_data.area; + seq_area_cells_by_type[cell_type] += cell_data.is_sequential ? cell_data.area : 0; + local_area_cells_by_type[cell_type] += cell_data.area; + local_seq_area_cells_by_type[cell_type] += cell_data.is_sequential ? cell_data.area : 0; + local_area += cell_data.area; + local_num_cells++; + local_num_cells_by_type[cell_type]++; - num_cells++; - num_cells_by_type[cell_type]++; + } else { + unknown_cell_area.insert(cell_type); + num_cells++; + num_cells_by_type[cell_type]++; + local_num_cells++; + local_num_cells_by_type[cell_type]++; + area_cells_by_type[cell_type] = 0; + seq_area_cells_by_type[cell_type] = 0; + local_area_cells_by_type[cell_type] = 0; + local_seq_area_cells_by_type[cell_type] = 0; + } + } else { + num_cells++; + num_cells_by_type[cell_type]++; + area_cells_by_type[cell_type] = 0; + seq_area_cells_by_type[cell_type] = 0; + local_num_cells++; + local_num_cells_by_type[cell_type]++; + local_area_cells_by_type[cell_type] = 0; + local_seq_area_cells_by_type[cell_type] = 0; + } } for (auto &it : mod->processes) { if (!design->selected(mod, it.second)) continue; num_processes++; + local_num_processes++; } + RTLIL::IdString cell_name = mod->name; + auto s = cell_name.str(); } unsigned int estimate_xilinx_lc() @@ -238,22 +327,119 @@ struct statdata_t return tran_cnt; } - void log_data(RTLIL::IdString mod_name, bool top_mod) + /* + format a floating point value to a of 8 characters, with at most 7 digits or scientific notation + uses - to mark zero or very small values + */ + std::string f_val(double value) { - log(" Number of wires: %6u\n", num_wires); - log(" Number of wire bits: %6u\n", num_wire_bits); - log(" Number of public wires: %6u\n", num_pub_wires); - log(" Number of public wire bits: %6u\n", num_pub_wire_bits); - log(" Number of ports: %6u\n", num_ports); - log(" Number of port bits: %6u\n", num_port_bits); - log(" Number of memories: %6u\n", num_memories); - log(" Number of memory bits: %6u\n", num_memory_bits); - log(" Number of processes: %6u\n", num_processes); - log(" Number of cells: %6u\n", num_cells); - for (auto &it : num_cells_by_type) - if (it.second) - log(" %-26s %6u\n", log_id(it.first), it.second); + if (std::abs(value) < 1e-12) + return " -"; + char buf[16]; + + int len = std::snprintf(buf, sizeof(buf), "%.3f", value); + + while (len > 0 && buf[len - 1] == '0') + --len; + if (len > 0 && buf[len - 1] == '.') + --len; + buf[len] = '\0'; + + if (len <= 7) { + return std::string(8 - len, ' ') + std::string(buf); + } + + // use scientific notation, this should always fit in 8 characters + std::snprintf(buf, sizeof(buf), "%8.3G", value); + + return std::string(buf); + } + + void print_log_line(const std::string &name, unsigned int count_local, double area_local, unsigned int count_global, double area_global, + int spacer = 0, bool print_area = true, bool print_hierarchical = true) + { + const std::string indent(2 * spacer, ' '); + + std::string count_local_str = f_val(static_cast(count_local)); + std::string count_global_str = f_val(static_cast(count_global)); + std::string area_local_str = f_val(area_local); + std::string area_global_str = f_val(area_global); + + if (print_area) { + if (print_hierarchical) { + log(" %s %s %s %s %s%s\n", count_global_str.c_str(), area_global_str.c_str(), count_local_str.c_str(), + area_local_str.c_str(), indent.c_str(), name.c_str()); + } else { + if (count_local > 0) + log(" %s %s %s%s\n", count_local_str.c_str(), area_local_str.c_str(), indent.c_str(), name.c_str()); + } + } else { + if (print_hierarchical) { + log(" %s %s %s%s\n", count_global_str.c_str(), count_local_str.c_str(), indent.c_str(), name.c_str()); + } else { + if (count_local > 0) + log(" %s %s%s\n", count_local_str.c_str(), indent.c_str(), name.c_str()); + } + } + } + + void print_log_header(bool print_area = true, bool print_hierarchical = true) + { + if (print_area) { + if (print_hierarchical) { + log(" %8s-%8s-%8s-%8s-%s\n", "+", "--------", "--------", "--------", "Count including submodules."); + log(" %8s %8s-%8s-%8s-%s\n", "|", "+", "--------", "--------", "Area including submodules."); + log(" %8s %8s %8s-%8s-%s\n", "|", "|", "+", "--------", "Local count, excluding submodules."); + log(" %8s %8s %8s %8s-%s\n", "|", "|", "|", "+", "Local area, excluding submodules."); + log(" %8s %8s %8s %8s \n", "|", "|", "|", "|"); + } else { + log(" %8s-%8s-%s\n", "+", "--------", "Local Count including submodules."); + log(" %8s %8s-%s\n", "|", "+", "Local Area including submodules."); + log(" %8s %8s \n", "|", "|"); + } + } else { + if (print_hierarchical) { + log(" %8s-%8s-%8s-%s\n", "+", "--------", "--------", "Count including submodules."); + log(" %8s %8s-%8s-%s\n", "|", "+", "--------", "Local count, excluding submodules."); + log(" %8s %8s \n", "|", "|"); + } else { + log(" %8s-%8s-%s\n", "+", "--------", "Local Count including submodules."); + log(" %8s \n", "|"); + } + } + } + + void log_data(RTLIL::IdString mod_name, bool top_mod, bool print_area = true, bool print_hierarchical = true) + { + + print_log_header(print_area, print_hierarchical); + + print_log_line("wires", local_num_wires, 0, num_wires, 0, 0, print_area, print_hierarchical); + print_log_line("wire bits", local_num_wire_bits, 0, num_wire_bits, 0, 0, print_area, print_hierarchical); + print_log_line("public wires", local_num_pub_wires, 0, num_pub_wires, 0, 0, print_area, print_hierarchical); + print_log_line("public wire bits", local_num_pub_wire_bits, 0, num_pub_wire_bits, 0, 0, print_area, print_hierarchical); + print_log_line("ports", local_num_ports, 0, num_ports, 0, 0, print_area, print_hierarchical); + print_log_line("port bits", local_num_port_bits, 0, num_port_bits, 0, 0, print_area, print_hierarchical); + print_log_line("memories", local_num_memories, 0, num_memories, 0, 0, print_area, print_hierarchical); + print_log_line("memory bits", local_num_memory_bits, 0, num_memory_bits, 0, 0, print_area, print_hierarchical); + print_log_line("processes", local_num_processes, 0, num_processes, 0, 0, print_area, print_hierarchical); + print_log_line("cells", local_num_cells, local_area, num_cells, area, 0, print_area, print_hierarchical); + for (auto &it : num_cells_by_type) + if (it.second) { + auto name = string(log_id(it.first)); + print_log_line(name, local_num_cells_by_type.count(it.first) ? local_num_cells_by_type.at(it.first) : 0, + local_area_cells_by_type.count(it.first) ? local_area_cells_by_type.at(it.first) : 0, it.second, + area_cells_by_type.at(it.first), 1, print_area, print_hierarchical); + } + if (num_submodules > 0) { + print_log_line("submodules", num_submodules, 0, num_submodules, submodule_area, 0, print_area, print_hierarchical); + for (auto &it : num_submodules_by_type) + if (it.second) + print_log_line(string(log_id(it.first)), it.second, 0, it.second, + submodules_area_by_type.count(it.first) ? submodules_area_by_type.at(it.first) : 0, 1, + print_area, print_hierarchical); + } if (!unknown_cell_area.empty()) { log("\n"); for (auto cell_type : unknown_cell_area) @@ -263,17 +449,15 @@ struct statdata_t if (area != 0) { log("\n"); log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area); - log(" of which used for sequential elements: %f (%.2f%%)\n", sequential_area, 100.0*sequential_area/area); + log(" of which used for sequential elements: %f (%.2f%%)\n", sequential_area, 100.0 * sequential_area / area); } - if (tech == "xilinx") - { + if (tech == "xilinx") { log("\n"); log(" Estimated number of LCs: %10u\n", estimate_xilinx_lc()); } - if (tech == "cmos") - { + if (tech == "cmos") { bool tran_cnt_exact = true; unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact); @@ -282,87 +466,203 @@ struct statdata_t } } - void log_data_json(const char *mod_name, bool first_module) + string json_line(unsigned int count_local, double area_local, unsigned int count_global, double area_global) + { + + return stringf("{ \"count\": \"%u\", \"area\": \"%f\", \"local_count\": \"%u\", \"local_area\": \"%f\" }", count_global, area_global, + count_local, area_local); + } + + void log_data_json(const char *mod_name, bool first_module, bool hierarchical = false) { if (!first_module) log(",\n"); - log(" %s: {\n", json11::Json(mod_name).dump().c_str()); - log(" \"num_wires\": %u,\n", num_wires); - log(" \"num_wire_bits\": %u,\n", num_wire_bits); - log(" \"num_pub_wires\": %u,\n", num_pub_wires); - log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits); - log(" \"num_ports\": %u,\n", num_ports); - log(" \"num_port_bits\": %u,\n", num_port_bits); - log(" \"num_memories\": %u,\n", num_memories); - log(" \"num_memory_bits\": %u,\n", num_memory_bits); - log(" \"num_processes\": %u,\n", num_processes); - log(" \"num_cells\": %u,\n", num_cells); - if (area != 0) { - log(" \"area\": %f,\n", area); - } - log(" \"num_cells_by_type\": {\n"); - bool first_line = true; - for (auto &it : num_cells_by_type) - if (it.second) { - if (!first_line) - log(",\n"); - log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); - first_line = false; + if (hierarchical) { + log(" %s: {\n", json11::Json(mod_name).dump().c_str()); + log(" \"num_wires\": %s,\n", json_line(local_num_wires, 0, num_wires, 0).c_str()); + log(" \"num_wire_bits\": %s,\n", json_line(local_num_wire_bits, 0, num_wire_bits, 0).c_str()); + log(" \"num_pub_wires\": %s,\n", json_line(local_num_pub_wires, 0, num_pub_wires, 0).c_str()); + log(" \"num_pub_wire_bits\": %s,\n", json_line(local_num_pub_wire_bits, 0, num_pub_wire_bits, 0).c_str()); + log(" \"num_ports\": %s,\n", json_line(local_num_ports, 0, num_ports, 0).c_str()); + log(" \"num_port_bits\": %s,\n", json_line(local_num_port_bits, 0, num_port_bits, 0).c_str()); + log(" \"num_memories\": %s,\n", json_line(local_num_memories, 0, num_memories, 0).c_str()); + log(" \"num_memory_bits\": %s,\n", json_line(local_num_memory_bits, 0, num_memory_bits, 0).c_str()); + log(" \"num_processes\": %s,\n", json_line(local_num_processes, 0, num_processes, 0).c_str()); + log(" \"num_cells\": %s,\n", json_line(local_num_cells, local_area, num_cells, area).c_str()); + log(" \"num_submodules\": %s,\n", json_line(0, 0, num_submodules, submodule_area).c_str()); + log(" \"sequential_area\": %s,\n", json_line(0, local_sequential_area, 0, sequential_area).c_str()); + + log(" \"num_cells_by_type\": {\n"); + bool first_line = true; + for (auto &it : num_cells_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %s", json11::Json(log_id(it.first)).dump().c_str(), + json_line(local_num_cells_by_type.count(it.first) ? local_num_cells_by_type.at(it.first) : 0, + local_area_cells_by_type.count(it.first) ? local_area_cells_by_type.at(it.first) : 0, it.second, + area_cells_by_type.at(it.first)) + .c_str()); + first_line = false; + } + log("\n },\n"); + log(" \"num_submodules_by_type\": {\n"); + first_line = true; + for (auto &it : num_submodules_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %s", json11::Json(log_id(it.first)).dump().c_str(), + json_line(0, 0, it.second, + submodules_area_by_type.count(it.first) ? submodules_area_by_type.at(it.first) : 0) + .c_str()); + first_line = false; + } + log("\n }\n"); + if (tech == "xilinx") { + log(" \"estimated_num_lc\": %u,\n", estimate_xilinx_lc()); } - log("\n"); - log(" }"); - if (tech == "xilinx") - { - log(",\n"); - log(" \"estimated_num_lc\": %u", estimate_xilinx_lc()); + if (tech == "cmos") { + bool tran_cnt_exact = true; + unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact); + log(" \"estimated_num_transistors\": \"%u%s\"\n", tran_cnt, tran_cnt_exact ? "" : "+"); + } + log(" }"); + + } else { + + log(" %s: {\n", json11::Json(mod_name).dump().c_str()); + log(" \"num_wires\": %u,\n", num_wires); + log(" \"num_wire_bits\": %u,\n", num_wire_bits); + log(" \"num_pub_wires\": %u,\n", num_pub_wires); + log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits); + log(" \"num_ports\": %u,\n", num_ports); + log(" \"num_port_bits\": %u,\n", num_port_bits); + log(" \"num_memories\": %u,\n", num_memories); + log(" \"num_memory_bits\": %u,\n", num_memory_bits); + log(" \"num_processes\": %u,\n", num_processes); + log(" \"num_cells\": %u,\n", local_num_cells); + log(" \"num_submodules\": %u,\n", num_submodules); + if (area != 0) { + log(" \"area\": %f,\n", area); + log(" \"sequential_area\": %f,\n", sequential_area); + } + log(" \"num_cells_by_type\": {\n"); + bool first_line = true; + for (auto &it : local_num_cells_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); + first_line = false; + } + for (auto &it : num_submodules_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); + first_line = false; + } + log("\n"); + log(" }"); + if (tech == "xilinx") { + log(",\n"); + log(" \"estimated_num_lc\": %u", estimate_xilinx_lc()); + } + if (tech == "cmos") { + bool tran_cnt_exact = true; + unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact); + log(",\n"); + log(" \"estimated_num_transistors\": \"%u%s\"", tran_cnt, tran_cnt_exact ? "" : "+"); + } + log("\n"); + log(" }"); } - if (tech == "cmos") - { - bool tran_cnt_exact = true; - unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact); - log(",\n"); - log(" \"estimated_num_transistors\": \"%u%s\"", tran_cnt, tran_cnt_exact ? "" : "+"); - } - log("\n"); - log(" }"); } }; -statdata_t hierarchy_worker(std::map &mod_stat, RTLIL::IdString mod, int level, bool quiet = false) +statdata_t hierarchy_worker(std::map &mod_stat, RTLIL::IdString mod, int level, bool quiet = false, bool has_area = true, + bool hierarchy_mode = true) { statdata_t mod_data = mod_stat.at(mod); - std::map num_cells_by_type; - num_cells_by_type.swap(mod_data.num_cells_by_type); - for (auto &it : num_cells_by_type) + for (auto &it : mod_data.num_submodules_by_type) { if (mod_stat.count(it.first) > 0) { if (!quiet) - log(" %*s%-*s %6u\n", 2*level, "", 26-2*level, log_id(it.first), it.second); - mod_data = mod_data + hierarchy_worker(mod_stat, it.first, level+1, quiet) * it.second; - mod_data.num_cells -= it.second; - } else { - mod_data.num_cells_by_type[it.first] += it.second; + mod_data.print_log_line(string(log_id(it.first)), mod_stat.at(it.first).local_num_cells, + mod_stat.at(it.first).local_area, mod_stat.at(it.first).num_cells, mod_stat.at(it.first).area, + level, has_area, hierarchy_mode); + hierarchy_worker(mod_stat, it.first, level + 1, quiet, has_area, hierarchy_mode) * it.second; } + } return mod_data; } +statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *top_mod, std::map &mod_stat, + bool width_mode, dict &cell_area, string techname) +{ + if (top_mod == nullptr) + top_mod = design->top_module(); + statdata_t mod_data(design, top_mod, width_mode, cell_area, techname); + for (auto cell : top_mod->selected_cells()) { + if (cell_area.count(cell->type) == 0) { + if (design->has(cell->type)) { + if (!(design->module(cell->type)->attributes.count(ID::blackbox))) { + // deal with modules + mod_data.add( + hierarchy_builder(design, design->module(cell->type), mod_stat, width_mode, cell_area, techname)); + mod_data.num_submodules_by_type[cell->type]++; + mod_data.submodules_area_by_type[cell->type] += mod_stat.at(cell->type).area; + mod_data.submodule_area += mod_stat.at(cell->type).area; + mod_data.num_submodules++; + mod_data.unknown_cell_area.erase(cell->type); + mod_data.num_cells -= mod_data.num_cells_by_type.erase(cell->type); + mod_data.area_cells_by_type.erase(cell->type); + mod_data.local_num_cells -= mod_data.local_num_cells_by_type.erase(cell->type); + mod_data.local_area_cells_by_type.erase(cell->type); + } else { + // deal with blackbox cells + if (design->module(cell->type)->attributes.count(ID::area) && + design->module(cell->type)->attributes.at(ID::area).size() == 0) { + mod_data.num_submodules_by_type[cell->type]++; + mod_data.num_submodules++; + mod_data.submodules_area_by_type[cell->type] += + double(design->module(cell->type)->attributes.at(ID::area).as_int()); + mod_data.area += double(design->module(cell->type)->attributes.at(ID::area).as_int()); + mod_data.unknown_cell_area.erase(cell->type); + } else { + mod_data.unknown_cell_area.insert(cell->type); + mod_data.num_submodules++; + mod_data.num_submodules_by_type[cell->type]++; + mod_data.submodules_area_by_type[cell->type] = 0; + mod_data.seq_area_cells_by_type[cell->type] = 0; + } + } + } + } + } + mod_stat[top_mod->name] = mod_data; + return mod_data; +} + void read_liberty_cellarea(dict &cell_area, string liberty_file) { - std::istream* f = uncompressed(liberty_file.c_str()); + std::istream *f = uncompressed(liberty_file.c_str()); yosys_input_files.insert(liberty_file); LibertyParser libparser(*f, liberty_file); delete f; - for (auto cell : libparser.ast->children) - { + for (auto cell : libparser.ast->children) { if (cell->id != "cell" || cell->args.size() != 1) continue; const LibertyAst *ar = cell->find("area"); bool is_flip_flop = cell->find("ff") != nullptr; - if (ar != nullptr && !ar->value.empty()) - cell_area["\\" + cell->args[0]] = {/*area=*/atof(ar->value.c_str()), is_flip_flop}; + if (ar != nullptr && !ar->value.empty()) { + string prefix = cell->args[0].substr(0, 1) == "$" ? "" : "\\"; + cell_area[prefix + cell->args[0]] = {atof(ar->value.c_str()), is_flip_flop}; + } } } @@ -381,6 +681,7 @@ struct StatPass : public Pass { log("\n"); log("Print some statistics (number of objects) on the selected portion of the\n"); log("design.\n"); + log("Extracts the area of cells from a liberty file, if provided.\n"); log("\n"); log(" -top \n"); log(" print design hierarchy with this module as top. if the design is fully\n"); @@ -402,35 +703,38 @@ struct StatPass : public Pass { log(" output the statistics in a machine-readable JSON format.\n"); log(" this is output to the console; use \"tee\" to output to a file.\n"); log("\n"); + log(" -hierarchy\n"); + log(" print hierarchical statistics, i.e. The area and number of cells include submodules.\n"); + log(" this changes the format of the json output.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { - bool width_mode = false, json_mode = false; + bool width_mode = false, json_mode = false, hierarchy_mode = false; RTLIL::Module *top_mod = nullptr; std::map mod_stat; dict cell_area; string techname; size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { + for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-width") { width_mode = true; continue; } - if (args[argidx] == "-liberty" && argidx+1 < args.size()) { + if (args[argidx] == "-liberty" && argidx + 1 < args.size()) { string liberty_file = args[++argidx]; rewrite_filename(liberty_file); read_liberty_cellarea(cell_area, liberty_file); continue; } - if (args[argidx] == "-tech" && argidx+1 < args.size()) { + if (args[argidx] == "-tech" && argidx + 1 < args.size()) { techname = args[++argidx]; continue; } - if (args[argidx] == "-top" && argidx+1 < args.size()) { - if (design->module(RTLIL::escape_id(args[argidx+1])) == nullptr) - log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str()); + if (args[argidx] == "-top" && argidx + 1 < args.size()) { + if (design->module(RTLIL::escape_id(args[argidx + 1])) == nullptr) + log_cmd_error("Can't find module %s.\n", args[argidx + 1].c_str()); top_mod = design->module(RTLIL::escape_id(args[++argidx])); continue; } @@ -438,11 +742,15 @@ struct StatPass : public Pass { json_mode = true; continue; } + if (args[argidx] == "-hierarchy") { + hierarchy_mode = true; + continue; + } break; } extra_args(args, argidx, design); - if(!json_mode) + if (!json_mode) log_header(design, "Printing statistics.\n"); if (techname != "" && techname != "xilinx" && techname != "cmos" && !json_mode) @@ -457,24 +765,40 @@ struct StatPass : public Pass { log(" \"modules\": {\n"); } + printf("building cell area\n"); + if (top_mod != nullptr) { + hierarchy_builder(design, top_mod, mod_stat, width_mode, cell_area, techname); + } else { + for (auto mod : design->selected_modules()) { + if (mod_stat.count(mod->name) == 0) { + hierarchy_builder(design, mod, mod_stat, width_mode, cell_area, techname); + } + } + } + + printf("built hierarchy\n"); bool first_module = true; - for (auto mod : design->selected_modules()) - { + // determine if anything has a area. + bool has_area = false; + for (auto &it : mod_stat) { + if (it.second.area > 0 || it.second.sequential_area > 0) { + has_area = true; + break; + } + } + for (auto mod : design->selected_modules()) { if (!top_mod && design->full_selection()) if (mod->get_bool_attribute(ID::top)) top_mod = mod; - - statdata_t data(design, mod, width_mode, cell_area, techname); - mod_stat[mod->name] = data; - + statdata_t data = mod_stat.at(mod->name); if (json_mode) { - data.log_data_json(mod->name.c_str(), first_module); + data.log_data_json(mod->name.c_str(), first_module, hierarchy_mode); first_module = false; } else { log("\n"); log("=== %s%s ===\n", log_id(mod->name), mod->is_selected_whole() ? "" : " (partially selected)"); log("\n"); - data.log_data(mod->name, false); + data.log_data(mod->name, false, has_area, hierarchy_mode); } } @@ -483,22 +807,24 @@ struct StatPass : public Pass { log(top_mod == nullptr ? " }\n" : " },\n"); } - if (top_mod != nullptr) - { + if (top_mod != nullptr) { if (!json_mode && GetSize(mod_stat) > 1) { log("\n"); log("=== design hierarchy ===\n"); log("\n"); - log(" %-28s %6d\n", log_id(top_mod->name), 1); + mod_stat[top_mod->name].print_log_header(has_area, hierarchy_mode); + mod_stat[top_mod->name].print_log_line(log_id(top_mod->name), mod_stat[top_mod->name].local_num_cells, + mod_stat[top_mod->name].local_area, mod_stat[top_mod->name].num_cells, + mod_stat[top_mod->name].area, 0, has_area, hierarchy_mode); } - statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0, /*quiet=*/json_mode); + statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0, /*quiet=*/json_mode, has_area, hierarchy_mode); if (json_mode) - data.log_data_json("design", true); + data.log_data_json("design", true, true); else if (GetSize(mod_stat) > 1) { log("\n"); - data.log_data(top_mod->name, true); + data.log_data(top_mod->name, true, has_area, hierarchy_mode); } design->scratchpad_set_int("stat.num_wires", data.num_wires); @@ -520,6 +846,7 @@ struct StatPass : public Pass { } log("\n"); + printf("processed statistics\n"); } } StatPass; From 2a97987cf208d353ff76f6c3964ea2ee689c0955 Mon Sep 17 00:00:00 2001 From: clemens Date: Tue, 12 Aug 2025 09:16:05 +0200 Subject: [PATCH 091/176] formatting and remove debug statements --- passes/cmds/stat.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 0d19849c3..24b21d674 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -22,9 +22,9 @@ #include "kernel/celltypes.h" #include "kernel/cost.h" #include "kernel/gzip.h" +#include "kernel/log_help.h" #include "kernel/yosys.h" #include "libs/json11/json11.hpp" -#include "kernel/log_help.h" #include "passes/techmap/libparse.h" #include @@ -667,8 +667,9 @@ void read_liberty_cellarea(dict &cell_area, string libert } struct StatPass : public Pass { - StatPass() : Pass("stat", "print some statistics") { } - bool formatted_help() override { + StatPass() : Pass("stat", "print some statistics") {} + bool formatted_help() override + { auto *help = PrettyHelp::get_current(); help->set_group("passes/status"); return false; @@ -765,7 +766,6 @@ struct StatPass : public Pass { log(" \"modules\": {\n"); } - printf("building cell area\n"); if (top_mod != nullptr) { hierarchy_builder(design, top_mod, mod_stat, width_mode, cell_area, techname); } else { @@ -776,7 +776,6 @@ struct StatPass : public Pass { } } - printf("built hierarchy\n"); bool first_module = true; // determine if anything has a area. bool has_area = false; From 8582136a459c6ac38c1edcab9ed0e8c563ddfe73 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 12 Aug 2025 12:39:36 +0200 Subject: [PATCH 092/176] simplify: fix $initstate segfault --- frontends/ast/simplify.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index c25d0183f..b1a615d76 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -3369,13 +3369,14 @@ skip_dynamic_range_lvalue_expansion:; wire->str = stringf("$initstate$%d_wire", myidx); while (wire->simplify(true, 1, -1, false)) { } - auto cell = std::make_unique(location, AST_CELL, std::make_unique(location, AST_CELLTYPE), std::make_unique(location, AST_ARGUMENT, std::make_unique(location, AST_IDENTIFIER))); + auto cell_owned = std::make_unique(location, AST_CELL, std::make_unique(location, AST_CELLTYPE), std::make_unique(location, AST_ARGUMENT, std::make_unique(location, AST_IDENTIFIER))); + auto* cell = cell_owned.get(); cell->str = stringf("$initstate$%d", myidx); cell->children[0]->str = "$initstate"; cell->children[1]->str = "\\Y"; cell->children[1]->children[0]->str = wire->str; cell->children[1]->children[0]->id2ast = wire; - current_ast_mod->children.push_back(std::move(cell)); + current_ast_mod->children.push_back(std::move(cell_owned)); while (cell->simplify(true, 1, -1, false)) { } newNode = std::make_unique(location, AST_IDENTIFIER); From 6042ae0e8a18b1707a388b21630c1d819ea728d2 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 12 Aug 2025 12:59:31 +0200 Subject: [PATCH 093/176] simplify: add smoke test for system function calls --- tests/verilog/fcall_smoke.ys | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/verilog/fcall_smoke.ys diff --git a/tests/verilog/fcall_smoke.ys b/tests/verilog/fcall_smoke.ys new file mode 100644 index 000000000..a878e76f6 --- /dev/null +++ b/tests/verilog/fcall_smoke.ys @@ -0,0 +1,15 @@ +read_verilog -sv < Date: Tue, 12 Aug 2025 14:38:20 +0200 Subject: [PATCH 094/176] check: Limit detailed cell edge checking for $pmux and $bmux While these cells can't have a quadratic number of edges between A, B and Y, they do have a quadratic number of edges between S and Y. --- passes/cmds/check.cc | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc index 8bbcb8da0..3017630a6 100644 --- a/passes/cmds/check.cc +++ b/passes/cmds/check.cc @@ -195,16 +195,23 @@ struct CheckPass : public Pass { // in port widths are those for us to check. if (!cell->type.in( ID($add), ID($sub), - ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) + ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), + ID($pmux), ID($bmux))) return false; int in_widths = 0, out_widths = 0; - for (auto &conn : cell->connections()) { - if (cell->input(conn.first)) - in_widths += conn.second.size(); - if (cell->output(conn.first)) - out_widths += conn.second.size(); + if (cell->type.in(ID($pmux), ID($bmux))) { + // We're skipping inputs A and B, since each of their bits contributes only one edge + in_widths = GetSize(cell->getPort(ID::S)); + out_widths = GetSize(cell->getPort(ID::Y)); + } else { + for (auto &conn : cell->connections()) { + if (cell->input(conn.first)) + in_widths += conn.second.size(); + if (cell->output(conn.first)) + out_widths += conn.second.size(); + } } const int threshold = 1024; From 1f876f3a226ebb7b5e6227c915b868361a86ba37 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 12 Aug 2025 15:26:36 +0200 Subject: [PATCH 095/176] abstract: Add -initstates option --- passes/cmds/abstract.cc | 65 +++++++++++++++++++++++----- tests/various/abstract_initstates.ys | 30 +++++++++++++ 2 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 tests/various/abstract_initstates.ys diff --git a/passes/cmds/abstract.cc b/passes/cmds/abstract.cc index d4eb22ca5..907a16fe0 100644 --- a/passes/cmds/abstract.cc +++ b/passes/cmds/abstract.cc @@ -373,6 +373,12 @@ struct AbstractPass : public Pass { log(" abstractions performed by either mode. This option is not supported in\n"); log(" the -init mode.\n"); log("\n"); + log(" -initstates \n"); + log(" Perform conditional abstraction for the first time steps. See the\n"); + log(" description of the -state and -value modes for details on how the\n"); + log(" condition affects the abstractions performed by either mode. This option\n"); + log(" is not supported in the -init mode.\n"); + log("\n"); log(" -slice :\n"); log(" -slice \n"); log(" -rtlilslice :\n"); @@ -402,8 +408,10 @@ struct AbstractPass : public Pass { Always = -1, ActiveLow = false, // ensuring we can use bool(enable) ActiveHigh = true, + Initstates = 2, }; Enable enable = Enable::Always; + int initstates = 0; std::string enable_name; std::vector slices; for (argidx = 1; argidx < args.size(); argidx++) @@ -435,6 +443,13 @@ struct AbstractPass : public Pass { enable = Enable::ActiveLow; continue; } + if (arg == "-initstates" && argidx + 1 < args.size()) { + if (enable != Enable::Always) + log_cmd_error("Multiple enable condition are not supported\n"); + initstates = atoi(args[++argidx].c_str()); + enable = Enable::Initstates; + continue; + } if (arg == "-slice" && argidx + 1 < args.size()) { slices.emplace_back(SliceIndices::HdlSlice, args[++argidx]); continue; @@ -451,22 +466,50 @@ struct AbstractPass : public Pass { if (mode == Mode::Initial) log_cmd_error("Conditional initial value abstraction is not supported\n"); - if (enable_name.empty()) - log_cmd_error("Unspecified enable wire\n"); + switch (enable) { + case Enable::Always: + log_assert(false); + case Enable::ActiveLow: + case Enable::ActiveHigh: { + if (enable_name.empty()) + log_cmd_error("Unspecified enable wire\n"); + } break; + case Enable::Initstates: { + if (initstates <= 0) + log_cmd_error("Number of initial time steps must be positive\n"); + } break; + } } unsigned int changed = 0; if ((mode == State) || (mode == Value)) { for (auto mod : design->selected_modules()) { - EnableLogic enable_logic = { State::S1, true }; - if (enable != Enable::Always) { - Wire *enable_wire = mod->wire("\\" + enable_name); - if (!enable_wire) - log_cmd_error("Enable wire %s not found in module %s\n", enable_name.c_str(), mod->name.c_str()); - if (GetSize(enable_wire) != 1) - log_cmd_error("Enable wire %s must have width 1 but has width %d in module %s\n", - enable_name.c_str(), GetSize(enable_wire), mod->name.c_str()); - enable_logic = { enable_wire, enable == Enable::ActiveHigh }; + EnableLogic enable_logic; + + switch (enable) { + case Enable::Always: { + enable_logic = { State::S1, true }; + } break; + case Enable::ActiveLow: + case Enable::ActiveHigh: { + Wire *enable_wire = mod->wire("\\" + enable_name); + if (!enable_wire) + log_cmd_error("Enable wire %s not found in module %s\n", enable_name.c_str(), mod->name.c_str()); + if (GetSize(enable_wire) != 1) + log_cmd_error("Enable wire %s must have width 1 but has width %d in module %s\n", + enable_name.c_str(), GetSize(enable_wire), mod->name.c_str()); + enable_logic = { enable_wire, enable == Enable::ActiveHigh }; + } break; + case Enable::Initstates: { + SigBit in_init_states = mod->Initstate(NEW_ID); + for (int i = 1; i < initstates; i++) { + Wire *in_init_states_q = mod->addWire(NEW_ID); + mod->addFf(NEW_ID, in_init_states, in_init_states_q); + in_init_states_q->attributes[ID::init] = State::S1; + in_init_states = in_init_states_q; + } + enable_logic = { in_init_states, true }; + } break; } if (mode == State) changed += abstract_state(mod, enable_logic, slices); diff --git a/tests/various/abstract_initstates.ys b/tests/various/abstract_initstates.ys new file mode 100644 index 000000000..35d17cf62 --- /dev/null +++ b/tests/various/abstract_initstates.ys @@ -0,0 +1,30 @@ +read_verilog < Date: Wed, 13 Aug 2025 01:48:59 +0300 Subject: [PATCH 096/176] opt_dff: fix timeout issue --- passes/opt/opt_dff.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index 210c4828f..2fb0f947f 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -199,7 +199,7 @@ struct OptDffWorker const auto complimentary_var = find_comp(left, right); - if (complimentary_var) { + if (complimentary_var && new_patterns.count(right)) { new_patterns.erase(right); right.erase(complimentary_var.value()); new_patterns.insert(right); From 8634d83320e7c1362ae554c46f339055db27e25f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 13 Aug 2025 00:25:15 +0000 Subject: [PATCH 097/176] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b0f565338..10f8add20 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+30 +YOSYS_VER := 0.56+101 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 4ba42c4752795e5d7db003b330d904ad61d1ba8b Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 15 Jul 2025 01:26:24 +0000 Subject: [PATCH 098/176] Move ABC pass state to a struct instead of storing it in global variables. --- passes/techmap/abc.cc | 124 +++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index cc37677ce..16d27a0e6 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -113,23 +113,42 @@ bool map_mux8; bool map_mux16; bool markgroups; -int map_autoidx; -SigMap assign_map; -RTLIL::Module *module; -std::vector signal_list; -dict signal_map; -FfInitVals initvals; + pool enabled_gates; bool cmos_cost; -bool had_init; -bool clk_polarity, en_polarity, arst_polarity, srst_polarity; -RTLIL::SigSpec clk_sig, en_sig, arst_sig, srst_sig; -dict pi_map, po_map; +struct AbcModuleState { + int map_autoidx = 0; + SigMap assign_map; + RTLIL::Module *module = nullptr; + std::vector signal_list; + dict signal_map; + FfInitVals initvals; + bool had_init = false; -int undef_bits_lost; + bool clk_polarity = false; + bool en_polarity = false; + bool arst_polarity = false; + bool srst_polarity = false; + RTLIL::SigSpec clk_sig, en_sig, arst_sig, srst_sig; + dict pi_map, po_map; -int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1) + int undef_bits_lost = 0; + + int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); + void mark_port(RTLIL::SigSpec sig); + void extract_cell(RTLIL::Cell *cell, bool keepff); + std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr); + void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts); + void handle_loops(); + void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, + std::vector &liberty_files, std::vector &genlib_files, std::string constr_file, + bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, + std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, + const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector &dont_use_cells); +}; + +int AbcModuleState::map_signal(RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) { assign_map.apply(bit); @@ -167,14 +186,14 @@ int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, return gate.id; } -void mark_port(RTLIL::SigSpec sig) +void AbcModuleState::mark_port(RTLIL::SigSpec sig) { for (auto &bit : assign_map(sig)) if (bit.wire != nullptr && signal_map.count(bit) > 0) signal_list[signal_map[bit]].is_port = true; } -void extract_cell(RTLIL::Cell *cell, bool keepff) +void AbcModuleState::extract_cell(RTLIL::Cell *cell, bool keepff) { if (RTLIL::builtin_ff_cell_types().count(cell->type)) { FfData ff(&initvals, cell); @@ -377,7 +396,7 @@ void extract_cell(RTLIL::Cell *cell, bool keepff) } } -std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr) +std::string AbcModuleState::remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire) { std::string abc_sname = abc_name.substr(1); bool isnew = false; @@ -416,7 +435,7 @@ std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullp return stringf("$abc$%d$%s", map_autoidx, abc_name.c_str()+1); } -void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts) +void AbcModuleState::dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts) { if (f == nullptr) return; @@ -445,7 +464,7 @@ void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &w fprintf(f, "}\n"); } -void handle_loops() +void AbcModuleState::handle_loops() { // http://en.wikipedia.org/wiki/Topological_sorting // (Kahn, Arthur B. (1962), "Topological sorting of large networks") @@ -646,13 +665,15 @@ std::string replace_tempdir(std::string text, std::string tempdir_name, bool sho struct abc_output_filter { + const AbcModuleState &state; bool got_cr; int escape_seq_state; std::string linebuf; std::string tempdir_name; bool show_tempdir; - abc_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir) + abc_output_filter(const AbcModuleState& state, std::string tempdir_name, bool show_tempdir) + : state(state), tempdir_name(tempdir_name), show_tempdir(show_tempdir) { got_cr = false; escape_seq_state = 0; @@ -693,8 +714,8 @@ struct abc_output_filter int pi, po; if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) { log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n", - pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???", - po, po_map.count(po) ? po_map.at(po).c_str() : "???"); + pi, state.pi_map.count(pi) ? state.pi_map.at(pi).c_str() : "???", + po, state.po_map.count(po) ? state.po_map.at(po).c_str() : "???"); return; } @@ -703,20 +724,16 @@ struct abc_output_filter } }; -void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, +void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, std::vector &liberty_files, std::vector &genlib_files, std::string constr_file, bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector &dont_use_cells) { module = current_module; + initvals.set(&assign_map, module); map_autoidx = autoidx++; - signal_map.clear(); - signal_list.clear(); - pi_map.clear(); - po_map.clear(); - if (clk_str != "$") { clk_polarity = true; @@ -1109,7 +1126,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); #ifndef YOSYS_LINK_ABC - abc_output_filter filt(tempdir_name, show_tempdir); + abc_output_filter filt(*this, tempdir_name, show_tempdir); int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1)); #else string temp_stdouterr_name = stringf("%s/stdouterr.txt", tempdir_name.c_str()); @@ -1652,13 +1669,6 @@ struct AbcPass : public Pass { log_header(design, "Executing ABC pass (technology mapping using ABC).\n"); log_push(); - assign_map.clear(); - signal_list.clear(); - signal_map.clear(); - initvals.clear(); - pi_map.clear(); - po_map.clear(); - std::string exe_file = yosys_abc_executable; std::string script_file, default_liberty_file, constr_file, clk_str; std::vector liberty_files, genlib_files, dont_use_cells; @@ -1667,13 +1677,6 @@ struct AbcPass : public Pass { bool show_tempdir = false, sop_mode = false; bool abc_dress = false; vector lut_costs; - markgroups = false; - - map_mux4 = false; - map_mux8 = false; - map_mux16 = false; - enabled_gates.clear(); - cmos_cost = false; // get arguments from scratchpad first, then override by command arguments std::string lut_arg, luts_arg, g_arg; @@ -2049,11 +2052,10 @@ struct AbcPass : public Pass { continue; } - assign_map.set(mod); - initvals.set(&assign_map, mod); - if (!dff_mode || !clk_str.empty()) { - abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, + AbcModuleState state; + state.assign_map.set(mod); + state.abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress, dont_use_cells); continue; } @@ -2074,6 +2076,10 @@ struct AbcPass : public Pass { dict> cell_to_bit, cell_to_bit_up, cell_to_bit_down; dict> bit_to_cell, bit_to_cell_up, bit_to_cell_down; + SigMap assign_map; + assign_map.set(mod); + FfInitVals initvals; + initvals.set(&assign_map, mod); for (auto cell : all_cells) { clkdomain_t key; @@ -2207,27 +2213,21 @@ struct AbcPass : public Pass { std::get<6>(it.first) ? "" : "!", log_signal(std::get<7>(it.first))); for (auto &it : assigned_cells) { - clk_polarity = std::get<0>(it.first); - clk_sig = assign_map(std::get<1>(it.first)); - en_polarity = std::get<2>(it.first); - en_sig = assign_map(std::get<3>(it.first)); - arst_polarity = std::get<4>(it.first); - arst_sig = assign_map(std::get<5>(it.first)); - srst_polarity = std::get<6>(it.first); - srst_sig = assign_map(std::get<7>(it.first)); - abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$", + AbcModuleState state; + state.assign_map.set(mod); + state.clk_polarity = std::get<0>(it.first); + state.clk_sig = assign_map(std::get<1>(it.first)); + state.en_polarity = std::get<2>(it.first); + state.en_sig = assign_map(std::get<3>(it.first)); + state.arst_polarity = std::get<4>(it.first); + state.arst_sig = assign_map(std::get<5>(it.first)); + state.srst_polarity = std::get<6>(it.first); + state.srst_sig = assign_map(std::get<7>(it.first)); + state.abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !state.clk_sig.empty(), "$", keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress, dont_use_cells); - assign_map.set(mod); } } - assign_map.clear(); - signal_list.clear(); - signal_map.clear(); - initvals.clear(); - pi_map.clear(); - po_map.clear(); - log_pop(); } } AbcPass; From ceedcecfae4a2110f42f471f10ec8a901a73264e Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 15 Jul 2025 03:38:54 +0000 Subject: [PATCH 099/176] Move the input parameters to `abc_module` that are identical across modules to an `AbcConfig` struct. --- passes/techmap/abc.cc | 260 ++++++++++++++++++++++-------------------- 1 file changed, 137 insertions(+), 123 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 16d27a0e6..28e39998d 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -117,7 +117,30 @@ bool markgroups; pool enabled_gates; bool cmos_cost; +struct AbcConfig +{ + std::string script_file; + std::string exe_file; + std::vector liberty_files; + std::vector genlib_files; + std::string constr_file; + vector lut_costs; + std::string delay_target; + std::string sop_inputs; + std::string sop_products; + std::string lutin_shared; + std::vector dont_use_cells; + bool cleanup = true; + bool keepff = false; + bool fast_mode = false; + bool show_tempdir = false; + bool sop_mode = false; + bool abc_dress = false; +}; + struct AbcModuleState { + const AbcConfig &config; + int map_autoidx = 0; SigMap assign_map; RTLIL::Module *module = nullptr; @@ -135,17 +158,16 @@ struct AbcModuleState { int undef_bits_lost = 0; + AbcModuleState(const AbcConfig &config) : config(config) {} + int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); void mark_port(RTLIL::SigSpec sig); void extract_cell(RTLIL::Cell *cell, bool keepff); std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr); void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts); void handle_loops(); - void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, - std::vector &liberty_files, std::vector &genlib_files, std::string constr_file, - bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, - std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, - const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector &dont_use_cells); + void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, const std::vector &cells, + bool dff_mode, std::string clk_str); }; int AbcModuleState::map_signal(RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) @@ -724,11 +746,8 @@ struct abc_output_filter } }; -void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, - std::vector &liberty_files, std::vector &genlib_files, std::string constr_file, - bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, - std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, - const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector &dont_use_cells) +void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_module, const std::vector &cells, + bool dff_mode, std::string clk_str) { module = current_module; initvals.set(&assign_map, module); @@ -805,38 +824,39 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); std::string tempdir_name; - if (cleanup) + if (config.cleanup) tempdir_name = get_base_tmpdir() + "/"; else tempdir_name = "_tmp_"; tempdir_name += proc_program_prefix() + "yosys-abc-XXXXXX"; tempdir_name = make_temp_dir(tempdir_name); log_header(design, "Extracting gate netlist of module `%s' to `%s/input.blif'..\n", - module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); + module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, config.show_tempdir).c_str()); std::string abc_script = stringf("read_blif \"%s/input.blif\"; ", tempdir_name.c_str()); - if (!liberty_files.empty() || !genlib_files.empty()) { + if (!config.liberty_files.empty() || !config.genlib_files.empty()) { std::string dont_use_args; - for (std::string dont_use_cell : dont_use_cells) { + for (std::string dont_use_cell : config.dont_use_cells) { dont_use_args += stringf("-X \"%s\" ", dont_use_cell.c_str()); } bool first_lib = true; - for (std::string liberty_file : liberty_files) { + for (std::string liberty_file : config.liberty_files) { abc_script += stringf("read_lib %s %s -w \"%s\" ; ", dont_use_args.c_str(), first_lib ? "" : "-m", liberty_file.c_str()); first_lib = false; } - for (std::string liberty_file : genlib_files) + for (std::string liberty_file : config.genlib_files) abc_script += stringf("read_library \"%s\"; ", liberty_file.c_str()); - if (!constr_file.empty()) - abc_script += stringf("read_constr -v \"%s\"; ", constr_file.c_str()); + if (!config.constr_file.empty()) + abc_script += stringf("read_constr -v \"%s\"; ", config.constr_file.c_str()); } else - if (!lut_costs.empty()) + if (!config.lut_costs.empty()) abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); else abc_script += stringf("read_library %s/stdcells.genlib; ", tempdir_name.c_str()); - if (!script_file.empty()) { + if (!config.script_file.empty()) { + const std::string &script_file = config.script_file; if (script_file[0] == '+') { for (size_t i = 1; i < script_file.size(); i++) if (script_file[i] == '\'') @@ -847,37 +867,38 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo abc_script += script_file[i]; } else abc_script += stringf("source %s", script_file.c_str()); - } else if (!lut_costs.empty()) { + } else if (!config.lut_costs.empty()) { bool all_luts_cost_same = true; - for (int this_cost : lut_costs) - if (this_cost != lut_costs.front()) + for (int this_cost : config.lut_costs) + if (this_cost != config.lut_costs.front()) all_luts_cost_same = false; - abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; - if (all_luts_cost_same && !fast_mode) + abc_script += config.fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; + if (all_luts_cost_same && !config.fast_mode) abc_script += "; lutpack {S}"; - } else if (!liberty_files.empty() || !genlib_files.empty()) - abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR); - else if (sop_mode) - abc_script += fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP; + } else if (!config.liberty_files.empty() || !config.genlib_files.empty()) + abc_script += config.constr_file.empty() ? + (config.fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (config.fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR); + else if (config.sop_mode) + abc_script += config.fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP; else - abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL; + abc_script += config.fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL; - if (script_file.empty() && !delay_target.empty()) + if (config.script_file.empty() && !config.delay_target.empty()) for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1)) abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8); for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos)) - abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3); + abc_script = abc_script.substr(0, pos) + config.delay_target + abc_script.substr(pos+3); for (size_t pos = abc_script.find("{I}"); pos != std::string::npos; pos = abc_script.find("{I}", pos)) - abc_script = abc_script.substr(0, pos) + sop_inputs + abc_script.substr(pos+3); + abc_script = abc_script.substr(0, pos) + config.sop_inputs + abc_script.substr(pos+3); for (size_t pos = abc_script.find("{P}"); pos != std::string::npos; pos = abc_script.find("{P}", pos)) - abc_script = abc_script.substr(0, pos) + sop_products + abc_script.substr(pos+3); + abc_script = abc_script.substr(0, pos) + config.sop_products + abc_script.substr(pos+3); for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos)) - abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3); - if (abc_dress) + abc_script = abc_script.substr(0, pos) + config.lutin_shared + abc_script.substr(pos+3); + if (config.abc_dress) abc_script += stringf("; dress \"%s/input.blif\"", tempdir_name.c_str()); abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str()); abc_script = add_echos_to_abc_cmd(abc_script); @@ -913,7 +934,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo had_init = false; for (auto c : cells) - extract_cell(c, keepff); + extract_cell(c, config.keepff); if (undef_bits_lost) log("Replacing %d occurrences of constant undef bits with constant zero bits\n", undef_bits_lost); @@ -1112,21 +1133,21 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*cell_cost.at(ID($_MUX_))); fclose(f); - if (!lut_costs.empty()) { + if (!config.lut_costs.empty()) { buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str()); f = fopen(buffer.c_str(), "wt"); if (f == nullptr) log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); - for (int i = 0; i < GetSize(lut_costs); i++) - fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i)); + for (int i = 0; i < GetSize(config.lut_costs); i++) + fprintf(f, "%d %d.00 1.00\n", i+1, config.lut_costs.at(i)); fclose(f); } - buffer = stringf("\"%s\" -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); - log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); + buffer = stringf("\"%s\" -s -f %s/abc.script 2>&1", config.exe_file.c_str(), tempdir_name.c_str()); + log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, config.show_tempdir).c_str()); #ifndef YOSYS_LINK_ABC - abc_output_filter filt(*this, tempdir_name, show_tempdir); + abc_output_filter filt(*this, tempdir_name, config.show_tempdir); int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1)); #else string temp_stdouterr_name = stringf("%s/stdouterr.txt", tempdir_name.c_str()); @@ -1150,7 +1171,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo // These needs to be mutable, supposedly due to getopt char *abc_argv[5]; string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str()); - abc_argv[0] = strdup(exe_file.c_str()); + abc_argv[0] = strdup(config.exe_file.c_str()); abc_argv[1] = strdup("-s"); abc_argv[2] = strdup("-f"); abc_argv[3] = strdup(tmp_script_name.c_str()); @@ -1167,7 +1188,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo fclose(old_stdout); fclose(old_stderr); std::ifstream temp_stdouterr_r(temp_stdouterr_name); - abc_output_filter filt(tempdir_name, show_tempdir); + abc_output_filter filt(*this, tempdir_name, config.show_tempdir); for (std::string line; std::getline(temp_stdouterr_r, line); ) filt.next_line(line + "\n"); temp_stdouterr_r.close(); @@ -1181,9 +1202,9 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo if (ifs.fail()) log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); - bool builtin_lib = liberty_files.empty() && genlib_files.empty(); + bool builtin_lib = config.liberty_files.empty() && config.genlib_files.empty(); RTLIL::Design *mapped_design = new RTLIL::Design; - parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, sop_mode); + parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, config.sop_mode); ifs.close(); @@ -1459,7 +1480,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo log("Don't call ABC as there is nothing to map.\n"); } - if (cleanup) + if (config.cleanup) { log("Removing temp directory.\n"); remove_directory(tempdir_name); @@ -1669,57 +1690,52 @@ struct AbcPass : public Pass { log_header(design, "Executing ABC pass (technology mapping using ABC).\n"); log_push(); - std::string exe_file = yosys_abc_executable; - std::string script_file, default_liberty_file, constr_file, clk_str; - std::vector liberty_files, genlib_files, dont_use_cells; - std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1"; - bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; - bool show_tempdir = false, sop_mode = false; - bool abc_dress = false; - vector lut_costs; + AbcConfig config; // get arguments from scratchpad first, then override by command arguments std::string lut_arg, luts_arg, g_arg; - exe_file = design->scratchpad_get_string("abc.exe", exe_file /* inherit default value if not set */); - script_file = design->scratchpad_get_string("abc.script", script_file); - default_liberty_file = design->scratchpad_get_string("abc.liberty", default_liberty_file); - constr_file = design->scratchpad_get_string("abc.constr", constr_file); + config.exe_file = design->scratchpad_get_string("abc.exe", yosys_abc_executable /* inherit default value if not set */); + config.script_file = design->scratchpad_get_string("abc.script", ""); + std::string default_liberty_file = design->scratchpad_get_string("abc.liberty", ""); + config.constr_file = design->scratchpad_get_string("abc.constr", ""); if (design->scratchpad.count("abc.D")) { - delay_target = "-D " + design->scratchpad_get_string("abc.D"); + config.delay_target = "-D " + design->scratchpad_get_string("abc.D"); } if (design->scratchpad.count("abc.I")) { - sop_inputs = "-I " + design->scratchpad_get_string("abc.I"); + config.sop_inputs = "-I " + design->scratchpad_get_string("abc.I"); } if (design->scratchpad.count("abc.P")) { - sop_products = "-P " + design->scratchpad_get_string("abc.P"); + config.sop_products = "-P " + design->scratchpad_get_string("abc.P"); } if (design->scratchpad.count("abc.S")) { - lutin_shared = "-S " + design->scratchpad_get_string("abc.S"); + config.lutin_shared = "-S " + design->scratchpad_get_string("abc.S"); + } else { + config.lutin_shared = "-S 1"; } lut_arg = design->scratchpad_get_string("abc.lut", lut_arg); luts_arg = design->scratchpad_get_string("abc.luts", luts_arg); - sop_mode = design->scratchpad_get_bool("abc.sop", sop_mode); + config.sop_mode = design->scratchpad_get_bool("abc.sop", false); map_mux4 = design->scratchpad_get_bool("abc.mux4", map_mux4); map_mux8 = design->scratchpad_get_bool("abc.mux8", map_mux8); map_mux16 = design->scratchpad_get_bool("abc.mux16", map_mux16); - abc_dress = design->scratchpad_get_bool("abc.dress", abc_dress); + config.abc_dress = design->scratchpad_get_bool("abc.dress", false); g_arg = design->scratchpad_get_string("abc.g", g_arg); - fast_mode = design->scratchpad_get_bool("abc.fast", fast_mode); - dff_mode = design->scratchpad_get_bool("abc.dff", dff_mode); + config.fast_mode = design->scratchpad_get_bool("abc.fast", false); + bool dff_mode = design->scratchpad_get_bool("abc.dff", false); + std::string clk_str; if (design->scratchpad.count("abc.clk")) { clk_str = design->scratchpad_get_string("abc.clk"); dff_mode = true; } - keepff = design->scratchpad_get_bool("abc.keepff", keepff); - cleanup = !design->scratchpad_get_bool("abc.nocleanup", !cleanup); - keepff = design->scratchpad_get_bool("abc.keepff", keepff); - show_tempdir = design->scratchpad_get_bool("abc.showtmp", show_tempdir); + config.keepff = design->scratchpad_get_bool("abc.keepff", false); + config.cleanup = !design->scratchpad_get_bool("abc.nocleanup", false); + config.show_tempdir = design->scratchpad_get_bool("abc.showtmp", false); markgroups = design->scratchpad_get_bool("abc.markgroups", markgroups); if (design->scratchpad_get_bool("abc.debug")) { - cleanup = false; - show_tempdir = true; + config.cleanup = false; + config.show_tempdir = true; } size_t argidx, g_argidx = -1; @@ -1736,43 +1752,43 @@ struct AbcPass : public Pass { for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if (arg == "-exe" && argidx+1 < args.size()) { - exe_file = args[++argidx]; + config.exe_file = args[++argidx]; continue; } if (arg == "-script" && argidx+1 < args.size()) { - script_file = args[++argidx]; + config.script_file = args[++argidx]; continue; } if (arg == "-liberty" && argidx+1 < args.size()) { - liberty_files.push_back(args[++argidx]); + config.liberty_files.push_back(args[++argidx]); continue; } if (arg == "-dont_use" && argidx+1 < args.size()) { - dont_use_cells.push_back(args[++argidx]); + config.dont_use_cells.push_back(args[++argidx]); continue; } if (arg == "-genlib" && argidx+1 < args.size()) { - genlib_files.push_back(args[++argidx]); + config.genlib_files.push_back(args[++argidx]); continue; } if (arg == "-constr" && argidx+1 < args.size()) { - constr_file = args[++argidx]; + config.constr_file = args[++argidx]; continue; } if (arg == "-D" && argidx+1 < args.size()) { - delay_target = "-D " + args[++argidx]; + config.delay_target = "-D " + args[++argidx]; continue; } if (arg == "-I" && argidx+1 < args.size()) { - sop_inputs = "-I " + args[++argidx]; + config.sop_inputs = "-I " + args[++argidx]; continue; } if (arg == "-P" && argidx+1 < args.size()) { - sop_products = "-P " + args[++argidx]; + config.sop_products = "-P " + args[++argidx]; continue; } if (arg == "-S" && argidx+1 < args.size()) { - lutin_shared = "-S " + args[++argidx]; + config.lutin_shared = "-S " + args[++argidx]; continue; } if (arg == "-lut" && argidx+1 < args.size()) { @@ -1784,7 +1800,7 @@ struct AbcPass : public Pass { continue; } if (arg == "-sop") { - sop_mode = true; + config.sop_mode = true; continue; } if (arg == "-mux4") { @@ -1800,7 +1816,7 @@ struct AbcPass : public Pass { continue; } if (arg == "-dress") { - abc_dress = true; + config.abc_dress = true; continue; } if (arg == "-g" && argidx+1 < args.size()) { @@ -1812,7 +1828,7 @@ struct AbcPass : public Pass { continue; } if (arg == "-fast") { - fast_mode = true; + config.fast_mode = true; continue; } if (arg == "-dff") { @@ -1825,15 +1841,15 @@ struct AbcPass : public Pass { continue; } if (arg == "-keepff") { - keepff = true; + config.keepff = true; continue; } if (arg == "-nocleanup") { - cleanup = false; + config.cleanup = false; continue; } if (arg == "-showtmp") { - show_tempdir = true; + config.show_tempdir = true; continue; } if (arg == "-markgroups") { @@ -1844,25 +1860,25 @@ struct AbcPass : public Pass { } extra_args(args, argidx, design); - if (genlib_files.empty() && liberty_files.empty() && !default_liberty_file.empty()) - liberty_files.push_back(default_liberty_file); + if (config.genlib_files.empty() && config.liberty_files.empty() && !default_liberty_file.empty()) + config.liberty_files.push_back(default_liberty_file); - rewrite_filename(script_file); - if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+') - script_file = std::string(pwd) + "/" + script_file; - for (int i = 0; i < GetSize(liberty_files); i++) { - rewrite_filename(liberty_files[i]); - if (!liberty_files[i].empty() && !is_absolute_path(liberty_files[i])) - liberty_files[i] = std::string(pwd) + "/" + liberty_files[i]; + rewrite_filename(config.script_file); + if (!config.script_file.empty() && !is_absolute_path(config.script_file) && config.script_file[0] != '+') + config.script_file = std::string(pwd) + "/" + config.script_file; + for (int i = 0; i < GetSize(config.liberty_files); i++) { + rewrite_filename(config.liberty_files[i]); + if (!config.liberty_files[i].empty() && !is_absolute_path(config.liberty_files[i])) + config.liberty_files[i] = std::string(pwd) + "/" + config.liberty_files[i]; } - for (int i = 0; i < GetSize(genlib_files); i++) { - rewrite_filename(genlib_files[i]); - if (!genlib_files[i].empty() && !is_absolute_path(genlib_files[i])) - genlib_files[i] = std::string(pwd) + "/" + genlib_files[i]; + for (int i = 0; i < GetSize(config.genlib_files); i++) { + rewrite_filename(config.genlib_files[i]); + if (!config.genlib_files[i].empty() && !is_absolute_path(config.genlib_files[i])) + config.genlib_files[i] = std::string(pwd) + "/" + config.genlib_files[i]; } - rewrite_filename(constr_file); - if (!constr_file.empty() && !is_absolute_path(constr_file)) - constr_file = std::string(pwd) + "/" + constr_file; + rewrite_filename(config.constr_file); + if (!config.constr_file.empty() && !is_absolute_path(config.constr_file)) + config.constr_file = std::string(pwd) + "/" + config.constr_file; // handle -lut argument if (!lut_arg.empty()) { @@ -1875,24 +1891,24 @@ struct AbcPass : public Pass { lut_mode = atoi(lut_arg.c_str()); lut_mode2 = lut_mode; } - lut_costs.clear(); + config.lut_costs.clear(); for (int i = 0; i < lut_mode; i++) - lut_costs.push_back(1); + config.lut_costs.push_back(1); for (int i = lut_mode; i < lut_mode2; i++) - lut_costs.push_back(2 << (i - lut_mode)); + config.lut_costs.push_back(2 << (i - lut_mode)); } //handle -luts argument if (!luts_arg.empty()){ - lut_costs.clear(); + config.lut_costs.clear(); for (auto &tok : split_tokens(luts_arg, ",")) { auto parts = split_tokens(tok, ":"); - if (GetSize(parts) == 0 && !lut_costs.empty()) - lut_costs.push_back(lut_costs.back()); + if (GetSize(parts) == 0 && !config.lut_costs.empty()) + config.lut_costs.push_back(config.lut_costs.back()); else if (GetSize(parts) == 1) - lut_costs.push_back(atoi(parts.at(0).c_str())); + config.lut_costs.push_back(atoi(parts.at(0).c_str())); else if (GetSize(parts) == 2) - while (GetSize(lut_costs) < std::atoi(parts.at(0).c_str())) - lut_costs.push_back(atoi(parts.at(1).c_str())); + while (GetSize(config.lut_costs) < std::atoi(parts.at(0).c_str())) + config.lut_costs.push_back(atoi(parts.at(1).c_str())); else log_cmd_error("Invalid -luts syntax.\n"); } @@ -2023,9 +2039,9 @@ struct AbcPass : public Pass { } } - if (!lut_costs.empty() && !(liberty_files.empty() && genlib_files.empty())) + if (!config.lut_costs.empty() && !(config.liberty_files.empty() && config.genlib_files.empty())) log_cmd_error("Got -lut and -liberty/-genlib! These two options are exclusive.\n"); - if (!constr_file.empty() && (liberty_files.empty() && genlib_files.empty())) + if (!config.constr_file.empty() && (config.liberty_files.empty() && config.genlib_files.empty())) log_cmd_error("Got -constr but no -liberty/-genlib!\n"); if (enabled_gates.empty()) { @@ -2053,10 +2069,9 @@ struct AbcPass : public Pass { } if (!dff_mode || !clk_str.empty()) { - AbcModuleState state; + AbcModuleState state(config); state.assign_map.set(mod); - state.abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, - delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress, dont_use_cells); + state.abc_module(design, mod, mod->selected_cells(), dff_mode, clk_str); continue; } @@ -2213,7 +2228,7 @@ struct AbcPass : public Pass { std::get<6>(it.first) ? "" : "!", log_signal(std::get<7>(it.first))); for (auto &it : assigned_cells) { - AbcModuleState state; + AbcModuleState state(config); state.assign_map.set(mod); state.clk_polarity = std::get<0>(it.first); state.clk_sig = assign_map(std::get<1>(it.first)); @@ -2223,8 +2238,7 @@ struct AbcPass : public Pass { state.arst_sig = assign_map(std::get<5>(it.first)); state.srst_polarity = std::get<6>(it.first); state.srst_sig = assign_map(std::get<7>(it.first)); - state.abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !state.clk_sig.empty(), "$", - keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress, dont_use_cells); + state.abc_module(design, mod, it.second, !state.clk_sig.empty(), "$"); } } From 53c72c0d3944535e7d81d785d4c6f78c7cafcc33 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 15 Jul 2025 03:54:41 +0000 Subject: [PATCH 100/176] Move code in `abc_module()` that modifies the design into a new function `extract()` Splits up the big `abc_module()` function and isolates the code that modifies the design after running ABC. --- passes/techmap/abc.cc | 491 ++++++++++++++++++++++-------------------- 1 file changed, 255 insertions(+), 236 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 28e39998d..494494a49 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -148,6 +148,7 @@ struct AbcModuleState { dict signal_map; FfInitVals initvals; bool had_init = false; + bool did_run_abc = false; bool clk_polarity = false; bool en_polarity = false; @@ -158,6 +159,8 @@ struct AbcModuleState { int undef_bits_lost = 0; + std::string tempdir_name; + AbcModuleState(const AbcConfig &config) : config(config) {} int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); @@ -168,6 +171,8 @@ struct AbcModuleState { void handle_loops(); void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, const std::vector &cells, bool dff_mode, std::string clk_str); + void extract(RTLIL::Design *design); + void finish(); }; int AbcModuleState::map_signal(RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) @@ -823,7 +828,6 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo if (dff_mode && clk_sig.empty()) log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); - std::string tempdir_name; if (config.cleanup) tempdir_name = get_base_tmpdir() + "/"; else @@ -1193,194 +1197,155 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo filt.next_line(line + "\n"); temp_stdouterr_r.close(); #endif - if (ret != 0) + if (ret != 0) { log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); - - buffer = stringf("%s/%s", tempdir_name.c_str(), "output.blif"); - std::ifstream ifs; - ifs.open(buffer); - if (ifs.fail()) - log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); - - bool builtin_lib = config.liberty_files.empty() && config.genlib_files.empty(); - RTLIL::Design *mapped_design = new RTLIL::Design; - parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, config.sop_mode); - - ifs.close(); - - log_header(design, "Re-integrating ABC results.\n"); - RTLIL::Module *mapped_mod = mapped_design->module(ID(netlist)); - if (mapped_mod == nullptr) - log_error("ABC output file does not contain a module `netlist'.\n"); - for (auto w : mapped_mod->wires()) { - RTLIL::Wire *orig_wire = nullptr; - RTLIL::Wire *wire = module->addWire(remap_name(w->name, &orig_wire)); - if (orig_wire != nullptr && orig_wire->attributes.count(ID::src)) - wire->attributes[ID::src] = orig_wire->attributes[ID::src]; - if (markgroups) wire->attributes[ID::abcgroup] = map_autoidx; - design->select(module, wire); + return; } + did_run_abc = true; + return; + } + log("Don't call ABC as there is nothing to map.\n"); +} - SigMap mapped_sigmap(mapped_mod); - FfInitVals mapped_initvals(&mapped_sigmap, mapped_mod); +void AbcModuleState::extract(RTLIL::Design *design) +{ + if (!did_run_abc) { + return; + } - dict cell_stats; - for (auto c : mapped_mod->cells()) + std::string buffer = stringf("%s/%s", tempdir_name.c_str(), "output.blif"); + std::ifstream ifs; + ifs.open(buffer); + if (ifs.fail()) + log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); + + bool builtin_lib = config.liberty_files.empty() && config.genlib_files.empty(); + RTLIL::Design *mapped_design = new RTLIL::Design; + parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, config.sop_mode); + + ifs.close(); + + log_header(design, "Re-integrating ABC results.\n"); + RTLIL::Module *mapped_mod = mapped_design->module(ID(netlist)); + if (mapped_mod == nullptr) + log_error("ABC output file does not contain a module `netlist'.\n"); + for (auto w : mapped_mod->wires()) { + RTLIL::Wire *orig_wire = nullptr; + RTLIL::Wire *wire = module->addWire(remap_name(w->name, &orig_wire)); + if (orig_wire != nullptr && orig_wire->attributes.count(ID::src)) + wire->attributes[ID::src] = orig_wire->attributes[ID::src]; + if (markgroups) wire->attributes[ID::abcgroup] = map_autoidx; + design->select(module, wire); + } + + SigMap mapped_sigmap(mapped_mod); + FfInitVals mapped_initvals(&mapped_sigmap, mapped_mod); + + dict cell_stats; + for (auto c : mapped_mod->cells()) + { + if (builtin_lib) { - if (builtin_lib) - { - cell_stats[RTLIL::unescape_id(c->type)]++; - if (c->type.in(ID(ZERO), ID(ONE))) { - RTLIL::SigSig conn; - RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name); - conn.first = module->wire(name_y); - conn.second = RTLIL::SigSpec(c->type == ID(ZERO) ? 0 : 1, 1); - module->connect(conn); - continue; - } - if (c->type == ID(BUF)) { - RTLIL::SigSig conn; - RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name); - RTLIL::IdString name_a = remap_name(c->getPort(ID::A).as_wire()->name); - conn.first = module->wire(name_y); - conn.second = module->wire(name_a); - module->connect(conn); - continue; - } - if (c->type == ID(NOT)) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_NOT_)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type.in(ID(AND), ID(OR), ID(XOR), ID(NAND), ID(NOR), ID(XNOR), ID(ANDNOT), ID(ORNOT))) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type.in(ID(MUX), ID(NMUX))) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::S, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type == ID(MUX4)) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX4_)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::S, ID::T, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type == ID(MUX8)) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX8_)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::S, ID::T, ID::U, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type == ID(MUX16)) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX16_)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::I, ID::J, ID::K, - ID::L, ID::M, ID::N, ID::O, ID::P, ID::S, ID::T, ID::U, ID::V, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type.in(ID(AOI3), ID(OAI3))) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::C, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type.in(ID(AOI4), ID(OAI4))) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type == ID(DFF)) { - log_assert(clk_sig.size() == 1); - FfData ff(module, &initvals, remap_name(c->name)); - ff.width = 1; - ff.is_fine = true; - ff.has_clk = true; - ff.pol_clk = clk_polarity; - ff.sig_clk = clk_sig; - if (en_sig.size() != 0) { - log_assert(en_sig.size() == 1); - ff.has_ce = true; - ff.pol_ce = en_polarity; - ff.sig_ce = en_sig; - } - RTLIL::Const init = mapped_initvals(c->getPort(ID::Q)); - if (had_init) - ff.val_init = init; - else - ff.val_init = State::Sx; - if (arst_sig.size() != 0) { - log_assert(arst_sig.size() == 1); - ff.has_arst = true; - ff.pol_arst = arst_polarity; - ff.sig_arst = arst_sig; - ff.val_arst = init; - } - if (srst_sig.size() != 0) { - log_assert(srst_sig.size() == 1); - ff.has_srst = true; - ff.pol_srst = srst_polarity; - ff.sig_srst = srst_sig; - ff.val_srst = init; - } - ff.sig_d = module->wire(remap_name(c->getPort(ID::D).as_wire()->name)); - ff.sig_q = module->wire(remap_name(c->getPort(ID::Q).as_wire()->name)); - RTLIL::Cell *cell = ff.emit(); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - design->select(module, cell); - continue; - } - } - else - cell_stats[RTLIL::unescape_id(c->type)]++; - - if (c->type.in(ID(_const0_), ID(_const1_))) { + cell_stats[RTLIL::unescape_id(c->type)]++; + if (c->type.in(ID(ZERO), ID(ONE))) { RTLIL::SigSig conn; - conn.first = module->wire(remap_name(c->connections().begin()->second.as_wire()->name)); - conn.second = RTLIL::SigSpec(c->type == ID(_const0_) ? 0 : 1, 1); + RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name); + conn.first = module->wire(name_y); + conn.second = RTLIL::SigSpec(c->type == ID(ZERO) ? 0 : 1, 1); module->connect(conn); continue; } - - if (c->type == ID(_dff_)) { + if (c->type == ID(BUF)) { + RTLIL::SigSig conn; + RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name); + RTLIL::IdString name_a = remap_name(c->getPort(ID::A).as_wire()->name); + conn.first = module->wire(name_y); + conn.second = module->wire(name_a); + module->connect(conn); + continue; + } + if (c->type == ID(NOT)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_NOT_)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type.in(ID(AND), ID(OR), ID(XOR), ID(NAND), ID(NOR), ID(XNOR), ID(ANDNOT), ID(ORNOT))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type.in(ID(MUX), ID(NMUX))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::S, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type == ID(MUX4)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX4_)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::S, ID::T, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type == ID(MUX8)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX8_)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::S, ID::T, ID::U, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type == ID(MUX16)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX16_)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::I, ID::J, ID::K, + ID::L, ID::M, ID::N, ID::O, ID::P, ID::S, ID::T, ID::U, ID::V, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type.in(ID(AOI3), ID(OAI3))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::C, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type.in(ID(AOI4), ID(OAI4))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type == ID(DFF)) { log_assert(clk_sig.size() == 1); FfData ff(module, &initvals, remap_name(c->name)); ff.width = 1; @@ -1390,6 +1355,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo ff.sig_clk = clk_sig; if (en_sig.size() != 0) { log_assert(en_sig.size() == 1); + ff.has_ce = true; ff.pol_ce = en_polarity; ff.sig_ce = en_sig; } @@ -1400,12 +1366,14 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo ff.val_init = State::Sx; if (arst_sig.size() != 0) { log_assert(arst_sig.size() == 1); + ff.has_arst = true; ff.pol_arst = arst_polarity; ff.sig_arst = arst_sig; ff.val_arst = init; } if (srst_sig.size() != 0) { log_assert(srst_sig.size() == 1); + ff.has_srst = true; ff.pol_srst = srst_polarity; ff.sig_srst = srst_sig; ff.val_srst = init; @@ -1417,69 +1385,116 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo design->select(module, cell); continue; } + } + else + cell_stats[RTLIL::unescape_id(c->type)]++; - if (c->type == ID($lut) && GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID::LUT).as_int() == 2) { - SigSpec my_a = module->wire(remap_name(c->getPort(ID::A).as_wire()->name)); - SigSpec my_y = module->wire(remap_name(c->getPort(ID::Y).as_wire()->name)); - module->connect(my_y, my_a); - continue; - } - - RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - cell->parameters = c->parameters; - for (auto &conn : c->connections()) { - RTLIL::SigSpec newsig; - for (auto &c : conn.second.chunks()) { - if (c.width == 0) - continue; - log_assert(c.width == 1); - newsig.append(module->wire(remap_name(c.wire->name))); - } - cell->setPort(conn.first, newsig); - } - design->select(module, cell); + if (c->type.in(ID(_const0_), ID(_const1_))) { + RTLIL::SigSig conn; + conn.first = module->wire(remap_name(c->connections().begin()->second.as_wire()->name)); + conn.second = RTLIL::SigSpec(c->type == ID(_const0_) ? 0 : 1, 1); + module->connect(conn); + continue; } - for (auto conn : mapped_mod->connections()) { - if (!conn.first.is_fully_const()) - conn.first = module->wire(remap_name(conn.first.as_wire()->name)); - if (!conn.second.is_fully_const()) - conn.second = module->wire(remap_name(conn.second.as_wire()->name)); + if (c->type == ID(_dff_)) { + log_assert(clk_sig.size() == 1); + FfData ff(module, &initvals, remap_name(c->name)); + ff.width = 1; + ff.is_fine = true; + ff.has_clk = true; + ff.pol_clk = clk_polarity; + ff.sig_clk = clk_sig; + if (en_sig.size() != 0) { + log_assert(en_sig.size() == 1); + ff.pol_ce = en_polarity; + ff.sig_ce = en_sig; + } + RTLIL::Const init = mapped_initvals(c->getPort(ID::Q)); + if (had_init) + ff.val_init = init; + else + ff.val_init = State::Sx; + if (arst_sig.size() != 0) { + log_assert(arst_sig.size() == 1); + ff.pol_arst = arst_polarity; + ff.sig_arst = arst_sig; + ff.val_arst = init; + } + if (srst_sig.size() != 0) { + log_assert(srst_sig.size() == 1); + ff.pol_srst = srst_polarity; + ff.sig_srst = srst_sig; + ff.val_srst = init; + } + ff.sig_d = module->wire(remap_name(c->getPort(ID::D).as_wire()->name)); + ff.sig_q = module->wire(remap_name(c->getPort(ID::Q).as_wire()->name)); + RTLIL::Cell *cell = ff.emit(); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + design->select(module, cell); + continue; + } + + if (c->type == ID($lut) && GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID::LUT).as_int() == 2) { + SigSpec my_a = module->wire(remap_name(c->getPort(ID::A).as_wire()->name)); + SigSpec my_y = module->wire(remap_name(c->getPort(ID::Y).as_wire()->name)); + module->connect(my_y, my_a); + continue; + } + + RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + cell->parameters = c->parameters; + for (auto &conn : c->connections()) { + RTLIL::SigSpec newsig; + for (auto &c : conn.second.chunks()) { + if (c.width == 0) + continue; + log_assert(c.width == 1); + newsig.append(module->wire(remap_name(c.wire->name))); + } + cell->setPort(conn.first, newsig); + } + design->select(module, cell); + } + + for (auto conn : mapped_mod->connections()) { + if (!conn.first.is_fully_const()) + conn.first = module->wire(remap_name(conn.first.as_wire()->name)); + if (!conn.second.is_fully_const()) + conn.second = module->wire(remap_name(conn.second.as_wire()->name)); + module->connect(conn); + } + + cell_stats.sort(); + for (auto &it : cell_stats) + log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); + int in_wires = 0, out_wires = 0; + for (auto &si : signal_list) + if (si.is_port) { + char buffer[100]; + snprintf(buffer, 100, "\\ys__n%d", si.id); + RTLIL::SigSig conn; + if (si.type != G(NONE)) { + conn.first = si.bit; + conn.second = module->wire(remap_name(buffer)); + out_wires++; + } else { + conn.first = module->wire(remap_name(buffer)); + conn.second = si.bit; + in_wires++; + } module->connect(conn); } + log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); + log("ABC RESULTS: input signals: %8d\n", in_wires); + log("ABC RESULTS: output signals: %8d\n", out_wires); - cell_stats.sort(); - for (auto &it : cell_stats) - log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); - int in_wires = 0, out_wires = 0; - for (auto &si : signal_list) - if (si.is_port) { - char buffer[100]; - snprintf(buffer, 100, "\\ys__n%d", si.id); - RTLIL::SigSig conn; - if (si.type != G(NONE)) { - conn.first = si.bit; - conn.second = module->wire(remap_name(buffer)); - out_wires++; - } else { - conn.first = module->wire(remap_name(buffer)); - conn.second = si.bit; - in_wires++; - } - module->connect(conn); - } - log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); - log("ABC RESULTS: input signals: %8d\n", in_wires); - log("ABC RESULTS: output signals: %8d\n", out_wires); - - delete mapped_design; - } - else - { - log("Don't call ABC as there is nothing to map.\n"); - } + delete mapped_design; +} +void AbcModuleState::finish() +{ if (config.cleanup) { log("Removing temp directory.\n"); @@ -2072,6 +2087,8 @@ struct AbcPass : public Pass { AbcModuleState state(config); state.assign_map.set(mod); state.abc_module(design, mod, mod->selected_cells(), dff_mode, clk_str); + state.extract(design); + state.finish(); continue; } @@ -2239,6 +2256,8 @@ struct AbcPass : public Pass { state.srst_polarity = std::get<6>(it.first); state.srst_sig = assign_map(std::get<7>(it.first)); state.abc_module(design, mod, it.second, !state.clk_sig.empty(), "$"); + state.extract(design); + state.finish(); } } From 885bb744e3b7c25d684b9f8db2a4c5e970ce65d3 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 15 Jul 2025 04:17:48 +0000 Subject: [PATCH 101/176] Make `module` a parameter of the function so we can change its constness in context --- passes/techmap/abc.cc | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 494494a49..fb889f530 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -143,7 +143,6 @@ struct AbcModuleState { int map_autoidx = 0; SigMap assign_map; - RTLIL::Module *module = nullptr; std::vector signal_list; dict signal_map; FfInitVals initvals; @@ -165,13 +164,13 @@ struct AbcModuleState { int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); void mark_port(RTLIL::SigSpec sig); - void extract_cell(RTLIL::Cell *cell, bool keepff); + void extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool keepff); std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr); void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts); - void handle_loops(); - void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, const std::vector &cells, + void handle_loops(RTLIL::Module *module); + void abc_module(RTLIL::Design *design, RTLIL::Module *module, const std::vector &cells, bool dff_mode, std::string clk_str); - void extract(RTLIL::Design *design); + void extract(RTLIL::Design *design, RTLIL::Module *module); void finish(); }; @@ -220,7 +219,7 @@ void AbcModuleState::mark_port(RTLIL::SigSpec sig) signal_list[signal_map[bit]].is_port = true; } -void AbcModuleState::extract_cell(RTLIL::Cell *cell, bool keepff) +void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool keepff) { if (RTLIL::builtin_ff_cell_types().count(cell->type)) { FfData ff(&initvals, cell); @@ -491,7 +490,7 @@ void AbcModuleState::dump_loop_graph(FILE *f, int &nr, dict> &edg fprintf(f, "}\n"); } -void AbcModuleState::handle_loops() +void AbcModuleState::handle_loops(RTLIL::Module *module) { // http://en.wikipedia.org/wiki/Topological_sorting // (Kahn, Arthur B. (1962), "Topological sorting of large networks") @@ -751,10 +750,9 @@ struct abc_output_filter } }; -void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_module, const std::vector &cells, +void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, const std::vector &cells, bool dff_mode, std::string clk_str) { - module = current_module; initvals.set(&assign_map, module); map_autoidx = autoidx++; @@ -938,7 +936,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo had_init = false; for (auto c : cells) - extract_cell(c, config.keepff); + extract_cell(module, c, config.keepff); if (undef_bits_lost) log("Replacing %d occurrences of constant undef bits with constant zero bits\n", undef_bits_lost); @@ -964,7 +962,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo if (srst_sig.size() != 0) mark_port(srst_sig); - handle_loops(); + handle_loops(module); buffer = stringf("%s/input.blif", tempdir_name.c_str()); f = fopen(buffer.c_str(), "wt"); @@ -1207,7 +1205,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo log("Don't call ABC as there is nothing to map.\n"); } -void AbcModuleState::extract(RTLIL::Design *design) +void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) { if (!did_run_abc) { return; @@ -2087,7 +2085,7 @@ struct AbcPass : public Pass { AbcModuleState state(config); state.assign_map.set(mod); state.abc_module(design, mod, mod->selected_cells(), dff_mode, clk_str); - state.extract(design); + state.extract(design, mod); state.finish(); continue; } @@ -2256,7 +2254,7 @@ struct AbcPass : public Pass { state.srst_polarity = std::get<6>(it.first); state.srst_sig = assign_map(std::get<7>(it.first)); state.abc_module(design, mod, it.second, !state.clk_sig.empty(), "$"); - state.extract(design); + state.extract(design, mod); state.finish(); } } From ccb23ffc1a37d2227c759a4b8f9c9e096ef71982 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 15 Jul 2025 04:19:09 +0000 Subject: [PATCH 102/176] Fix indentation --- passes/techmap/abc.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index fb889f530..0c2576c1a 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -947,8 +947,8 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, co } for (auto cell : module->cells()) - for (auto &port_it : cell->connections()) - mark_port(port_it.second); + for (auto &port_it : cell->connections()) + mark_port(port_it.second); if (clk_sig.size() != 0) mark_port(clk_sig); From 1eb8844e38ce0dd88f797e26661cfd31007a1597 Mon Sep 17 00:00:00 2001 From: clemens Date: Wed, 13 Aug 2025 08:36:26 +0200 Subject: [PATCH 103/176] fix labeling in report fix design hierarchy containing wrong values. remove left over debug print. --- passes/cmds/stat.cc | 62 +++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 24b21d674..8ed4e5b93 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -338,7 +338,7 @@ struct statdata_t { char buf[16]; - int len = std::snprintf(buf, sizeof(buf), "%.3f", value); + int len = snprintf(buf, sizeof(buf), "%.3f", value); while (len > 0 && buf[len - 1] == '0') --len; @@ -351,13 +351,13 @@ struct statdata_t { } // use scientific notation, this should always fit in 8 characters - std::snprintf(buf, sizeof(buf), "%8.3G", value); + snprintf(buf, sizeof(buf), "%8.3G", value); return std::string(buf); } void print_log_line(const std::string &name, unsigned int count_local, double area_local, unsigned int count_global, double area_global, - int spacer = 0, bool print_area = true, bool print_hierarchical = true) + int spacer = 0, bool print_area = true, bool print_hierarchical = true, bool print_global_only = false) { const std::string indent(2 * spacer, ' '); @@ -370,6 +370,8 @@ struct statdata_t { if (print_hierarchical) { log(" %s %s %s %s %s%s\n", count_global_str.c_str(), area_global_str.c_str(), count_local_str.c_str(), area_local_str.c_str(), indent.c_str(), name.c_str()); + } else if (print_global_only) { + log(" %s %s %s%s\n", count_global_str.c_str(), area_global_str.c_str(), indent.c_str(), name.c_str()); } else { if (count_local > 0) log(" %s %s %s%s\n", count_local_str.c_str(), area_local_str.c_str(), indent.c_str(), name.c_str()); @@ -377,6 +379,8 @@ struct statdata_t { } else { if (print_hierarchical) { log(" %s %s %s%s\n", count_global_str.c_str(), count_local_str.c_str(), indent.c_str(), name.c_str()); + } else if (print_global_only) { + log(" %s %s%s\n", count_global_str.c_str(), indent.c_str(), name.c_str()); } else { if (count_local > 0) log(" %s %s%s\n", count_local_str.c_str(), indent.c_str(), name.c_str()); @@ -384,7 +388,7 @@ struct statdata_t { } } - void print_log_header(bool print_area = true, bool print_hierarchical = true) + void print_log_header(bool print_area = true, bool print_hierarchical = true, bool print_global_only = false) { if (print_area) { if (print_hierarchical) { @@ -393,9 +397,13 @@ struct statdata_t { log(" %8s %8s %8s-%8s-%s\n", "|", "|", "+", "--------", "Local count, excluding submodules."); log(" %8s %8s %8s %8s-%s\n", "|", "|", "|", "+", "Local area, excluding submodules."); log(" %8s %8s %8s %8s \n", "|", "|", "|", "|"); + } else if (print_global_only) { + log(" %8s-%8s-%s\n", "+", "--------", "Count including submodules."); + log(" %8s %8s-%s\n", "|", "+", "Area including submodules."); + log(" %8s %8s \n", "|", "|"); } else { - log(" %8s-%8s-%s\n", "+", "--------", "Local Count including submodules."); - log(" %8s %8s-%s\n", "|", "+", "Local Area including submodules."); + log(" %8s-%8s-%s\n", "+", "--------", "Local Count, excluding submodules."); + log(" %8s %8s-%s\n", "|", "+", "Local Area, excluding submodules."); log(" %8s %8s \n", "|", "|"); } } else { @@ -403,42 +411,47 @@ struct statdata_t { log(" %8s-%8s-%8s-%s\n", "+", "--------", "--------", "Count including submodules."); log(" %8s %8s-%8s-%s\n", "|", "+", "--------", "Local count, excluding submodules."); log(" %8s %8s \n", "|", "|"); + } else if (print_global_only) { + log(" %8s-%8s-%s\n", "+", "--------", "Count including submodules."); + log(" %8s %8s \n", "|", "|"); } else { - log(" %8s-%8s-%s\n", "+", "--------", "Local Count including submodules."); + log(" %8s-%8s-%s\n", "+", "--------", "Local Count, excluding submodules."); log(" %8s \n", "|"); } } } - void log_data(RTLIL::IdString mod_name, bool top_mod, bool print_area = true, bool print_hierarchical = true) + void log_data(RTLIL::IdString mod_name, bool top_mod, bool print_area = true, bool print_hierarchical = true, bool print_global_only = false) { - print_log_header(print_area, print_hierarchical); + print_log_header(print_area, print_hierarchical, print_global_only); - print_log_line("wires", local_num_wires, 0, num_wires, 0, 0, print_area, print_hierarchical); - print_log_line("wire bits", local_num_wire_bits, 0, num_wire_bits, 0, 0, print_area, print_hierarchical); - print_log_line("public wires", local_num_pub_wires, 0, num_pub_wires, 0, 0, print_area, print_hierarchical); - print_log_line("public wire bits", local_num_pub_wire_bits, 0, num_pub_wire_bits, 0, 0, print_area, print_hierarchical); - print_log_line("ports", local_num_ports, 0, num_ports, 0, 0, print_area, print_hierarchical); - print_log_line("port bits", local_num_port_bits, 0, num_port_bits, 0, 0, print_area, print_hierarchical); - print_log_line("memories", local_num_memories, 0, num_memories, 0, 0, print_area, print_hierarchical); - print_log_line("memory bits", local_num_memory_bits, 0, num_memory_bits, 0, 0, print_area, print_hierarchical); - print_log_line("processes", local_num_processes, 0, num_processes, 0, 0, print_area, print_hierarchical); - print_log_line("cells", local_num_cells, local_area, num_cells, area, 0, print_area, print_hierarchical); + print_log_line("wires", local_num_wires, 0, num_wires, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("wire bits", local_num_wire_bits, 0, num_wire_bits, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("public wires", local_num_pub_wires, 0, num_pub_wires, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("public wire bits", local_num_pub_wire_bits, 0, num_pub_wire_bits, 0, 0, print_area, print_hierarchical, + print_global_only); + print_log_line("ports", local_num_ports, 0, num_ports, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("port bits", local_num_port_bits, 0, num_port_bits, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("memories", local_num_memories, 0, num_memories, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("memory bits", local_num_memory_bits, 0, num_memory_bits, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("processes", local_num_processes, 0, num_processes, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("cells", local_num_cells, local_area, num_cells, area, 0, print_area, print_hierarchical, print_global_only); for (auto &it : num_cells_by_type) if (it.second) { auto name = string(log_id(it.first)); print_log_line(name, local_num_cells_by_type.count(it.first) ? local_num_cells_by_type.at(it.first) : 0, local_area_cells_by_type.count(it.first) ? local_area_cells_by_type.at(it.first) : 0, it.second, - area_cells_by_type.at(it.first), 1, print_area, print_hierarchical); + area_cells_by_type.at(it.first), 1, print_area, print_hierarchical, print_global_only); } if (num_submodules > 0) { - print_log_line("submodules", num_submodules, 0, num_submodules, submodule_area, 0, print_area, print_hierarchical); + print_log_line("submodules", num_submodules, 0, num_submodules, submodule_area, 0, print_area, print_hierarchical, + print_global_only); for (auto &it : num_submodules_by_type) if (it.second) print_log_line(string(log_id(it.first)), it.second, 0, it.second, submodules_area_by_type.count(it.first) ? submodules_area_by_type.at(it.first) : 0, 1, - print_area, print_hierarchical); + print_area, print_hierarchical, print_global_only); } if (!unknown_cell_area.empty()) { log("\n"); @@ -811,7 +824,7 @@ struct StatPass : public Pass { log("\n"); log("=== design hierarchy ===\n"); log("\n"); - mod_stat[top_mod->name].print_log_header(has_area, hierarchy_mode); + mod_stat[top_mod->name].print_log_header(has_area, hierarchy_mode, true); mod_stat[top_mod->name].print_log_line(log_id(top_mod->name), mod_stat[top_mod->name].local_num_cells, mod_stat[top_mod->name].local_area, mod_stat[top_mod->name].num_cells, mod_stat[top_mod->name].area, 0, has_area, hierarchy_mode); @@ -823,7 +836,7 @@ struct StatPass : public Pass { data.log_data_json("design", true, true); else if (GetSize(mod_stat) > 1) { log("\n"); - data.log_data(top_mod->name, true, has_area, hierarchy_mode); + data.log_data(top_mod->name, true, has_area, hierarchy_mode, true); } design->scratchpad_set_int("stat.num_wires", data.num_wires); @@ -845,7 +858,6 @@ struct StatPass : public Pass { } log("\n"); - printf("processed statistics\n"); } } StatPass; From 383d11c2ac9254836f8107e4a2fa6901b7bccd09 Mon Sep 17 00:00:00 2001 From: clemens Date: Wed, 13 Aug 2025 10:09:02 +0200 Subject: [PATCH 104/176] fix design overview in json. Fix some unknown cells apearing twice. --- passes/cmds/stat.cc | 118 ++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 42 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 8ed4e5b93..ea9dfcd3c 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -486,7 +486,7 @@ struct statdata_t { count_local, area_local); } - void log_data_json(const char *mod_name, bool first_module, bool hierarchical = false) + void log_data_json(const char *mod_name, bool first_module, bool hierarchical = false, bool global_only = false) { if (!first_module) log(",\n"); @@ -543,41 +543,77 @@ struct statdata_t { log(" }"); } else { - - log(" %s: {\n", json11::Json(mod_name).dump().c_str()); - log(" \"num_wires\": %u,\n", num_wires); - log(" \"num_wire_bits\": %u,\n", num_wire_bits); - log(" \"num_pub_wires\": %u,\n", num_pub_wires); - log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits); - log(" \"num_ports\": %u,\n", num_ports); - log(" \"num_port_bits\": %u,\n", num_port_bits); - log(" \"num_memories\": %u,\n", num_memories); - log(" \"num_memory_bits\": %u,\n", num_memory_bits); - log(" \"num_processes\": %u,\n", num_processes); - log(" \"num_cells\": %u,\n", local_num_cells); - log(" \"num_submodules\": %u,\n", num_submodules); - if (area != 0) { - log(" \"area\": %f,\n", area); - log(" \"sequential_area\": %f,\n", sequential_area); + if (global_only) { + log(" %s: {\n", json11::Json(mod_name).dump().c_str()); + log(" \"num_wires\": %u,\n", num_wires); + log(" \"num_wire_bits\": %u,\n", num_wire_bits); + log(" \"num_pub_wires\": %u,\n", num_pub_wires); + log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits); + log(" \"num_ports\": %u,\n", num_ports); + log(" \"num_port_bits\": %u,\n", num_port_bits); + log(" \"num_memories\": %u,\n", num_memories); + log(" \"num_memory_bits\": %u,\n", num_memory_bits); + log(" \"num_processes\": %u,\n", num_processes); + log(" \"num_cells\": %u,\n", num_cells); + log(" \"num_submodules\": %u,\n", num_submodules); + if (area != 0) { + log(" \"area\": %f,\n", area); + log(" \"sequential_area\": %f,\n", sequential_area); + } + log(" \"num_cells_by_type\": {\n"); + bool first_line = true; + for (auto &it : num_cells_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); + first_line = false; + } + for (auto &it : num_submodules_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); + first_line = false; + } + log("\n"); + log(" }"); + } else { + log(" %s: {\n", json11::Json(mod_name).dump().c_str()); + log(" \"num_wires\": %u,\n", local_num_wires); + log(" \"num_wire_bits\": %u,\n", local_num_wire_bits); + log(" \"num_pub_wires\": %u,\n", local_num_pub_wires); + log(" \"num_pub_wire_bits\": %u,\n", local_num_pub_wire_bits); + log(" \"num_ports\": %u,\n", local_num_ports); + log(" \"num_port_bits\": %u,\n", local_num_port_bits); + log(" \"num_memories\": %u,\n", local_num_memories); + log(" \"num_memory_bits\": %u,\n", local_num_memory_bits); + log(" \"num_processes\": %u,\n", local_num_processes); + log(" \"num_cells\": %u,\n", local_num_cells); + log(" \"num_submodules\": %u,\n", num_submodules); + if (area != 0) { + log(" \"area\": %f,\n", area); + log(" \"sequential_area\": %f,\n", sequential_area); + } + log(" \"num_cells_by_type\": {\n"); + bool first_line = true; + for (auto &it : local_num_cells_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); + first_line = false; + } + for (auto &it : num_submodules_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); + first_line = false; + } + log("\n"); + log(" }"); } - log(" \"num_cells_by_type\": {\n"); - bool first_line = true; - for (auto &it : local_num_cells_by_type) - if (it.second) { - if (!first_line) - log(",\n"); - log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); - first_line = false; - } - for (auto &it : num_submodules_by_type) - if (it.second) { - if (!first_line) - log(",\n"); - log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); - first_line = false; - } - log("\n"); - log(" }"); if (tech == "xilinx") { log(",\n"); log(" \"estimated_num_lc\": %u", estimate_xilinx_lc()); @@ -644,12 +680,10 @@ statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *t double(design->module(cell->type)->attributes.at(ID::area).as_int()); mod_data.area += double(design->module(cell->type)->attributes.at(ID::area).as_int()); mod_data.unknown_cell_area.erase(cell->type); - } else { - mod_data.unknown_cell_area.insert(cell->type); - mod_data.num_submodules++; - mod_data.num_submodules_by_type[cell->type]++; - mod_data.submodules_area_by_type[cell->type] = 0; - mod_data.seq_area_cells_by_type[cell->type] = 0; + mod_data.num_cells -= mod_data.num_cells_by_type.erase(cell->type); + mod_data.area_cells_by_type.erase(cell->type); + mod_data.local_num_cells -= mod_data.local_num_cells_by_type.erase(cell->type); + mod_data.local_area_cells_by_type.erase(cell->type); } } } @@ -833,7 +867,7 @@ struct StatPass : public Pass { statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0, /*quiet=*/json_mode, has_area, hierarchy_mode); if (json_mode) - data.log_data_json("design", true, true); + data.log_data_json("design", true, hierarchy_mode, true); else if (GetSize(mod_stat) > 1) { log("\n"); data.log_data(top_mod->name, true, has_area, hierarchy_mode, true); From 910ff3ff36806106ab065e949e0b80c4bf701ec0 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 13 Aug 2025 10:54:47 +0200 Subject: [PATCH 105/176] verilog: demote some parser errors to warnings again --- frontends/verilog/verilog_error.cc | 16 ++++++++++++++++ frontends/verilog/verilog_error.h | 1 + frontends/verilog/verilog_parser.y | 14 +++++++------- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/frontends/verilog/verilog_error.cc b/frontends/verilog/verilog_error.cc index 19e634b5d..491b8c7f5 100644 --- a/frontends/verilog/verilog_error.cc +++ b/frontends/verilog/verilog_error.cc @@ -42,6 +42,15 @@ static void verr_at(std::string filename, int begin_line, char const *fmt, va_li exit(1); } +static void vwarn_at(std::string filename, int begin_line, char const *fmt, va_list ap) +{ + char buffer[1024]; + char *p = buffer; + p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap); + p += snprintf(p, buffer + sizeof(buffer) - p, "\n"); + YOSYS_NAMESPACE_PREFIX log_file_warning(filename, begin_line, "%s", buffer); +} + [[noreturn]] void VERILOG_FRONTEND::err_at_loc(Location loc, char const *fmt, ...) { @@ -49,4 +58,11 @@ void VERILOG_FRONTEND::err_at_loc(Location loc, char const *fmt, ...) va_start(args, fmt); verr_at(loc.begin.filename ? *(loc.begin.filename) : "UNKNOWN", loc.begin.line, fmt, args); } +void VERILOG_FRONTEND::warn_at_loc(Location loc, char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vwarn_at(loc.begin.filename ? *(loc.begin.filename) : "UNKNOWN", loc.begin.line, fmt, args); + va_end(args); +} diff --git a/frontends/verilog/verilog_error.h b/frontends/verilog/verilog_error.h index 07198a2ba..b36de19b8 100644 --- a/frontends/verilog/verilog_error.h +++ b/frontends/verilog/verilog_error.h @@ -11,6 +11,7 @@ namespace VERILOG_FRONTEND { [[noreturn]] void err_at_loc(Location loc, char const *fmt, ...); + void warn_at_loc(Location loc, char const *fmt, ...); }; YOSYS_NAMESPACE_END diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 46dfeedd0..e8ca5d078 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1304,7 +1304,7 @@ specify_item: specify_rise_fall_ptr_t timing = std::move($9); if (specify_edge != 0 && target->dat == nullptr) - err_at_loc(@3, "Found specify edge but no data spec.\n"); + err_at_loc(@3, "Found specify edge but no data spec."); auto cell_owned = std::make_unique(@$, AST_CELL); auto cell = cell_owned.get(); @@ -1379,7 +1379,7 @@ specify_item: TOK_ID TOK_LPAREN specify_edge expr specify_condition TOK_COMMA specify_edge expr specify_condition TOK_COMMA specify_triple specify_opt_triple TOK_RPAREN TOK_SEMICOL { if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" && *$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange") - err_at_loc(@1, "Unsupported specify rule type: %s\n", $1->c_str()); + err_at_loc(@1, "Unsupported specify rule type: %s", $1->c_str()); auto src_pen = AstNode::mkconst_int(@3, $3 != 0, false, 1); auto src_pol = AstNode::mkconst_int(@3, $3 == 'p', false, 1); @@ -1518,19 +1518,19 @@ specify_rise_fall: $$ = std::make_unique(); $$->rise = std::move(*$2); $$->fall = std::move(*$4); - err_at_loc(@$, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + warn_at_loc(@$, "Path delay expressions beyond rise/fall not currently supported. Ignoring."); } | TOK_LPAREN specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_RPAREN { $$ = std::make_unique(); $$->rise = std::move(*$2); $$->fall = std::move(*$4); - err_at_loc(@$, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + warn_at_loc(@$, "Path delay expressions beyond rise/fall not currently supported. Ignoring."); } | TOK_LPAREN specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_COMMA specify_triple TOK_RPAREN { $$ = std::make_unique(); $$->rise = std::move(*$2); $$->fall = std::move(*$4); - err_at_loc(@$, "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + warn_at_loc(@$, "Path delay expressions beyond rise/fall not currently supported. Ignoring."); } specify_triple: @@ -2585,7 +2585,7 @@ assert: node->str = *$1; } if (!$3) - err_at_loc(@$, "SystemVerilog does not allow \"restrict\" without \"property\".\n"); + warn_at_loc(@$, "SystemVerilog does not allow \"restrict\" without \"property\"."); } | opt_sva_label TOK_RESTRICT opt_property TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { if (mode->norestrict) { @@ -2596,7 +2596,7 @@ assert: node->str = *$1; } if (!$3) - err_at_loc(@$, "SystemVerilog does not allow \"restrict\" without \"property\".\n"); + warn_at_loc(@$, "SystemVerilog does not allow \"restrict\" without \"property\"."); }; assert_property: From 1603828b30c997ffe1cd237fad292e5de27c8c6a Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 13 Aug 2025 10:56:48 +0200 Subject: [PATCH 106/176] verilog_parser: fix locations of warnings for restrict keyword --- frontends/verilog/verilog_parser.y | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index e8ca5d078..e299d3148 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2585,7 +2585,7 @@ assert: node->str = *$1; } if (!$3) - warn_at_loc(@$, "SystemVerilog does not allow \"restrict\" without \"property\"."); + warn_at_loc(@3, "SystemVerilog does not allow \"restrict\" without \"property\"."); } | opt_sva_label TOK_RESTRICT opt_property TOK_LPAREN TOK_EVENTUALLY expr TOK_RPAREN TOK_SEMICOL { if (mode->norestrict) { @@ -2596,7 +2596,7 @@ assert: node->str = *$1; } if (!$3) - warn_at_loc(@$, "SystemVerilog does not allow \"restrict\" without \"property\"."); + warn_at_loc(@3, "SystemVerilog does not allow \"restrict\" without \"property\"."); }; assert_property: From 77089a8d031399e7677ca99006f094138406276e Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Wed, 7 May 2025 12:22:37 +0200 Subject: [PATCH 107/176] rename: add -move-to-cell option in -wire mode --- passes/cmds/rename.cc | 54 +++++++++++++++++++---- tests/various/rename_wire_move_to_cell.ys | 35 +++++++++++++++ 2 files changed, 80 insertions(+), 9 deletions(-) create mode 100644 tests/various/rename_wire_move_to_cell.ys diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc index e0586ec7e..4b5b41f23 100644 --- a/passes/cmds/rename.cc +++ b/passes/cmds/rename.cc @@ -67,7 +67,7 @@ static std::string derive_name_from_src(const std::string &src, int counter) return stringf("\\%s$%d", src_base.c_str(), counter); } -static IdString derive_name_from_cell_output_wire(const RTLIL::Cell *cell, string suffix) +static IdString derive_name_from_cell_output_wire(const RTLIL::Cell *cell, string suffix, bool move_to_cell) { // Find output const SigSpec *output = nullptr; @@ -93,13 +93,23 @@ static IdString derive_name_from_cell_output_wire(const RTLIL::Cell *cell, strin name += chunk.wire->name.str(); if (chunk.wire->width != chunk.width) { - name += "["; - if (chunk.width != 1) - name += std::to_string(chunk.offset + chunk.width) + ":"; - name += std::to_string(chunk.offset) + "]"; + int lhs = chunk.wire->to_hdl_index(chunk.offset + chunk.width - 1); + int rhs = chunk.wire->to_hdl_index(chunk.offset); + if (chunk.wire->upto) + std::swap(lhs, rhs); + + if (lhs != rhs) + name += stringf("[%d:%d]", lhs, rhs); + else + name += stringf("[%d]", lhs); } } + RTLIL::Wire *wire; + + if (move_to_cell && (!(wire = cell->module->wire(name)) || !(wire->port_input || wire->port_output))) + return name; + if (suffix.empty()) { suffix = cell->type.str(); } @@ -232,13 +242,17 @@ struct RenamePass : public Pass { log("cells with private names.\n"); log("\n"); log("\n"); - log(" rename -wire [selection] [-suffix ]\n"); + log(" rename -wire [selection] [-move-to-cell] [-suffix ]\n"); log("\n"); log("Assign auto-generated names based on the wires they drive to all selected\n"); log("cells with private names. Ignores cells driving privatly named wires.\n"); log("By default, the cell is named after the wire with the cell type as suffix.\n"); log("The -suffix option can be used to set the suffix to the given string instead.\n"); log("\n"); + log("The -move-to-cell option can be used to name the cell after the wire without\n"); + log("any suffix. If this would lead to conflicts, the suffix is added to the wire\n"); + log("instead. For cells driving ports, the -move-to-cell option is ignored.\n"); + log("\n"); log("\n"); log(" rename -enumerate [-pattern ] [selection]\n"); log("\n"); @@ -286,6 +300,7 @@ struct RenamePass : public Pass { std::string cell_suffix = ""; bool flag_src = false; bool flag_wire = false; + bool flag_move_to_cell = false; bool flag_enumerate = false; bool flag_witness = false; bool flag_hide = false; @@ -345,6 +360,10 @@ struct RenamePass : public Pass { got_mode = true; continue; } + if (arg == "-move-to-cell" && flag_wire && !flag_move_to_cell) { + flag_move_to_cell = true; + continue; + } if (arg == "-pattern" && argidx+1 < args.size() && args[argidx+1].find('%') != std::string::npos) { int pos = args[++argidx].find('%'); pattern_prefix = args[argidx].substr(0, pos); @@ -396,9 +415,26 @@ struct RenamePass : public Pass { dict new_cell_names; for (auto cell : module->selected_cells()) if (cell->name[0] == '$') - new_cell_names[cell] = derive_name_from_cell_output_wire(cell, cell_suffix); - for (auto &it : new_cell_names) - module->rename(it.first, it.second); + new_cell_names[cell] = derive_name_from_cell_output_wire(cell, cell_suffix, flag_move_to_cell); + for (auto &[cell, new_name] : new_cell_names) { + if (flag_move_to_cell) { + RTLIL::Wire *found_wire = module->wire(new_name); + if (found_wire) { + std::string wire_suffix = cell_suffix; + if (wire_suffix.empty()) { + for (auto const &[port, _] : cell->connections()) { + if (cell->output(port)) { + wire_suffix += stringf("%s.%s", cell->type.c_str(), port.c_str() + 1); + break; + } + } + } + IdString new_wire_name = found_wire->name.str() + wire_suffix; + module->rename(found_wire, new_wire_name); + } + } + module->rename(cell, new_name); + } } } else diff --git a/tests/various/rename_wire_move_to_cell.ys b/tests/various/rename_wire_move_to_cell.ys new file mode 100644 index 000000000..482447edd --- /dev/null +++ b/tests/various/rename_wire_move_to_cell.ys @@ -0,0 +1,35 @@ +read_verilog < Date: Thu, 14 Aug 2025 00:13:23 +0300 Subject: [PATCH 110/176] opt_dff: add test --- tests/opt/opt_dff-simplify.il | 648 ++++++++++++++++++++++++++++++++++ tests/opt/opt_dff-simplify.ys | 12 + 2 files changed, 660 insertions(+) create mode 100644 tests/opt/opt_dff-simplify.il create mode 100644 tests/opt/opt_dff-simplify.ys diff --git a/tests/opt/opt_dff-simplify.il b/tests/opt/opt_dff-simplify.il new file mode 100644 index 000000000..3b86e9e35 --- /dev/null +++ b/tests/opt/opt_dff-simplify.il @@ -0,0 +1,648 @@ +# Generated by Yosys 0.53+24 (git sha1 ab636979e, sccache clang++ 19.1.7 -fPIC -O3 -O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address,undefined) +autoidx 171528 +attribute \hdlname "csr_regfile_0000000000000000_1" +module \csr_regfile_0000000000000000_1 + wire $delete_wire$169641 + wire $delete_wire$169642 + wire $delete_wire$169643 + wire $delete_wire$169644 + wire $delete_wire$169645 + wire $delete_wire$169646 + wire $delete_wire$169647 + wire $delete_wire$169648 + wire $delete_wire$169649 + wire $delete_wire$169650 + wire $delete_wire$169651 + wire $delete_wire$169652 + wire $delete_wire$169653 + wire $delete_wire$169654 + wire $delete_wire$169655 + wire $delete_wire$169656 + wire $delete_wire$169657 + wire $delete_wire$169658 + wire $delete_wire$169659 + wire $delete_wire$169660 + wire $delete_wire$169661 + wire $delete_wire$169662 + wire $delete_wire$169663 + wire $delete_wire$169664 + wire $delete_wire$169665 + wire $delete_wire$169666 + wire $delete_wire$169667 + wire $delete_wire$169668 + wire $delete_wire$169669 + wire $delete_wire$169670 + wire $delete_wire$169671 + wire $delete_wire$169672 + wire $delete_wire$169673 + wire $delete_wire$169674 + wire $delete_wire$169675 + wire $delete_wire$169676 + wire $delete_wire$169677 + wire $delete_wire$169678 + wire $delete_wire$169679 + wire $delete_wire$169680 + wire $delete_wire$169681 + wire $delete_wire$169682 + wire $delete_wire$169683 + wire $delete_wire$169684 + wire $delete_wire$169685 + wire $delete_wire$169686 + wire $delete_wire$169687 + wire $delete_wire$169688 + wire $delete_wire$169689 + wire $delete_wire$169690 + wire $delete_wire$169691 + wire $delete_wire$169692 + wire $delete_wire$169693 + wire $delete_wire$169694 + wire $delete_wire$169695 + wire $delete_wire$169696 + wire $delete_wire$169697 + wire $delete_wire$169698 + wire $delete_wire$169699 + wire $delete_wire$169700 + wire $delete_wire$169701 + wire $delete_wire$169702 + wire $delete_wire$169703 + wire $delete_wire$169704 + wire $delete_wire$169705 + wire $delete_wire$169706 + wire $delete_wire$169707 + wire $delete_wire$169708 + wire $delete_wire$169709 + wire $delete_wire$169710 + wire $delete_wire$169711 + wire $delete_wire$169712 + wire width 32 $delete_wire$169713 + wire $delete_wire$169714 + wire $delete_wire$169715 + wire $delete_wire$169716 + wire $delete_wire$169717 + wire $delete_wire$169718 + wire $delete_wire$169719 + wire $delete_wire$169720 + wire $delete_wire$169721 + wire $delete_wire$169722 + wire $delete_wire$169723 + wire $delete_wire$169724 + wire $delete_wire$169725 + wire $delete_wire$169726 + wire $delete_wire$169727 + wire $delete_wire$169728 + wire $delete_wire$169729 + wire $delete_wire$169730 + wire $delete_wire$169731 + wire $delete_wire$169732 + wire $delete_wire$169733 + wire $delete_wire$169734 + wire $delete_wire$169735 + wire $delete_wire$169736 + wire $delete_wire$169737 + wire $delete_wire$169738 + wire $delete_wire$169739 + wire $delete_wire$169740 + wire $delete_wire$169741 + wire $delete_wire$169742 + wire $delete_wire$169743 + wire $delete_wire$169744 + wire $delete_wire$169745 + wire $delete_wire$169746 + wire $delete_wire$169747 + wire $delete_wire$169748 + wire $delete_wire$169749 + wire $delete_wire$169750 + wire $delete_wire$169751 + wire $delete_wire$169752 + wire $delete_wire$169753 + wire $delete_wire$169754 + wire $delete_wire$169755 + wire $delete_wire$169756 + wire $delete_wire$169757 + wire $delete_wire$169758 + wire $delete_wire$169759 + wire $delete_wire$169760 + wire $delete_wire$169761 + wire $delete_wire$169762 + wire $delete_wire$169763 + wire $delete_wire$169764 + wire $delete_wire$169765 + wire $delete_wire$169766 + wire $delete_wire$169767 + wire $delete_wire$169768 + wire $delete_wire$169769 + wire $delete_wire$169770 + wire $delete_wire$169771 + wire $delete_wire$169772 + wire $delete_wire$169773 + wire $delete_wire$169774 + wire $delete_wire$169775 + wire $delete_wire$169776 + wire $delete_wire$169777 + wire $delete_wire$169778 + wire $delete_wire$169779 + wire $delete_wire$169780 + wire $delete_wire$169781 + wire $delete_wire$169782 + wire $delete_wire$169783 + wire $delete_wire$169784 + wire $delete_wire$169785 + wire $delete_wire$169786 + wire $delete_wire$169787 + wire $delete_wire$169788 + wire $delete_wire$169789 + wire $delete_wire$169790 + wire $delete_wire$169791 + wire $delete_wire$169792 + wire $delete_wire$169793 + wire $delete_wire$169794 + wire $delete_wire$169795 + wire $delete_wire$169796 + wire $delete_wire$169797 + wire $delete_wire$169798 + wire $delete_wire$169799 + wire $delete_wire$169800 + wire $delete_wire$169801 + wire $delete_wire$169802 + wire $delete_wire$169803 + wire $delete_wire$169804 + wire $delete_wire$169805 + wire $delete_wire$169806 + wire $delete_wire$169807 + wire $delete_wire$169808 + wire $delete_wire$169809 + wire $delete_wire$169810 + wire $delete_wire$169811 + wire $delete_wire$169812 + wire $delete_wire$169813 + wire $delete_wire$169814 + wire $delete_wire$169815 + wire $delete_wire$169816 + wire $delete_wire$169817 + wire $delete_wire$169818 + wire $delete_wire$169819 + wire $delete_wire$169820 + wire $delete_wire$169821 + wire width 5 $delete_wire$169822 + wire width 17 $delete_wire$169823 + wire $delete_wire$169824 + wire $delete_wire$169825 + wire $delete_wire$169826 + wire $delete_wire$169827 + wire $delete_wire$169828 + wire $delete_wire$169829 + wire $delete_wire$169830 + wire $delete_wire$169831 + wire $delete_wire$169832 + wire $delete_wire$169833 + wire $delete_wire$169834 + wire $delete_wire$169835 + wire $delete_wire$169836 + wire $delete_wire$169837 + wire $delete_wire$169838 + wire $delete_wire$169839 + wire $delete_wire$169840 + wire $delete_wire$169960 + wire $delete_wire$169961 + wire $delete_wire$169962 + wire $delete_wire$169963 + wire $delete_wire$169964 + wire $delete_wire$169965 + wire $delete_wire$169966 + wire $delete_wire$169967 + wire $delete_wire$169968 + wire $delete_wire$169969 + wire $delete_wire$169970 + wire $delete_wire$169971 + wire $delete_wire$169972 + wire $delete_wire$169973 + wire $delete_wire$169974 + wire $delete_wire$169975 + wire $delete_wire$169976 + wire $delete_wire$169977 + wire $delete_wire$169978 + wire $delete_wire$169979 + wire $delete_wire$169980 + wire $delete_wire$169981 + wire $delete_wire$169982 + wire $delete_wire$169983 + wire $delete_wire$169984 + wire $delete_wire$169985 + wire $delete_wire$169986 + wire $delete_wire$169987 + wire $delete_wire$169988 + wire $delete_wire$169989 + wire $delete_wire$169990 + wire $delete_wire$169991 + wire $delete_wire$169992 + wire $delete_wire$169993 + wire $delete_wire$169994 + wire $delete_wire$169995 + wire $delete_wire$169996 + wire $delete_wire$169997 + wire $delete_wire$169998 + wire $delete_wire$169999 + wire $delete_wire$170000 + wire $delete_wire$170001 + wire $delete_wire$170002 + wire $delete_wire$170003 + wire $delete_wire$170004 + wire $delete_wire$170005 + wire $delete_wire$170006 + wire $delete_wire$170007 + wire $delete_wire$170008 + wire $delete_wire$170009 + wire $delete_wire$170010 + wire $delete_wire$170011 + wire $delete_wire$170012 + wire $delete_wire$170013 + wire $delete_wire$170014 + wire $delete_wire$170015 + wire $delete_wire$170016 + wire $delete_wire$170017 + wire $delete_wire$170018 + wire $delete_wire$170019 + wire $delete_wire$170020 + wire $delete_wire$170021 + wire $delete_wire$170022 + wire $delete_wire$170023 + wire $delete_wire$170024 + wire $delete_wire$170025 + wire $delete_wire$170026 + wire $delete_wire$170027 + wire $delete_wire$170028 + wire $delete_wire$170029 + wire $delete_wire$170030 + wire $delete_wire$170031 + wire $delete_wire$170032 + wire $delete_wire$170033 + wire $delete_wire$170034 + wire $delete_wire$170035 + wire $delete_wire$170036 + wire $delete_wire$170037 + wire $delete_wire$170038 + wire $delete_wire$170039 + wire $delete_wire$170040 + wire $delete_wire$170041 + wire $delete_wire$170042 + wire $delete_wire$170043 + wire $delete_wire$170044 + wire $delete_wire$170045 + wire $delete_wire$170046 + wire $delete_wire$170047 + wire $delete_wire$170048 + wire $delete_wire$170049 + wire $delete_wire$170050 + wire $delete_wire$170051 + wire $delete_wire$170052 + wire $delete_wire$170053 + wire $delete_wire$170054 + wire $delete_wire$170055 + wire $delete_wire$170056 + wire $delete_wire$170057 + wire $delete_wire$170058 + wire $delete_wire$170059 + wire $delete_wire$170635 + wire $delete_wire$170636 + wire $delete_wire$170637 + wire $delete_wire$170638 + wire $delete_wire$170639 + wire $delete_wire$170640 + wire $delete_wire$170641 + wire $delete_wire$170642 + wire $delete_wire$170643 + wire $delete_wire$170644 + wire $delete_wire$170645 + wire $delete_wire$170646 + wire $delete_wire$170647 + wire $delete_wire$170648 + wire $delete_wire$170649 + wire $delete_wire$170650 + wire $delete_wire$170651 + wire $delete_wire$170652 + wire $delete_wire$170653 + wire $delete_wire$170654 + wire $delete_wire$170655 + wire $delete_wire$170656 + wire $delete_wire$170657 + wire $delete_wire$170658 + wire $delete_wire$170659 + wire $delete_wire$170660 + wire $delete_wire$170661 + wire $delete_wire$170662 + wire $delete_wire$170663 + wire $delete_wire$170664 + wire $delete_wire$170665 + wire $delete_wire$170666 + wire $delete_wire$170667 + wire $delete_wire$170668 + wire $delete_wire$170669 + wire $delete_wire$170670 + wire $delete_wire$170749 + wire $delete_wire$170750 + wire $delete_wire$170751 + wire $delete_wire$170752 + wire $delete_wire$170753 + wire $delete_wire$170754 + wire $delete_wire$170755 + wire width 2 $delete_wire$170756 + wire width 2 $delete_wire$170757 + wire $delete_wire$170758 + wire $delete_wire$170759 + wire $delete_wire$170760 + wire $delete_wire$170761 + wire $delete_wire$170762 + wire $delete_wire$170763 + wire $delete_wire$170764 + wire $delete_wire$170765 + wire $delete_wire$170766 + wire $delete_wire$170767 + wire $delete_wire$170768 + wire $delete_wire$170769 + wire $delete_wire$170770 + wire $delete_wire$170771 + wire $delete_wire$170772 + wire $delete_wire$170773 + wire $delete_wire$170774 + wire $delete_wire$170775 + wire $delete_wire$170859 + wire $delete_wire$170860 + wire $delete_wire$170861 + wire $delete_wire$170862 + wire $delete_wire$170863 + wire $delete_wire$170864 + wire $delete_wire$170865 + wire $delete_wire$170866 + wire $delete_wire$170867 + wire $delete_wire$170868 + wire $delete_wire$170869 + wire $delete_wire$170870 + wire $delete_wire$170871 + wire $delete_wire$170872 + wire $delete_wire$170873 + wire $delete_wire$170874 + wire $delete_wire$170875 + wire $delete_wire$170876 + wire $delete_wire$170877 + wire $delete_wire$170878 + wire $delete_wire$170879 + wire $delete_wire$170880 + wire $delete_wire$170881 + wire $delete_wire$170882 + wire $delete_wire$170996 + wire $delete_wire$170997 + wire $delete_wire$170998 + wire $delete_wire$170999 + wire $delete_wire$171000 + wire $delete_wire$171001 + wire $delete_wire$171002 + wire $delete_wire$171003 + wire $delete_wire$171004 + wire $delete_wire$171005 + wire $delete_wire$171006 + wire $delete_wire$171007 + wire $delete_wire$171008 + wire $delete_wire$171009 + wire $delete_wire$171010 + wire $delete_wire$171011 + wire $delete_wire$171035 + wire $delete_wire$171036 + wire $delete_wire$171037 + wire $delete_wire$171038 + wire $delete_wire$171039 + wire $delete_wire$171040 + wire $delete_wire$171041 + wire $delete_wire$171042 + wire $delete_wire$171043 + wire $delete_wire$171044 + wire $delete_wire$171045 + wire $delete_wire$171046 + wire $delete_wire$171047 + wire $delete_wire$171048 + wire $delete_wire$171049 + wire $delete_wire$171172 + wire $delete_wire$171173 + wire $delete_wire$171174 + wire $delete_wire$171175 + wire $delete_wire$171176 + wire $delete_wire$171177 + wire $delete_wire$171178 + wire $delete_wire$171179 + wire $delete_wire$171180 + wire $delete_wire$171181 + wire $delete_wire$171182 + wire $delete_wire$171183 + wire $delete_wire$171184 + wire $delete_wire$171185 + wire $delete_wire$171186 + wire $delete_wire$171187 + wire $delete_wire$171188 + wire $delete_wire$171189 + wire $delete_wire$171190 + wire width 2 $delete_wire$171200 + wire width 2 $delete_wire$171201 + wire $delete_wire$171202 + wire $delete_wire$171203 + wire $delete_wire$171204 + wire $delete_wire$171205 + wire $delete_wire$171206 + wire $delete_wire$171207 + wire $delete_wire$171226 + wire $delete_wire$171227 + wire $delete_wire$171228 + wire $delete_wire$171229 + wire $delete_wire$171230 + wire $delete_wire$171231 + wire $delete_wire$171232 + wire $delete_wire$171254 + wire $delete_wire$171255 + wire $delete_wire$171256 + wire $delete_wire$171257 + wire $delete_wire$171258 + wire $delete_wire$171259 + wire $delete_wire$171267 + wire $delete_wire$171268 + wire $delete_wire$171269 + wire $delete_wire$171270 + wire $delete_wire$171271 + wire $delete_wire$171272 + wire $delete_wire$171314 + wire $delete_wire$171315 + wire $delete_wire$171316 + wire $delete_wire$171317 + wire $delete_wire$171318 + wire $delete_wire$171338 + wire $delete_wire$171339 + wire $delete_wire$171340 + wire $delete_wire$171341 + wire $delete_wire$171350 + wire $delete_wire$171351 + wire $delete_wire$171352 + wire $delete_wire$171353 + wire $delete_wire$171354 + wire $delete_wire$171355 + wire $delete_wire$171356 + wire $delete_wire$171357 + wire $delete_wire$171358 + wire $delete_wire$171359 + wire $delete_wire$171360 + wire width 2 $delete_wire$171361 + wire $delete_wire$171362 + wire $delete_wire$171371 + wire $delete_wire$171372 + wire $delete_wire$171373 + wire $delete_wire$171374 + wire $delete_wire$171387 + wire $delete_wire$171388 + wire $delete_wire$171389 + wire $delete_wire$171390 + wire $delete_wire$171408 + wire $delete_wire$171409 + wire $delete_wire$171441 + wire $delete_wire$171442 + wire $delete_wire$171449 + wire $delete_wire$171450 + wire $delete_wire$171454 + wire $delete_wire$171455 + wire $delete_wire$171471 + wire $delete_wire$171472 + wire $delete_wire$171477 + wire $delete_wire$171501 + wire $delete_wire$171502 + wire $delete_wire$171507 + wire $delete_wire$171512 + wire $delete_wire$171513 + wire $delete_wire$171514 + wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216088$6333_Y + wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216089$6332_Y + wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216090$6331_Y + wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216091$6330_Y + wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216092$6329_Y + wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216093$6328_Y + wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216094$6327_Y + wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216095$6326_Y + wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216096$6325_Y + wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216097$6324_Y + wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216098$6323_Y + wire width 32 $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216099$6322_Y + wire \N2231 + wire \N3558 + attribute \unused_bits "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31" + wire width 32 \dcsr_d + wire \dcsr_q_prv__0_ + cell $adff $procdff$137332 + parameter \ARST_POLARITY 0 + parameter \ARST_VALUE 1'1 + parameter \CLK_POLARITY 1'1 + parameter \WIDTH 1 + connect \ARST $delete_wire$170004 + connect \CLK $delete_wire$171206 + connect \D \dcsr_d [0] + connect \Q \dcsr_q_prv__0_ + end + cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216087$6334 + parameter \WIDTH 32 + connect \A { $delete_wire$170875 $delete_wire$171472 $delete_wire$171181 $delete_wire$169735 $delete_wire$169994 $delete_wire$169963 $delete_wire$170670 $delete_wire$169702 $delete_wire$169975 $delete_wire$170002 $delete_wire$169641 $delete_wire$171011 $delete_wire$171006 $delete_wire$171173 $delete_wire$171387 $delete_wire$170769 $delete_wire$170881 $delete_wire$169743 $delete_wire$169731 $delete_wire$169710 $delete_wire$169756 $delete_wire$170018 $delete_wire$169779 $delete_wire$170037 $delete_wire$169794 $delete_wire$171339 $delete_wire$171256 $delete_wire$171205 $delete_wire$169670 $delete_wire$171352 $delete_wire$171315 \dcsr_q_prv__0_ } + connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216088$6333_Y + connect \S $delete_wire$169809 + connect \Y { $delete_wire$169830 $delete_wire$171390 $delete_wire$169837 $delete_wire$169679 $delete_wire$169677 $delete_wire$169767 $delete_wire$169828 $delete_wire$170038 $delete_wire$169704 $delete_wire$169653 $delete_wire$169707 $delete_wire$169684 $delete_wire$169986 $delete_wire$169712 $delete_wire$170033 $delete_wire$169759 $delete_wire$171513 $delete_wire$170012 $delete_wire$170876 $delete_wire$170007 $delete_wire$169965 $delete_wire$169825 $delete_wire$169655 $delete_wire$169839 $delete_wire$170034 $delete_wire$170042 $delete_wire$171338 $delete_wire$169833 $delete_wire$169762 $delete_wire$169835 $delete_wire$169764 \N2231 } + end + cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216088$6333 + parameter \WIDTH 32 + connect \A { $delete_wire$170014 $delete_wire$171257 $delete_wire$170770 $delete_wire$169725 $delete_wire$170873 $delete_wire$171514 $delete_wire$170870 $delete_wire$169692 $delete_wire$171184 $delete_wire$170045 $delete_wire$169649 $delete_wire$170859 $delete_wire$171455 $delete_wire$170053 $delete_wire$170044 $delete_wire$170768 $delete_wire$170659 $delete_wire$169742 $delete_wire$169730 $delete_wire$169718 $delete_wire$169741 $delete_wire$170019 $delete_wire$169778 $delete_wire$170024 $delete_wire$169807 $delete_wire$171046 $delete_wire$171374 $delete_wire$170861 $delete_wire$169669 $delete_wire$171182 $delete_wire$171388 \dcsr_q_prv__0_ } + connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216089$6332_Y + connect \S $delete_wire$169810 + connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216088$6333_Y + end + cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216089$6332 + parameter \WIDTH 32 + connect \A { $delete_wire$169820 $delete_wire$171507 $delete_wire$171441 $delete_wire$169724 $delete_wire$169992 $delete_wire$169691 $delete_wire$171356 $delete_wire$169700 $delete_wire$169977 $delete_wire$170046 $delete_wire$169648 $delete_wire$170774 $delete_wire$171038 $delete_wire$171005 $delete_wire$170057 $delete_wire$171226 $delete_wire$170874 $delete_wire$169755 $delete_wire$169729 $delete_wire$171450 $delete_wire$169754 $delete_wire$170020 $delete_wire$169777 $delete_wire$170025 $delete_wire$169806 $delete_wire$170643 $delete_wire$171177 $delete_wire$171449 $delete_wire$169668 $delete_wire$171512 $delete_wire$171501 \dcsr_q_prv__0_ } + connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216090$6331_Y + connect \S $delete_wire$169997 + connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216089$6332_Y + end + cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216090$6331 + parameter \WIDTH 32 + connect \A { $delete_wire$169819 $delete_wire$170772 $delete_wire$170773 $delete_wire$169723 $delete_wire$169990 $delete_wire$169690 $delete_wire$170669 $delete_wire$169699 $delete_wire$169978 $delete_wire$170047 $delete_wire$169647 $delete_wire$171049 $delete_wire$171007 $delete_wire$170872 $delete_wire$170056 $delete_wire$171004 $delete_wire$171202 $delete_wire$169793 $delete_wire$169728 $delete_wire$170664 $delete_wire$169753 $delete_wire$170021 $delete_wire$169776 $delete_wire$170026 $delete_wire$169805 $delete_wire$170644 $delete_wire$171008 $delete_wire$170657 $delete_wire$169658 $delete_wire$171003 $delete_wire$170749 \dcsr_q_prv__0_ } + connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216091$6330_Y + connect \S $delete_wire$169826 + connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216090$6331_Y + end + cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216091$6330 + parameter \WIDTH 32 + connect \A { 4'0100 $delete_wire$169823 2'00 $delete_wire$169822 1'0 $delete_wire$169781 $delete_wire$170757 } + connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216092$6329_Y + connect \S $delete_wire$170006 + connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216091$6330_Y + end + cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216092$6329 + parameter \WIDTH 32 + connect \A { $delete_wire$169818 $delete_wire$170762 $delete_wire$170868 $delete_wire$169722 $delete_wire$169991 $delete_wire$169689 $delete_wire$170642 $delete_wire$169698 $delete_wire$169979 $delete_wire$170048 $delete_wire$169646 $delete_wire$171409 $delete_wire$171259 $delete_wire$170043 $delete_wire$170055 $delete_wire$171471 $delete_wire$170646 $delete_wire$169792 $delete_wire$169727 $delete_wire$169740 $delete_wire$169752 $delete_wire$170022 $delete_wire$169775 $delete_wire$170027 $delete_wire$169804 $delete_wire$170666 $delete_wire$170663 $delete_wire$171179 $delete_wire$169666 $delete_wire$171186 $delete_wire$170655 \dcsr_q_prv__0_ } + connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216093$6328_Y + connect \S $delete_wire$169972 + connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216092$6329_Y + end + cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216093$6328 + parameter \WIDTH 32 + connect \A { $delete_wire$169817 $delete_wire$171190 $delete_wire$171408 $delete_wire$169721 $delete_wire$171002 $delete_wire$169688 $delete_wire$171270 $delete_wire$169697 $delete_wire$169980 $delete_wire$169982 $delete_wire$169645 $delete_wire$171180 $delete_wire$169771 $delete_wire$170860 $delete_wire$170054 $delete_wire$171009 $delete_wire$170639 $delete_wire$169791 $delete_wire$170879 $delete_wire$169739 $delete_wire$169751 $delete_wire$170049 $delete_wire$169774 $delete_wire$170028 $delete_wire$169803 $delete_wire$170645 $delete_wire$169989 $delete_wire$171272 $delete_wire$169665 $delete_wire$171174 $delete_wire$170653 \dcsr_q_prv__0_ } + connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216094$6327_Y + connect \S $delete_wire$170036 + connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216093$6328_Y + end + cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216094$6327 + parameter \WIDTH 32 + connect \A { $delete_wire$169816 $delete_wire$171228 $delete_wire$171454 $delete_wire$169720 $delete_wire$170997 $delete_wire$169687 $delete_wire$170649 $delete_wire$169696 $delete_wire$169981 $delete_wire$170050 $delete_wire$169644 $delete_wire$170760 $delete_wire$169786 $delete_wire$170862 $delete_wire$170032 $delete_wire$171389 $delete_wire$171043 $delete_wire$169790 $delete_wire$169749 $delete_wire$169738 $delete_wire$169750 $delete_wire$169983 $delete_wire$169773 $delete_wire$170029 $delete_wire$169802 $delete_wire$170660 $delete_wire$169962 $delete_wire$170658 $delete_wire$169664 $delete_wire$170751 $delete_wire$170640 \dcsr_q_prv__0_ } + connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216095$6326_Y + connect \S $delete_wire$169705 + connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216094$6327_Y + end + cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216095$6326 + parameter \WIDTH 32 + connect \A { $delete_wire$169815 $delete_wire$171372 $delete_wire$171175 $delete_wire$169719 $delete_wire$171044 $delete_wire$169686 $delete_wire$171231 $delete_wire$169695 $delete_wire$170008 $delete_wire$170052 $delete_wire$169643 $delete_wire$170996 $delete_wire$169785 $delete_wire$170865 $delete_wire$170636 $delete_wire$171185 $delete_wire$171188 $delete_wire$169789 $delete_wire$171045 $delete_wire$169737 $delete_wire$169765 $delete_wire$171268 $delete_wire$169772 $delete_wire$170016 $delete_wire$169801 $delete_wire$170665 $delete_wire$170058 $delete_wire$169961 $delete_wire$169663 $delete_wire$171502 $delete_wire$170652 \dcsr_q_prv__0_ } + connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216096$6325_Y + connect \S $delete_wire$170650 + connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216095$6326_Y + end + cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216096$6325 + parameter \WIDTH 32 + connect \A { $delete_wire$169814 $delete_wire$170753 $delete_wire$171176 $delete_wire$169709 $delete_wire$170999 $delete_wire$169685 $delete_wire$170647 $delete_wire$169694 $delete_wire$169999 $delete_wire$170051 $delete_wire$169642 $delete_wire$170863 $delete_wire$169784 $delete_wire$170755 $delete_wire$170754 $delete_wire$171204 $delete_wire$171373 $delete_wire$169788 $delete_wire$170059 $delete_wire$169736 $delete_wire$169748 $delete_wire$171351 $delete_wire$169787 $delete_wire$171340 $delete_wire$169800 $delete_wire$170638 $delete_wire$169970 $delete_wire$169974 $delete_wire$169662 $delete_wire$170764 $delete_wire$170651 \dcsr_q_prv__0_ } + connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216097$6324_Y + connect \S $delete_wire$169996 + connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216096$6325_Y + end + cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216097$6324 + parameter \WIDTH 32 + connect \A { $delete_wire$169813 $delete_wire$171229 $delete_wire$170765 $delete_wire$169717 $delete_wire$171035 $delete_wire$169675 $delete_wire$170637 $delete_wire$169693 $delete_wire$170000 $delete_wire$171000 $delete_wire$169650 $delete_wire$171442 $delete_wire$169783 $delete_wire$170882 $delete_wire$171318 $delete_wire$171010 $delete_wire$171357 $delete_wire$169821 $delete_wire$170880 $delete_wire$169726 $delete_wire$169747 $delete_wire$169984 $delete_wire$169770 $delete_wire$170031 $delete_wire$169799 $delete_wire$171048 $delete_wire$169969 $delete_wire$170656 $delete_wire$169661 $delete_wire$171354 $delete_wire$170661 \dcsr_q_prv__0_ } + connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216098$6323_Y + connect \S $delete_wire$169671 + connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216097$6324_Y + end + cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216098$6323 + parameter \WIDTH 32 + connect \A { $delete_wire$169998 $delete_wire$171350 $delete_wire$170759 $delete_wire$169716 $delete_wire$169993 $delete_wire$169683 $delete_wire$170654 $delete_wire$169667 $delete_wire$170001 $delete_wire$171371 $delete_wire$169674 $delete_wire$170667 $delete_wire$169782 $delete_wire$171187 $delete_wire$170878 $delete_wire$170766 $delete_wire$171254 $delete_wire$169796 $delete_wire$170877 $delete_wire$169734 $delete_wire$169746 $delete_wire$171207 $delete_wire$169769 $delete_wire$170009 $delete_wire$169798 $delete_wire$171172 $delete_wire$169968 $delete_wire$171271 $delete_wire$169660 $delete_wire$171232 $delete_wire$170662 \dcsr_q_prv__0_ } + connect \B $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216099$6322_Y + connect \S $delete_wire$169831 + connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216098$6323_Y + end + cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216099$6322 + parameter \WIDTH 32 + connect \A { $delete_wire$169811 $delete_wire$171355 $delete_wire$170763 $delete_wire$169715 $delete_wire$171039 $delete_wire$169682 $delete_wire$169988 $delete_wire$169657 $delete_wire$170015 $delete_wire$171317 $delete_wire$169673 $delete_wire$170866 $delete_wire$169768 $delete_wire$170998 $delete_wire$170752 $delete_wire$170023 $delete_wire$170767 $delete_wire$169795 $delete_wire$170030 $delete_wire$169733 $delete_wire$169745 $delete_wire$171360 $delete_wire$169834 $delete_wire$170010 $delete_wire$169976 $delete_wire$171203 $delete_wire$169967 $delete_wire$171477 $delete_wire$169659 $delete_wire$171230 $delete_wire$170641 \dcsr_q_prv__0_ } + connect \B $delete_wire$169713 + connect \S $delete_wire$171001 + connect \Y $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:216099$6322_Y + end + cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:217099$7332 + parameter \WIDTH 32 + connect \A { $delete_wire$170013 $delete_wire$171353 $delete_wire$171037 $delete_wire$169714 $delete_wire$171269 $delete_wire$169681 $delete_wire$170668 $delete_wire$169656 $delete_wire$170003 $delete_wire$171189 $delete_wire$169672 $delete_wire$169960 $delete_wire$169780 $delete_wire$170775 $delete_wire$170871 $delete_wire$170864 $delete_wire$171183 $delete_wire$169808 $delete_wire$170017 $delete_wire$169732 $delete_wire$169744 $delete_wire$171359 $delete_wire$171041 $delete_wire$171040 $delete_wire$170761 $delete_wire$170635 $delete_wire$169966 $delete_wire$169971 $delete_wire$169701 $delete_wire$170648 $delete_wire$171255 \dcsr_q_prv__0_ } + connect \B { $delete_wire$169829 $delete_wire$171316 $delete_wire$169836 $delete_wire$169678 $delete_wire$169676 $delete_wire$169766 $delete_wire$169827 $delete_wire$170039 $delete_wire$169703 $delete_wire$169652 $delete_wire$169706 $delete_wire$169708 $delete_wire$169987 $delete_wire$169711 $delete_wire$169985 $delete_wire$169758 $delete_wire$169973 $delete_wire$170011 $delete_wire$170869 $delete_wire$169812 $delete_wire$169964 $delete_wire$169824 $delete_wire$169654 $delete_wire$169838 $delete_wire$170035 $delete_wire$169840 $delete_wire$171341 $delete_wire$169832 $delete_wire$169761 $delete_wire$169797 $delete_wire$169763 \N2231 } + connect \S $delete_wire$169760 + connect \Y { \dcsr_d [31:9] $delete_wire$171047 $delete_wire$170040 $delete_wire$170750 \dcsr_d [5:2] $delete_wire$171227 \N3558 } + end + cell $mux $ternary$/workspace/OpenROAD-flow-scripts/flow/designs/src/ariane133/ariane.sv2v.v:217233$7498 + parameter \WIDTH 5 + connect \A { $delete_wire$169995 $delete_wire$169651 $delete_wire$171042 $delete_wire$171201 } + connect \B { $delete_wire$170867 $delete_wire$170041 $delete_wire$171178 $delete_wire$171358 \N3558 } + connect \S $delete_wire$170771 + connect \Y { \dcsr_d [8:6] \dcsr_d [1:0] } + end +end diff --git a/tests/opt/opt_dff-simplify.ys b/tests/opt/opt_dff-simplify.ys new file mode 100644 index 000000000..3a4d6778c --- /dev/null +++ b/tests/opt/opt_dff-simplify.ys @@ -0,0 +1,12 @@ +read_rtlil opt_dff-simplify.il +opt_dff + +select -assert-count 8 t:$ne r:A_WIDTH=3 %i +select -assert-count 5 t:$ne r:A_WIDTH=2 %i + +select -assert-none t:$ne r:A_WIDTH=13 %i +select -assert-none t:$ne r:A_WIDTH=14 %i +select -assert-none t:$ne r:A_WIDTH=15 %i +select -assert-none t:$ne r:A_WIDTH=10 %i +select -assert-none t:$ne r:A_WIDTH=12 %i +select -assert-none t:$ne r:A_WIDTH=11 %i From a265b23ac0c686e7e54613f58da4f132f406eca5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 14 Aug 2025 00:25:16 +0000 Subject: [PATCH 111/176] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 10f8add20..8ec8715d3 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+101 +YOSYS_VER := 0.56+105 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 1dbf2df9837a33381b1bf62269edd8eaec144a3c Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 14 Aug 2025 09:15:43 +0200 Subject: [PATCH 112/176] Add libfl-dev for CodeQL CI job --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 75d799fe1..95595924a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Install deps - run: sudo apt-get install bison flex libreadline-dev tcl-dev libffi-dev + run: sudo apt-get install bison flex libfl-dev libreadline-dev tcl-dev libffi-dev - name: Checkout repository uses: actions/checkout@v4 From 4de3ee093eecf4e766734fddb113187df36be31a Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Sat, 26 Jul 2025 09:34:37 +0000 Subject: [PATCH 113/176] Mark kept FF output wires as ports directly instead of via the 'keep' attribute --- passes/techmap/abc.cc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 0c2576c1a..dfaee9415 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -291,12 +291,15 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool return; } - if (keepff) - for (auto &c : ff.sig_q.chunks()) - if (c.wire != nullptr) - c.wire->attributes[ID::keep] = 1; - - map_signal(ff.sig_q, type, map_signal(ff.sig_d)); + int gate_id = map_signal(ff.sig_q, type, map_signal(ff.sig_d)); + if (keepff) { + SigBit bit = ff.sig_q; + if (assign_map(bit).wire != nullptr) { + signal_list[gate_id].is_port = true; + } + if (bit.wire != nullptr) + bit.wire->attributes[ID::keep] = 1; + } ff.remove(); return; From ac8259b02e6d2ac98fd903603d012c8180540aba Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 17 Jul 2025 06:16:54 +0000 Subject: [PATCH 114/176] Preserve `assign_map` across ABC invocations. Currently `assign_map` is rebuilt from the module from scratch every time we invoke ABC. That doesn't scale when we do thousands of ABC runs over large modules. Instead, create it once and then maintain incrementally it as we update the module. --- passes/techmap/abc.cc | 130 ++++++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 62 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index dfaee9415..75f19f77b 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -142,7 +142,6 @@ struct AbcModuleState { const AbcConfig &config; int map_autoidx = 0; - SigMap assign_map; std::vector signal_list; dict signal_map; FfInitVals initvals; @@ -162,19 +161,19 @@ struct AbcModuleState { AbcModuleState(const AbcConfig &config) : config(config) {} - int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); - void mark_port(RTLIL::SigSpec sig); - void extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool keepff); + int map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); + void mark_port(const SigMap &assign_map, RTLIL::SigSpec sig); + void extract_cell(const SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff); std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr); void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts); - void handle_loops(RTLIL::Module *module); - void abc_module(RTLIL::Design *design, RTLIL::Module *module, const std::vector &cells, + void handle_loops(SigMap &assign_map, RTLIL::Module *module); + void abc_module(RTLIL::Design *design, RTLIL::Module *module, SigMap &assign_map, const std::vector &cells, bool dff_mode, std::string clk_str); - void extract(RTLIL::Design *design, RTLIL::Module *module); + void extract(SigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module); void finish(); }; -int AbcModuleState::map_signal(RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) +int AbcModuleState::map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) { assign_map.apply(bit); @@ -212,14 +211,14 @@ int AbcModuleState::map_signal(RTLIL::SigBit bit, gate_type_t gate_type, int in1 return gate.id; } -void AbcModuleState::mark_port(RTLIL::SigSpec sig) +void AbcModuleState::mark_port(const SigMap &assign_map, RTLIL::SigSpec sig) { for (auto &bit : assign_map(sig)) if (bit.wire != nullptr && signal_map.count(bit) > 0) signal_list[signal_map[bit]].is_port = true; } -void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool keepff) +void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff) { if (RTLIL::builtin_ff_cell_types().count(cell->type)) { FfData ff(&initvals, cell); @@ -291,7 +290,7 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool return; } - int gate_id = map_signal(ff.sig_q, type, map_signal(ff.sig_d)); + int gate_id = map_signal(assign_map, ff.sig_q, type, map_signal(assign_map, ff.sig_d)); if (keepff) { SigBit bit = ff.sig_q; if (assign_map(bit).wire != nullptr) { @@ -301,6 +300,8 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool bit.wire->attributes[ID::keep] = 1; } + map_signal(assign_map, ff.sig_q, type, map_signal(assign_map, ff.sig_d)); + ff.remove(); return; } @@ -313,7 +314,7 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool assign_map.apply(sig_a); assign_map.apply(sig_y); - map_signal(sig_y, cell->type == ID($_BUF_) ? G(BUF) : G(NOT), map_signal(sig_a)); + map_signal(assign_map, sig_y, cell->type == ID($_BUF_) ? G(BUF) : G(NOT), map_signal(assign_map, sig_a)); module->remove(cell); return; @@ -329,25 +330,25 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool assign_map.apply(sig_b); assign_map.apply(sig_y); - int mapped_a = map_signal(sig_a); - int mapped_b = map_signal(sig_b); + int mapped_a = map_signal(assign_map, sig_a); + int mapped_b = map_signal(assign_map, sig_b); if (cell->type == ID($_AND_)) - map_signal(sig_y, G(AND), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(AND), mapped_a, mapped_b); else if (cell->type == ID($_NAND_)) - map_signal(sig_y, G(NAND), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(NAND), mapped_a, mapped_b); else if (cell->type == ID($_OR_)) - map_signal(sig_y, G(OR), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(OR), mapped_a, mapped_b); else if (cell->type == ID($_NOR_)) - map_signal(sig_y, G(NOR), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(NOR), mapped_a, mapped_b); else if (cell->type == ID($_XOR_)) - map_signal(sig_y, G(XOR), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(XOR), mapped_a, mapped_b); else if (cell->type == ID($_XNOR_)) - map_signal(sig_y, G(XNOR), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(XNOR), mapped_a, mapped_b); else if (cell->type == ID($_ANDNOT_)) - map_signal(sig_y, G(ANDNOT), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(ANDNOT), mapped_a, mapped_b); else if (cell->type == ID($_ORNOT_)) - map_signal(sig_y, G(ORNOT), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(ORNOT), mapped_a, mapped_b); else log_abort(); @@ -367,11 +368,11 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool assign_map.apply(sig_s); assign_map.apply(sig_y); - int mapped_a = map_signal(sig_a); - int mapped_b = map_signal(sig_b); - int mapped_s = map_signal(sig_s); + int mapped_a = map_signal(assign_map, sig_a); + int mapped_b = map_signal(assign_map, sig_b); + int mapped_s = map_signal(assign_map, sig_s); - map_signal(sig_y, cell->type == ID($_MUX_) ? G(MUX) : G(NMUX), mapped_a, mapped_b, mapped_s); + map_signal(assign_map, sig_y, cell->type == ID($_MUX_) ? G(MUX) : G(NMUX), mapped_a, mapped_b, mapped_s); module->remove(cell); return; @@ -389,11 +390,11 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool assign_map.apply(sig_c); assign_map.apply(sig_y); - int mapped_a = map_signal(sig_a); - int mapped_b = map_signal(sig_b); - int mapped_c = map_signal(sig_c); + int mapped_a = map_signal(assign_map, sig_a); + int mapped_b = map_signal(assign_map, sig_b); + int mapped_c = map_signal(assign_map, sig_c); - map_signal(sig_y, cell->type == ID($_AOI3_) ? G(AOI3) : G(OAI3), mapped_a, mapped_b, mapped_c); + map_signal(assign_map, sig_y, cell->type == ID($_AOI3_) ? G(AOI3) : G(OAI3), mapped_a, mapped_b, mapped_c); module->remove(cell); return; @@ -413,12 +414,12 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool assign_map.apply(sig_d); assign_map.apply(sig_y); - int mapped_a = map_signal(sig_a); - int mapped_b = map_signal(sig_b); - int mapped_c = map_signal(sig_c); - int mapped_d = map_signal(sig_d); + int mapped_a = map_signal(assign_map, sig_a); + int mapped_b = map_signal(assign_map, sig_b); + int mapped_c = map_signal(assign_map, sig_c); + int mapped_d = map_signal(assign_map, sig_d); - map_signal(sig_y, cell->type == ID($_AOI4_) ? G(AOI4) : G(OAI4), mapped_a, mapped_b, mapped_c, mapped_d); + map_signal(assign_map, sig_y, cell->type == ID($_AOI4_) ? G(AOI4) : G(OAI4), mapped_a, mapped_b, mapped_c, mapped_d); module->remove(cell); return; @@ -493,7 +494,13 @@ void AbcModuleState::dump_loop_graph(FILE *f, int &nr, dict> &edg fprintf(f, "}\n"); } -void AbcModuleState::handle_loops(RTLIL::Module *module) +void connect(SigMap &assign_map, RTLIL::Module *module, const RTLIL::SigSig &conn) +{ + module->connect(conn); + assign_map.add(conn.first, conn.second); +} + +void AbcModuleState::handle_loops(SigMap &assign_map, RTLIL::Module *module) { // http://en.wikipedia.org/wiki/Topological_sorting // (Kahn, Arthur B. (1962), "Topological sorting of large networks") @@ -598,7 +605,7 @@ void AbcModuleState::handle_loops(RTLIL::Module *module) first_line = false; } - int id3 = map_signal(RTLIL::SigSpec(wire)); + int id3 = map_signal(assign_map, RTLIL::SigSpec(wire)); signal_list[id1].is_port = true; signal_list[id3].is_port = true; log_assert(id3 == int(in_edges_count.size())); @@ -617,7 +624,7 @@ void AbcModuleState::handle_loops(RTLIL::Module *module) } edges[id1].swap(edges[id3]); - module->connect(RTLIL::SigSig(signal_list[id3].bit, signal_list[id1].bit)); + connect(assign_map, module, RTLIL::SigSig(signal_list[id3].bit, signal_list[id1].bit)); dump_loop_graph(dot_f, dot_nr, edges, workpool, in_edges_count); } } @@ -753,7 +760,7 @@ struct abc_output_filter } }; -void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, const std::vector &cells, +void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, SigMap &assign_map, const std::vector &cells, bool dff_mode, std::string clk_str) { initvals.set(&assign_map, module); @@ -939,33 +946,33 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, co had_init = false; for (auto c : cells) - extract_cell(module, c, config.keepff); + extract_cell(assign_map, module, c, config.keepff); if (undef_bits_lost) log("Replacing %d occurrences of constant undef bits with constant zero bits\n", undef_bits_lost); for (auto wire : module->wires()) { if (wire->port_id > 0 || wire->get_bool_attribute(ID::keep)) - mark_port(wire); + mark_port(assign_map, wire); } for (auto cell : module->cells()) for (auto &port_it : cell->connections()) - mark_port(port_it.second); + mark_port(assign_map, port_it.second); if (clk_sig.size() != 0) - mark_port(clk_sig); + mark_port(assign_map, clk_sig); if (en_sig.size() != 0) - mark_port(en_sig); + mark_port(assign_map, en_sig); if (arst_sig.size() != 0) - mark_port(arst_sig); + mark_port(assign_map, arst_sig); if (srst_sig.size() != 0) - mark_port(srst_sig); + mark_port(assign_map, srst_sig); - handle_loops(module); + handle_loops(assign_map, module); buffer = stringf("%s/input.blif", tempdir_name.c_str()); f = fopen(buffer.c_str(), "wt"); @@ -1208,7 +1215,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, co log("Don't call ABC as there is nothing to map.\n"); } -void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) +void AbcModuleState::extract(SigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module) { if (!did_run_abc) { return; @@ -1253,7 +1260,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name); conn.first = module->wire(name_y); conn.second = RTLIL::SigSpec(c->type == ID(ZERO) ? 0 : 1, 1); - module->connect(conn); + connect(assign_map, module, conn); continue; } if (c->type == ID(BUF)) { @@ -1262,7 +1269,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) RTLIL::IdString name_a = remap_name(c->getPort(ID::A).as_wire()->name); conn.first = module->wire(name_y); conn.second = module->wire(name_a); - module->connect(conn); + connect(assign_map, module, conn); continue; } if (c->type == ID(NOT)) { @@ -1394,7 +1401,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) RTLIL::SigSig conn; conn.first = module->wire(remap_name(c->connections().begin()->second.as_wire()->name)); conn.second = RTLIL::SigSpec(c->type == ID(_const0_) ? 0 : 1, 1); - module->connect(conn); + connect(assign_map, module, conn); continue; } @@ -1439,7 +1446,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) if (c->type == ID($lut) && GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID::LUT).as_int() == 2) { SigSpec my_a = module->wire(remap_name(c->getPort(ID::A).as_wire()->name)); SigSpec my_y = module->wire(remap_name(c->getPort(ID::Y).as_wire()->name)); - module->connect(my_y, my_a); + connect(assign_map, module, RTLIL::SigSig(my_a, my_y)); continue; } @@ -1464,7 +1471,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) conn.first = module->wire(remap_name(conn.first.as_wire()->name)); if (!conn.second.is_fully_const()) conn.second = module->wire(remap_name(conn.second.as_wire()->name)); - module->connect(conn); + connect(assign_map, module, conn); } cell_stats.sort(); @@ -1485,7 +1492,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) conn.second = si.bit; in_wires++; } - module->connect(conn); + connect(assign_map, module, conn); } log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); log("ABC RESULTS: input signals: %8d\n", in_wires); @@ -2079,6 +2086,9 @@ struct AbcPass : public Pass { for (auto mod : design->selected_modules()) { + SigMap assign_map; + assign_map.set(mod); + if (mod->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(mod)); continue; @@ -2086,9 +2096,8 @@ struct AbcPass : public Pass { if (!dff_mode || !clk_str.empty()) { AbcModuleState state(config); - state.assign_map.set(mod); - state.abc_module(design, mod, mod->selected_cells(), dff_mode, clk_str); - state.extract(design, mod); + state.abc_module(design, mod, assign_map, mod->selected_cells(), dff_mode, clk_str); + state.extract(assign_map, design, mod); state.finish(); continue; } @@ -2109,8 +2118,6 @@ struct AbcPass : public Pass { dict> cell_to_bit, cell_to_bit_up, cell_to_bit_down; dict> bit_to_cell, bit_to_cell_up, bit_to_cell_down; - SigMap assign_map; - assign_map.set(mod); FfInitVals initvals; initvals.set(&assign_map, mod); for (auto cell : all_cells) @@ -2247,7 +2254,6 @@ struct AbcPass : public Pass { for (auto &it : assigned_cells) { AbcModuleState state(config); - state.assign_map.set(mod); state.clk_polarity = std::get<0>(it.first); state.clk_sig = assign_map(std::get<1>(it.first)); state.en_polarity = std::get<2>(it.first); @@ -2256,8 +2262,8 @@ struct AbcPass : public Pass { state.arst_sig = assign_map(std::get<5>(it.first)); state.srst_polarity = std::get<6>(it.first); state.srst_sig = assign_map(std::get<7>(it.first)); - state.abc_module(design, mod, it.second, !state.clk_sig.empty(), "$"); - state.extract(design, mod); + state.abc_module(design, mod, assign_map, it.second, !state.clk_sig.empty(), "$"); + state.extract(assign_map, design, mod); state.finish(); } } From 2654bd53553b3502cd65f5e0fb0a6566fe1584be Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Sun, 27 Jul 2025 23:44:41 +0000 Subject: [PATCH 115/176] Compute `is_port` in AbcPass without iterating through all cells and wires in the module every time we run ABC. This does not scale when we run ABC thousands of times in a single AbcPass. --- kernel/ffinit.h | 6 +- kernel/ffmerge.h | 2 +- kernel/hashlib.h | 3 +- kernel/sigtools.h | 172 +++++++++++++++++++++++++++++++++--------- passes/techmap/abc.cc | 172 +++++++++++++++++++++++++++++------------- 5 files changed, 264 insertions(+), 91 deletions(-) diff --git a/kernel/ffinit.h b/kernel/ffinit.h index 6d4c97ac3..66c13b68f 100644 --- a/kernel/ffinit.h +++ b/kernel/ffinit.h @@ -27,10 +27,10 @@ YOSYS_NAMESPACE_BEGIN struct FfInitVals { - const SigMap *sigmap; + const SigMapView *sigmap; dict> initbits; - void set(const SigMap *sigmap_, RTLIL::Module *module) + void set(const SigMapView *sigmap_, RTLIL::Module *module) { sigmap = sigmap_; initbits.clear(); @@ -126,7 +126,7 @@ struct FfInitVals initbits.clear(); } - FfInitVals (const SigMap *sigmap, RTLIL::Module *module) + FfInitVals (const SigMapView *sigmap, RTLIL::Module *module) { set(sigmap, module); } diff --git a/kernel/ffmerge.h b/kernel/ffmerge.h index 5428da324..028987503 100644 --- a/kernel/ffmerge.h +++ b/kernel/ffmerge.h @@ -58,7 +58,7 @@ YOSYS_NAMESPACE_BEGIN struct FfMergeHelper { - const SigMap *sigmap; + const SigMapView *sigmap; RTLIL::Module *module; FfInitVals *initvals; diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 52ff96028..7a5650fa3 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -1353,7 +1353,8 @@ public: return p; } - // Merge sets if the given indices belong to different sets + // Merge sets if the given indices belong to different sets. + // Makes ifind(j) the root of the merged set. void imerge(int i, int j) { i = ifind(i); diff --git a/kernel/sigtools.h b/kernel/sigtools.h index 3b0d7b40d..7962eaa70 100644 --- a/kernel/sigtools.h +++ b/kernel/sigtools.h @@ -237,6 +237,42 @@ using sort_by_name_id_guard = typename std::enable_if class SigSet> : public SigSet::type>> {}; +struct SigMapView +{ + mfp database; + + // Modify bit to its representative + void apply(RTLIL::SigBit &bit) const + { + bit = database.find(bit); + } + + void apply(RTLIL::SigSpec &sig) const + { + for (auto &bit : sig) + apply(bit); + } + + RTLIL::SigBit operator()(RTLIL::SigBit bit) const + { + apply(bit); + return bit; + } + + RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const + { + apply(sig); + return sig; + } + + RTLIL::SigSpec operator()(RTLIL::Wire *wire) const + { + SigSpec sig(wire); + apply(sig); + return sig; + } +}; + /** * SigMap wraps a union-find "database" * to map SigBits of a module to canonical representative SigBits. @@ -244,10 +280,8 @@ class SigSet> : public SigSet database; - SigMap(RTLIL::Module *module = NULL) { if (module != NULL) @@ -320,37 +354,6 @@ struct SigMap inline void add(Wire *wire) { return add(RTLIL::SigSpec(wire)); } - // Modify bit to its representative - void apply(RTLIL::SigBit &bit) const - { - bit = database.find(bit); - } - - void apply(RTLIL::SigSpec &sig) const - { - for (auto &bit : sig) - apply(bit); - } - - RTLIL::SigBit operator()(RTLIL::SigBit bit) const - { - apply(bit); - return bit; - } - - RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const - { - apply(sig); - return sig; - } - - RTLIL::SigSpec operator()(RTLIL::Wire *wire) const - { - SigSpec sig(wire); - apply(sig); - return sig; - } - // All non-const bits RTLIL::SigSpec allbits() const { @@ -362,6 +365,107 @@ struct SigMap } }; +/** + * SiValgMap wraps a union-find "database" to map SigBits of a module to + * canonical representative SigBits plus some optional Val value associated with the bits. + * Val has a commutative, associative, idempotent operator|=, a default constructor + * which constructs an identity element, and a copy constructor. + * SigBits that are connected share a set in the underlying database; + * the associated value is the "sum" of all the values associated with the contributing bits. + * If any of the SigBits in a set are a constant, the canonical SigBit is a constant. + */ +template +struct SigValMap final : public SigMapView +{ + dict values; + + void swap(SigValMap &other) + { + database.swap(other.database); + values.swap(other.values); + } + + void clear() + { + database.clear(); + values.clear(); + } + + // Rebuild SigMap for all connections in module + void set(RTLIL::Module *module) + { + int bitcount = 0; + for (auto &it : module->connections()) + bitcount += it.first.size(); + + database.clear(); + values.clear(); + database.reserve(bitcount); + + for (auto &it : module->connections()) + add(it.first, it.second); + } + + // Add connections from "from" to "to", bit-by-bit. + void add(const RTLIL::SigSpec& from, const RTLIL::SigSpec& to) + { + log_assert(GetSize(from) == GetSize(to)); + + for (int i = 0; i < GetSize(from); i++) + { + int bfi = database.lookup(from[i]); + int bti = database.lookup(to[i]); + if (bfi == bti) { + continue; + } + + const RTLIL::SigBit &bf = database[bfi]; + const RTLIL::SigBit &bt = database[bti]; + if (bf.wire == nullptr) { + // bf is constant so make it the canonical representative. + database.imerge(bti, bfi); + merge_value(bt, bf); + } else { + // Make bt the canonical representative. + database.imerge(bfi, bti); + merge_value(bf, bt); + } + } + } + + void addVal(const RTLIL::SigBit &bit, const Val &val) + { + values[database.find(bit)] |= val; + } + + void addVal(const RTLIL::SigSpec &sig, const Val &val) + { + for (const auto &bit : sig) + addVal(bit, val); + } + + Val apply_and_get_value(RTLIL::SigBit &bit) const + { + bit = database.find(bit); + auto it = values.find(bit); + return it == values.end() ? Val() : it->second; + } + +private: + void merge_value(const RTLIL::SigBit &from, const RTLIL::SigBit &to) + { + auto it = values.find(from); + if (it == values.end()) { + return; + } + // values[to] could resize the underlying `entries` so + // finish using `it` first. + Val v = it->second; + values.erase(it); + values[to] |= v; + } +}; + YOSYS_NAMESPACE_END #endif /* SIGTOOLS_H */ diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 75f19f77b..f3d53d042 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -138,6 +138,18 @@ struct AbcConfig bool abc_dress = false; }; +struct AbcSigVal { + bool is_port; + + AbcSigVal(bool is_port = false) : is_port(is_port) {} + AbcSigVal &operator|=(const AbcSigVal &other) { + is_port |= other.is_port; + return *this; + } +}; + +using AbcSigMap = SigValMap; + struct AbcModuleState { const AbcConfig &config; @@ -161,21 +173,21 @@ struct AbcModuleState { AbcModuleState(const AbcConfig &config) : config(config) {} - int map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); - void mark_port(const SigMap &assign_map, RTLIL::SigSpec sig); - void extract_cell(const SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff); + int map_signal(const AbcSigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); + void mark_port(const AbcSigMap &assign_map, RTLIL::SigSpec sig); + bool extract_cell(const AbcSigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff); std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr); void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts); - void handle_loops(SigMap &assign_map, RTLIL::Module *module); - void abc_module(RTLIL::Design *design, RTLIL::Module *module, SigMap &assign_map, const std::vector &cells, + void handle_loops(AbcSigMap &assign_map, RTLIL::Module *module); + void abc_module(RTLIL::Design *design, RTLIL::Module *module, AbcSigMap &assign_map, const std::vector &cells, bool dff_mode, std::string clk_str); - void extract(SigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module); + void extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module); void finish(); }; -int AbcModuleState::map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) +int AbcModuleState::map_signal(const AbcSigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) { - assign_map.apply(bit); + AbcSigVal val = assign_map.apply_and_get_value(bit); if (bit == State::Sx) undef_bits_lost++; @@ -188,7 +200,7 @@ int AbcModuleState::map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate gate.in2 = -1; gate.in3 = -1; gate.in4 = -1; - gate.is_port = false; + gate.is_port = bit.wire != nullptr && val.is_port; gate.bit = bit; gate.init = initvals(bit); signal_list.push_back(gate); @@ -211,40 +223,40 @@ int AbcModuleState::map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate return gate.id; } -void AbcModuleState::mark_port(const SigMap &assign_map, RTLIL::SigSpec sig) +void AbcModuleState::mark_port(const AbcSigMap &assign_map, RTLIL::SigSpec sig) { for (auto &bit : assign_map(sig)) if (bit.wire != nullptr && signal_map.count(bit) > 0) signal_list[signal_map[bit]].is_port = true; } -void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff) +bool AbcModuleState::extract_cell(const AbcSigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff) { if (RTLIL::builtin_ff_cell_types().count(cell->type)) { FfData ff(&initvals, cell); gate_type_t type = G(FF); if (!ff.has_clk) - return; + return false; if (ff.has_gclk) - return; + return false; if (ff.has_aload) - return; + return false; if (ff.has_sr) - return; + return false; if (!ff.is_fine) - return; + return false; if (clk_polarity != ff.pol_clk) - return; + return false; if (clk_sig != assign_map(ff.sig_clk)) - return; + return false; if (ff.has_ce) { if (en_polarity != ff.pol_ce) - return; + return false; if (en_sig != assign_map(ff.sig_ce)) - return; + return false; } else { if (GetSize(en_sig) != 0) - return; + return false; } if (ff.val_init == State::S1) { type = G(FF1); @@ -255,39 +267,39 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul } if (ff.has_arst) { if (arst_polarity != ff.pol_arst) - return; + return false; if (arst_sig != assign_map(ff.sig_arst)) - return; + return false; if (ff.val_arst == State::S1) { if (type == G(FF0)) - return; + return false; type = G(FF1); } else if (ff.val_arst == State::S0) { if (type == G(FF1)) - return; + return false; type = G(FF0); } } else { if (GetSize(arst_sig) != 0) - return; + return false; } if (ff.has_srst) { if (srst_polarity != ff.pol_srst) - return; + return false; if (srst_sig != assign_map(ff.sig_srst)) - return; + return false; if (ff.val_srst == State::S1) { if (type == G(FF0)) - return; + return false; type = G(FF1); } else if (ff.val_srst == State::S0) { if (type == G(FF1)) - return; + return false; type = G(FF0); } } else { if (GetSize(srst_sig) != 0) - return; + return false; } int gate_id = map_signal(assign_map, ff.sig_q, type, map_signal(assign_map, ff.sig_d)); @@ -303,7 +315,7 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul map_signal(assign_map, ff.sig_q, type, map_signal(assign_map, ff.sig_d)); ff.remove(); - return; + return true; } if (cell->type.in(ID($_BUF_), ID($_NOT_))) @@ -317,7 +329,7 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul map_signal(assign_map, sig_y, cell->type == ID($_BUF_) ? G(BUF) : G(NOT), map_signal(assign_map, sig_a)); module->remove(cell); - return; + return true; } if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_))) @@ -353,7 +365,7 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul log_abort(); module->remove(cell); - return; + return true; } if (cell->type.in(ID($_MUX_), ID($_NMUX_))) @@ -375,7 +387,7 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul map_signal(assign_map, sig_y, cell->type == ID($_MUX_) ? G(MUX) : G(NMUX), mapped_a, mapped_b, mapped_s); module->remove(cell); - return; + return true; } if (cell->type.in(ID($_AOI3_), ID($_OAI3_))) @@ -397,7 +409,7 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul map_signal(assign_map, sig_y, cell->type == ID($_AOI3_) ? G(AOI3) : G(OAI3), mapped_a, mapped_b, mapped_c); module->remove(cell); - return; + return true; } if (cell->type.in(ID($_AOI4_), ID($_OAI4_))) @@ -422,8 +434,10 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul map_signal(assign_map, sig_y, cell->type == ID($_AOI4_) ? G(AOI4) : G(OAI4), mapped_a, mapped_b, mapped_c, mapped_d); module->remove(cell); - return; + return true; } + + return false; } std::string AbcModuleState::remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire) @@ -494,13 +508,13 @@ void AbcModuleState::dump_loop_graph(FILE *f, int &nr, dict> &edg fprintf(f, "}\n"); } -void connect(SigMap &assign_map, RTLIL::Module *module, const RTLIL::SigSig &conn) +void connect(AbcSigMap &assign_map, RTLIL::Module *module, const RTLIL::SigSig &conn) { module->connect(conn); assign_map.add(conn.first, conn.second); } -void AbcModuleState::handle_loops(SigMap &assign_map, RTLIL::Module *module) +void AbcModuleState::handle_loops(AbcSigMap &assign_map, RTLIL::Module *module) { // http://en.wikipedia.org/wiki/Topological_sorting // (Kahn, Arthur B. (1962), "Topological sorting of large networks") @@ -760,7 +774,7 @@ struct abc_output_filter } }; -void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, SigMap &assign_map, const std::vector &cells, +void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, AbcSigMap &assign_map, const std::vector &cells, bool dff_mode, std::string clk_str) { initvals.set(&assign_map, module); @@ -945,18 +959,18 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, Si undef_bits_lost = 0; had_init = false; + std::vector kept_cells; for (auto c : cells) - extract_cell(assign_map, module, c, config.keepff); + if (!extract_cell(assign_map, module, c, config.keepff)) + kept_cells.push_back(c); if (undef_bits_lost) log("Replacing %d occurrences of constant undef bits with constant zero bits\n", undef_bits_lost); - for (auto wire : module->wires()) { - if (wire->port_id > 0 || wire->get_bool_attribute(ID::keep)) - mark_port(assign_map, wire); - } - - for (auto cell : module->cells()) + // Wires with port_id > 0, ID::keep, and connections to cells outside our cell set have already + // been accounted for via AbcSigVal::is_port. Now we just need to account for + // connections to cells inside our cell set that weren't removed by extract_cell(). + for (auto cell : kept_cells) for (auto &port_it : cell->connections()) mark_port(assign_map, port_it.second); @@ -1215,7 +1229,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, Si log("Don't call ABC as there is nothing to map.\n"); } -void AbcModuleState::extract(SigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module) +void AbcModuleState::extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module) { if (!did_run_abc) { return; @@ -1512,6 +1526,47 @@ void AbcModuleState::finish() log_pop(); } +// For every signal that connects cells from different sets, or a cell in a set to a cell not in any set, +// mark it as a port in `assign_map`. +void assign_cell_connection_ports(RTLIL::Module *module, const std::vector *> &cell_sets, + AbcSigMap &assign_map) +{ + pool cells_in_no_set; + for (RTLIL::Cell *cell : module->cells()) { + cells_in_no_set.insert(cell); + } + // For every canonical signal in `assign_map`, the index of the set it is connected to, + // or -1 if it connects a cell in one set to a cell in another set or not in any set. + dict signal_cell_set; + for (int i = 0; i < int(cell_sets.size()); ++i) { + for (RTLIL::Cell *cell : *cell_sets[i]) { + cells_in_no_set.erase(cell); + for (auto &port_it : cell->connections()) { + for (SigBit bit : port_it.second) { + assign_map.apply(bit); + auto it = signal_cell_set.find(bit); + if (it == signal_cell_set.end()) + signal_cell_set[bit] = i; + else if (it->second >= 0 && it->second != i) { + it->second = -1; + assign_map.addVal(bit, AbcSigVal(true)); + } + } + } + } + } + for (RTLIL::Cell *cell : cells_in_no_set) { + for (auto &port_it : cell->connections()) { + for (SigBit bit : port_it.second) { + assign_map.apply(bit); + auto it = signal_cell_set.find(bit); + if (it != signal_cell_set.end() && it->second >= 0) + assign_map.addVal(bit, AbcSigVal(true)); + } + } + } +} + struct AbcPass : public Pass { AbcPass() : Pass("abc", "use ABC for technology mapping") { } void help() override @@ -2086,17 +2141,24 @@ struct AbcPass : public Pass { for (auto mod : design->selected_modules()) { - SigMap assign_map; - assign_map.set(mod); - if (mod->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(mod)); continue; } + AbcSigMap assign_map; + assign_map.set(mod); + + for (auto wire : mod->wires()) + if (wire->port_id > 0 || wire->get_bool_attribute(ID::keep)) + assign_map.addVal(SigSpec(wire), AbcSigVal(true)); + if (!dff_mode || !clk_str.empty()) { + std::vector cells = mod->selected_cells(); + assign_cell_connection_ports(mod, {&cells}, assign_map); + AbcModuleState state(config); - state.abc_module(design, mod, assign_map, mod->selected_cells(), dff_mode, clk_str); + state.abc_module(design, mod, assign_map, cells, dff_mode, clk_str); state.extract(assign_map, design, mod); state.finish(); continue; @@ -2252,6 +2314,12 @@ struct AbcPass : public Pass { std::get<4>(it.first) ? "" : "!", log_signal(std::get<5>(it.first)), std::get<6>(it.first) ? "" : "!", log_signal(std::get<7>(it.first))); + { + std::vector*> cell_sets; + for (auto &it : assigned_cells) + cell_sets.push_back(&it.second); + assign_cell_connection_ports(mod, cell_sets, assign_map); + } for (auto &it : assigned_cells) { AbcModuleState state(config); state.clk_polarity = std::get<0>(it.first); From 62c441107dfdf7eac04ebbdc74d5693da69988a9 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 5 Aug 2025 22:21:30 +0000 Subject: [PATCH 116/176] Build FfInitVals for the entire module once and use it for every ABC run. --- passes/techmap/abc.cc | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index f3d53d042..9aaac84e9 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -156,7 +156,7 @@ struct AbcModuleState { int map_autoidx = 0; std::vector signal_list; dict signal_map; - FfInitVals initvals; + FfInitVals &initvals; bool had_init = false; bool did_run_abc = false; @@ -171,7 +171,8 @@ struct AbcModuleState { std::string tempdir_name; - AbcModuleState(const AbcConfig &config) : config(config) {} + AbcModuleState(const AbcConfig &config, FfInitVals &initvals) + : config(config), initvals(initvals) {} int map_signal(const AbcSigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); void mark_port(const AbcSigMap &assign_map, RTLIL::SigSpec sig); @@ -777,7 +778,6 @@ struct abc_output_filter void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, AbcSigMap &assign_map, const std::vector &cells, bool dff_mode, std::string clk_str) { - initvals.set(&assign_map, module); map_autoidx = autoidx++; if (clk_str != "$") @@ -2148,6 +2148,11 @@ struct AbcPass : public Pass { AbcSigMap assign_map; assign_map.set(mod); + // Create an FfInitVals and use it for all ABC runs. FfInitVals only cares about + // wires with the ID::init attribute and we don't add or remove any such wires + // in this pass. + FfInitVals initvals; + initvals.set(&assign_map, mod); for (auto wire : mod->wires()) if (wire->port_id > 0 || wire->get_bool_attribute(ID::keep)) @@ -2157,7 +2162,7 @@ struct AbcPass : public Pass { std::vector cells = mod->selected_cells(); assign_cell_connection_ports(mod, {&cells}, assign_map); - AbcModuleState state(config); + AbcModuleState state(config, initvals); state.abc_module(design, mod, assign_map, cells, dff_mode, clk_str); state.extract(assign_map, design, mod); state.finish(); @@ -2180,8 +2185,6 @@ struct AbcPass : public Pass { dict> cell_to_bit, cell_to_bit_up, cell_to_bit_down; dict> bit_to_cell, bit_to_cell_up, bit_to_cell_down; - FfInitVals initvals; - initvals.set(&assign_map, mod); for (auto cell : all_cells) { clkdomain_t key; @@ -2321,7 +2324,7 @@ struct AbcPass : public Pass { assign_cell_connection_ports(mod, cell_sets, assign_map); } for (auto &it : assigned_cells) { - AbcModuleState state(config); + AbcModuleState state(config, initvals); state.clk_polarity = std::get<0>(it.first); state.clk_sig = assign_map(std::get<1>(it.first)); state.en_polarity = std::get<2>(it.first); From ec18d1aede7cfcc6415e19be635a86bc09c88c4f Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 15 Aug 2025 10:48:32 +1200 Subject: [PATCH 117/176] rename.cc: Fixup ports after -unescape --- passes/cmds/rename.cc | 2 ++ tests/various/rename_unescape.ys | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc index 7e3f87147..167997dc0 100644 --- a/passes/cmds/rename.cc +++ b/passes/cmds/rename.cc @@ -598,6 +598,8 @@ struct RenamePass : public Pass { for (auto &it : new_cell_names) module->rename(it.first, it.second); + + module->fixup_ports(); } } else diff --git a/tests/various/rename_unescape.ys b/tests/various/rename_unescape.ys index 546d97357..2bb5286cc 100644 --- a/tests/various/rename_unescape.ys +++ b/tests/various/rename_unescape.ys @@ -39,3 +39,18 @@ select -assert-count 1 w:d__1 select -assert-count 1 w:_e select -assert-count 1 w:wire_ select -assert-count 1 w:$add$< Date: Wed, 13 Aug 2025 21:22:45 +0000 Subject: [PATCH 118/176] Make OptMuxtree int-indexed vectors into hashtables For one of our large circuits, this reduced the time for an OPT_MUXTREE pass from 169s to 5s. --- passes/opt/opt_muxtree.cc | 48 +++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc index 100b1b495..e1ed5da08 100644 --- a/passes/opt/opt_muxtree.cc +++ b/passes/opt/opt_muxtree.cc @@ -23,6 +23,8 @@ #include "kernel/celltypes.h" #include #include +#include +#include #include USING_YOSYS_NAMESPACE @@ -291,14 +293,14 @@ struct OptMuxtreeWorker // database of known inactive signals // the payload is a reference counter used to manage the // list. when it is non-zero the signal in known to be inactive - vector known_inactive; + std::unordered_map known_inactive; // database of known active signals - vector known_active; + std::unordered_map known_active; // this is just used to keep track of visited muxes in order to prohibit // endless recursion in mux loops - vector visited_muxes; + std::unordered_set visited_muxes; }; void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx, bool do_replace_known, bool do_enable_ports, int abort_count) @@ -315,17 +317,18 @@ struct OptMuxtreeWorker if (i == port_idx) continue; if (muxinfo.ports[i].ctrl_sig >= 0) - knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)++; + ++knowledge.known_inactive[muxinfo.ports[i].ctrl_sig]; } if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated) - knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)++; + ++knowledge.known_active[muxinfo.ports[port_idx].ctrl_sig]; vector parent_muxes; for (int m : muxinfo.ports[port_idx].input_muxes) { - if (knowledge.visited_muxes[m]) + auto it = knowledge.visited_muxes.find(m); + if (it != knowledge.visited_muxes.end()) continue; - knowledge.visited_muxes[m] = true; + knowledge.visited_muxes.insert(it, m); parent_muxes.push_back(m); } for (int m : parent_muxes) { @@ -344,16 +347,24 @@ struct OptMuxtreeWorker return; } for (int m : parent_muxes) - knowledge.visited_muxes[m] = false; + knowledge.visited_muxes.erase(m); - if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated) - knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)--; + if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated) { + auto it = knowledge.known_active.find(muxinfo.ports[port_idx].ctrl_sig); + if (it != knowledge.known_active.end()) + if (--it->second == 0) + knowledge.known_active.erase(it); + } for (int i = 0; i < GetSize(muxinfo.ports); i++) { if (i == port_idx) continue; - if (muxinfo.ports[i].ctrl_sig >= 0) - knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)--; + if (muxinfo.ports[i].ctrl_sig >= 0) { + auto it = knowledge.known_inactive.find(muxinfo.ports[i].ctrl_sig); + if (it != knowledge.known_inactive.end()) + if (--it->second == 0) + knowledge.known_inactive.erase(it); + } } } @@ -373,11 +384,11 @@ struct OptMuxtreeWorker vector bits = sig2bits(sig, false); for (int i = 0; i < GetSize(bits); i++) { if (bits[i] >= 0) { - if (knowledge.known_inactive.at(bits[i])) { + if (knowledge.known_inactive.count(bits[i]) > 0) { sig[i] = State::S0; did_something = true; } else - if (knowledge.known_active.at(bits[i])) { + if (knowledge.known_active.count(bits[i]) > 0) { sig[i] = State::S1; did_something = true; } @@ -435,7 +446,7 @@ struct OptMuxtreeWorker portinfo_t &portinfo = muxinfo.ports[port_idx]; if (portinfo.const_deactivated) continue; - if (knowledge.known_active.at(portinfo.ctrl_sig)) { + if (knowledge.known_active.count(portinfo.ctrl_sig) > 0) { eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count); return; } @@ -449,7 +460,7 @@ struct OptMuxtreeWorker if (portinfo.const_deactivated) continue; if (port_idx < GetSize(muxinfo.ports)-1) - if (knowledge.known_inactive.at(portinfo.ctrl_sig)) + if (knowledge.known_inactive.count(portinfo.ctrl_sig) > 0) continue; eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count); @@ -462,10 +473,7 @@ struct OptMuxtreeWorker { log_assert(glob_abort_cnt > 0); knowledge_t knowledge; - knowledge.known_inactive.resize(GetSize(bit2info)); - knowledge.known_active.resize(GetSize(bit2info)); - knowledge.visited_muxes.resize(GetSize(mux2info)); - knowledge.visited_muxes[mux_idx] = true; + knowledge.visited_muxes.insert(mux_idx); eval_mux(knowledge, mux_idx, true, root_enable_muxes.at(mux_idx), 3); } }; From bf625951d774d2747fa606f923ba5cf34b935a4a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 00:26:03 +0000 Subject: [PATCH 119/176] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8ec8715d3..ed9b10d79 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+105 +YOSYS_VER := 0.56+110 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 6d62a1fff72c38c2c7b38b86c75d7b3043a27def Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 15 Aug 2025 05:43:53 +0000 Subject: [PATCH 120/176] Fix vararg alignment --- kernel/io.cc | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/kernel/io.cc b/kernel/io.cc index 9811919ba..ef73a3b3d 100644 --- a/kernel/io.cc +++ b/kernel/io.cc @@ -412,6 +412,70 @@ static std::string string_view_stringf(std::string_view spec, ...) return result; } +static int spec_parameter_size(std::string_view spec) +{ + // Every valid spec starts with '%' which means the code below + // won't look before the spec start. + switch (spec[spec.size() - 1]) { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + switch (spec[spec.size() - 2]) { + case 'h': + if (spec[spec.size() - 3] == 'h') + return sizeof(char); + return sizeof(short); + case 'l': + if (spec[spec.size() - 3] == 'l') + return sizeof(long long); + return sizeof(long); + case 'L': + case 'q': + return sizeof(long long); + case 'j': + return sizeof(intmax_t); + case 'z': + case 'Z': + return sizeof(size_t); + case 't': + return sizeof(ptrdiff_t); + } + return sizeof(int); + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + case 'a': + case 'A': + if (spec[spec.size() - 2] == 'L') + return sizeof(long double); + if (spec[spec.size() - 2] == 'l' && spec[spec.size() - 3] == 'l') + return sizeof(long double); + return sizeof(double); + case 'c': + if (spec[spec.size() - 2] == 'l') { + return sizeof(wchar_t); + } + return sizeof(unsigned char); + case 'C': + return sizeof(wchar_t); + case 's': + case 'p': + case 'S': + case 'n': + return sizeof(void *); + case 'm': + return sizeof(int); + default: + return -1; + } +} + template static void format_emit_stringf(std::string &result, std::string_view spec, int *dynamic_ints, DynamicIntCount num_dynamic_ints, Arg arg) @@ -439,7 +503,13 @@ void format_emit_long_long(std::string &result, std::string_view spec, int *dyna result += std::to_string(static_cast(arg)); return; } - format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg); + if (spec_parameter_size(spec) <= 4) { + // On some platforms (Wasm) we must ensure that the arg is properly aligned + // after the dynamic `int` parameters. + format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, (int)arg); + } else { + format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg); + } } void format_emit_unsigned_long_long(std::string &result, std::string_view spec, int *dynamic_ints, @@ -454,7 +524,13 @@ void format_emit_unsigned_long_long(std::string &result, std::string_view spec, result += static_cast(arg); return; } - format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg); + if (spec_parameter_size(spec) <= 4) { + // On some platforms (Wasm) we must ensure that the arg is properly aligned + // after the dynamic `int` parameters. + format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, (unsigned int)arg); + } else { + format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg); + } } void format_emit_double(std::string &result, std::string_view spec, int *dynamic_ints, From e906ea3f1ba4e9097bb763d188ba7e15399c7f6c Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 15 Aug 2025 23:58:58 +0000 Subject: [PATCH 121/176] Add tests for dynamic precision and with with an int parameter --- tests/unit/kernel/ioTest.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/unit/kernel/ioTest.cc b/tests/unit/kernel/ioTest.cc index 7cb8498cb..43a71eb79 100644 --- a/tests/unit/kernel/ioTest.cc +++ b/tests/unit/kernel/ioTest.cc @@ -69,4 +69,14 @@ TEST(KernelStringfTest, dynamicWidthAndPrecision) EXPECT_EQ(stringf("%*.*f", 8, 4, 1.0), " 1.0000"); } +TEST(KernelStringfTest, dynamicPrecisionInt) +{ + EXPECT_EQ(stringf("%.*d", 4, 7), "0007"); +} + +TEST(KernelStringfTest, dynamicWidthAndPrecisionInt) +{ + EXPECT_EQ(stringf("%*.*d", 8, 4, 7), " 0007"); +} + YOSYS_NAMESPACE_END From d10fdc0ec5ee17e5fb5d6e1f12c081fffc719750 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 16 Aug 2025 00:24:02 +0000 Subject: [PATCH 122/176] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ed9b10d79..e83d32ac2 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+110 +YOSYS_VER := 0.56+125 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From f5b219f59eb02fb0d8a4a9fad731cf0cc96368ab Mon Sep 17 00:00:00 2001 From: suisseWalter <42143099+suisseWalter@users.noreply.github.com> Date: Sat, 16 Aug 2025 08:36:06 +0200 Subject: [PATCH 123/176] Update passes/cmds/stat.cc Co-authored-by: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> --- passes/cmds/stat.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 5cb223ba8..6d8d3105f 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -413,7 +413,7 @@ struct statdata_t { log(" %8s %8s \n", "|", "|"); } else if (print_global_only) { log(" %8s-%8s-%s\n", "+", "--------", "Count including submodules."); - log(" %8s %8s \n", "|", "|"); + log(" %8s \n", "|"); } else { log(" %8s-%8s-%s\n", "+", "--------", "Local Count, excluding submodules."); log(" %8s \n", "|"); From a6e0ab5ea5b6938f3ff67e5b36ecdf8797ce852c Mon Sep 17 00:00:00 2001 From: clemens Date: Sat, 16 Aug 2025 09:09:57 +0200 Subject: [PATCH 124/176] Update (sequential) area to be only local without -hierarchy --- passes/cmds/stat.cc | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 6d8d3105f..c41b8831f 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -461,8 +461,20 @@ struct statdata_t { if (area != 0) { log("\n"); - log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area); - log(" of which used for sequential elements: %f (%.2f%%)\n", sequential_area, 100.0 * sequential_area / area); + if (print_hierarchical || print_global_only) { + log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area); + log(" of which used for sequential elements: %f (%.2f%%)\n", sequential_area, 100.0 * sequential_area / area); + } else { + double local_area = 0; + for (auto &it : local_area_cells_by_type) + local_area += it.second; + double local_sequential_area = 0; + for (auto &it : local_seq_area_cells_by_type) + local_sequential_area += it.second; + log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), local_area); + log(" of which used for sequential elements: %f (%.2f%%)\n", local_sequential_area, + 100.0 * local_sequential_area / local_area); + } } if (tech == "xilinx") { @@ -666,9 +678,12 @@ statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *t mod_data.submodule_area += mod_stat.at(cell->type).area; mod_data.num_submodules++; mod_data.unknown_cell_area.erase(cell->type); - mod_data.num_cells -= (mod_data.num_cells_by_type.count(cell->type) != 0)? mod_data.num_cells_by_type.at(cell->type): 0; + mod_data.num_cells -= + (mod_data.num_cells_by_type.count(cell->type) != 0) ? mod_data.num_cells_by_type.at(cell->type) : 0; mod_data.num_cells_by_type.erase(cell->type); - mod_data.local_num_cells -= (mod_data.local_num_cells_by_type.count(cell->type) != 0)? mod_data.local_num_cells_by_type.at(cell->type): 0; + mod_data.local_num_cells -= (mod_data.local_num_cells_by_type.count(cell->type) != 0) + ? mod_data.local_num_cells_by_type.at(cell->type) + : 0; mod_data.local_num_cells_by_type.erase(cell->type); mod_data.local_area_cells_by_type.erase(cell->type); } else { @@ -681,9 +696,12 @@ statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *t double(design->module(cell->type)->attributes.at(ID::area).as_int()); mod_data.area += double(design->module(cell->type)->attributes.at(ID::area).as_int()); mod_data.unknown_cell_area.erase(cell->type); - mod_data.num_cells -= (mod_data.num_cells_by_type.count(cell->type) != 0)? mod_data.num_cells_by_type.at(cell->type): 0; + mod_data.num_cells -= + (mod_data.num_cells_by_type.count(cell->type) != 0) ? mod_data.num_cells_by_type.at(cell->type) : 0; mod_data.num_cells_by_type.erase(cell->type); - mod_data.local_num_cells -= (mod_data.local_num_cells_by_type.count(cell->type) != 0)? mod_data.local_num_cells_by_type.at(cell->type): 0; + mod_data.local_num_cells -= (mod_data.local_num_cells_by_type.count(cell->type) != 0) + ? mod_data.local_num_cells_by_type.at(cell->type) + : 0; mod_data.local_num_cells_by_type.erase(cell->type); mod_data.local_area_cells_by_type.erase(cell->type); } From d8fb4da437b9fc1b4e818f8bfac10ded3a1cee15 Mon Sep 17 00:00:00 2001 From: clemens Date: Sat, 16 Aug 2025 09:32:08 +0200 Subject: [PATCH 125/176] updated testcase --- tests/various/stat.ys | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/various/stat.ys b/tests/various/stat.ys index 50e1a35d8..1644f63e3 100644 --- a/tests/various/stat.ys +++ b/tests/various/stat.ys @@ -71,7 +71,7 @@ module \child end EOT logger -expect log "Chip area for top module '\\top': 112.492800" 1 -logger -expect log "of which used for sequential elements: 94.348800" 2 +logger -expect log "of which used for sequential elements: 94.348800" 1 logger -expect log "2 18.144 cells" 1 logger -expect log "4 112.493 cells" 1 logger -expect log "2 94.349 sg13g2_dfrbp_1" 1 From 5fc0e77c3d8d954594ef933d6270b5864f410661 Mon Sep 17 00:00:00 2001 From: clemens Date: Tue, 12 Aug 2025 08:56:05 +0200 Subject: [PATCH 126/176] add functionality to be able to use parameterised cells. cells can have their area as a function of the input port width. --- passes/cmds/stat.cc | 143 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index c41b8831f..827ee0f05 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -34,6 +34,9 @@ PRIVATE_NAMESPACE_BEGIN struct cell_area_t { double area; bool is_sequential; + vector single_parameter_area; + vector> double_parameter_area; + vector parameter_names; }; struct statdata_t { @@ -206,6 +209,89 @@ struct statdata_t { } if (!cell_area.empty()) { + // check if cell_area provides a area calculator + if (cell_area.count(cell->type)) { + cell_area_t cell_data = cell_area.at(cell->type); + if (cell_data.single_parameter_area.size() > 0) { + // assume that we just take the max of the A,B,Y ports + + int width_a = cell->hasPort(ID::A) ? GetSize(cell->getPort(ID::A)) : 0; + int width_b = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : 0; + int width_y = cell->hasPort(ID::Y) ? GetSize(cell->getPort(ID::Y)) : 0; + int width_q = cell->hasPort(ID::Q) ? GetSize(cell->getPort(ID::Q)) : 0; + int max_width = max({width_a, width_b, width_y, width_q}); + if (!cell_area.count(cell_type)) { + cell_area[cell_type] = cell_data; + } + if (cell_data.single_parameter_area.size() > max_width - 1u) { + cell_area.at(cell_type).area = cell_data.single_parameter_area.at(max_width - 1); + cell_area.at(cell_type).is_sequential = cell_data.is_sequential; + + } else { + printf("too small single_parameter_area %s %d %f\n", cell_type.c_str(), max_width, + cell_data.single_parameter_area.back()); + cell_area.at(cell_type).area = cell_data.single_parameter_area.back(); + cell_area.at(cell_type).is_sequential = cell_data.is_sequential; + } + // printf("single_paramter_extraction %s %d %f\n", cell_type.c_str(), max_width, + // cell_area.at(cell_type).area); + } + vector widths; + if (cell_data.parameter_names.size() > 0) { + for (auto &it : cell_data.parameter_names) { + RTLIL::IdString port_name; + // TODO: there has to be a better way to do this + if (it == "A") { + port_name = ID::A; + } else if (it == "B") { + port_name = ID::B; + } else if (it == "Y") { + port_name = ID::Y; + } else if (it == "Q") { + port_name = ID::Q; + } else if (it == "S") { + port_name = ID::S; + } else { + port_name = ID(it); + } + if (cell->hasPort(port_name)) { + int width = GetSize(cell->getPort(port_name)); + widths.push_back(width); + } else { + widths.push_back(0); + } + } + } + + if (cell_data.double_parameter_area.size() > 0) { + if (!cell_area.count(cell_type)) { + cell_area[cell_type] = cell_data; + } + if (widths.size() == 2) { + unsigned int width_a = widths.at(0); + unsigned int width_b = widths.at(1); + if (width_a > 0 && width_b > 0) { + if (cell_data.double_parameter_area.size() > width_a - 1 && + cell_data.double_parameter_area.at(width_a - 1).size() > width_b - 1) { + cell_area.at(cell_type).area = + cell_data.double_parameter_area.at(width_a - 1).at(width_b - 1); + cell_area.at(cell_type).is_sequential = cell_data.is_sequential; + } else { + printf("too small double_parameter_area %s %d %d %f\n", cell_type.c_str(), + width_a, width_b, cell_data.double_parameter_area.back().back()); + cell_area.at(cell_type).area = cell_data.double_parameter_area.back().back(); + cell_area.at(cell_type).is_sequential = cell_data.is_sequential; + } + } else { + cell_area.at(cell_type).area = cell_data.area; + cell_area.at(cell_type).is_sequential = cell_data.is_sequential; + } + } else { + printf("double_paramter_extraction %s %zu %f\n", cell_type.c_str(), widths.size(), + cell_area.at(cell_type).area); + } + } + } if (cell_area.count(cell_type)) { cell_area_t cell_data = cell_area.at(cell_type); @@ -726,9 +812,64 @@ void read_liberty_cellarea(dict &cell_area, string libert const LibertyAst *ar = cell->find("area"); bool is_flip_flop = cell->find("ff") != nullptr; + vector single_parameter_area; + vector> double_parameter_area; + vector port_names; + const LibertyAst *sar = cell->find("single_area_parameterised"); + if (sar != nullptr) { + for (const auto &s : sar->args) { + double value = 0; + auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), value); + // ec != std::errc() means parse error, or ptr didn't consume entire string + if (ec != std::errc() || ptr != s.data() + s.size()) + break; + single_parameter_area.push_back(value); + } + if (single_parameter_area.size() == 0) + printf("error: %s\n", sar->args[single_parameter_area.size() - 1].c_str()); + // check if it is a double parameterised area + } + const LibertyAst *dar = cell->find("double_area_parameterised"); + if (dar != nullptr) { + for (const auto &s : dar->args) { + + // printf("value: %s\n",sar->value.c_str()); + // printf("args1: %s\n",dar->args[0].c_str()); + + vector sub_array; + std::string::size_type start = 0; + std::string::size_type end = s.find_first_of(",", start); + while (end != std::string::npos) { + sub_array.push_back(s.substr(start, end - start)); + start = end + 1; + end = s.find_first_of(",", start); + } + sub_array.push_back(s.substr(start, end)); + + vector cast_sub_array; + for (const auto &s : sub_array) { + double value = 0; + auto [ptr, ec] = std::from_chars(s.data() + 1, s.data() + s.size(), value); + if (ec != std::errc() || ptr != s.data() + s.size()) + break; + cast_sub_array.push_back(value); + } + double_parameter_area.push_back(cast_sub_array); + if (cast_sub_array.size() == 0) + printf("error: %s\n", s.c_str()); + } + } + const LibertyAst *par = cell->find("port_names"); + if (par != nullptr) { + for (const auto &s : par->args) { + port_names.push_back(s); + } + } + if (ar != nullptr && !ar->value.empty()) { string prefix = cell->args[0].substr(0, 1) == "$" ? "" : "\\"; - cell_area[prefix + cell->args[0]] = {atof(ar->value.c_str()), is_flip_flop}; + cell_area[prefix + cell->args[0]] = {atof(ar->value.c_str()), is_flip_flop, single_parameter_area, double_parameter_area, + port_names}; } } } From 50fe9dd7f26615c8e90d01bb443644096e9f6185 Mon Sep 17 00:00:00 2001 From: clemens Date: Tue, 12 Aug 2025 09:37:55 +0200 Subject: [PATCH 127/176] clean parsing code --- passes/cmds/stat.cc | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 827ee0f05..a036b1930 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -818,12 +818,12 @@ void read_liberty_cellarea(dict &cell_area, string libert const LibertyAst *sar = cell->find("single_area_parameterised"); if (sar != nullptr) { for (const auto &s : sar->args) { - double value = 0; - auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), value); - // ec != std::errc() means parse error, or ptr didn't consume entire string - if (ec != std::errc() || ptr != s.data() + s.size()) - break; - single_parameter_area.push_back(value); + try { + double value = std::stod(s); + single_parameter_area.push_back(value); + } catch (const std::exception &e) { + log_error("Failed to parse single parameter area value '%s': %s\n", s.c_str(), e.what()); + } } if (single_parameter_area.size() == 0) printf("error: %s\n", sar->args[single_parameter_area.size() - 1].c_str()); @@ -849,10 +849,12 @@ void read_liberty_cellarea(dict &cell_area, string libert vector cast_sub_array; for (const auto &s : sub_array) { double value = 0; - auto [ptr, ec] = std::from_chars(s.data() + 1, s.data() + s.size(), value); - if (ec != std::errc() || ptr != s.data() + s.size()) - break; - cast_sub_array.push_back(value); + try { + value = std::stod(s); + cast_sub_array.push_back(value); + } catch (const std::exception &e) { + log_error("Failed to parse double parameter area value '%s': %s\n", s.c_str(), e.what()); + } } double_parameter_area.push_back(cast_sub_array); if (cast_sub_array.size() == 0) From 8b1f77ebd297ab312af81be0661f44f09b0edb43 Mon Sep 17 00:00:00 2001 From: clemens Date: Wed, 13 Aug 2025 15:16:15 +0200 Subject: [PATCH 128/176] cleanup. printf to errors or warnings --- passes/cmds/stat.cc | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index a036b1930..4d01b8535 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -228,19 +228,16 @@ struct statdata_t { cell_area.at(cell_type).is_sequential = cell_data.is_sequential; } else { - printf("too small single_parameter_area %s %d %f\n", cell_type.c_str(), max_width, - cell_data.single_parameter_area.back()); + log_warning("too small single_parameter_area %s width: %d size: %d\n", cell_type.c_str(), max_width, + (int)cell_data.single_parameter_area.size()); cell_area.at(cell_type).area = cell_data.single_parameter_area.back(); cell_area.at(cell_type).is_sequential = cell_data.is_sequential; } - // printf("single_paramter_extraction %s %d %f\n", cell_type.c_str(), max_width, - // cell_area.at(cell_type).area); } vector widths; if (cell_data.parameter_names.size() > 0) { for (auto &it : cell_data.parameter_names) { RTLIL::IdString port_name; - // TODO: there has to be a better way to do this if (it == "A") { port_name = ID::A; } else if (it == "B") { @@ -277,8 +274,9 @@ struct statdata_t { cell_data.double_parameter_area.at(width_a - 1).at(width_b - 1); cell_area.at(cell_type).is_sequential = cell_data.is_sequential; } else { - printf("too small double_parameter_area %s %d %d %f\n", cell_type.c_str(), - width_a, width_b, cell_data.double_parameter_area.back().back()); + log_warning("too small double_parameter_area %s, width_a: %d, width_b: %d, size_a: %d, size_b: %d\n", cell_type.c_str(), + (int)width_a, width_b, cell_data.double_parameter_area.size(), + (int)cell_data.double_parameter_area.at(width_a - 1).size()); cell_area.at(cell_type).area = cell_data.double_parameter_area.back().back(); cell_area.at(cell_type).is_sequential = cell_data.is_sequential; } @@ -287,8 +285,8 @@ struct statdata_t { cell_area.at(cell_type).is_sequential = cell_data.is_sequential; } } else { - printf("double_paramter_extraction %s %zu %f\n", cell_type.c_str(), widths.size(), - cell_area.at(cell_type).area); + log_error("double_parameter_area for %s has %d parameters, but only 2 are expected.\n", cell_type.c_str(), + (int)cell_data.double_parameter_area.size()); } } } @@ -826,15 +824,13 @@ void read_liberty_cellarea(dict &cell_area, string libert } } if (single_parameter_area.size() == 0) - printf("error: %s\n", sar->args[single_parameter_area.size() - 1].c_str()); + log_error("single parameter area has size 0: %s\n", sar->args[single_parameter_area.size() - 1].c_str()); // check if it is a double parameterised area } const LibertyAst *dar = cell->find("double_area_parameterised"); if (dar != nullptr) { for (const auto &s : dar->args) { - // printf("value: %s\n",sar->value.c_str()); - // printf("args1: %s\n",dar->args[0].c_str()); vector sub_array; std::string::size_type start = 0; @@ -858,7 +854,7 @@ void read_liberty_cellarea(dict &cell_area, string libert } double_parameter_area.push_back(cast_sub_array); if (cast_sub_array.size() == 0) - printf("error: %s\n", s.c_str()); + log_error("double paramter array has size 0: %s\n", s.c_str()); } } const LibertyAst *par = cell->find("port_names"); From 73d1177665815012981f439138f97937c4a90373 Mon Sep 17 00:00:00 2001 From: clemens Date: Thu, 14 Aug 2025 09:57:44 +0200 Subject: [PATCH 129/176] testcases one testcase for single parameter cells. one testcase for double parameter cells. --- tests/various/stat_area_by_width.lib | 42 +++++++++++++ tests/various/stat_high_level.ys | 92 ++++++++++++++++++++++++++++ tests/various/stat_high_level2.ys | 91 +++++++++++++++++++++++++++ 3 files changed, 225 insertions(+) create mode 100644 tests/various/stat_area_by_width.lib create mode 100644 tests/various/stat_high_level.ys create mode 100644 tests/various/stat_high_level2.ys diff --git a/tests/various/stat_area_by_width.lib b/tests/various/stat_area_by_width.lib new file mode 100644 index 000000000..73e266472 --- /dev/null +++ b/tests/various/stat_area_by_width.lib @@ -0,0 +1,42 @@ + +/************************************************************************ + + Copyright 2025 Clemens Walter, + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +************************************************************************/ +//Mock library for Yosys pre techmap +library (mock) { +cell ( "$reduce_xor" ) { + area : 3.0 ; + delay : 2.5 ; + single_area_parameterised ( 3.0, 5.5, 8.0, 10.5, 13.0, 15.5, 18.0, 20.5, 23.0, 25.5, 28.0, 30.5, 33.0, 35.5, 38.0, 40.5, 43.0, 45.5, 48.0, 50.5, 53.0, 55.5, 58.0, 60.5, 63.0, 65.5, 68.0, 70.5, 73.0, 75.5, 78.0, 80.5, 83.0, 85.5, 88.0, 90.5, 93.0, 95.5, 98.0, 100.5, 103.0, 105.5, 108.0, 110.5, 113.0, 115.5, 118.0, 120.5, ) ; + +} + +cell ( "$xor" ) { + area : 5.0 ; + delay : 2.0 ; + single_area_parameterised ( 5.0, 7.5, 10.0, 12.5, 15.0, 17.5, 20.0, 22.5, 25.0, 27.5, 30.0, 32.5, 35.0, 37.5, 40.0, 42.5, 45.0, 47.5, 50.0, 52.5, 55.0, ) ; + +} + +cell ( "$bmux" ) { + area : 3.0 ; + delay : 2.0 ; + port_names ( "Y", "S" ) ; + double_area_parameterised ( " 3.0, 6.0, 9.0, 12.0, 15.0, 18.0, 21.0, 24.0, 27.0, 30.0, 33.0, 36.0, 39.0, 42.0, 45.0, 48.0, 51.0, 54.0, 57.0, 60.0, 63.0, 66.0, 69.0, 72.0, 75.0, 78.0, 81.0, 84.0, 87.0, 90.0, 93.0, 96.0, 99.0, 102.0, 105.0, 108.0, 111.0, 114.0, 117.0, 120.0, 123.0, 126.0, 129.0, 132.0, 135.0, 138.0, 141.0, 144.0, 147.0, 150.0, 153.0, 156.0, 159.0, 162.0, 165.0, 168.0, 171.0, 174.0, 177.0, 180.0, 183.0, 186.0, 189.0, 192.0, 195.0, 198.0, 201.0, 204.0, 207.0, 210.0, 213.0, 216.0, 219.0, 222.0, 225.0, 228.0, 231.0, 234.0, 237.0, 240.0, 243.0, 246.0, 249.0, 252.0, 255.0, 258.0, 261.0, 264.0, 267.0, 270.0, 273.0, 276.0, 279.0, 282.0, 285.0, 288.0, 291.0, 294.0, 297.0, 300.0, 303.0, 306.0, 309.0, 312.0, 315.0, 318.0, 321.0, 324.0, 327.0, 330.0, 333.0, 336.0, 339.0, 342.0, 345.0, 348.0, 351.0, 354.0, 357.0, 360.0, 363.0, 366.0, 369.0, 372.0, 375.0, 378.0, 381.0, 384.0,", " 6.0, 12.0, 18.0, 24.0, 30.0, 36.0, 42.0, 48.0, 54.0, 60.0, 66.0, 72.0, 78.0, 84.0, 90.0, 96.0, 102.0, 108.0, 114.0, 120.0, 126.0, 132.0, 138.0, 144.0, 150.0, 156.0, 162.0, 168.0, 174.0, 180.0, 186.0, 192.0, 198.0, 204.0, 210.0, 216.0, 222.0, 228.0, 234.0, 240.0, 246.0, 252.0, 258.0, 264.0, 270.0, 276.0, 282.0, 288.0, 294.0, 300.0, 306.0, 312.0, 318.0, 324.0, 330.0, 336.0, 342.0, 348.0, 354.0, 360.0, 366.0, 372.0, 378.0, 384.0, 390.0, 396.0, 402.0, 408.0, 414.0, 420.0, 426.0, 432.0, 438.0, 444.0, 450.0, 456.0, 462.0, 468.0, 474.0, 480.0, 486.0, 492.0, 498.0, 504.0, 510.0, 516.0, 522.0, 528.0, 534.0, 540.0, 546.0, 552.0, 558.0, 564.0, 570.0, 576.0, 582.0, 588.0, 594.0, 600.0, 606.0, 612.0, 618.0, 624.0, 630.0, 636.0, 642.0, 648.0, 654.0, 660.0, 666.0, 672.0, 678.0, 684.0, 690.0, 696.0, 702.0, 708.0, 714.0, 720.0, 726.0, 732.0, 738.0, 744.0, 750.0, 756.0, 762.0, 768.0,", " 9.0, 18.0, 27.0, 36.0, 45.0, 54.0, 63.0, 72.0, 81.0, 90.0, 99.0, 108.0, 117.0, 126.0, 135.0, 144.0, 153.0, 162.0, 171.0, 180.0, 189.0, 198.0, 207.0, 216.0, 225.0, 234.0, 243.0, 252.0, 261.0, 270.0, 279.0, 288.0, 297.0, 306.0, 315.0, 324.0, 333.0, 342.0, 351.0, 360.0, 369.0, 378.0, 387.0, 396.0, 405.0, 414.0, 423.0, 432.0, 441.0, 450.0, 459.0, 468.0, 477.0, 486.0, 495.0, 504.0, 513.0, 522.0, 531.0, 540.0, 549.0, 558.0, 567.0, 576.0, 585.0, 594.0, 603.0, 612.0, 621.0, 630.0, 639.0, 648.0, 657.0, 666.0, 675.0, 684.0, 693.0, 702.0, 711.0, 720.0, 729.0, 738.0, 747.0, 756.0, 765.0, 774.0, 783.0, 792.0, 801.0, 810.0, 819.0, 828.0, 837.0, 846.0, 855.0, 864.0, 873.0, 882.0, 891.0, 900.0, 909.0, 918.0, 927.0, 936.0, 945.0, 954.0, 963.0, 972.0, 981.0, 990.0, 999.0, 1008.0, 1017.0, 1026.0, 1035.0, 1044.0, 1053.0, 1062.0, 1071.0, 1080.0, 1089.0, 1098.0, 1107.0, 1116.0, 1125.0, 1134.0, 1143.0, 1152.0,", " 12.0, 24.0, 36.0, 48.0, 60.0, 72.0, 84.0, 96.0, 108.0, 120.0, 132.0, 144.0, 156.0, 168.0, 180.0, 192.0, 204.0, 216.0, 228.0, 240.0, 252.0, 264.0, 276.0, 288.0, 300.0, 312.0, 324.0, 336.0, 348.0, 360.0, 372.0, 384.0, 396.0, 408.0, 420.0, 432.0, 444.0, 456.0, 468.0, 480.0, 492.0, 504.0, 516.0, 528.0, 540.0, 552.0, 564.0, 576.0, 588.0, 600.0, 612.0, 624.0, 636.0, 648.0, 660.0, 672.0, 684.0, 696.0, 708.0, 720.0, 732.0, 744.0, 756.0, 768.0, 780.0, 792.0, 804.0, 816.0, 828.0, 840.0, 852.0, 864.0, 876.0, 888.0, 900.0, 912.0, 924.0, 936.0, 948.0, 960.0, 972.0, 984.0, 996.0, 1008.0, 1020.0, 1032.0, 1044.0, 1056.0, 1068.0, 1080.0, 1092.0, 1104.0, 1116.0, 1128.0, 1140.0, 1152.0, 1164.0, 1176.0, 1188.0, 1200.0, 1212.0, 1224.0, 1236.0, 1248.0, 1260.0, 1272.0, 1284.0, 1296.0, 1308.0, 1320.0, 1332.0, 1344.0, 1356.0, 1368.0, 1380.0, 1392.0, 1404.0, 1416.0, 1428.0, 1440.0, 1452.0, 1464.0, 1476.0, 1488.0, 1500.0, 1512.0, 1524.0, 1536.0,", " 15.0, 30.0, 45.0, 60.0, 75.0, 90.0, 105.0, 120.0, 135.0, 150.0, 165.0, 180.0, 195.0, 210.0, 225.0, 240.0, 255.0, 270.0, 285.0, 300.0, 315.0, 330.0, 345.0, 360.0, 375.0, 390.0, 405.0, 420.0, 435.0, 450.0, 465.0, 480.0, 495.0, 510.0, 525.0, 540.0, 555.0, 570.0, 585.0, 600.0, 615.0, 630.0, 645.0, 660.0, 675.0, 690.0, 705.0, 720.0, 735.0, 750.0, 765.0, 780.0, 795.0, 810.0, 825.0, 840.0, 855.0, 870.0, 885.0, 900.0, 915.0, 930.0, 945.0, 960.0, 975.0, 990.0, 1005.0, 1020.0, 1035.0, 1050.0, 1065.0, 1080.0, 1095.0, 1110.0, 1125.0, 1140.0, 1155.0, 1170.0, 1185.0, 1200.0, 1215.0, 1230.0, 1245.0, 1260.0, 1275.0, 1290.0, 1305.0, 1320.0, 1335.0, 1350.0, 1365.0, 1380.0, 1395.0, 1410.0, 1425.0, 1440.0, 1455.0, 1470.0, 1485.0, 1500.0, 1515.0, 1530.0, 1545.0, 1560.0, 1575.0, 1590.0, 1605.0, 1620.0, 1635.0, 1650.0, 1665.0, 1680.0, 1695.0, 1710.0, 1725.0, 1740.0, 1755.0, 1770.0, 1785.0, 1800.0, 1815.0, 1830.0, 1845.0, 1860.0, 1875.0, 1890.0, 1905.0, 1920.0,", " 18.0, 36.0, 54.0, 72.0, 90.0, 108.0, 126.0, 144.0, 162.0, 180.0, 198.0, 216.0, 234.0, 252.0, 270.0, 288.0, 306.0, 324.0, 342.0, 360.0, 378.0, 396.0, 414.0, 432.0, 450.0, 468.0, 486.0, 504.0, 522.0, 540.0, 558.0, 576.0, 594.0, 612.0, 630.0, 648.0, 666.0, 684.0, 702.0, 720.0, 738.0, 756.0, 774.0, 792.0, 810.0, 828.0, 846.0, 864.0, 882.0, 900.0, 918.0, 936.0, 954.0, 972.0, 990.0, 1008.0, 1026.0, 1044.0, 1062.0, 1080.0, 1098.0, 1116.0, 1134.0, 1152.0, 1170.0, 1188.0, 1206.0, 1224.0, 1242.0, 1260.0, 1278.0, 1296.0, 1314.0, 1332.0, 1350.0, 1368.0, 1386.0, 1404.0, 1422.0, 1440.0, 1458.0, 1476.0, 1494.0, 1512.0, 1530.0, 1548.0, 1566.0, 1584.0, 1602.0, 1620.0, 1638.0, 1656.0, 1674.0, 1692.0, 1710.0, 1728.0, 1746.0, 1764.0, 1782.0, 1800.0, 1818.0, 1836.0, 1854.0, 1872.0, 1890.0, 1908.0, 1926.0, 1944.0, 1962.0, 1980.0, 1998.0, 2016.0, 2034.0, 2052.0, 2070.0, 2088.0, 2106.0, 2124.0, 2142.0, 2160.0, 2178.0, 2196.0, 2214.0, 2232.0, 2250.0, 2268.0, 2286.0, 2304.0,", " 21.0, 42.0, 63.0, 84.0, 105.0, 126.0, 147.0, 168.0, 189.0, 210.0, 231.0, 252.0, 273.0, 294.0, 315.0, 336.0, 357.0, 378.0, 399.0, 420.0, 441.0, 462.0, 483.0, 504.0, 525.0, 546.0, 567.0, 588.0, 609.0, 630.0, 651.0, 672.0, 693.0, 714.0, 735.0, 756.0, 777.0, 798.0, 819.0, 840.0, 861.0, 882.0, 903.0, 924.0, 945.0, 966.0, 987.0, 1008.0, 1029.0, 1050.0, 1071.0, 1092.0, 1113.0, 1134.0, 1155.0, 1176.0, 1197.0, 1218.0, 1239.0, 1260.0, 1281.0, 1302.0, 1323.0, 1344.0, 1365.0, 1386.0, 1407.0, 1428.0, 1449.0, 1470.0, 1491.0, 1512.0, 1533.0, 1554.0, 1575.0, 1596.0, 1617.0, 1638.0, 1659.0, 1680.0, 1701.0, 1722.0, 1743.0, 1764.0, 1785.0, 1806.0, 1827.0, 1848.0, 1869.0, 1890.0, 1911.0, 1932.0, 1953.0, 1974.0, 1995.0, 2016.0, 2037.0, 2058.0, 2079.0, 2100.0, 2121.0, 2142.0, 2163.0, 2184.0, 2205.0, 2226.0, 2247.0, 2268.0, 2289.0, 2310.0, 2331.0, 2352.0, 2373.0, 2394.0, 2415.0, 2436.0, 2457.0, 2478.0, 2499.0, 2520.0, 2541.0, 2562.0, 2583.0, 2604.0, 2625.0, 2646.0, 2667.0, 2688.0,", " 24.0, 48.0, 72.0, 96.0, 120.0, 144.0, 168.0, 192.0, 216.0, 240.0, 264.0, 288.0, 312.0, 336.0, 360.0, 384.0, 408.0, 432.0, 456.0, 480.0, 504.0, 528.0, 552.0, 576.0, 600.0, 624.0, 648.0, 672.0, 696.0, 720.0, 744.0, 768.0, 792.0, 816.0, 840.0, 864.0, 888.0, 912.0, 936.0, 960.0, 984.0, 1008.0, 1032.0, 1056.0, 1080.0, 1104.0, 1128.0, 1152.0, 1176.0, 1200.0, 1224.0, 1248.0, 1272.0, 1296.0, 1320.0, 1344.0, 1368.0, 1392.0, 1416.0, 1440.0, 1464.0, 1488.0, 1512.0, 1536.0, 1560.0, 1584.0, 1608.0, 1632.0, 1656.0, 1680.0, 1704.0, 1728.0, 1752.0, 1776.0, 1800.0, 1824.0, 1848.0, 1872.0, 1896.0, 1920.0, 1944.0, 1968.0, 1992.0, 2016.0, 2040.0, 2064.0, 2088.0, 2112.0, 2136.0, 2160.0, 2184.0, 2208.0, 2232.0, 2256.0, 2280.0, 2304.0, 2328.0, 2352.0, 2376.0, 2400.0, 2424.0, 2448.0, 2472.0, 2496.0, 2520.0, 2544.0, 2568.0, 2592.0, 2616.0, 2640.0, 2664.0, 2688.0, 2712.0, 2736.0, 2760.0, 2784.0, 2808.0, 2832.0, 2856.0, 2880.0, 2904.0, 2928.0, 2952.0, 2976.0, 3000.0, 3024.0, 3048.0, 3072.0,", " 27.0, 54.0, 81.0, 108.0, 135.0, 162.0, 189.0, 216.0, 243.0, 270.0, 297.0, 324.0, 351.0, 378.0, 405.0, 432.0, 459.0, 486.0, 513.0, 540.0, 567.0, 594.0, 621.0, 648.0, 675.0, 702.0, 729.0, 756.0, 783.0, 810.0, 837.0, 864.0, 891.0, 918.0, 945.0, 972.0, 999.0, 1026.0, 1053.0, 1080.0, 1107.0, 1134.0, 1161.0, 1188.0, 1215.0, 1242.0, 1269.0, 1296.0, 1323.0, 1350.0, 1377.0, 1404.0, 1431.0, 1458.0, 1485.0, 1512.0, 1539.0, 1566.0, 1593.0, 1620.0, 1647.0, 1674.0, 1701.0, 1728.0, 1755.0, 1782.0, 1809.0, 1836.0, 1863.0, 1890.0, 1917.0, 1944.0, 1971.0, 1998.0, 2025.0, 2052.0, 2079.0, 2106.0, 2133.0, 2160.0, 2187.0, 2214.0, 2241.0, 2268.0, 2295.0, 2322.0, 2349.0, 2376.0, 2403.0, 2430.0, 2457.0, 2484.0, 2511.0, 2538.0, 2565.0, 2592.0, 2619.0, 2646.0, 2673.0, 2700.0, 2727.0, 2754.0, 2781.0, 2808.0, 2835.0, 2862.0, 2889.0, 2916.0, 2943.0, 2970.0, 2997.0, 3024.0, 3051.0, 3078.0, 3105.0, 3132.0, 3159.0, 3186.0, 3213.0, 3240.0, 3267.0, 3294.0, 3321.0, 3348.0, 3375.0, 3402.0, 3429.0, 3456.0,", " 30.0, 60.0, 90.0, 120.0, 150.0, 180.0, 210.0, 240.0, 270.0, 300.0, 330.0, 360.0, 390.0, 420.0, 450.0, 480.0, 510.0, 540.0, 570.0, 600.0, 630.0, 660.0, 690.0, 720.0, 750.0, 780.0, 810.0, 840.0, 870.0, 900.0, 930.0, 960.0, 990.0, 1020.0, 1050.0, 1080.0, 1110.0, 1140.0, 1170.0, 1200.0, 1230.0, 1260.0, 1290.0, 1320.0, 1350.0, 1380.0, 1410.0, 1440.0, 1470.0, 1500.0, 1530.0, 1560.0, 1590.0, 1620.0, 1650.0, 1680.0, 1710.0, 1740.0, 1770.0, 1800.0, 1830.0, 1860.0, 1890.0, 1920.0, 1950.0, 1980.0, 2010.0, 2040.0, 2070.0, 2100.0, 2130.0, 2160.0, 2190.0, 2220.0, 2250.0, 2280.0, 2310.0, 2340.0, 2370.0, 2400.0, 2430.0, 2460.0, 2490.0, 2520.0, 2550.0, 2580.0, 2610.0, 2640.0, 2670.0, 2700.0, 2730.0, 2760.0, 2790.0, 2820.0, 2850.0, 2880.0, 2910.0, 2940.0, 2970.0, 3000.0, 3030.0, 3060.0, 3090.0, 3120.0, 3150.0, 3180.0, 3210.0, 3240.0, 3270.0, 3300.0, 3330.0, 3360.0, 3390.0, 3420.0, 3450.0, 3480.0, 3510.0, 3540.0, 3570.0, 3600.0, 3630.0, 3660.0, 3690.0, 3720.0, 3750.0, 3780.0, 3810.0, 3840.0,", " 33.0, 66.0, 99.0, 132.0, 165.0, 198.0, 231.0, 264.0, 297.0, 330.0, 363.0, 396.0, 429.0, 462.0, 495.0, 528.0, 561.0, 594.0, 627.0, 660.0, 693.0, 726.0, 759.0, 792.0, 825.0, 858.0, 891.0, 924.0, 957.0, 990.0, 1023.0, 1056.0, 1089.0, 1122.0, 1155.0, 1188.0, 1221.0, 1254.0, 1287.0, 1320.0, 1353.0, 1386.0, 1419.0, 1452.0, 1485.0, 1518.0, 1551.0, 1584.0, 1617.0, 1650.0, 1683.0, 1716.0, 1749.0, 1782.0, 1815.0, 1848.0, 1881.0, 1914.0, 1947.0, 1980.0, 2013.0, 2046.0, 2079.0, 2112.0, 2145.0, 2178.0, 2211.0, 2244.0, 2277.0, 2310.0, 2343.0, 2376.0, 2409.0, 2442.0, 2475.0, 2508.0, 2541.0, 2574.0, 2607.0, 2640.0, 2673.0, 2706.0, 2739.0, 2772.0, 2805.0, 2838.0, 2871.0, 2904.0, 2937.0, 2970.0, 3003.0, 3036.0, 3069.0, 3102.0, 3135.0, 3168.0, 3201.0, 3234.0, 3267.0, 3300.0, 3333.0, 3366.0, 3399.0, 3432.0, 3465.0, 3498.0, 3531.0, 3564.0, 3597.0, 3630.0, 3663.0, 3696.0, 3729.0, 3762.0, 3795.0, 3828.0, 3861.0, 3894.0, 3927.0, 3960.0, 3993.0, 4026.0, 4059.0, 4092.0, 4125.0, 4158.0, 4191.0, 4224.0,", " 36.0, 72.0, 108.0, 144.0, 180.0, 216.0, 252.0, 288.0, 324.0, 360.0, 396.0, 432.0, 468.0, 504.0, 540.0, 576.0, 612.0, 648.0, 684.0, 720.0, 756.0, 792.0, 828.0, 864.0, 900.0, 936.0, 972.0, 1008.0, 1044.0, 1080.0, 1116.0, 1152.0, 1188.0, 1224.0, 1260.0, 1296.0, 1332.0, 1368.0, 1404.0, 1440.0, 1476.0, 1512.0, 1548.0, 1584.0, 1620.0, 1656.0, 1692.0, 1728.0, 1764.0, 1800.0, 1836.0, 1872.0, 1908.0, 1944.0, 1980.0, 2016.0, 2052.0, 2088.0, 2124.0, 2160.0, 2196.0, 2232.0, 2268.0, 2304.0, 2340.0, 2376.0, 2412.0, 2448.0, 2484.0, 2520.0, 2556.0, 2592.0, 2628.0, 2664.0, 2700.0, 2736.0, 2772.0, 2808.0, 2844.0, 2880.0, 2916.0, 2952.0, 2988.0, 3024.0, 3060.0, 3096.0, 3132.0, 3168.0, 3204.0, 3240.0, 3276.0, 3312.0, 3348.0, 3384.0, 3420.0, 3456.0, 3492.0, 3528.0, 3564.0, 3600.0, 3636.0, 3672.0, 3708.0, 3744.0, 3780.0, 3816.0, 3852.0, 3888.0, 3924.0, 3960.0, 3996.0, 4032.0, 4068.0, 4104.0, 4140.0, 4176.0, 4212.0, 4248.0, 4284.0, 4320.0, 4356.0, 4392.0, 4428.0, 4464.0, 4500.0, 4536.0, 4572.0, 4608.0,", " 39.0, 78.0, 117.0, 156.0, 195.0, 234.0, 273.0, 312.0, 351.0, 390.0, 429.0, 468.0, 507.0, 546.0, 585.0, 624.0, 663.0, 702.0, 741.0, 780.0, 819.0, 858.0, 897.0, 936.0, 975.0, 1014.0, 1053.0, 1092.0, 1131.0, 1170.0, 1209.0, 1248.0, 1287.0, 1326.0, 1365.0, 1404.0, 1443.0, 1482.0, 1521.0, 1560.0, 1599.0, 1638.0, 1677.0, 1716.0, 1755.0, 1794.0, 1833.0, 1872.0, 1911.0, 1950.0, 1989.0, 2028.0, 2067.0, 2106.0, 2145.0, 2184.0, 2223.0, 2262.0, 2301.0, 2340.0, 2379.0, 2418.0, 2457.0, 2496.0, 2535.0, 2574.0, 2613.0, 2652.0, 2691.0, 2730.0, 2769.0, 2808.0, 2847.0, 2886.0, 2925.0, 2964.0, 3003.0, 3042.0, 3081.0, 3120.0, 3159.0, 3198.0, 3237.0, 3276.0, 3315.0, 3354.0, 3393.0, 3432.0, 3471.0, 3510.0, 3549.0, 3588.0, 3627.0, 3666.0, 3705.0, 3744.0, 3783.0, 3822.0, 3861.0, 3900.0, 3939.0, 3978.0, 4017.0, 4056.0, 4095.0, 4134.0, 4173.0, 4212.0, 4251.0, 4290.0, 4329.0, 4368.0, 4407.0, 4446.0, 4485.0, 4524.0, 4563.0, 4602.0, 4641.0, 4680.0, 4719.0, 4758.0, 4797.0, 4836.0, 4875.0, 4914.0, 4953.0, 4992.0,", ) ; + +} +} \ No newline at end of file diff --git a/tests/various/stat_high_level.ys b/tests/various/stat_high_level.ys new file mode 100644 index 000000000..03e5e957e --- /dev/null +++ b/tests/various/stat_high_level.ys @@ -0,0 +1,92 @@ + +read_rtlil << EOT +module \top + wire input 1 \A + wire output 2 \Y + wire output 3 \N + + cell $and \sub1 + parameter \A_SIGNED 0 + parameter \A_WIDTH 1 + parameter \B_SIGNED 0 + parameter \B_WIDTH 1 + parameter \Y_WIDTH 1 + connect \A \A + connect \B 1'0 + connect \Y \Y + end + + cell \child \sequential + connect \A \A + connect \B 1'0 + connect \R 1'0 + connect \Y \Y + connect \N \N + end + + cell \child \sequential1 + connect \A \A + connect \B 1'0 + connect \R 1'0 + connect \Y \Y + connect \N \N + end + + cell $xor \sub2 + parameter \A_SIGNED 0 + parameter \A_WIDTH 1 + parameter \B_SIGNED 0 + parameter \B_WIDTH 1 + parameter \Y_WIDTH 1 + connect \A \A + connect \B 1'0 + connect \Y \Y + end +end + +module \child + wire input 1 \A + wire input 2 \B + wire input 3 \R + + wire output 4 \Y + wire output 5 \N + wire \Y1 + wire \Y2 + cell \sg13g2_dfrbp_1 \sequential_ff + connect \CLK \A + connect \D \Y2 + connect \Q \Y + connect \Q_N \N + connect \RESET_B \R + end + + cell $xor \sub2 + parameter \A_SIGNED 0 + parameter \A_WIDTH 1 + parameter \B_SIGNED 0 + parameter \B_WIDTH 1 + parameter \Y_WIDTH 1 + connect \A \B + connect \B 1'0 + connect \Y \Y1 + end + + cell $reduce_xor \sub3 + parameter \A_SIGNED 0 + parameter \A_WIDTH 10 + parameter \Y_WIDTH 1 + connect \A 10'0000000000 + connect \Y \Y2 + end + +end +EOT +logger -expect log "Chip area for top module '\\top': 66.000000" 1 +logger -expect log "3 30.5 3 30.5 cells" 1 +logger -expect log "2 51 - - \$reduce_xor" 2 +logger -expect log "8 66 2 5 cells" 2 +logger -expect-no-warnings +stat -liberty ./stat_area_by_width.lib -top \top -hierarchy + + diff --git a/tests/various/stat_high_level2.ys b/tests/various/stat_high_level2.ys new file mode 100644 index 000000000..63d59da95 --- /dev/null +++ b/tests/various/stat_high_level2.ys @@ -0,0 +1,91 @@ + +read_rtlil << EOT +module \top + wire input 1 \A + wire output 2 \Y + wire output 3 \N + + cell $and \sub1 + parameter \A_SIGNED 0 + parameter \A_WIDTH 1 + parameter \B_SIGNED 0 + parameter \B_WIDTH 1 + parameter \Y_WIDTH 1 + connect \A \A + connect \B 1'0 + connect \Y \Y + end + + cell \child \sequential + connect \A \A + connect \B 1'0 + connect \R 1'0 + connect \Y \Y + connect \N \N + end + + cell \child \sequential1 + connect \A \A + connect \B 1'0 + connect \R 1'0 + connect \Y \Y + connect \N \N + end + + cell $xor \sub2 + parameter \A_SIGNED 0 + parameter \A_WIDTH 1 + parameter \B_SIGNED 0 + parameter \B_WIDTH 1 + parameter \Y_WIDTH 1 + connect \A \A + connect \B 1'0 + connect \Y \Y + end +end + +module \child + wire input 1 \A + wire input 2 \B + wire input 3 \R + + wire output 4 \Y + wire output 5 \N + wire \Y1 + wire \Y2 + wire width 2 \A2 + cell \sg13g2_dfrbp_1 \sequential_ff + connect \CLK \A + connect \D \Y2 + connect \Q \Y + connect \Q_N \N + connect \RESET_B \R + end + + cell $bmux \bmux1 + parameter \WIDTH 2 + parameter \S_WIDTH 2 + connect \A 8'00000000 + connect \S 2'00 + connect \Y \A2 + end + + cell $reduce_xor \sub3 + parameter \A_SIGNED 0 + parameter \A_WIDTH 10 + parameter \Y_WIDTH 1 + connect \A 10'0000000000 + connect \Y \Y2 + end + +end +EOT + +logger -expect log "Chip area for top module '\\top': 80.000000" 1 +logger -expect log "1 12 1 12 \$bmux" 1 +logger -expect log "3 37.5 3 37.5 cells" 1 +logger -expect log "8 80 2 5 cells" 2 +logger -expect-no-warnings +stat -liberty ./stat_area_by_width.lib -top \top -hierarchy + + From 4e45b5e1bb26a7c742b7abab7c4f78d80be0c052 Mon Sep 17 00:00:00 2001 From: clemens Date: Thu, 14 Aug 2025 11:13:40 +0200 Subject: [PATCH 130/176] permit trailing comma --- passes/cmds/stat.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 4d01b8535..07b1e5228 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -275,7 +275,7 @@ struct statdata_t { cell_area.at(cell_type).is_sequential = cell_data.is_sequential; } else { log_warning("too small double_parameter_area %s, width_a: %d, width_b: %d, size_a: %d, size_b: %d\n", cell_type.c_str(), - (int)width_a, width_b, cell_data.double_parameter_area.size(), + width_a, width_b, (int)cell_data.double_parameter_area.size(), (int)cell_data.double_parameter_area.at(width_a - 1).size()); cell_area.at(cell_type).area = cell_data.double_parameter_area.back().back(); cell_area.at(cell_type).is_sequential = cell_data.is_sequential; @@ -816,6 +816,10 @@ void read_liberty_cellarea(dict &cell_area, string libert const LibertyAst *sar = cell->find("single_area_parameterised"); if (sar != nullptr) { for (const auto &s : sar->args) { + if (s.empty()) { + //catches trailing commas + continue; + } try { double value = std::stod(s); single_parameter_area.push_back(value); @@ -845,11 +849,15 @@ void read_liberty_cellarea(dict &cell_area, string libert vector cast_sub_array; for (const auto &s : sub_array) { double value = 0; + if (s.empty()) { + //catches trailing commas + continue; + } try { value = std::stod(s); cast_sub_array.push_back(value); } catch (const std::exception &e) { - log_error("Failed to parse double parameter area value '%s': %s\n", s.c_str(), e.what()); + log_error("Failed to parse double parameter area value for '%s': %s\n", s.c_str(), e.what()); } } double_parameter_area.push_back(cast_sub_array); From 9278bed853e0e391d42a646bb1633da9ae5f7597 Mon Sep 17 00:00:00 2001 From: clemens Date: Thu, 14 Aug 2025 16:33:59 +0200 Subject: [PATCH 131/176] removed copyright notice on lib file. Should be covered by the yosys license not anything else. --- tests/various/stat_area_by_width.lib | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/tests/various/stat_area_by_width.lib b/tests/various/stat_area_by_width.lib index 73e266472..1e98aa488 100644 --- a/tests/various/stat_area_by_width.lib +++ b/tests/various/stat_area_by_width.lib @@ -1,22 +1,5 @@ -/************************************************************************ - - Copyright 2025 Clemens Walter, - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -************************************************************************/ -//Mock library for Yosys pre techmap +//library for testcases, can also be used as a template for new libraries library (mock) { cell ( "$reduce_xor" ) { area : 3.0 ; From 3f2c4f6f83b699c02fdad90aef8afdc0052531b4 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Sun, 17 Aug 2025 23:34:11 +0000 Subject: [PATCH 132/176] Remove redundant construction of `assign_map`. We call 'assign_map.set()' below which wipes the `SigMap` and reconstructs it. This operation is expensive because it scans the whole module. I think it's better to make heavyweight operations more visible so I'm removing the less obvious operation. --- passes/opt/opt_merge.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index b519d33d6..5ca19bc2f 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -227,7 +227,7 @@ struct OptMergeWorker } OptMergeWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all, bool mode_keepdc) : - design(design), module(module), assign_map(module), mode_share_all(mode_share_all) + design(design), module(module), mode_share_all(mode_share_all) { total_count = 0; ct.setup_internals(); From d73cd78001a4ea2d3279f7533b3f443128f63bad Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 00:27:23 +0000 Subject: [PATCH 133/176] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e83d32ac2..d9f9f432b 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+125 +YOSYS_VER := 0.56+141 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From e0e70d11580df9743acf8fac2c91e8a305bcbf35 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 18 Aug 2025 03:07:45 +0000 Subject: [PATCH 134/176] Remove some `c_str()` calls where they're no longer needed as parameters to `stringf()`. --- backends/btor/btor.cc | 6 +-- backends/firrtl/firrtl.cc | 66 ++++++++++++++--------------- backends/intersynth/intersynth.cc | 8 ++-- backends/simplec/simplec.cc | 70 +++++++++++++++---------------- backends/spice/spice.cc | 22 +++++----- 5 files changed, 86 insertions(+), 86 deletions(-) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index bfd293557..1daf68c9d 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -129,7 +129,7 @@ struct BtorWorker std::replace(src.begin(), src.end(), ' ', '_'); if (srcsymbols.count(src) || module->count_id("\\" + src)) { for (int i = 1;; i++) { - string s = stringf("%s-%d", src.c_str(), i); + string s = stringf("%s-%d", src, i); if (!srcsymbols.count(s) && !module->count_id("\\" + s)) { src = s; break; @@ -192,7 +192,7 @@ struct BtorWorker void btorf_push(const string &id) { if (verbose) { - f << indent << stringf(" ; begin %s\n", id.c_str()); + f << indent << stringf(" ; begin %s\n", id); indent += " "; } } @@ -201,7 +201,7 @@ struct BtorWorker { if (verbose) { indent = indent.substr(4); - f << indent << stringf(" ; end %s\n", id.c_str()); + f << indent << stringf(" ; end %s\n", id); } } diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index e4254f85a..7c9feebb1 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -253,7 +253,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream const std::string extmoduleFileinfo = getFileinfo(cell); // Emit extmodule header. - f << stringf(" extmodule %s: %s\n", exported_name.c_str(), extmoduleFileinfo.c_str()); + f << stringf(" extmodule %s: %s\n", exported_name, extmoduleFileinfo); // Emit extmodule ports. for (auto wire : mod_instance->wires()) @@ -280,7 +280,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream // Emit extmodule "defname" field. This is the name of the verilog blackbox // that is used when verilog is emitted, so we use the name of mod_instance // here. - f << stringf("%sdefname = %s\n", indent.c_str(), blackbox_name.c_str()); + f << stringf("%sdefname = %s\n", indent, blackbox_name); // Emit extmodule generic parameters. for (const auto &p : cell->parameters) @@ -301,7 +301,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream param_name.end() ); - f << stringf("%sparameter %s = %s\n", indent.c_str(), param_name.c_str(), param_value.c_str()); + f << stringf("%sparameter %s = %s\n", indent, param_name, param_value); } f << "\n"; @@ -417,7 +417,7 @@ struct FirrtlWorker else { string wire_id = make_id(chunk.wire->name); - new_expr = stringf("bits(%s, %d, %d)", wire_id.c_str(), chunk.offset + chunk.width - 1, chunk.offset); + new_expr = stringf("bits(%s, %d, %d)", wire_id, chunk.offset + chunk.width - 1, chunk.offset); } if (expr.empty()) @@ -477,7 +477,7 @@ struct FirrtlWorker instanceOf; std::string cellFileinfo = getFileinfo(cell); - wire_exprs.push_back(stringf("%s" "inst %s%s of %s %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceName.c_str(), cellFileinfo.c_str())); + wire_exprs.push_back(stringf("%s" "inst %s%s of %s %s", indent, cell_name, cell_name_comment, instanceName, cellFileinfo)); for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) { if (it->second.size() > 0) { @@ -518,7 +518,7 @@ struct FirrtlWorker // as part of the coalesced subfield assignments for this wire. register_reverse_wire_map(sourceExpr, *sinkSig); } else { - wire_exprs.push_back(stringf("\n%s%s <= %s %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str(), cellFileinfo.c_str())); + wire_exprs.push_back(stringf("\n%s%s <= %s %s", indent, sinkExpr, sourceExpr, cellFileinfo)); } } } @@ -535,7 +535,7 @@ struct FirrtlWorker int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1; string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<name), moduleFileinfo.c_str()); + f << stringf(" module %s: %s\n", make_id(module->name), moduleFileinfo); vector port_decls, wire_decls, mem_exprs, cell_exprs, wire_exprs; std::vector memories = Mem::get_all_memories(module); @@ -602,7 +602,7 @@ struct FirrtlWorker if (cell->type.in(ID($not), ID($logic_not), ID($_NOT_), ID($neg), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_bool), ID($reduce_xnor))) { string a_expr = make_expr(cell->getPort(ID::A)); - wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), y_width, cellFileinfo.c_str())); + wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent, y_id, y_width, cellFileinfo)); if (a_signed) { a_expr = "asSInt(" + a_expr + ")"; @@ -610,7 +610,7 @@ struct FirrtlWorker // Don't use the results of logical operations (a single bit) to control padding if (!(cell->type.in(ID($eq), ID($eqx), ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($reduce_bool), ID($logic_not)) && y_width == 1) ) { - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + a_expr = stringf("pad(%s, %d)", a_expr, y_width); } // Assume the FIRRTL width is a single bit. @@ -622,27 +622,27 @@ struct FirrtlWorker firrtl_width = a_width; } else if (cell->type == ID($logic_not)) { primop = "eq"; - a_expr = stringf("%s, UInt(0)", a_expr.c_str()); + a_expr = stringf("%s, UInt(0)", a_expr); } else if (cell->type == ID($reduce_and)) primop = "andr"; else if (cell->type == ID($reduce_or)) primop = "orr"; else if (cell->type == ID($reduce_xor)) primop = "xorr"; else if (cell->type == ID($reduce_xnor)) { primop = "not"; - a_expr = stringf("xorr(%s)", a_expr.c_str()); + a_expr = stringf("xorr(%s)", a_expr); } else if (cell->type == ID($reduce_bool)) { primop = "neq"; // Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand. - a_expr = stringf("%s, %cInt<%d>(0)", a_expr.c_str(), a_signed ? 'S' : 'U', a_width); + a_expr = stringf("%s, %cInt<%d>(0)", a_expr, a_signed ? 'S' : 'U', a_width); } - string expr = stringf("%s(%s)", primop.c_str(), a_expr.c_str()); + string expr = stringf("%s(%s)", primop, a_expr); if ((firrtl_is_signed && !always_uint)) - expr = stringf("asUInt(%s)", expr.c_str()); + expr = stringf("asUInt(%s)", expr); - cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); + cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo)); register_reverse_wire_map(y_id, cell->getPort(ID::Y)); continue; @@ -654,13 +654,13 @@ struct FirrtlWorker string a_expr = make_expr(cell->getPort(ID::A)); string b_expr = make_expr(cell->getPort(ID::B)); std::string cellFileinfo = getFileinfo(cell); - wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), y_width, cellFileinfo.c_str())); + wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent, y_id, y_width, cellFileinfo)); if (a_signed) { a_expr = "asSInt(" + a_expr + ")"; // Expand the "A" operand to the result width if (a_width < y_width) { - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + a_expr = stringf("pad(%s, %d)", a_expr, y_width); a_width = y_width; } } @@ -670,7 +670,7 @@ struct FirrtlWorker b_expr = "asSInt(" + b_expr + ")"; // Expand the "B" operand to the result width if (b_width < y_width) { - b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); + b_expr = stringf("pad(%s, %d)", b_expr, y_width); b_width = y_width; } } @@ -680,11 +680,11 @@ struct FirrtlWorker if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($_XOR_), ID($xnor), ID($and), ID($_AND_), ID($or), ID($_OR_))) { if (a_width < y_width) { - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + a_expr = stringf("pad(%s, %d)", a_expr, y_width); a_width = y_width; } if (b_width < y_width) { - b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); + b_expr = stringf("pad(%s, %d)", b_expr, y_width); b_width = y_width; } } @@ -856,23 +856,23 @@ struct FirrtlWorker string expr; // Deal with $xnor == ~^ (not xor) if (primop == "xnor") { - expr = stringf("not(xor(%s, %s))", a_expr.c_str(), b_expr.c_str()); + expr = stringf("not(xor(%s, %s))", a_expr, b_expr); } else { - expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str()); + expr = stringf("%s(%s, %s)", primop, a_expr, b_expr); } // Deal with FIRRTL's "shift widens" semantics, or the need to widen the FIRRTL result. // If the operation is signed, the FIRRTL width will be 1 one bit larger. if (extract_y_bits) { - expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1); + expr = stringf("bits(%s, %d, 0)", expr, y_width - 1); } else if (firrtl_is_signed && (firrtl_width + 1) < y_width) { - expr = stringf("pad(%s, %d)", expr.c_str(), y_width); + expr = stringf("pad(%s, %d)", expr, y_width); } if ((firrtl_is_signed && !always_uint)) - expr = stringf("asUInt(%s)", expr.c_str()); + expr = stringf("asUInt(%s)", expr); - cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); + cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo)); register_reverse_wire_map(y_id, cell->getPort(ID::Y)); continue; @@ -887,9 +887,9 @@ struct FirrtlWorker string s_expr = make_expr(cell->getPort(ID::S)); wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), width, cellFileinfo.c_str())); - string expr = stringf("mux(%s, %s, %s)", s_expr.c_str(), b_expr.c_str(), a_expr.c_str()); + string expr = stringf("mux(%s, %s, %s)", s_expr, b_expr, a_expr); - cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); + cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo)); register_reverse_wire_map(y_id, cell->getPort(ID::Y)); continue; @@ -911,9 +911,9 @@ struct FirrtlWorker string expr = make_expr(cell->getPort(ID::D)); string clk_expr = "asClock(" + make_expr(cell->getPort(ID::CLK)) + ")"; - wire_decls.push_back(stringf("%sreg %s: UInt<%d>, %s %s\n", indent.c_str(), y_id.c_str(), width, clk_expr.c_str(), cellFileinfo.c_str())); + wire_decls.push_back(stringf("%sreg %s: UInt<%d>, %s %s\n", indent, y_id, width, clk_expr, cellFileinfo)); - cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); + cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo)); register_reverse_wire_map(y_id, cell->getPort(ID::Q)); continue; @@ -934,7 +934,7 @@ struct FirrtlWorker int b_sign = cell->parameters.at(ID::B_WIDTH).as_int() - 1; b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string); } - string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_expr.c_str()); + string expr = stringf("dshr(%s, %s)", a_expr, b_expr); cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), expr.c_str())); register_reverse_wire_map(y_id, cell->getPort(ID::Y)); @@ -973,7 +973,7 @@ struct FirrtlWorker // Verilog appears to treat the result as signed, so if the result is wider than "A", // we need to pad. if (a_width < y_width) { - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + a_expr = stringf("pad(%s, %d)", a_expr, y_width); } wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width)); cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), a_expr.c_str())); diff --git a/backends/intersynth/intersynth.cc b/backends/intersynth/intersynth.cc index dcf107de3..4c098e019 100644 --- a/backends/intersynth/intersynth.cc +++ b/backends/intersynth/intersynth.cc @@ -172,7 +172,7 @@ struct IntersynthBackend : public Backend { if (sig.size() != 0) { conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.size(), sig.size(), sig.size())); celltype_code += stringf(" b%d %s%s", sig.size(), ct.cell_output(cell->type, port.first) ? "*" : "", log_id(port.first)); - node_code += stringf(" %s %s", log_id(port.first), netname(conntypes_code, celltypes_code, constcells_code, sig).c_str()); + node_code += stringf(" %s %s", log_id(port.first), netname(conntypes_code, celltypes_code, constcells_code, sig)); } } for (auto ¶m : cell->parameters) { @@ -199,13 +199,13 @@ struct IntersynthBackend : public Backend { if (!flag_notypes) { *f << stringf("### Connection Types\n"); for (auto code : conntypes_code) - *f << stringf("%s", code.c_str()); + *f << stringf("%s", code); *f << stringf("\n### Cell Types\n"); for (auto code : celltypes_code) - *f << stringf("%s", code.c_str()); + *f << stringf("%s", code); } *f << stringf("\n### Netlists\n"); - *f << stringf("%s", netlists_code.c_str()); + *f << stringf("%s", netlists_code); for (auto lib : libs) delete lib; diff --git a/backends/simplec/simplec.cc b/backends/simplec/simplec.cc index e70c62a71..1ab586e43 100644 --- a/backends/simplec/simplec.cc +++ b/backends/simplec/simplec.cc @@ -218,8 +218,8 @@ struct SimplecWorker s[i] -= 'a' - 'A'; util_declarations.push_back(""); - util_declarations.push_back(stringf("#ifndef %s", s.c_str())); - util_declarations.push_back(stringf("#define %s", s.c_str())); + util_declarations.push_back(stringf("#ifndef %s", s)); + util_declarations.push_back(stringf("#define %s", s)); } string util_get_bit(const string &signame, int n, int idx) @@ -232,33 +232,33 @@ struct SimplecWorker if (generated_utils.count(util_name) == 0) { util_ifdef_guard(util_name); - util_declarations.push_back(stringf("static inline bool %s(const %s *sig)", util_name.c_str(), sigtype(n).c_str())); + util_declarations.push_back(stringf("static inline bool %s(const %s *sig)", util_name, sigtype(n))); util_declarations.push_back(stringf("{")); int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize; string value_name = stringf("value_%d_%d", std::min(n-1, (word_idx+1)*max_uintsize-1), word_idx*max_uintsize); - util_declarations.push_back(stringf(" return (sig->%s >> %d) & 1;", value_name.c_str(), word_offset)); + util_declarations.push_back(stringf(" return (sig->%s >> %d) & 1;", value_name, word_offset)); util_declarations.push_back(stringf("}")); util_declarations.push_back(stringf("#endif")); generated_utils.insert(util_name); } - return stringf("%s(&%s)", util_name.c_str(), signame.c_str()); + return stringf("%s(&%s)", util_name, signame); } string util_set_bit(const string &signame, int n, int idx, const string &expr) { if (n == 1 && idx == 0) - return stringf(" %s.value_0_0 = %s;", signame.c_str(), expr.c_str()); + return stringf(" %s.value_0_0 = %s;", signame, expr); string util_name = stringf("yosys_simplec_set_bit_%d_of_%d", idx, n); if (generated_utils.count(util_name) == 0) { util_ifdef_guard(util_name); - util_declarations.push_back(stringf("static inline void %s(%s *sig, bool value)", util_name.c_str(), sigtype(n).c_str())); + util_declarations.push_back(stringf("static inline void %s(%s *sig, bool value)", util_name, sigtype(n))); util_declarations.push_back(stringf("{")); int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize; @@ -266,9 +266,9 @@ struct SimplecWorker #if 0 util_declarations.push_back(stringf(" if (value)")); - util_declarations.push_back(stringf(" sig->%s |= 1UL << %d;", value_name.c_str(), word_offset)); + util_declarations.push_back(stringf(" sig->%s |= 1UL << %d;", value_name, word_offset)); util_declarations.push_back(stringf(" else")); - util_declarations.push_back(stringf(" sig->%s &= ~(1UL << %d);", value_name.c_str(), word_offset)); + util_declarations.push_back(stringf(" sig->%s &= ~(1UL << %d);", value_name, word_offset)); #else util_declarations.push_back(stringf(" sig->%s = (sig->%s & ~((uint%d_t)1 << %d)) | ((uint%d_t)value << %d);", value_name.c_str(), value_name.c_str(), max_uintsize, word_offset, max_uintsize, word_offset)); @@ -279,7 +279,7 @@ struct SimplecWorker generated_utils.insert(util_name); } - return stringf(" %s(&%s, %s);", util_name.c_str(), signame.c_str(), expr.c_str()); + return stringf(" %s(&%s, %s);", util_name, signame, expr); } void create_module_struct(Module *mod) @@ -339,38 +339,38 @@ struct SimplecWorker for (int i = 0; i < GetSize(topo.sorted); i++) topoidx[mod->cell(topo.sorted[i])] = i; - string ifdef_name = stringf("yosys_simplec_%s_state_t", cid(mod->name).c_str()); + string ifdef_name = stringf("yosys_simplec_%s_state_t", cid(mod->name)); for (int i = 0; i < GetSize(ifdef_name); i++) if ('a' <= ifdef_name[i] && ifdef_name[i] <= 'z') ifdef_name[i] -= 'a' - 'A'; struct_declarations.push_back(""); - struct_declarations.push_back(stringf("#ifndef %s", ifdef_name.c_str())); - struct_declarations.push_back(stringf("#define %s", ifdef_name.c_str())); - struct_declarations.push_back(stringf("struct %s_state_t", cid(mod->name).c_str())); + struct_declarations.push_back(stringf("#ifndef %s", ifdef_name)); + struct_declarations.push_back(stringf("#define %s", ifdef_name)); + struct_declarations.push_back(stringf("struct %s_state_t", cid(mod->name))); struct_declarations.push_back("{"); struct_declarations.push_back(" // Input Ports"); for (Wire *w : mod->wires()) if (w->port_input) - struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); + struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w))); struct_declarations.push_back(""); struct_declarations.push_back(" // Output Ports"); for (Wire *w : mod->wires()) if (!w->port_input && w->port_output) - struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); + struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w))); struct_declarations.push_back(""); struct_declarations.push_back(" // Internal Wires"); for (Wire *w : mod->wires()) if (!w->port_input && !w->port_output) - struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); + struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w))); for (Cell *c : mod->cells()) if (design->module(c->type)) - struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type).c_str(), cid(c->name).c_str(), log_id(c))); + struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type), cid(c->name), log_id(c))); struct_declarations.push_back(stringf("};")); struct_declarations.push_back("#endif"); @@ -407,14 +407,14 @@ struct SimplecWorker string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0"; string expr; - if (cell->type == ID($_AND_)) expr = stringf("%s & %s", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_NAND_)) expr = stringf("!(%s & %s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_OR_)) expr = stringf("%s | %s", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_NOR_)) expr = stringf("!(%s | %s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_XOR_)) expr = stringf("%s ^ %s", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_XNOR_)) expr = stringf("!(%s ^ %s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_ANDNOT_)) expr = stringf("%s & (!%s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_ORNOT_)) expr = stringf("%s | (!%s)", a_expr.c_str(), b_expr.c_str()); + if (cell->type == ID($_AND_)) expr = stringf("%s & %s", a_expr, b_expr); + if (cell->type == ID($_NAND_)) expr = stringf("!(%s & %s)", a_expr, b_expr); + if (cell->type == ID($_OR_)) expr = stringf("%s | %s", a_expr, b_expr); + if (cell->type == ID($_NOR_)) expr = stringf("!(%s | %s)", a_expr, b_expr); + if (cell->type == ID($_XOR_)) expr = stringf("%s ^ %s", a_expr, b_expr); + if (cell->type == ID($_XNOR_)) expr = stringf("!(%s ^ %s)", a_expr, b_expr); + if (cell->type == ID($_ANDNOT_)) expr = stringf("%s & (!%s)", a_expr, b_expr); + if (cell->type == ID($_ORNOT_)) expr = stringf("%s | (!%s)", a_expr, b_expr); log_assert(y.wire); funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + @@ -436,8 +436,8 @@ struct SimplecWorker string c_expr = c.wire ? util_get_bit(work->prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0"; string expr; - if (cell->type == ID($_AOI3_)) expr = stringf("!((%s & %s) | %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str()); - if (cell->type == ID($_OAI3_)) expr = stringf("!((%s | %s) & %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str()); + if (cell->type == ID($_AOI3_)) expr = stringf("!((%s & %s) | %s)", a_expr, b_expr, c_expr); + if (cell->type == ID($_OAI3_)) expr = stringf("!((%s | %s) & %s)", a_expr, b_expr, c_expr); log_assert(y.wire); funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + @@ -461,8 +461,8 @@ struct SimplecWorker string d_expr = d.wire ? util_get_bit(work->prefix + cid(d.wire->name), d.wire->width, d.offset) : d.data ? "1" : "0"; string expr; - if (cell->type == ID($_AOI4_)) expr = stringf("!((%s & %s) | (%s & %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str()); - if (cell->type == ID($_OAI4_)) expr = stringf("!((%s | %s) & (%s | %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str()); + if (cell->type == ID($_AOI4_)) expr = stringf("!((%s & %s) | (%s & %s))", a_expr, b_expr, c_expr, d_expr); + if (cell->type == ID($_OAI4_)) expr = stringf("!((%s | %s) & (%s | %s))", a_expr, b_expr, c_expr, d_expr); log_assert(y.wire); funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + @@ -484,9 +484,9 @@ struct SimplecWorker string s_expr = s.wire ? util_get_bit(work->prefix + cid(s.wire->name), s.wire->width, s.offset) : s.data ? "1" : "0"; // casts to bool are a workaround for CBMC bug (https://github.com/diffblue/cbmc/issues/933) - string expr = stringf("%s ? %s(bool)%s : %s(bool)%s", s_expr.c_str(), - cell->type == ID($_NMUX_) ? "!" : "", b_expr.c_str(), - cell->type == ID($_NMUX_) ? "!" : "", a_expr.c_str()); + string expr = stringf("%s ? %s(bool)%s : %s(bool)%s", s_expr, + cell->type == ID($_NMUX_) ? "!" : "", b_expr, + cell->type == ID($_NMUX_) ? "!" : "", a_expr); log_assert(y.wire); funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + @@ -518,7 +518,7 @@ struct SimplecWorker continue; if (verbose) log(" Propagating %s.%s[%d:%d].\n", work->log_prefix.c_str(), log_id(chunk.wire), chunk.offset+chunk.width-1, chunk.offset); - funct_declarations.push_back(stringf(" // Updated signal in %s: %s", work->log_prefix.c_str(), log_signal(chunk))); + funct_declarations.push_back(stringf(" // Updated signal in %s: %s", work->log_prefix, log_signal(chunk))); } for (SigBit bit : dirtysig) @@ -636,7 +636,7 @@ struct SimplecWorker reactivated_cells.clear(); funct_declarations.push_back(""); - funct_declarations.push_back(stringf("static void %s(struct %s_state_t *state)", func_name.c_str(), cid(work->module->name).c_str())); + funct_declarations.push_back(stringf("static void %s(struct %s_state_t *state)", func_name, cid(work->module->name))); funct_declarations.push_back("{"); for (auto &line : preamble) funct_declarations.push_back(line); diff --git a/backends/spice/spice.cc b/backends/spice/spice.cc index e55db95e1..573093ff7 100644 --- a/backends/spice/spice.cc +++ b/backends/spice/spice.cc @@ -51,16 +51,16 @@ static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg, if (s.wire->port_id) use_inames = true; if (s.wire->width > 1) - f << stringf(" %s.%d", spice_id2str(s.wire->name, use_inames, inums).c_str(), s.offset); + f << stringf(" %s.%d", spice_id2str(s.wire->name, use_inames, inums), s.offset); else - f << stringf(" %s", spice_id2str(s.wire->name, use_inames, inums).c_str()); + f << stringf(" %s", spice_id2str(s.wire->name, use_inames, inums)); } else { if (s == RTLIL::State::S0) - f << stringf(" %s", neg.c_str()); + f << stringf(" %s", neg); else if (s == RTLIL::State::S1) - f << stringf(" %s", pos.c_str()); + f << stringf(" %s", pos); else - f << stringf(" %s%d", ncpf.c_str(), nc_counter++); + f << stringf(" %s%d", ncpf, nc_counter++); } } @@ -119,7 +119,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De } } - f << stringf(" %s\n", spice_id2str(cell->type).c_str()); + f << stringf(" %s\n", spice_id2str(cell->type)); } for (auto &conn : module->connections()) @@ -127,7 +127,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De f << (buf == "DC" ? stringf("V%d", conn_counter++) : stringf("X%d", cell_counter++)); print_spice_net(f, conn.second.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums); print_spice_net(f, conn.first.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums); - f << (buf == "DC" ? " DC 0\n" : stringf(" %s\n", buf.c_str())); + f << (buf == "DC" ? " DC 0\n" : stringf(" %s\n", buf)); } } @@ -242,18 +242,18 @@ struct SpiceBackend : public Backend { ports.at(wire->port_id-1) = wire; } - *f << stringf(".SUBCKT %s", spice_id2str(module->name).c_str()); + *f << stringf(".SUBCKT %s", spice_id2str(module->name)); for (RTLIL::Wire *wire : ports) { log_assert(wire != NULL); if (wire->width > 1) { for (int i = 0; i < wire->width; i++) - *f << stringf(" %s.%d", spice_id2str(wire->name).c_str(), big_endian ? wire->width - 1 - i : i); + *f << stringf(" %s.%d", spice_id2str(wire->name), big_endian ? wire->width - 1 - i : i); } else - *f << stringf(" %s", spice_id2str(wire->name).c_str()); + *f << stringf(" %s", spice_id2str(wire->name)); } *f << stringf("\n"); print_spice_module(*f, module, design, neg, pos, buf, ncpf, big_endian, use_inames); - *f << stringf(".ENDS %s\n\n", spice_id2str(module->name).c_str()); + *f << stringf(".ENDS %s\n\n", spice_id2str(module->name)); } if (!top_module_name.empty()) { From 6a2984540b5cc0d70966b10b3e6e7c73d5c910a8 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 18 Jul 2024 15:48:52 +0200 Subject: [PATCH 135/176] bitpattern: comments --- kernel/bitpattern.h | 49 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h index 821490dca..0e12e6dce 100644 --- a/kernel/bitpattern.h +++ b/kernel/bitpattern.h @@ -25,6 +25,18 @@ YOSYS_NAMESPACE_BEGIN +/** + * This file implements BitPatternPool for efficiently storing and querying + * sets of fixed-width 2-valued logic constants compressed as "bit patterns". + * A bit pattern can have don't cares on one or more bit positions (State::Sa). + * + * In terms of logic synthesis: + * A BitPatternPool is a sum of products (SOP). + * BitPatternPool::bits_t is a cube. + * + * BitPatternPool does not permit adding new patterns, only removing. + * Its intended use case is in analysing cases in case/match constructs in HDL. + */ struct BitPatternPool { int width; @@ -67,6 +79,9 @@ struct BitPatternPool } } + /** + * Constructs a pool of all possible patterns (all don't-care bits) + */ BitPatternPool(int width) { this->width = width; @@ -78,6 +93,10 @@ struct BitPatternPool } } + /** + * Convert a constant SigSpec to a pattern. Normalize Yosys many-valued + * to three-valued logic. + */ bits_t sig2bits(RTLIL::SigSpec sig) { bits_t bits; @@ -88,6 +107,9 @@ struct BitPatternPool return bits; } + /** + * Two cubes match if their intersection is non-empty. + */ bool match(bits_t a, bits_t b) { log_assert(int(a.bitdata.size()) == width); @@ -98,6 +120,15 @@ struct BitPatternPool return true; } + /** + * Does cube sig overlap any cube in the pool? + * For example: + * pool({aaa}).has_any(01a) == true + * pool({01a}).has_any(01a) == true + * pool({011}).has_any(01a) == true + * pool({01a}).has_any(011) == true + * pool({111}).has_any(01a) == false + */ bool has_any(RTLIL::SigSpec sig) { bits_t bits = sig2bits(sig); @@ -107,6 +138,15 @@ struct BitPatternPool return false; } + /** + * Is cube sig covered by a cube in the pool? + * For example: + * pool({aaa}).has_all(01a) == true + * pool({01a}).has_any(01a) == true + * pool({01a}).has_any(011) == true + * pool({011}).has_all(01a) == false + * pool({111}).has_all(01a) == false + */ bool has_all(RTLIL::SigSpec sig) { bits_t bits = sig2bits(sig); @@ -121,6 +161,12 @@ struct BitPatternPool return false; } + /** + * Remove cube sig from the pool, splitting the remaining cubes. True if success. + * For example: + * Taking 011 out of pool({01a}) -> pool({010}), returns true. + * Taking 011 out of pool({010}) does nothing, returns false. + */ bool take(RTLIL::SigSpec sig) { bool status = false; @@ -143,6 +189,9 @@ struct BitPatternPool return status; } + /** + * Remove all patterns. Returns false if already empty. + */ bool take_all() { if (database.empty()) From 7ee62c832b19d5b18b822af7603a6fb1898ca748 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 18 Aug 2025 19:50:43 +0200 Subject: [PATCH 136/176] bitpattern: unit test --- tests/unit/kernel/bitpatternTest.cc | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/unit/kernel/bitpatternTest.cc diff --git a/tests/unit/kernel/bitpatternTest.cc b/tests/unit/kernel/bitpatternTest.cc new file mode 100644 index 000000000..001d47060 --- /dev/null +++ b/tests/unit/kernel/bitpatternTest.cc @@ -0,0 +1,32 @@ +#include + +#include "kernel/bitpattern.h" +#include "kernel/rtlil.h" + +YOSYS_NAMESPACE_BEGIN + +TEST(BitpatternTest, has) +{ + SigSpec _aaa = {RTLIL::Sa, RTLIL::Sa, RTLIL::Sa}; + SigSpec _01a = {RTLIL::S0, RTLIL::S1, RTLIL::Sa}; + SigSpec _011 = {RTLIL::S0, RTLIL::S1, RTLIL::S1}; + SigSpec _111 = {RTLIL::S1, RTLIL::S1, RTLIL::S1}; + + EXPECT_TRUE(BitPatternPool(_aaa).has_any(_01a)); + EXPECT_TRUE(BitPatternPool(_01a).has_any(_01a)); + // 011 overlaps with 01a + EXPECT_TRUE(BitPatternPool(_011).has_any(_01a)); + // overlap is symmetric + EXPECT_TRUE(BitPatternPool(_01a).has_any(_011)); + EXPECT_FALSE(BitPatternPool(_111).has_any(_01a)); + + EXPECT_TRUE(BitPatternPool(_aaa).has_all(_01a)); + EXPECT_TRUE(BitPatternPool(_01a).has_all(_01a)); + // 011 is covered by 01a + EXPECT_TRUE(BitPatternPool(_01a).has_all(_011)); + // 01a is not covered by 011 + EXPECT_FALSE(BitPatternPool(_011).has_all(_01a)); + EXPECT_FALSE(BitPatternPool(_111).has_all(_01a)); +} + +YOSYS_NAMESPACE_END From b640a16b07ec7c313ee3d97a4a84b0eccd3d59f9 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 18 Aug 2025 20:39:00 +0200 Subject: [PATCH 137/176] Revert "Workflow adjustments" --- .github/workflows/extra-builds.yml | 16 +--- .github/workflows/test-build.yml | 36 ++++----- .github/workflows/test-compile.yml | 16 +--- .github/workflows/test-sanitizers.yml | 105 -------------------------- .github/workflows/test-verific.yml | 16 +--- 5 files changed, 28 insertions(+), 161 deletions(-) delete mode 100644 .github/workflows/test-sanitizers.yml diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 11fd42a6c..458eb76a6 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -1,14 +1,6 @@ name: Test extra build flows -on: - # always test main - push: - branches: - - main - # test PRs - pull_request: - # allow triggering tests, ignores skip check - workflow_dispatch: +on: [push, pull_request] jobs: pre_job: @@ -19,11 +11,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - # but never cancel main - cancel_others: ${{ github.ref != 'refs/heads/main' }} + cancel_others: 'true' + # only run on push *or* pull_request, not both + concurrent_skipping: 'same_content_newer' vs-prep: name: Prepare Visual Studio build diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index f44dee1ba..f9574594a 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -1,14 +1,6 @@ name: Build and run tests -on: - # always test main - push: - branches: - - main - # test PRs - pull_request: - # allow triggering tests, ignores skip check - workflow_dispatch: +on: [push, pull_request] jobs: pre_job: @@ -19,12 +11,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - # but never cancel main - cancel_others: ${{ github.ref != 'refs/heads/main' }} - + cancel_others: 'true' + # only run on push *or* pull_request, not both + concurrent_skipping: 'same_content_newer' pre_docs_job: runs-on: ubuntu-latest outputs: @@ -33,16 +24,15 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - # don't run on readme changes paths_ignore: '["**/README.md"]' # cancel previous builds if a new commit is pushed - # but never cancel main - cancel_others: ${{ github.ref != 'refs/heads/main' }} + cancel_others: 'true' + # only run on push *or* pull_request, not both + concurrent_skipping: 'same_content_newer' build-yosys: name: Reusable build runs-on: ${{ matrix.os }} - # pre_job is a subset of pre_docs_job, so we can always build for pre_docs_job needs: pre_docs_job if: needs.pre_docs_job.outputs.should_skip != 'true' env: @@ -50,6 +40,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] + sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -67,6 +58,7 @@ jobs: mkdir build cd build make -f ../Makefile config-$CC + echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf make -f ../Makefile -j$procs ENABLE_LTO=1 - name: Log yosys-config output @@ -82,7 +74,7 @@ jobs: - name: Store build artifact uses: actions/upload-artifact@v4 with: - name: build-${{ matrix.os }} + name: build-${{ matrix.os }}-${{ matrix.sanitizer }} path: build.tar retention-days: 1 @@ -93,9 +85,12 @@ jobs: if: needs.pre_job.outputs.should_skip != 'true' env: CC: clang + ASAN_OPTIONS: halt_on_error=1 + UBSAN_OPTIONS: halt_on_error=1 strategy: matrix: os: [ubuntu-latest, macos-latest] + sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -144,7 +139,7 @@ jobs: - name: Download build artifact uses: actions/download-artifact@v4 with: - name: build-${{ matrix.os }} + name: build-${{ matrix.os }}-${{ matrix.sanitizer }} - name: Uncompress build shell: bash @@ -214,6 +209,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] + sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -227,7 +223,7 @@ jobs: - name: Download build artifact uses: actions/download-artifact@v4 with: - name: build-${{ matrix.os }} + name: build-${{ matrix.os }}-${{ matrix.sanitizer }} - name: Uncompress build shell: bash diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index f208b911a..7a706e69a 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -1,14 +1,6 @@ name: Compiler testing -on: - # always test main - push: - branches: - - main - # test PRs - pull_request: - # allow triggering tests, ignores skip check - workflow_dispatch: +on: [push, pull_request] jobs: pre_job: @@ -19,11 +11,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - # but never cancel main - cancel_others: ${{ github.ref != 'refs/heads/main' }} + cancel_others: 'true' + # only run on push *or* pull_request, not both + concurrent_skipping: 'same_content_newer' test-compile: runs-on: ${{ matrix.os }} diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml deleted file mode 100644 index fb76d1266..000000000 --- a/.github/workflows/test-sanitizers.yml +++ /dev/null @@ -1,105 +0,0 @@ -name: Check clang sanitizers - -on: - # always test main - push: - branches: - - main - # ignore PRs due to time needed - # allow triggering tests, ignores skip check - workflow_dispatch: - -jobs: - pre_job: - runs-on: ubuntu-latest - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@v5 - with: - # don't run on documentation changes - paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' - - run_san: - name: Build and run tests - runs-on: ${{ matrix.os }} - needs: pre_job - if: needs.pre_job.outputs.should_skip != 'true' - env: - CC: clang - ASAN_OPTIONS: halt_on_error=1 - UBSAN_OPTIONS: halt_on_error=1 - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - sanitizer: ['undefined,address'] - fail-fast: false - steps: - - name: Checkout Yosys - uses: actions/checkout@v4 - with: - submodules: true - persist-credentials: false - - - name: Setup environment - uses: ./.github/actions/setup-build-env - - - name: Build - shell: bash - run: | - mkdir build - cd build - make -f ../Makefile config-$CC - echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf - make -f ../Makefile -j$procs ENABLE_LTO=1 - - - name: Log yosys-config output - run: | - ./yosys-config || true - - - name: Get iverilog - shell: bash - run: | - git clone https://github.com/steveicarus/iverilog.git - cd iverilog - echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_ENV - - - name: Get vcd2fst - shell: bash - run: | - git clone https://github.com/mmicko/libwave.git - mkdir -p ${{ github.workspace }}/.local/ - cd libwave - cmake . -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/.local - make -j$procs - make install - - - name: Cache iverilog - id: cache-iverilog - uses: actions/cache@v4 - with: - path: .local/ - key: ${{ matrix.os }}-${IVERILOG_GIT} - - - name: Build iverilog - if: steps.cache-iverilog.outputs.cache-hit != 'true' - shell: bash - run: | - mkdir -p ${{ github.workspace }}/.local/ - cd iverilog - autoconf - CC=gcc CXX=g++ ./configure --prefix=${{ github.workspace }}/.local - make -j$procs - make install - - - name: Run tests - shell: bash - run: | - make -j$procs test TARGETS= EXTRA_TARGETS= CONFIG=$CC - - - name: Report errors - if: ${{ failure() }} - shell: bash - run: | - find tests/**/*.err -print -exec cat {} \; diff --git a/.github/workflows/test-verific.yml b/.github/workflows/test-verific.yml index 9af07b920..013c9f8ca 100644 --- a/.github/workflows/test-verific.yml +++ b/.github/workflows/test-verific.yml @@ -1,14 +1,6 @@ name: Build and run tests with Verific (Linux) -on: - # always test main - push: - branches: - - main - # test PRs - pull_request: - # allow triggering tests, ignores skip check - workflow_dispatch: +on: [push, pull_request] jobs: pre-job: @@ -19,11 +11,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - # but never cancel main - cancel_others: ${{ github.ref != 'refs/heads/main' }} + cancel_others: 'true' + # only run on push *or* pull_request, not both + concurrent_skipping: 'same_content_newer' test-verific: needs: pre-job From 6cbd44daa5362b87a084809f6f3b6808815a08ba Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Mon, 18 Aug 2025 22:34:15 +0300 Subject: [PATCH 138/176] wheels: bison 3.8 on almalinux + memory pressure easing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - cibw now builds and uses bison 3.8.2 explicitly on platforms with no or out-of-date bison — AlmaLinux 8 only goes up to Bison 3.0 - cibw environment now includes `OPTFLAGS=-O3` to avoid generating debug info for abc, saving space in memory during linking - setup.py attempts to build `yosys-abc` independently first to avoid memory pressure from gigantic abc link step running in parallel with something else --- .github/workflows/wheels.yml | 15 ++++++--- .github/workflows/wheels/_run_cibw_linux.py | 14 ++++++-- .github/workflows/wheels/cibw_before_all.sh | 36 ++++++++++++++------- .gitignore | 1 + setup.py | 20 +++++++++--- 5 files changed, 64 insertions(+), 22 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d81e340aa..b48b981a8 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -4,7 +4,7 @@ name: Build Wheels for PyPI on: workflow_dispatch: schedule: - - cron: '0 10 * * 0' + - cron: "0 10 * * 0" jobs: build_wheels: @@ -54,9 +54,6 @@ jobs: fetch-depth: 0 submodules: true persist-credentials: false - - if: ${{ matrix.os.family == 'linux' }} - name: "[Linux] Set up QEMU" - uses: docker/setup-qemu-action@v3 - uses: actions/setup-python@v5 - name: Get Boost Source shell: bash @@ -68,6 +65,12 @@ jobs: run: | mkdir -p ffi curl -L https://github.com/libffi/libffi/releases/download/v3.4.6/libffi-3.4.6.tar.gz | tar --strip-components=1 -xzC ffi + - if: ${{ matrix.os.family == 'linux' }} + name: "[Linux] Bison 3.8.2" + shell: bash + run: | + mkdir -p bison + curl -L https://ftpmirror.gnu.org/gnu/bison/bison-3.8.2.tar.gz | tar --strip-components=1 -xzC bison ## Software installed by default in GitHub Action Runner VMs: ## https://github.com/actions/runner-images - if: ${{ matrix.os.family == 'macos' }} @@ -100,16 +103,20 @@ jobs: CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28 CIBW_BEFORE_ALL: bash ./.github/workflows/wheels/cibw_before_all.sh CIBW_ENVIRONMENT: > + OPTFLAGS=-O3 CXXFLAGS=-I./boost/pfx/include LINKFLAGS=-L./boost/pfx/lib PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a' + PATH=$PWD/bison/src:$PATH CIBW_ENVIRONMENT_MACOS: > + OPTFLAGS=-O3 CXXFLAGS=-I./boost/pfx/include LINKFLAGS=-L./boost/pfx/lib PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig MACOSX_DEPLOYMENT_TARGET=11 makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a CONFIG=clang' + PATH=$PWD/bison/src:$PATH CIBW_BEFORE_BUILD: bash ./.github/workflows/wheels/cibw_before_build.sh CIBW_TEST_COMMAND: python3 {project}/tests/arch/ecp5/add_sub.py - uses: actions/upload-artifact@v4 diff --git a/.github/workflows/wheels/_run_cibw_linux.py b/.github/workflows/wheels/_run_cibw_linux.py index 894470a5a..fb4e0b839 100644 --- a/.github/workflows/wheels/_run_cibw_linux.py +++ b/.github/workflows/wheels/_run_cibw_linux.py @@ -20,11 +20,19 @@ import os import yaml import platform import subprocess +from pathlib import Path -__dir__ = os.path.dirname(os.path.abspath(__file__)) +__yosys_root__ = Path(__file__).absolute().parents[3] +for source in ["boost", "ffi", "bison"]: + if not (__yosys_root__ / source).is_dir(): + print( + "You need to download boost, ffi and bison in a similar manner to wheels.yml first." + ) + exit(-1) -workflow = yaml.safe_load(open(os.path.join(os.path.dirname(__dir__), "wheels.yml"))) +with open(__yosys_root__ / ".github" / "workflows" / "wheels.yml") as f: + workflow = yaml.safe_load(f) env = os.environ.copy() @@ -40,5 +48,5 @@ for key, value in cibw_step["env"].items(): continue env[key] = value -env["CIBW_ARCHS"] = os.getenv("CIBW_ARCHS") or platform.machine() +env["CIBW_ARCHS"] = os.getenv("CIBW_ARCHS", platform.machine()) subprocess.check_call(["cibuildwheel"], env=env) diff --git a/.github/workflows/wheels/cibw_before_all.sh b/.github/workflows/wheels/cibw_before_all.sh index fbb8dcad8..1aef650d7 100644 --- a/.github/workflows/wheels/cibw_before_all.sh +++ b/.github/workflows/wheels/cibw_before_all.sh @@ -1,23 +1,37 @@ -set -e -set -x +#!/bin/bash +set -e -x # Build-time dependencies ## Linux Docker Images if command -v yum &> /dev/null; then - yum install -y flex bison + yum install -y flex # manylinux's bison versions are hopelessly out of date fi if command -v apk &> /dev/null; then apk add flex bison fi +if ! printf '%s\n' '%require "3.8"' '%%' 'start: ;' | bison -o /dev/null /dev/stdin ; then + ( + set -e -x + cd bison + ./configure + make clean + make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu) + ) +fi + ## macOS/Windows -- installed in GitHub Action itself, not container -# Build Static FFI (platform-dependent but not Python version dependent) -cd ffi -## Ultimate libyosys.so will be shared, so we need fPIC for the static libraries -CFLAGS=-fPIC CXXFLAGS=-fPIC ./configure --prefix=$PWD/pfx -## Without this, SHELL has a space in its path which breaks the makefile -make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu) -## Forces static library to be used in all situations -sed -i.bak 's@-L${toolexeclibdir} -lffi@${toolexeclibdir}/libffi.a@' ./pfx/lib/pkgconfig/libffi.pc +# Runtime Dependencies +## Build Static FFI (platform-dependent but not Python version dependent) +( + set -e -x + cd ffi + ## Ultimate libyosys.so will be shared, so we need fPIC for the static libraries + CFLAGS=-fPIC CXXFLAGS=-fPIC ./configure --prefix=$PWD/pfx + make clean + make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu) + ## Forces static library to be used in all situations + sed -i.bak 's@-L${toolexeclibdir} -lffi@${toolexeclibdir}/libffi.a@' ./pfx/lib/pkgconfig/libffi.pc +) diff --git a/.gitignore b/.gitignore index 3b77edf1f..cac630d7c 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,7 @@ /kernel/python_wrappers.cc /boost /ffi +/bison /venv /*.whl /*.egg-info diff --git a/setup.py b/setup.py index a199530d0..4a6ef5af9 100644 --- a/setup.py +++ b/setup.py @@ -51,16 +51,27 @@ class libyosys_so_ext(Extension): ] def custom_build(self, bext: build_ext): + make_flags_split = shlex.split(os.getenv("makeFlags", "")) + # abc linking takes a lot of memory, best get it out of the way first + bext.spawn( + [ + "make", + f"-j{os.cpu_count() or 1}", + "yosys-abc", + *make_flags_split, + *self.args, + ] + ) + # build libyosys and share with abc out of the way bext.spawn( [ "make", f"-j{os.cpu_count() or 1}", self.name, - "yosys-abc", "share", + *make_flags_split, + *self.args, ] - + shlex.split(os.getenv("makeFlags", "")) - + self.args ) build_path = os.path.dirname(os.path.dirname(bext.get_ext_fullpath(self.name))) pyosys_path = os.path.join(build_path, "pyosys") @@ -85,6 +96,7 @@ class libyosys_so_ext(Extension): shutil.copytree("share", share_target) + class custom_build_ext(build_ext): def build_extension(self, ext) -> None: if not hasattr(ext, "custom_build"): @@ -100,8 +112,8 @@ setup( long_description=open(os.path.join(__dir__, "README.md")).read(), long_description_content_type="text/markdown", install_requires=["wheel", "setuptools"], + license="MIT", classifiers=[ - "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Intended Audience :: Developers", "Operating System :: POSIX :: Linux", From 2ed7a7aac92a8f2fc9148a11b2f536f7f7468792 Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Tue, 19 Aug 2025 01:28:46 +0300 Subject: [PATCH 139/176] wheels: fix PATH variables --- .github/workflows/wheels.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index b48b981a8..41d9183fc 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -77,8 +77,7 @@ jobs: name: "[macOS] Flex/Bison" run: | brew install flex bison - echo "PATH=$(brew --prefix flex)/bin:$PATH" >> $GITHUB_ENV - echo "PATH=$(brew --prefix bison)/bin:$PATH" >> $GITHUB_ENV + echo "PATH=$(brew --prefix flex)/bin:$(brew --prefix bison)/bin:$PATH" >> $GITHUB_ENV - if: ${{ matrix.os.family == 'windows' }} name: "[Windows] Flex/Bison" run: | @@ -108,7 +107,7 @@ jobs: LINKFLAGS=-L./boost/pfx/lib PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a' - PATH=$PWD/bison/src:$PATH + PATH="$PWD/bison/src:$PATH" CIBW_ENVIRONMENT_MACOS: > OPTFLAGS=-O3 CXXFLAGS=-I./boost/pfx/include @@ -116,7 +115,7 @@ jobs: PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig MACOSX_DEPLOYMENT_TARGET=11 makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a CONFIG=clang' - PATH=$PWD/bison/src:$PATH + PATH="$PWD/bison/src:$PATH" CIBW_BEFORE_BUILD: bash ./.github/workflows/wheels/cibw_before_build.sh CIBW_TEST_COMMAND: python3 {project}/tests/arch/ecp5/add_sub.py - uses: actions/upload-artifact@v4 From eb773ce071339316034e1dc89156dd686db6bbc2 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 19 Aug 2025 11:29:53 +1200 Subject: [PATCH 140/176] Reapply "Workflow adjustments" This reverts commit b640a16b07ec7c313ee3d97a4a84b0eccd3d59f9. --- .github/workflows/extra-builds.yml | 16 +++- .github/workflows/test-build.yml | 36 +++++---- .github/workflows/test-compile.yml | 16 +++- .github/workflows/test-sanitizers.yml | 105 ++++++++++++++++++++++++++ .github/workflows/test-verific.yml | 16 +++- 5 files changed, 161 insertions(+), 28 deletions(-) create mode 100644 .github/workflows/test-sanitizers.yml diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 458eb76a6..11fd42a6c 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -1,6 +1,14 @@ name: Test extra build flows -on: [push, pull_request] +on: + # always test main + push: + branches: + - main + # test PRs + pull_request: + # allow triggering tests, ignores skip check + workflow_dispatch: jobs: pre_job: @@ -11,11 +19,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: + # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - cancel_others: 'true' - # only run on push *or* pull_request, not both - concurrent_skipping: 'same_content_newer' + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} vs-prep: name: Prepare Visual Studio build diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index f9574594a..f44dee1ba 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -1,6 +1,14 @@ name: Build and run tests -on: [push, pull_request] +on: + # always test main + push: + branches: + - main + # test PRs + pull_request: + # allow triggering tests, ignores skip check + workflow_dispatch: jobs: pre_job: @@ -11,11 +19,12 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: + # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - cancel_others: 'true' - # only run on push *or* pull_request, not both - concurrent_skipping: 'same_content_newer' + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} + pre_docs_job: runs-on: ubuntu-latest outputs: @@ -24,15 +33,16 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: + # don't run on readme changes paths_ignore: '["**/README.md"]' # cancel previous builds if a new commit is pushed - cancel_others: 'true' - # only run on push *or* pull_request, not both - concurrent_skipping: 'same_content_newer' + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} build-yosys: name: Reusable build runs-on: ${{ matrix.os }} + # pre_job is a subset of pre_docs_job, so we can always build for pre_docs_job needs: pre_docs_job if: needs.pre_docs_job.outputs.should_skip != 'true' env: @@ -40,7 +50,6 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] - sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -58,7 +67,6 @@ jobs: mkdir build cd build make -f ../Makefile config-$CC - echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf make -f ../Makefile -j$procs ENABLE_LTO=1 - name: Log yosys-config output @@ -74,7 +82,7 @@ jobs: - name: Store build artifact uses: actions/upload-artifact@v4 with: - name: build-${{ matrix.os }}-${{ matrix.sanitizer }} + name: build-${{ matrix.os }} path: build.tar retention-days: 1 @@ -85,12 +93,9 @@ jobs: if: needs.pre_job.outputs.should_skip != 'true' env: CC: clang - ASAN_OPTIONS: halt_on_error=1 - UBSAN_OPTIONS: halt_on_error=1 strategy: matrix: os: [ubuntu-latest, macos-latest] - sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -139,7 +144,7 @@ jobs: - name: Download build artifact uses: actions/download-artifact@v4 with: - name: build-${{ matrix.os }}-${{ matrix.sanitizer }} + name: build-${{ matrix.os }} - name: Uncompress build shell: bash @@ -209,7 +214,6 @@ jobs: strategy: matrix: os: [ubuntu-latest] - sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -223,7 +227,7 @@ jobs: - name: Download build artifact uses: actions/download-artifact@v4 with: - name: build-${{ matrix.os }}-${{ matrix.sanitizer }} + name: build-${{ matrix.os }} - name: Uncompress build shell: bash diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index 7a706e69a..f208b911a 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -1,6 +1,14 @@ name: Compiler testing -on: [push, pull_request] +on: + # always test main + push: + branches: + - main + # test PRs + pull_request: + # allow triggering tests, ignores skip check + workflow_dispatch: jobs: pre_job: @@ -11,11 +19,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: + # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - cancel_others: 'true' - # only run on push *or* pull_request, not both - concurrent_skipping: 'same_content_newer' + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} test-compile: runs-on: ${{ matrix.os }} diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml new file mode 100644 index 000000000..fb76d1266 --- /dev/null +++ b/.github/workflows/test-sanitizers.yml @@ -0,0 +1,105 @@ +name: Check clang sanitizers + +on: + # always test main + push: + branches: + - main + # ignore PRs due to time needed + # allow triggering tests, ignores skip check + workflow_dispatch: + +jobs: + pre_job: + runs-on: ubuntu-latest + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5 + with: + # don't run on documentation changes + paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' + + run_san: + name: Build and run tests + runs-on: ${{ matrix.os }} + needs: pre_job + if: needs.pre_job.outputs.should_skip != 'true' + env: + CC: clang + ASAN_OPTIONS: halt_on_error=1 + UBSAN_OPTIONS: halt_on_error=1 + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + sanitizer: ['undefined,address'] + fail-fast: false + steps: + - name: Checkout Yosys + uses: actions/checkout@v4 + with: + submodules: true + persist-credentials: false + + - name: Setup environment + uses: ./.github/actions/setup-build-env + + - name: Build + shell: bash + run: | + mkdir build + cd build + make -f ../Makefile config-$CC + echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf + make -f ../Makefile -j$procs ENABLE_LTO=1 + + - name: Log yosys-config output + run: | + ./yosys-config || true + + - name: Get iverilog + shell: bash + run: | + git clone https://github.com/steveicarus/iverilog.git + cd iverilog + echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_ENV + + - name: Get vcd2fst + shell: bash + run: | + git clone https://github.com/mmicko/libwave.git + mkdir -p ${{ github.workspace }}/.local/ + cd libwave + cmake . -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/.local + make -j$procs + make install + + - name: Cache iverilog + id: cache-iverilog + uses: actions/cache@v4 + with: + path: .local/ + key: ${{ matrix.os }}-${IVERILOG_GIT} + + - name: Build iverilog + if: steps.cache-iverilog.outputs.cache-hit != 'true' + shell: bash + run: | + mkdir -p ${{ github.workspace }}/.local/ + cd iverilog + autoconf + CC=gcc CXX=g++ ./configure --prefix=${{ github.workspace }}/.local + make -j$procs + make install + + - name: Run tests + shell: bash + run: | + make -j$procs test TARGETS= EXTRA_TARGETS= CONFIG=$CC + + - name: Report errors + if: ${{ failure() }} + shell: bash + run: | + find tests/**/*.err -print -exec cat {} \; diff --git a/.github/workflows/test-verific.yml b/.github/workflows/test-verific.yml index 013c9f8ca..9af07b920 100644 --- a/.github/workflows/test-verific.yml +++ b/.github/workflows/test-verific.yml @@ -1,6 +1,14 @@ name: Build and run tests with Verific (Linux) -on: [push, pull_request] +on: + # always test main + push: + branches: + - main + # test PRs + pull_request: + # allow triggering tests, ignores skip check + workflow_dispatch: jobs: pre-job: @@ -11,11 +19,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: + # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - cancel_others: 'true' - # only run on push *or* pull_request, not both - concurrent_skipping: 'same_content_newer' + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} test-verific: needs: pre-job From b42be1df80470eba66ebb1e120379c44edf89652 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 19 Aug 2025 10:40:42 +1200 Subject: [PATCH 141/176] ci: Fix test-cells --- .github/workflows/test-build.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index f44dee1ba..acc295f4a 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -176,7 +176,6 @@ jobs: strategy: matrix: os: [ubuntu-latest] - sanitizer: [undefined] steps: - name: Checkout Yosys uses: actions/checkout@v4 @@ -189,7 +188,7 @@ jobs: - name: Download build artifact uses: actions/download-artifact@v4 with: - name: build-${{ matrix.os }}-${{ matrix.sanitizer }} + name: build-${{ matrix.os }} - name: Uncompress build shell: bash From d63f43acf0c532b6c0f04e41f873f9c7dec18dd9 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 19 Aug 2025 10:46:02 +1200 Subject: [PATCH 142/176] ci: iverilog before yosys --- .github/workflows/test-sanitizers.yml | 31 ++++++++++++++++----------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml index fb76d1266..d4dfb9d84 100644 --- a/.github/workflows/test-sanitizers.yml +++ b/.github/workflows/test-sanitizers.yml @@ -45,19 +45,6 @@ jobs: - name: Setup environment uses: ./.github/actions/setup-build-env - - name: Build - shell: bash - run: | - mkdir build - cd build - make -f ../Makefile config-$CC - echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf - make -f ../Makefile -j$procs ENABLE_LTO=1 - - - name: Log yosys-config output - run: | - ./yosys-config || true - - name: Get iverilog shell: bash run: | @@ -93,6 +80,24 @@ jobs: make -j$procs make install + - name: Check iverilog + shell: bash + run: | + iverilog -V + + - name: Build + shell: bash + run: | + mkdir build + cd build + make -f ../Makefile config-$CC + echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf + make -f ../Makefile -j$procs ENABLE_LTO=1 + + - name: Log yosys-config output + run: | + ./yosys-config || true + - name: Run tests shell: bash run: | From 94d07872e6b29b72c91eb673d30208f9235fa5e5 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 19 Aug 2025 11:12:11 +1200 Subject: [PATCH 143/176] test-sanitizers.yml: Build in-tree Should fix missing `../../yosys-abc` --- .github/workflows/test-sanitizers.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml index d4dfb9d84..5639f6286 100644 --- a/.github/workflows/test-sanitizers.yml +++ b/.github/workflows/test-sanitizers.yml @@ -88,11 +88,9 @@ jobs: - name: Build shell: bash run: | - mkdir build - cd build - make -f ../Makefile config-$CC + make config-$CC echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf - make -f ../Makefile -j$procs ENABLE_LTO=1 + make -j$procs ENABLE_LTO=1 - name: Log yosys-config output run: | From 1cdf058df476d413bbdd486541a9cd1da426dbbd Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 19 Aug 2025 11:02:34 +1200 Subject: [PATCH 144/176] ci: Fix iverilog version caching --- .github/workflows/test-build.yml | 5 +++-- .github/workflows/test-sanitizers.yml | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index acc295f4a..16ad98bec 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -107,11 +107,12 @@ jobs: uses: ./.github/actions/setup-build-env - name: Get iverilog + id: get-iverilog shell: bash run: | git clone https://github.com/steveicarus/iverilog.git cd iverilog - echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_ENV + echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT - name: Get vcd2fst shell: bash @@ -128,7 +129,7 @@ jobs: uses: actions/cache@v4 with: path: .local/ - key: ${{ matrix.os }}-${IVERILOG_GIT} + key: ${{ matrix.os }}-${{ steps.get-iverilog.outputs.IVERILOG_GIT }} - name: Build iverilog if: steps.cache-iverilog.outputs.cache-hit != 'true' diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml index 5639f6286..255b9daa5 100644 --- a/.github/workflows/test-sanitizers.yml +++ b/.github/workflows/test-sanitizers.yml @@ -46,11 +46,12 @@ jobs: uses: ./.github/actions/setup-build-env - name: Get iverilog + id: get-iverilog shell: bash run: | git clone https://github.com/steveicarus/iverilog.git cd iverilog - echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_ENV + echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT - name: Get vcd2fst shell: bash @@ -67,7 +68,7 @@ jobs: uses: actions/cache@v4 with: path: .local/ - key: ${{ matrix.os }}-${IVERILOG_GIT} + key: ${{ matrix.os }}-${{ steps.get-iverilog.outputs.IVERILOG_GIT }} - name: Build iverilog if: steps.cache-iverilog.outputs.cache-hit != 'true' From bfc9a322e2a854418e6679e141be3d482dde808c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 00:24:35 +0000 Subject: [PATCH 145/176] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d9f9f432b..5165db4a0 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+141 +YOSYS_VER := 0.56+152 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 3ca2b7951fb35f1714a4b2dbb69f8e199ea94997 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 19 Aug 2025 17:05:51 +1200 Subject: [PATCH 146/176] memlib: Fix ubsan --- passes/memory/memlib.cc | 2 +- passes/memory/memlib.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/memory/memlib.cc b/passes/memory/memlib.cc index 8a7adc9ac..3a8c3c06e 100644 --- a/passes/memory/memlib.cc +++ b/passes/memory/memlib.cc @@ -878,7 +878,7 @@ struct Parser { } } } - var.clk_en = find_single_cap(pdef.clken, cram.options, portopts, "clken"); + var.clk_en = find_single_cap(pdef.clken, cram.options, portopts, "clken") != nullptr; } const PortWidthDef *wdef = find_single_cap(pdef.width, cram.options, portopts, "width"); if (wdef) { diff --git a/passes/memory/memlib.h b/passes/memory/memlib.h index 43dec7386..7394baf4e 100644 --- a/passes/memory/memlib.h +++ b/passes/memory/memlib.h @@ -109,7 +109,7 @@ struct PortVariant { PortKind kind; int clk_shared; ClkPolKind clk_pol; - bool clk_en; + bool clk_en = false; bool width_tied; int min_wr_wide_log2; int max_wr_wide_log2; From e1276560cd142995473b97df375c5928ca79d634 Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Tue, 19 Aug 2025 23:48:45 +0300 Subject: [PATCH 147/176] opt_dff: add another test --- tests/opt/opt_dff-simplify.ys | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/opt/opt_dff-simplify.ys b/tests/opt/opt_dff-simplify.ys index 3a4d6778c..a803c2475 100644 --- a/tests/opt/opt_dff-simplify.ys +++ b/tests/opt/opt_dff-simplify.ys @@ -1,3 +1,6 @@ +# 5287 issue +# Check only for complimentary patterns elimination + read_rtlil opt_dff-simplify.il opt_dff @@ -10,3 +13,31 @@ select -assert-none t:$ne r:A_WIDTH=15 %i select -assert-none t:$ne r:A_WIDTH=10 %i select -assert-none t:$ne r:A_WIDTH=12 %i select -assert-none t:$ne r:A_WIDTH=11 %i + +# Check for both complimentary and redundancy elimination + +read_verilog << EOT +module test(input clk, input h, input i, input m, output reg p); + wire D; + wire a; + wire j; + wire c; + wire mux_test; + wire n; + + always @(posedge clk) + p <= D; + assign j = n ? 1'hx : a; + assign a = i ? mux_test : p; + assign D = m ? h : j; + assign c = n ? 1'hx : p; + assign mux_test = m ? 1'hx : c; +endmodule +EOT + +cd test +proc +opt_dff + +select -assert-count 1 t:$ne r:A_WIDTH=2 %i +select -assert-none t:$ne r:A_WIDTH=3 %i From 3a5742ffd2e9a34b10af9a87748a7f1a7e94e62d Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 19 Aug 2025 03:21:54 +0000 Subject: [PATCH 148/176] Improve commutative hashing. The simple XOR `commutative_eat()` implementation produces a lot of collisions. https://www.preprints.org/manuscript/201710.0192/v1/download is a useful reference on this topic. Running the included `hashTest.cc` without the hashlib changes, I get 49,580,349 collisions. The 49,995,000 (i,j) pairs (0 <= i < 10000, i < j < 10000) hash into only 414,651 unique hash values. We get simple collisions like (0,1) colliding with (2,3). With the hashlib changes, we get only 707,099 collisions and 49,287,901 unique hash values. Much better! The `commutative_hash` implementation corresponds to `Sum(4)` in the paper mentioned above. --- kernel/hashlib.h | 39 ++++++++++++++++++++++++------ kernel/yosys_common.h | 1 + tests/unit/kernel/hashTest.cc | 45 +++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 tests/unit/kernel/hashTest.cc diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 7a5650fa3..b43b7302e 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -12,6 +12,7 @@ #ifndef HASHLIB_H #define HASHLIB_H +#include #include #include #include @@ -100,7 +101,7 @@ private: uint32_t hash = ((a << 5) + a) ^ b; return hash; } - public: +public: void hash32(uint32_t i) { state = djb2_xor(i, state); state = mkhash_xorshift(fudge ^ state); @@ -127,6 +128,7 @@ private: *this = hash_ops::hash_into(t, *this); } + [[deprecated]] void commutative_eat(hash_t t) { state ^= t; } @@ -356,6 +358,29 @@ template> class idict; template> class pool; template> class mfp; +// Computes the hash value of an unordered set of elements. +// See https://www.preprints.org/manuscript/201710.0192/v1/download. +// This is the Sum(4) algorithm from that paper, which has good collision resistance, +// much better than Sum(1) or Xor(1) (and somewhat better than Xor(4)). +class commutative_hash { +public: + commutative_hash() { + buckets.fill(0); + } + void eat(Hasher h) { + Hasher::hash_t v = h.yield(); + size_t index = v & (buckets.size() - 1); + buckets[index] += v; + } + [[nodiscard]] Hasher hash_into(Hasher h) const { + for (auto b : buckets) + h.eat(b); + return h; + } +private: + std::array buckets; +}; + template class dict { struct entry_t @@ -801,14 +826,14 @@ public: } [[nodiscard]] Hasher hash_into(Hasher h) const { + commutative_hash comm; for (auto &it : entries) { Hasher entry_hash; entry_hash.eat(it.udata.first); entry_hash.eat(it.udata.second); - h.commutative_eat(entry_hash.yield()); + comm.eat(entry_hash); } - h.eat(entries.size()); - return h; + return comm.hash_into(h); } void reserve(size_t n) { entries.reserve(n); } @@ -1184,11 +1209,11 @@ public: } [[nodiscard]] Hasher hash_into(Hasher h) const { + commutative_hash comm; for (auto &it : entries) { - h.commutative_eat(ops.hash(it.udata).yield()); + comm.eat(ops.hash(it.udata)); } - h.eat(entries.size()); - return h; + return comm.hash_into(h); } void reserve(size_t n) { entries.reserve(n); } diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index ecc8ce623..bc92e7869 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -20,6 +20,7 @@ #ifndef YOSYS_COMMON_H #define YOSYS_COMMON_H +#include #include #include #include diff --git a/tests/unit/kernel/hashTest.cc b/tests/unit/kernel/hashTest.cc new file mode 100644 index 000000000..6e4610ec8 --- /dev/null +++ b/tests/unit/kernel/hashTest.cc @@ -0,0 +1,45 @@ +#include +#include "kernel/yosys_common.h" + +#include + +YOSYS_NAMESPACE_BEGIN + +static Hasher hash(int x) +{ + Hasher h; + h.eat(x); + return h; +} + +TEST(CommutativeTest, basic) +{ + hashlib::commutative_hash comm1; + comm1.eat(hash(1)); + comm1.eat(hash(2)); + hashlib::commutative_hash comm2; + comm2.eat(hash(2)); + comm2.eat(hash(1)); + EXPECT_EQ(comm1.hash_into(Hasher()).yield(), comm2.hash_into(Hasher()).yield()); +} + +TEST(PoolHashTest, collisions) +{ + uint64_t collisions = 0; + std::unordered_set hashes; + for (int i = 0; i < 10000; ++i) { + for (int j = i + 1; j < 10000; ++j) { + pool p1; + p1.insert(i); + p1.insert(j); + auto h = p1.hash_into(Hasher()).yield(); + if (!hashes.insert(h).second) { + ++collisions; + } + } + } + std::cout << "pool collisions: " << collisions << std::endl; + EXPECT_LT(collisions, 1000000); +} + +YOSYS_NAMESPACE_END From 01de9fb453f8fadc23067d5c7e2442fcd1013d97 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 19 Aug 2025 16:35:34 +0200 Subject: [PATCH 149/176] hashlib: extend unit test with subset collisions, shorten runtime --- tests/unit/kernel/hashTest.cc | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/tests/unit/kernel/hashTest.cc b/tests/unit/kernel/hashTest.cc index 6e4610ec8..319d064a7 100644 --- a/tests/unit/kernel/hashTest.cc +++ b/tests/unit/kernel/hashTest.cc @@ -27,8 +27,8 @@ TEST(PoolHashTest, collisions) { uint64_t collisions = 0; std::unordered_set hashes; - for (int i = 0; i < 10000; ++i) { - for (int j = i + 1; j < 10000; ++j) { + for (int i = 0; i < 1000; ++i) { + for (int j = i + 1; j < 1000; ++j) { pool p1; p1.insert(i); p1.insert(j); @@ -39,7 +39,29 @@ TEST(PoolHashTest, collisions) } } std::cout << "pool collisions: " << collisions << std::endl; - EXPECT_LT(collisions, 1000000); + EXPECT_LT(collisions, 10'000); +} + +TEST(PoolHashTest, subset_collisions) +{ + uint64_t collisions = 0; + std::unordered_set hashes; + for (int i = 0; i < 1000 * 1000; ++i) { + + pool p1; + for (int b = 0; i >> b; ++b) { + if ((i >> b) & 1) { + p1.insert(b); + } + } + auto h = p1.hash_into(Hasher()).yield(); + if (!hashes.insert(h).second) { + ++collisions; + } + + } + std::cout << "pool subset collisions: " << collisions << std::endl; + EXPECT_LT(collisions, 100); } YOSYS_NAMESPACE_END From 7d0ea0d64f4e5845d78d9dc6c1757e909b0c4ada Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 19 Aug 2025 05:41:08 +0000 Subject: [PATCH 150/176] Refactor call to sorted_pmux_in to avoid copying the connection dictionary --- passes/opt/opt_merge.cc | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index 5ca19bc2f..f9ee7ba40 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -44,11 +44,8 @@ struct OptMergeWorker CellTypes ct; int total_count; - static vector> sorted_pmux_in(const dict &conn) + static vector> sorted_pmux_in(const SigSpec& sig_s, const SigSpec& sig_b) { - SigSpec sig_s = conn.at(ID::S); - SigSpec sig_b = conn.at(ID::B); - int s_width = GetSize(sig_s); int width = GetSize(sig_b) / s_width; @@ -104,11 +101,9 @@ struct OptMergeWorker a.sort_and_unify(); h = a.hash_into(h); } else if (cell->type == ID($pmux)) { - dict conn = cell->connections(); - assign_map.apply(conn.at(ID::A)); - assign_map.apply(conn.at(ID::B)); - assign_map.apply(conn.at(ID::S)); - for (const auto& [s_bit, b_chunk] : sorted_pmux_in(conn)) { + SigSpec sig_s = assign_map(cell->getPort(ID::S)); + SigSpec sig_b = assign_map(cell->getPort(ID::B)); + for (const auto& [s_bit, b_chunk] : sorted_pmux_in(sig_s, sig_b)) { h = s_bit.hash_into(h); h = b_chunk.hash_into(h); } From 8c04e5266c1819b21e2656dd2083948ecf914082 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 19 Aug 2025 05:09:16 +0000 Subject: [PATCH 151/176] Use commutative hashing instead of expensive allocation and sorting For one of our large circuits, this improves the `OptMergePass` runtime from about 150s to about 130s. It's also simpler code. --- passes/opt/opt_merge.cc | 50 +++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index f9ee7ba40..ba8168e74 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -44,17 +44,16 @@ struct OptMergeWorker CellTypes ct; int total_count; - static vector> sorted_pmux_in(const SigSpec& sig_s, const SigSpec& sig_b) + static Hasher hash_pmux_in(const SigSpec& sig_s, const SigSpec& sig_b, Hasher h) { int s_width = GetSize(sig_s); int width = GetSize(sig_b) / s_width; - vector> sb_pairs; + hashlib::commutative_hash comm; for (int i = 0; i < s_width; i++) - sb_pairs.push_back(pair(sig_s[i], sig_b.extract(i*width, width))); + comm.eat(hash_ops>::hash({sig_s[i], sig_b.extract(i*width, width)})); - std::sort(sb_pairs.begin(), sb_pairs.end()); - return sb_pairs; + return comm.hash_into(h); } static void sort_pmux_conn(dict &conn) @@ -86,12 +85,10 @@ struct OptMergeWorker // (builtin || stdcell) && (unary || binary) && symmetrical if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($mul), ID($logic_and), ID($logic_or), ID($_AND_), ID($_OR_), ID($_XOR_))) { - std::array inputs = { - assign_map(cell->getPort(ID::A)), - assign_map(cell->getPort(ID::B)) - }; - std::sort(inputs.begin(), inputs.end()); - h = hash_ops>::hash_into(inputs, h); + hashlib::commutative_hash comm; + comm.eat(hash_ops::hash(assign_map(cell->getPort(ID::A)))); + comm.eat(hash_ops::hash(assign_map(cell->getPort(ID::B)))); + h = comm.hash_into(h); } else if (cell->type.in(ID($reduce_xor), ID($reduce_xnor))) { SigSpec a = assign_map(cell->getPort(ID::A)); a.sort(); @@ -103,40 +100,29 @@ struct OptMergeWorker } else if (cell->type == ID($pmux)) { SigSpec sig_s = assign_map(cell->getPort(ID::S)); SigSpec sig_b = assign_map(cell->getPort(ID::B)); - for (const auto& [s_bit, b_chunk] : sorted_pmux_in(sig_s, sig_b)) { - h = s_bit.hash_into(h); - h = b_chunk.hash_into(h); - } + h = hash_pmux_in(sig_s, sig_b, h); h = assign_map(cell->getPort(ID::A)).hash_into(h); } else { - std::vector> conns; - for (const auto& conn : cell->connections()) { - conns.push_back(conn); + hashlib::commutative_hash comm; + for (const auto& [port, sig] : cell->connections()) { + if (cell->output(port)) + continue; + comm.eat(hash_ops>::hash({port, assign_map(sig)})); } - std::sort(conns.begin(), conns.end()); - for (const auto& [port, sig] : conns) { - if (!cell->output(port)) { - h = port.hash_into(h); - h = assign_map(sig).hash_into(h); - } - } - + h = comm.hash_into(h); if (RTLIL::builtin_ff_cell_types().count(cell->type)) h = initvals(cell->getPort(ID::Q)).hash_into(h); - } return h; } static Hasher hash_cell_parameters(const RTLIL::Cell *cell, Hasher h) { - using Paramvec = std::vector>; - Paramvec params; + hashlib::commutative_hash comm; for (const auto& param : cell->parameters) { - params.push_back(param); + comm.eat(hash_ops>::hash(param)); } - std::sort(params.begin(), params.end()); - return hash_ops::hash_into(params, h); + return comm.hash_into(h); } Hasher hash_cell_function(const RTLIL::Cell *cell, Hasher h) const From 4926e846f6a81de2a98c1df6ccde4e6c72cd2815 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 00:22:37 +0000 Subject: [PATCH 152/176] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5165db4a0..19fab9780 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+152 +YOSYS_VER := 0.56+165 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 7f0130efce1ac96a0f4b4a30326ab98541258bd1 Mon Sep 17 00:00:00 2001 From: Ethan Mahintorabi Date: Wed, 20 Aug 2025 22:56:26 +0000 Subject: [PATCH 153/176] verilog: Fix missing sstream include Signed-off-by: Ethan Mahintorabi --- frontends/verilog/verilog_location.h | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/verilog/verilog_location.h b/frontends/verilog/verilog_location.h index 9b530fbeb..8ffe0552d 100644 --- a/frontends/verilog/verilog_location.h +++ b/frontends/verilog/verilog_location.h @@ -5,6 +5,7 @@ #include #include #include +#include /** * Provide frontend-wide location tracking like what bison generates From d10190606c34cc0d3b53679d32f5dd9448044dd4 Mon Sep 17 00:00:00 2001 From: Ethan Mahintorabi Date: Wed, 20 Aug 2025 22:58:51 +0000 Subject: [PATCH 154/176] verilog: Lower required bison version to 3.6 We're currently on version 3.6 of bison at Google, and Yosys still correctly builds with it. This should better reflect the actual requirements rather than an overly restrictive check. If features from 3.8 are required it seems like bumping would be appropriate. Signed-off-by: Ethan Mahintorabi --- frontends/verilog/verilog_parser.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index e299d3148..392d8921a 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -33,7 +33,7 @@ * */ -%require "3.8" +%require "3.6" %language "c++" %define api.value.type variant %define api.prefix {frontend_verilog_yy} From 4dea77417153a90b4e55101386649300733b75ed Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 18 Aug 2025 17:22:47 +0200 Subject: [PATCH 155/176] opt_muxtree: refactor --- passes/opt/opt_muxtree.cc | 415 ++++++++++++++++++++++++-------------- 1 file changed, 260 insertions(+), 155 deletions(-) diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc index e1ed5da08..ae9b1a632 100644 --- a/passes/opt/opt_muxtree.cc +++ b/passes/opt/opt_muxtree.cc @@ -30,7 +30,33 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -using RTLIL::id2cstr; +/** + * TERMINOLOGY + * + * A multiplexer tree (mux tree) is a tree composed exclusively of muxes. + * By mux, I mean $mux or $pmux. By port, I usually mean input port. + * The children of a node are all the muxes driving its input ports (A, B). + * It must be rooted in a "root mux", a mux which has multiple mux users + * or any number of non-mux users. Only the root and leaf nodes can be + * root muxes, not the internal nodes. Leaf nodes that are root muxes + * are roots of "input trees". + * + * OPERATING PRINCIPLE + * + * This pass traverses mux trees, learning port activations and making + * assumptions about them as it goes. When valid, ports are replaced + * with constants, or removed if they can never be activated. + * When valid, muxes are replaced with shorts from port to output, + * or removed if their outputs are found to be no longer observable. + * + * Input trees can be recursed into if limits_t::recursions_left allows. + * Otherwise, the input tree is queued for a re-run with a fresh knowledge_t. + * At any point, if glob_evals_left goes to 0, the pass terminates. + * + * Unlike share, this pass doesn't use SAT to learn things about logic + * driving the mux control signals, and traverses mux regions from users + * to drivers. + */ struct OptMuxtreeWorker { @@ -38,9 +64,10 @@ struct OptMuxtreeWorker RTLIL::Module *module; SigMap assign_map; int removed_count; - int glob_abort_cnt = 100000; + int glob_evals_left = 100000; struct bitinfo_t { + // Is bit directly used by non-mux cells or ports? bool seen_non_mux; pool mux_users; pool mux_drivers; @@ -50,12 +77,13 @@ struct OptMuxtreeWorker vector bit2info; struct portinfo_t { - int ctrl_sig; - pool input_sigs; - pool input_muxes; - bool const_activated; - bool const_deactivated; - bool enabled; + int ctrl_sig = -1; // No associated control signal by default + pool input_sigs = {}; + pool input_muxes = {}; + bool const_activated = false; + bool const_deactivated = false; + // Is the port reachable from inputs of a mux tree? + bool observable = false; }; struct muxinfo_t { @@ -68,13 +96,16 @@ struct OptMuxtreeWorker vector root_enable_muxes; pool root_mux_rerun; - OptMuxtreeWorker(RTLIL::Design *design, RTLIL::Module *module) : - design(design), module(module), assign_map(module), removed_count(0) - { - log("Running muxtree optimizer on module %s..\n", module->name.c_str()); - - log(" Creating internal representation of mux trees.\n"); + portinfo_t used_port_bit(RTLIL::SigSpec& sig, int mux_idx) { + portinfo_t portinfo = {}; + for (int bit_idx : sig2bits(sig)) { + bit2info[bit_idx].mux_users.insert(mux_idx); + portinfo.input_sigs.insert(bit_idx); + } + return portinfo; + } + void track_mux(Cell* cell) { // Populate bit2info[]: // .seen_non_mux // .mux_users @@ -84,73 +115,59 @@ struct OptMuxtreeWorker // .input_sigs // .const_activated // .const_deactivated - for (auto cell : module->cells()) - { - if (cell->type.in(ID($mux), ID($pmux))) - { - RTLIL::SigSpec sig_a = cell->getPort(ID::A); - RTLIL::SigSpec sig_b = cell->getPort(ID::B); - RTLIL::SigSpec sig_s = cell->getPort(ID::S); - RTLIL::SigSpec sig_y = cell->getPort(ID::Y); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_b = cell->getPort(ID::B); + RTLIL::SigSpec sig_s = cell->getPort(ID::S); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); - muxinfo_t muxinfo; - muxinfo.cell = cell; + muxinfo_t muxinfo; + muxinfo.cell = cell; + int this_mux_idx = GetSize(mux2info); - for (int i = 0; i < GetSize(sig_s); i++) { - RTLIL::SigSpec sig = sig_b.extract(i*GetSize(sig_a), GetSize(sig_a)); - RTLIL::SigSpec ctrl_sig = assign_map(sig_s.extract(i, 1)); - portinfo_t portinfo; - portinfo.ctrl_sig = sig2bits(ctrl_sig, false).front(); - for (int idx : sig2bits(sig)) { - bit2info[idx].mux_users.insert(GetSize(mux2info)); - portinfo.input_sigs.insert(idx); - } - portinfo.const_activated = ctrl_sig.is_fully_const() && ctrl_sig.as_bool(); - portinfo.const_deactivated = ctrl_sig.is_fully_const() && !ctrl_sig.as_bool(); - portinfo.enabled = false; - muxinfo.ports.push_back(portinfo); - } - - portinfo_t portinfo; - for (int idx : sig2bits(sig_a)) { - bit2info[idx].mux_users.insert(GetSize(mux2info)); - portinfo.input_sigs.insert(idx); - } - portinfo.ctrl_sig = -1; - portinfo.const_activated = false; - portinfo.const_deactivated = false; - portinfo.enabled = false; - muxinfo.ports.push_back(portinfo); - - for (int idx : sig2bits(sig_y)) - bit2info[idx].mux_drivers.insert(GetSize(mux2info)); - - for (int idx : sig2bits(sig_s)) - bit2info[idx].seen_non_mux = true; - - mux2info.push_back(muxinfo); - } - else - { - for (auto &it : cell->connections()) { - for (int idx : sig2bits(it.second)) - bit2info[idx].seen_non_mux = true; - } - } + // Analyze port B + // In case of $pmux, port B is multiple slices, concatenated, one per bit of port S + for (int i = 0; i < GetSize(sig_s); i++) { + RTLIL::SigSpec sig = sig_b.extract(i*GetSize(sig_a), GetSize(sig_a)); + RTLIL::SigSpec ctrl_sig = assign_map(sig_s.extract(i, 1)); + portinfo_t portinfo = used_port_bit(sig, this_mux_idx); + portinfo.ctrl_sig = sig2bits(ctrl_sig, false).front(); + portinfo.const_activated = ctrl_sig.is_fully_const() && ctrl_sig.as_bool(); + portinfo.const_deactivated = ctrl_sig.is_fully_const() && !ctrl_sig.as_bool(); + muxinfo.ports.push_back(portinfo); } + + // Analyze port A + muxinfo.ports.push_back(used_port_bit(sig_a, this_mux_idx)); + + for (int idx : sig2bits(sig_y)) + bit2info[idx].mux_drivers.insert(this_mux_idx); + + for (int idx : sig2bits(sig_s)) + bit2info[idx].seen_non_mux = true; + + mux2info.push_back(muxinfo); + } + + void see_non_mux_cell(Cell* cell) { + for (auto &it : cell->connections()) { + for (int idx : sig2bits(it.second)) + bit2info[idx].seen_non_mux = true; + } + } + + void see_non_mux_wires() { for (auto wire : module->wires()) { if (wire->port_output || wire->get_bool_attribute(ID::keep)) for (int idx : sig2bits(RTLIL::SigSpec(wire))) bit2info[idx].seen_non_mux = true; } + } - if (mux2info.empty()) { - log(" No muxes found in this module.\n"); - return; - } - - // Populate mux2info[].ports[]: - // .input_muxes + // Populate mux2info[].ports[]: + // .input_muxes + void fixup_input_muxes() { + // bit2info knows the mux users and mux drivers of bits + // use this to tell mux2info ports about what muxes are driven by it for (int i = 0; i < GetSize(bit2info); i++) for (int j : bit2info[i].mux_users) for (auto &p : mux2info[j].ports) { @@ -158,12 +175,15 @@ struct OptMuxtreeWorker for (int k : bit2info[i].mux_drivers) p.input_muxes.insert(k); } + } - log(" Evaluating internal representation of mux trees.\n"); - + void populate_roots() { + // mux_to_users[i] means "set of muxes using output of mux i" dict> mux_to_users; - root_muxes.resize(GetSize(mux2info)); + // Pure root muxes (outputs seen by non-muxes) root_enable_muxes.resize(GetSize(mux2info)); + // All root muxes (outputs seen by non-muxes or multiple muxes) + root_muxes.resize(GetSize(mux2info)); for (auto &bi : bit2info) { for (int i : bi.mux_drivers) @@ -177,16 +197,44 @@ struct OptMuxtreeWorker } } - for (auto &it : mux_to_users) - if (GetSize(it.second) > 1) - root_muxes.at(it.first) = true; + for (auto &[driving_mux, user_muxes] : mux_to_users) + if (GetSize(user_muxes) > 1) + root_muxes.at(driving_mux) = true; + } + + OptMuxtreeWorker(RTLIL::Design *design, RTLIL::Module *module) : + design(design), module(module), assign_map(module), removed_count(0) + { + log("Running muxtree optimizer on module %s..\n", module->name.c_str()); + + log(" Creating internal representation of mux trees.\n"); + + for (auto cell : module->cells()) + { + if (cell->type.in(ID($mux), ID($pmux))) + track_mux(cell); + else + see_non_mux_cell(cell); + } + see_non_mux_wires(); + + if (mux2info.empty()) { + log(" No muxes found in this module.\n"); + return; + } + + fixup_input_muxes(); + + log(" Evaluating internal representation of mux trees.\n"); + + populate_roots(); for (int mux_idx = 0; mux_idx < GetSize(root_muxes); mux_idx++) if (root_muxes.at(mux_idx)) { log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : ""); root_mux_rerun.erase(mux_idx); eval_root_mux(mux_idx); - if (glob_abort_cnt == 0) { + if (glob_evals_left == 0) { log(" Giving up (too many iterations)\n"); return; } @@ -198,21 +246,21 @@ struct OptMuxtreeWorker log_assert(root_enable_muxes.at(mux_idx)); root_mux_rerun.erase(mux_idx); eval_root_mux(mux_idx); - if (glob_abort_cnt == 0) { + if (glob_evals_left == 0) { log(" Giving up (too many iterations)\n"); return; } } log(" Analyzing evaluation results.\n"); - log_assert(glob_abort_cnt > 0); + log_assert(glob_evals_left > 0); for (auto &mi : mux2info) { vector live_ports; for (int port_idx = 0; port_idx < GetSize(mi.ports); port_idx++) { portinfo_t &pi = mi.ports[port_idx]; - if (pi.enabled) { + if (pi.observable) { live_ports.push_back(port_idx); } else { log(" dead port %d/%d on %s %s.\n", port_idx+1, GetSize(mi.ports), @@ -290,9 +338,10 @@ struct OptMuxtreeWorker struct knowledge_t { - // database of known inactive signals - // the payload is a reference counter used to manage the - // list. when it is non-zero the signal in known to be inactive + // Known inactive signals + // The payload is a reference counter used to manage the list + // When it is non-zero, the signal in known to be inactive + // When it reaches zero, the map element is removed std::unordered_map known_inactive; // database of known active signals @@ -303,84 +352,123 @@ struct OptMuxtreeWorker std::unordered_set visited_muxes; }; - void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx, bool do_replace_known, bool do_enable_ports, int abort_count) - { - if (glob_abort_cnt == 0) - return; - - muxinfo_t &muxinfo = mux2info[mux_idx]; - - if (do_enable_ports) - muxinfo.ports[port_idx].enabled = true; - + static void activate_port(knowledge_t &knowledge, int port_idx, const muxinfo_t &muxinfo) { + // First, mark all other ports inactive for (int i = 0; i < GetSize(muxinfo.ports); i++) { if (i == port_idx) continue; if (muxinfo.ports[i].ctrl_sig >= 0) ++knowledge.known_inactive[muxinfo.ports[i].ctrl_sig]; } - + // Mark port active unless it's the last one if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated) ++knowledge.known_active[muxinfo.ports[port_idx].ctrl_sig]; + } - vector parent_muxes; - for (int m : muxinfo.ports[port_idx].input_muxes) { - auto it = knowledge.visited_muxes.find(m); - if (it != knowledge.visited_muxes.end()) - continue; - knowledge.visited_muxes.insert(it, m); - parent_muxes.push_back(m); - } - for (int m : parent_muxes) { - if (root_enable_muxes.at(m)) - continue; - else if (root_muxes.at(m)) { - if (abort_count == 0) { - root_mux_rerun.insert(m); - root_enable_muxes.at(m) = true; - log_debug(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell)); - } else - eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1); - } else - eval_mux(knowledge, m, do_replace_known, do_enable_ports, abort_count); - if (glob_abort_cnt == 0) - return; - } - for (int m : parent_muxes) - knowledge.visited_muxes.erase(m); - - if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated) { - auto it = knowledge.known_active.find(muxinfo.ports[port_idx].ctrl_sig); - if (it != knowledge.known_active.end()) + static void deactivate_port(knowledge_t &knowledge, int port_idx, const muxinfo_t &muxinfo) { + auto unlearn = [](std::unordered_map& knowns, int i) { + auto it = knowns.find(i); + if (it != knowns.end()) if (--it->second == 0) - knowledge.known_active.erase(it); - } + knowns.erase(it); + }; + if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated) + unlearn(knowledge.known_active, muxinfo.ports[port_idx].ctrl_sig); + + // Undo inactivity assumptions for other ports for (int i = 0; i < GetSize(muxinfo.ports); i++) { if (i == port_idx) continue; - if (muxinfo.ports[i].ctrl_sig >= 0) { - auto it = knowledge.known_inactive.find(muxinfo.ports[i].ctrl_sig); - if (it != knowledge.known_inactive.end()) - if (--it->second == 0) - knowledge.known_inactive.erase(it); - } + if (muxinfo.ports[i].ctrl_sig >= 0) + unlearn(knowledge.known_inactive, muxinfo.ports[i].ctrl_sig); } } + struct limits_t { + // Are we allowed to replace inputs with constants? + // True if knowledge doesn't contain assumptions + bool do_replace_known = true; + // Are we allowed to mark ports as observable? + // True if we're recursing from a pure root mux + bool do_mark_ports_observable = true; + // How many more subtree recursions into input trees can we take? + // Then shalt thou count to three, no more, no less. Three shall be the number thou shalt count, and the number of the counting shall be three. + int recursions_left = 3; + limits_t subtree() const { + limits_t ret = *this; + log_assert(ret.recursions_left > 0); + ret.recursions_left--; + return ret; + } + }; + void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx, limits_t limits) + { + if (glob_evals_left == 0) + return; + + muxinfo_t &muxinfo = mux2info[mux_idx]; + + if (limits.do_mark_ports_observable) + muxinfo.ports[port_idx].observable = true; + + // For the purposes of recursion, we assume the port is active, + // meaning all other ports are inactive + activate_port(knowledge, port_idx, muxinfo); + + vector input_mux_queue; + for (int m : muxinfo.ports[port_idx].input_muxes) { + if (knowledge.visited_muxes.count(m)) + continue; + knowledge.visited_muxes.insert(m); + input_mux_queue.push_back(m); + } + for (int m : input_mux_queue) { + if (root_enable_muxes.at(m)) + continue; + else if (root_muxes.at(m)) { + if (limits.recursions_left == 0) { + // Ran out of subtree depth, re-eval this subtree in the next re-run + root_mux_rerun.insert(m); + root_enable_muxes.at(m) = true; + log_debug(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell)); + } else { + auto new_limits = limits.subtree(); + // Since our knowledge includes assumption, we can't generally allow replacing based on it + new_limits.do_replace_known = false; + eval_mux(knowledge, m, new_limits); + } + } else { + // This non-root input mux has only this mux as a user, + // so here we are allowed to pass along do_replace_known + eval_mux(knowledge, m, limits); + } + if (glob_evals_left == 0) + return; + } + + // Allow revisiting input muxes, since evaluating other ports should + // revisit these input muxes with different activation assumptions + for (int m : input_mux_queue) + knowledge.visited_muxes.erase(m); + + // Undo our assumptions that the port is active + deactivate_port(knowledge, port_idx, muxinfo); + } + void replace_known(knowledge_t &knowledge, muxinfo_t &muxinfo, IdString portname) { SigSpec sig = muxinfo.cell->getPort(portname); bool did_something = false; - int width = 0; + int width_if_b = 0; idict ctrl_bits; if (portname == ID::B) - width = GetSize(muxinfo.cell->getPort(ID::A)); + width_if_b = GetSize(muxinfo.cell->getPort(ID::A)); for (int bit : sig2bits(muxinfo.cell->getPort(ID::S), false)) ctrl_bits(bit); - int port_idx = 0, port_off = 0; + int slice_idx = 0, slice_off = 0; vector bits = sig2bits(sig, false); for (int i = 0; i < GetSize(bits); i++) { if (bits[i] >= 0) { @@ -393,17 +481,31 @@ struct OptMuxtreeWorker did_something = true; } if (ctrl_bits.count(bits[i])) { - if (width) { - sig[i] = ctrl_bits.at(bits[i]) == port_idx ? State::S1 : State::S0; - } else { + if (!width_if_b) { + // Single-bit $mux example + // mux: S ? B : A = Y + // A=S + // 0 ? B : 0 = 0 + // 1 ? B : 1 = B + // rewrite to A=0 + // 0 ? B : 0 = 0 + // 1 ? B : 0 = B + // which is equivalent sig[i] = State::S0; + } else { + // "Sliced" $pmux example + // B[i]=S[j] + // i == j => B[i] activated only when B[i] is high, safe to rewrite to 1 + // i != j => B[i] activated only when B[i] is low, safe to rewrite to 0 + sig[i] = ctrl_bits.at(bits[i]) == slice_idx ? State::S1 : State::S0; } did_something = true; } } - if (width) { - if (++port_off == width) - port_idx++, port_off=0; + if (width_if_b) { + // Roll over into next slice + if (++slice_off == width_if_b) + slice_idx++, slice_off=0; } } @@ -414,16 +516,17 @@ struct OptMuxtreeWorker } } - void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count) + void eval_mux(knowledge_t &knowledge, int mux_idx, limits_t limits) { - if (glob_abort_cnt == 0) + if (glob_evals_left == 0) return; - glob_abort_cnt--; + glob_evals_left--; muxinfo_t &muxinfo = mux2info[mux_idx]; + log_debug("\t\teval %s (replace %d enable %d)\n", log_id(muxinfo.cell), limits.do_replace_known, limits.do_mark_ports_observable); // set input ports to constants if we find known active or inactive signals - if (do_replace_known) { + if (limits.do_replace_known) { replace_known(knowledge, muxinfo, ID::A); replace_known(knowledge, muxinfo, ID::B); } @@ -433,21 +536,21 @@ struct OptMuxtreeWorker { portinfo_t &portinfo = muxinfo.ports[port_idx]; if (portinfo.const_activated) { - eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count); + eval_mux_port(knowledge, mux_idx, port_idx, limits); return; } } - // compare ports with known_active signals. if we find a match, only this - // port can be active. do not include the last port (its the default port - // that has no control signals). + // Compare ports with known active control signals. if we find a match, + // only this port can be active. Do not include the last port, + // it's the default port without an associated control signal for (int port_idx = 0; port_idx < GetSize(muxinfo.ports)-1; port_idx++) { portinfo_t &portinfo = muxinfo.ports[port_idx]; if (portinfo.const_deactivated) continue; if (knowledge.known_active.count(portinfo.ctrl_sig) > 0) { - eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count); + eval_mux_port(knowledge, mux_idx, port_idx, limits); return; } } @@ -462,19 +565,21 @@ struct OptMuxtreeWorker if (port_idx < GetSize(muxinfo.ports)-1) if (knowledge.known_inactive.count(portinfo.ctrl_sig) > 0) continue; - eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count); + eval_mux_port(knowledge, mux_idx, port_idx, limits); - if (glob_abort_cnt == 0) + if (glob_evals_left == 0) return; } } void eval_root_mux(int mux_idx) { - log_assert(glob_abort_cnt > 0); + log_assert(glob_evals_left > 0); knowledge_t knowledge; knowledge.visited_muxes.insert(mux_idx); - eval_mux(knowledge, mux_idx, true, root_enable_muxes.at(mux_idx), 3); + limits_t limits = {}; + limits.do_mark_ports_observable = root_enable_muxes.at(mux_idx); + eval_mux(knowledge, mux_idx, limits); } }; From 6fdcdd41de8c8bfa73fabf435da3b898c920a640 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 22 Aug 2025 00:23:32 +0000 Subject: [PATCH 156/176] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 19fab9780..70beb047e 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+165 +YOSYS_VER := 0.56+171 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From b5aa3ab9f7c395275c0aeca6ffc133fdb563f849 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 25 Aug 2025 03:09:04 +0000 Subject: [PATCH 157/176] hash_ops should take all parameters by reference instead of requiring copies of vectors, tuples etc --- kernel/hashlib.h | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index b43b7302e..9c53e6687 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -179,58 +179,58 @@ struct hash_ops { }; template struct hash_ops> { - static inline bool cmp(std::pair a, std::pair b) { + static inline bool cmp(const std::pair &a, const std::pair &b) { return a == b; } - [[nodiscard]] static inline Hasher hash_into(std::pair a, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(const std::pair &a, Hasher h) { h = hash_ops

::hash_into(a.first, h); h = hash_ops::hash_into(a.second, h); return h; } - HASH_TOP_LOOP_FST (std::pair a) HASH_TOP_LOOP_SND + HASH_TOP_LOOP_FST (const std::pair &a) HASH_TOP_LOOP_SND }; template struct hash_ops> { - static inline bool cmp(std::tuple a, std::tuple b) { + static inline bool cmp(const std::tuple &a, const std::tuple &b) { return a == b; } template - static inline typename std::enable_if::type hash_into(std::tuple, Hasher h) { + static inline typename std::enable_if::type hash_into(const std::tuple &, Hasher h) { return h; } template - static inline typename std::enable_if::type hash_into(std::tuple a, Hasher h) { + static inline typename std::enable_if::type hash_into(const std::tuple &a, Hasher h) { typedef hash_ops>::type> element_ops_t; h = hash_into(a, h); h = element_ops_t::hash_into(std::get(a), h); return h; } - HASH_TOP_LOOP_FST (std::tuple a) HASH_TOP_LOOP_SND + HASH_TOP_LOOP_FST (const std::tuple &a) HASH_TOP_LOOP_SND }; template struct hash_ops> { - static inline bool cmp(std::vector a, std::vector b) { + static inline bool cmp(const std::vector &a, const std::vector &b) { return a == b; } - [[nodiscard]] static inline Hasher hash_into(std::vector a, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(const std::vector &a, Hasher h) { h.eat((uint32_t)a.size()); for (auto k : a) h.eat(k); return h; } - HASH_TOP_LOOP_FST (std::vector a) HASH_TOP_LOOP_SND + HASH_TOP_LOOP_FST (const std::vector &a) HASH_TOP_LOOP_SND }; template struct hash_ops> { - static inline bool cmp(std::array a, std::array b) { + static inline bool cmp(const std::array &a, const std::array &b) { return a == b; } - [[nodiscard]] static inline Hasher hash_into(std::array a, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(const std::array &a, Hasher h) { for (const auto& k : a) h = hash_ops::hash_into(k, h); return h; } - HASH_TOP_LOOP_FST (std::array a) HASH_TOP_LOOP_SND + HASH_TOP_LOOP_FST (const std::array &a) HASH_TOP_LOOP_SND }; struct hash_cstr_ops { @@ -302,10 +302,10 @@ template<> struct hash_ops { }; template struct hash_ops> { - static inline bool cmp(std::variant a, std::variant b) { + static inline bool cmp(const std::variant &a, const std::variant &b) { return a == b; } - [[nodiscard]] static inline Hasher hash_into(std::variant a, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(const std::variant &a, Hasher h) { std::visit([& h](const auto &v) { h.eat(v); }, a); h.eat(a.index()); return h; @@ -313,10 +313,10 @@ template struct hash_ops> { }; template struct hash_ops> { - static inline bool cmp(std::optional a, std::optional b) { + static inline bool cmp(const std::optional &a, const std::optional &b) { return a == b; } - [[nodiscard]] static inline Hasher hash_into(std::optional a, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(const std::optional &a, Hasher h) { if(a.has_value()) h.eat(*a); else From 9f0904d048751e3f6518713f642ccc021e7f6b22 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 25 Aug 2025 07:46:34 +0200 Subject: [PATCH 158/176] Makefile: fix hardcoded -install_name for libyosys.so --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e182f51cc..b3ea79657 100644 --- a/Makefile +++ b/Makefile @@ -745,7 +745,7 @@ $(PROGRAM_PREFIX)yosys$(EXE): $(OBJS) libyosys.so: $(filter-out kernel/driver.o,$(OBJS)) ifeq ($(OS), Darwin) - $(P) $(CXX) -o libyosys.so -shared -undefined dynamic_lookup -Wl,-install_name,$(LIBDIR)/libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC) + $(P) $(CXX) -o libyosys.so -shared -undefined dynamic_lookup -Wl,-install_name,libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC) else $(P) $(CXX) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC) endif From b45e5854bfe19fa3c433e327fce19012e1b395c7 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 25 Aug 2025 16:36:07 +0200 Subject: [PATCH 159/176] opt_muxtree: comment wording --- passes/opt/opt_muxtree.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc index ae9b1a632..98803b935 100644 --- a/passes/opt/opt_muxtree.cc +++ b/passes/opt/opt_muxtree.cc @@ -427,14 +427,17 @@ struct OptMuxtreeWorker if (root_enable_muxes.at(m)) continue; else if (root_muxes.at(m)) { + // This leaf node of the current tree + // is the root of an input tree of the current tree if (limits.recursions_left == 0) { - // Ran out of subtree depth, re-eval this subtree in the next re-run + // Ran out of subtree depth, re-eval this input tree in the next re-run root_mux_rerun.insert(m); root_enable_muxes.at(m) = true; log_debug(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell)); } else { auto new_limits = limits.subtree(); - // Since our knowledge includes assumption, we can't generally allow replacing based on it + // Since our knowledge includes assumption, + // we can't generally allow replacing in an input tree based on it new_limits.do_replace_known = false; eval_mux(knowledge, m, new_limits); } From 15d24bf2e65450602f902574a131a8b97d2e6487 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Mon, 11 Nov 2024 11:22:05 +0100 Subject: [PATCH 160/176] synth_quicklogic: add -noflatten option --- techlibs/quicklogic/synth_quicklogic.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/techlibs/quicklogic/synth_quicklogic.cc b/techlibs/quicklogic/synth_quicklogic.cc index 07ec769b5..c9b8eb289 100644 --- a/techlibs/quicklogic/synth_quicklogic.cc +++ b/techlibs/quicklogic/synth_quicklogic.cc @@ -78,7 +78,7 @@ struct SynthQuickLogicPass : public ScriptPass { } string top_opt, blif_file, edif_file, family, currmodule, verilog_file, lib_path; - bool abc9, inferAdder, nobram, bramTypes, dsp, ioff; + bool abc9, inferAdder, nobram, bramTypes, dsp, ioff, flatten; void clear_flags() override { @@ -95,6 +95,7 @@ struct SynthQuickLogicPass : public ScriptPass { lib_path = "+/quicklogic/"; dsp = true; ioff = true; + flatten = true; } void set_scratchpad_defaults(RTLIL::Design *design) { @@ -163,6 +164,10 @@ struct SynthQuickLogicPass : public ScriptPass { ioff = false; continue; } + if (args[argidx] == "-noflatten") { + flatten = false; + continue; + } break; } extra_args(args, argidx, design); @@ -207,7 +212,8 @@ struct SynthQuickLogicPass : public ScriptPass { if (check_label("prepare")) { run("proc"); - run("flatten"); + if (flatten) + run("flatten", "(unless -noflatten)"); if (help_mode || family == "pp3") { run("tribuf -logic", " (for pp3)"); } From 83d953e957e90433ed0d57e8b2bca9850b435c18 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 26 Aug 2025 00:23:36 +0000 Subject: [PATCH 161/176] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b3ea79657..4cb86510a 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+171 +YOSYS_VER := 0.56+186 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 8333a83cef48c8ee08086ba5c4d0962ad7d814cc Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 27 Aug 2025 11:29:57 +0200 Subject: [PATCH 162/176] opt_dff: more explicit testing, typo --- tests/opt/opt_dff-simplify.ys | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tests/opt/opt_dff-simplify.ys b/tests/opt/opt_dff-simplify.ys index a803c2475..699bfe065 100644 --- a/tests/opt/opt_dff-simplify.ys +++ b/tests/opt/opt_dff-simplify.ys @@ -1,9 +1,17 @@ -# 5287 issue +# 5279 issue # Check only for complimentary patterns elimination -read_rtlil opt_dff-simplify.il +read_rtlil opt_dff-simplify.il + +select -assert-count 0 t:$adffe +select -assert-count 1 t:$adff +select -assert-count 0 t:$ne + opt_dff +select -assert-count 1 t:$adffe +select -assert-count 0 t:$adff + select -assert-count 8 t:$ne r:A_WIDTH=3 %i select -assert-count 5 t:$ne r:A_WIDTH=2 %i @@ -37,7 +45,14 @@ EOT cd test proc + +select -assert-count 0 t:$dffe +select -assert-count 1 t:$dff +select -assert-count 0 t:$ne + opt_dff +select -assert-count 1 t:$dffe +select -assert-count 0 t:$dff select -assert-count 1 t:$ne r:A_WIDTH=2 %i select -assert-none t:$ne r:A_WIDTH=3 %i From 88eb83a0c3e19c1c1cca42658aeb762abe2ed913 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 28 Aug 2025 11:58:02 +0200 Subject: [PATCH 163/176] Revert "Merge pull request #5301 from KrystalDelusion/krys/re_5280" This reverts commit c9a602e882fc036165ef0cde9cc2e26736c092cf, reversing changes made to 51eaaffe090cb25d447b30c3d262d8c3f04d1cb3. --- .github/workflows/extra-builds.yml | 16 +--- .github/workflows/test-build.yml | 44 +++++------ .github/workflows/test-compile.yml | 16 +--- .github/workflows/test-sanitizers.yml | 109 -------------------------- .github/workflows/test-verific.yml | 16 +--- passes/memory/memlib.cc | 2 +- passes/memory/memlib.h | 2 +- 7 files changed, 34 insertions(+), 171 deletions(-) delete mode 100644 .github/workflows/test-sanitizers.yml diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 11fd42a6c..458eb76a6 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -1,14 +1,6 @@ name: Test extra build flows -on: - # always test main - push: - branches: - - main - # test PRs - pull_request: - # allow triggering tests, ignores skip check - workflow_dispatch: +on: [push, pull_request] jobs: pre_job: @@ -19,11 +11,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - # but never cancel main - cancel_others: ${{ github.ref != 'refs/heads/main' }} + cancel_others: 'true' + # only run on push *or* pull_request, not both + concurrent_skipping: 'same_content_newer' vs-prep: name: Prepare Visual Studio build diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 16ad98bec..f9574594a 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -1,14 +1,6 @@ name: Build and run tests -on: - # always test main - push: - branches: - - main - # test PRs - pull_request: - # allow triggering tests, ignores skip check - workflow_dispatch: +on: [push, pull_request] jobs: pre_job: @@ -19,12 +11,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - # but never cancel main - cancel_others: ${{ github.ref != 'refs/heads/main' }} - + cancel_others: 'true' + # only run on push *or* pull_request, not both + concurrent_skipping: 'same_content_newer' pre_docs_job: runs-on: ubuntu-latest outputs: @@ -33,16 +24,15 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - # don't run on readme changes paths_ignore: '["**/README.md"]' # cancel previous builds if a new commit is pushed - # but never cancel main - cancel_others: ${{ github.ref != 'refs/heads/main' }} + cancel_others: 'true' + # only run on push *or* pull_request, not both + concurrent_skipping: 'same_content_newer' build-yosys: name: Reusable build runs-on: ${{ matrix.os }} - # pre_job is a subset of pre_docs_job, so we can always build for pre_docs_job needs: pre_docs_job if: needs.pre_docs_job.outputs.should_skip != 'true' env: @@ -50,6 +40,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] + sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -67,6 +58,7 @@ jobs: mkdir build cd build make -f ../Makefile config-$CC + echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf make -f ../Makefile -j$procs ENABLE_LTO=1 - name: Log yosys-config output @@ -82,7 +74,7 @@ jobs: - name: Store build artifact uses: actions/upload-artifact@v4 with: - name: build-${{ matrix.os }} + name: build-${{ matrix.os }}-${{ matrix.sanitizer }} path: build.tar retention-days: 1 @@ -93,9 +85,12 @@ jobs: if: needs.pre_job.outputs.should_skip != 'true' env: CC: clang + ASAN_OPTIONS: halt_on_error=1 + UBSAN_OPTIONS: halt_on_error=1 strategy: matrix: os: [ubuntu-latest, macos-latest] + sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -107,12 +102,11 @@ jobs: uses: ./.github/actions/setup-build-env - name: Get iverilog - id: get-iverilog shell: bash run: | git clone https://github.com/steveicarus/iverilog.git cd iverilog - echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT + echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_ENV - name: Get vcd2fst shell: bash @@ -129,7 +123,7 @@ jobs: uses: actions/cache@v4 with: path: .local/ - key: ${{ matrix.os }}-${{ steps.get-iverilog.outputs.IVERILOG_GIT }} + key: ${{ matrix.os }}-${IVERILOG_GIT} - name: Build iverilog if: steps.cache-iverilog.outputs.cache-hit != 'true' @@ -145,7 +139,7 @@ jobs: - name: Download build artifact uses: actions/download-artifact@v4 with: - name: build-${{ matrix.os }} + name: build-${{ matrix.os }}-${{ matrix.sanitizer }} - name: Uncompress build shell: bash @@ -177,6 +171,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] + sanitizer: [undefined] steps: - name: Checkout Yosys uses: actions/checkout@v4 @@ -189,7 +184,7 @@ jobs: - name: Download build artifact uses: actions/download-artifact@v4 with: - name: build-${{ matrix.os }} + name: build-${{ matrix.os }}-${{ matrix.sanitizer }} - name: Uncompress build shell: bash @@ -214,6 +209,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] + sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -227,7 +223,7 @@ jobs: - name: Download build artifact uses: actions/download-artifact@v4 with: - name: build-${{ matrix.os }} + name: build-${{ matrix.os }}-${{ matrix.sanitizer }} - name: Uncompress build shell: bash diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index f208b911a..7a706e69a 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -1,14 +1,6 @@ name: Compiler testing -on: - # always test main - push: - branches: - - main - # test PRs - pull_request: - # allow triggering tests, ignores skip check - workflow_dispatch: +on: [push, pull_request] jobs: pre_job: @@ -19,11 +11,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - # but never cancel main - cancel_others: ${{ github.ref != 'refs/heads/main' }} + cancel_others: 'true' + # only run on push *or* pull_request, not both + concurrent_skipping: 'same_content_newer' test-compile: runs-on: ${{ matrix.os }} diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml deleted file mode 100644 index 255b9daa5..000000000 --- a/.github/workflows/test-sanitizers.yml +++ /dev/null @@ -1,109 +0,0 @@ -name: Check clang sanitizers - -on: - # always test main - push: - branches: - - main - # ignore PRs due to time needed - # allow triggering tests, ignores skip check - workflow_dispatch: - -jobs: - pre_job: - runs-on: ubuntu-latest - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@v5 - with: - # don't run on documentation changes - paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' - - run_san: - name: Build and run tests - runs-on: ${{ matrix.os }} - needs: pre_job - if: needs.pre_job.outputs.should_skip != 'true' - env: - CC: clang - ASAN_OPTIONS: halt_on_error=1 - UBSAN_OPTIONS: halt_on_error=1 - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - sanitizer: ['undefined,address'] - fail-fast: false - steps: - - name: Checkout Yosys - uses: actions/checkout@v4 - with: - submodules: true - persist-credentials: false - - - name: Setup environment - uses: ./.github/actions/setup-build-env - - - name: Get iverilog - id: get-iverilog - shell: bash - run: | - git clone https://github.com/steveicarus/iverilog.git - cd iverilog - echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT - - - name: Get vcd2fst - shell: bash - run: | - git clone https://github.com/mmicko/libwave.git - mkdir -p ${{ github.workspace }}/.local/ - cd libwave - cmake . -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/.local - make -j$procs - make install - - - name: Cache iverilog - id: cache-iverilog - uses: actions/cache@v4 - with: - path: .local/ - key: ${{ matrix.os }}-${{ steps.get-iverilog.outputs.IVERILOG_GIT }} - - - name: Build iverilog - if: steps.cache-iverilog.outputs.cache-hit != 'true' - shell: bash - run: | - mkdir -p ${{ github.workspace }}/.local/ - cd iverilog - autoconf - CC=gcc CXX=g++ ./configure --prefix=${{ github.workspace }}/.local - make -j$procs - make install - - - name: Check iverilog - shell: bash - run: | - iverilog -V - - - name: Build - shell: bash - run: | - make config-$CC - echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf - make -j$procs ENABLE_LTO=1 - - - name: Log yosys-config output - run: | - ./yosys-config || true - - - name: Run tests - shell: bash - run: | - make -j$procs test TARGETS= EXTRA_TARGETS= CONFIG=$CC - - - name: Report errors - if: ${{ failure() }} - shell: bash - run: | - find tests/**/*.err -print -exec cat {} \; diff --git a/.github/workflows/test-verific.yml b/.github/workflows/test-verific.yml index 9af07b920..013c9f8ca 100644 --- a/.github/workflows/test-verific.yml +++ b/.github/workflows/test-verific.yml @@ -1,14 +1,6 @@ name: Build and run tests with Verific (Linux) -on: - # always test main - push: - branches: - - main - # test PRs - pull_request: - # allow triggering tests, ignores skip check - workflow_dispatch: +on: [push, pull_request] jobs: pre-job: @@ -19,11 +11,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - # but never cancel main - cancel_others: ${{ github.ref != 'refs/heads/main' }} + cancel_others: 'true' + # only run on push *or* pull_request, not both + concurrent_skipping: 'same_content_newer' test-verific: needs: pre-job diff --git a/passes/memory/memlib.cc b/passes/memory/memlib.cc index 3a8c3c06e..8a7adc9ac 100644 --- a/passes/memory/memlib.cc +++ b/passes/memory/memlib.cc @@ -878,7 +878,7 @@ struct Parser { } } } - var.clk_en = find_single_cap(pdef.clken, cram.options, portopts, "clken") != nullptr; + var.clk_en = find_single_cap(pdef.clken, cram.options, portopts, "clken"); } const PortWidthDef *wdef = find_single_cap(pdef.width, cram.options, portopts, "width"); if (wdef) { diff --git a/passes/memory/memlib.h b/passes/memory/memlib.h index 7394baf4e..43dec7386 100644 --- a/passes/memory/memlib.h +++ b/passes/memory/memlib.h @@ -109,7 +109,7 @@ struct PortVariant { PortKind kind; int clk_shared; ClkPolKind clk_pol; - bool clk_en = false; + bool clk_en; bool width_tied; int min_wr_wide_log2; int max_wr_wide_log2; From d4c4b2106697f62852cce03cd98eb78395a7779c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 29 Aug 2025 00:23:40 +0000 Subject: [PATCH 164/176] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4cb86510a..003743f49 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+186 +YOSYS_VER := 0.56+197 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 3426905e607dfd885339de450cbcb1cc3f51b78c Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 2 Sep 2025 09:48:17 +1200 Subject: [PATCH 165/176] CI: Use brew bundle Also skip `brew update`. Specify llvm@20 due to problems with clang-21 and macOS .dylib. --- .github/actions/setup-build-env/action.yml | 3 +-- Brewfile | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index 059287a63..285601406 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -14,8 +14,7 @@ runs: if: runner.os == 'macOS' shell: bash run: | - HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew update - HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install bison flex gawk libffi pkg-config bash autoconf llvm lld || true + brew bundle - name: Linux runtime environment if: runner.os == 'Linux' diff --git a/Brewfile b/Brewfile index 3696e40b0..a4efff9a2 100644 --- a/Brewfile +++ b/Brewfile @@ -10,5 +10,5 @@ brew "tcl-tk" brew "xdot" brew "bash" brew "boost-python3" -brew "llvm" +brew "llvm@19" brew "lld" From 2261c7e366005f1bc028259658eb3f6fb1d25ed6 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 2 Sep 2025 10:08:58 +1200 Subject: [PATCH 166/176] test-compile.yml: Compiler tests for arm mac --- .github/workflows/test-compile.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index 7a706e69a..7d87ab56e 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -36,9 +36,12 @@ jobs: - 'clang-19' - 'gcc-13' include: - # macOS + # macOS x86 - os: macos-13 compiler: 'clang' + # macOS arm + - os: macos-latest + compiler: 'clang' fail-fast: false steps: - name: Checkout Yosys From 5db312b6cfaa76b7458cd37923cdfa0b5bdf7357 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 2 Sep 2025 11:30:57 +1200 Subject: [PATCH 167/176] Bump to llvm@20 --- .github/actions/setup-build-env/action.yml | 2 +- Brewfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index 285601406..1c2386b06 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -28,7 +28,7 @@ runs: shell: bash run: | echo "${{ github.workspace }}/.local/bin" >> $GITHUB_PATH - echo "$(brew --prefix llvm)/bin" >> $GITHUB_PATH + echo "$(brew --prefix llvm@20)/bin" >> $GITHUB_PATH echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH echo "$(brew --prefix flex)/bin" >> $GITHUB_PATH echo "procs=$(sysctl -n hw.ncpu)" >> $GITHUB_ENV diff --git a/Brewfile b/Brewfile index a4efff9a2..d2c1063ca 100644 --- a/Brewfile +++ b/Brewfile @@ -10,5 +10,5 @@ brew "tcl-tk" brew "xdot" brew "bash" brew "boost-python3" -brew "llvm@19" +brew "llvm@20" brew "lld" From 11f5913da6e5c3c6e44c2d1f4b4526027bae6f04 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 2 Sep 2025 15:25:39 +1200 Subject: [PATCH 168/176] Brewfile: Skip tcl-tk --- Brewfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Brewfile b/Brewfile index d2c1063ca..7ed3fb906 100644 --- a/Brewfile +++ b/Brewfile @@ -6,7 +6,6 @@ brew "git" brew "graphviz" brew "pkg-config" brew "python3" -brew "tcl-tk" brew "xdot" brew "bash" brew "boost-python3" From 7fb6c1ee52ef0f64438b443a8d2d1cfdd91a863e Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 3 Sep 2025 03:32:00 +1200 Subject: [PATCH 169/176] test-compile.yml: Specify clang-19 Will trigger C++20 builds to run (which are currently failing). --- .github/workflows/test-compile.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index 7d87ab56e..95c6ea4c1 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -38,10 +38,10 @@ jobs: include: # macOS x86 - os: macos-13 - compiler: 'clang' + compiler: 'clang-19' # macOS arm - os: macos-latest - compiler: 'clang' + compiler: 'clang-19' fail-fast: false steps: - name: Checkout Yosys From d70f132792bcd02d3de8262eb20a861fccdc7d94 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 3 Sep 2025 03:32:01 +1200 Subject: [PATCH 170/176] wrapcell.cc: Avoid format name collision --- passes/cmds/wrapcell.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/passes/cmds/wrapcell.cc b/passes/cmds/wrapcell.cc index 0c15848e4..39a183e23 100644 --- a/passes/cmds/wrapcell.cc +++ b/passes/cmds/wrapcell.cc @@ -47,7 +47,7 @@ struct ContextData { std::string unused_outputs; }; -std::optional format(std::string fmt, const dict ¶meters, +std::optional format_with_params(std::string fmt, const dict ¶meters, const ContextData &context) { std::stringstream result; @@ -230,7 +230,7 @@ struct WrapcellPass : Pass { context.unused_outputs += "_" + RTLIL::unescape_id(chunk.format(cell)); } - std::optional unescaped_name = format(name_fmt, cell->parameters, context); + std::optional unescaped_name = format_with_params(name_fmt, cell->parameters, context); if (!unescaped_name) log_error("Formatting error when processing cell '%s' in module '%s'\n", log_id(cell), log_id(module)); @@ -270,7 +270,7 @@ struct WrapcellPass : Pass { if (rule.value_fmt.empty()) { subm->set_bool_attribute(rule.name); } else { - std::optional value = format(rule.value_fmt, cell->parameters, context); + std::optional value = format_with_params(rule.value_fmt, cell->parameters, context); if (!value) log_error("Formatting error when processing cell '%s' in module '%s'\n", From 5d59903f36ee1582989898000a49d5aa0c600695 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 3 Sep 2025 09:32:21 +1200 Subject: [PATCH 171/176] Bump Windows SDK --- .github/workflows/extra-builds.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 458eb76a6..9c15c3383 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -51,7 +51,7 @@ jobs: uses: microsoft/setup-msbuild@v2 - name: MSBuild working-directory: yosys-win32-vcxsrc-latest - run: msbuild YosysVS.sln /p:PlatformToolset=v142 /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.17763.0 + run: msbuild YosysVS.sln /p:PlatformToolset=v142 /p:Configuration=Release /p:WindowsTargetPlatformVersion=10.0.26100.0 wasi-build: name: WASI build From 45829e4d082846d9ade378669297c5afd8acb5d1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 00:21:58 +0000 Subject: [PATCH 172/176] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 003743f49..155deee0e 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+197 +YOSYS_VER := 0.56+213 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 7454699a0062932ac2a7978dec77b6b2cd764a60 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 3 Sep 2025 17:34:09 +0200 Subject: [PATCH 173/176] Update ABC to version as of 03/09/2025 --- abc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abc b/abc index fa7fa163d..8827bafb7 160000 --- a/abc +++ b/abc @@ -1 +1 @@ -Subproject commit fa7fa163dacdf81bdcb72b2d2713fbe9984b62bb +Subproject commit 8827bafb7f288de6749dc6e30fa452f2040949c0 From cd7f92429027c35bc237fb27bf996333e9419d7d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 00:22:11 +0000 Subject: [PATCH 174/176] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 155deee0e..c18fdb2c8 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+213 +YOSYS_VER := 0.56+220 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 3aca86049e79a165932e3e7660358376f45acaed Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 4 Sep 2025 08:00:38 +0200 Subject: [PATCH 175/176] Release version 0.57 --- CHANGELOG | 14 +++++++++++++- Makefile | 4 ++-- docs/source/conf.py | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6365a24e9..360989b2f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,8 +2,20 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.56 .. Yosys 0.57-dev +Yosys 0.56 .. Yosys 0.57 -------------------------- + * New commands and options + - Added "-initstates" option to "abstract" pass. + - Added "-set-assumes" option to "equiv_induct" + and "equiv_simple" passes. + - Added "-always" option to "raise_error" pass. + - Added "-hierarchy" option to "stat" pass. + - Added "-noflatten" option to "synth_quicklogic" pass. + + * Various + - smtbmc: Support skipping steps in cover mode. + - write_btor: support $buf. + - read_verilog: support package import. Yosys 0.55 .. Yosys 0.56 -------------------------- diff --git a/Makefile b/Makefile index c18fdb2c8..2b74548e8 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+220 +YOSYS_VER := 0.57 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) @@ -182,7 +182,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 9c447ad.. | wc -l`/;" Makefile +# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 9c447ad.. | wc -l`/;" Makefile ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) diff --git a/docs/source/conf.py b/docs/source/conf.py index ebec6915e..5b93e2e70 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -6,7 +6,7 @@ import os project = 'YosysHQ Yosys' author = 'YosysHQ GmbH' copyright ='2025 YosysHQ GmbH' -yosys_ver = "0.56" +yosys_ver = "0.57" # select HTML theme html_theme = 'furo-ys' From cec48c6abdb4493515330e17c97625675fc1583c Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 4 Sep 2025 08:03:57 +0200 Subject: [PATCH 176/176] Next dev cycle --- CHANGELOG | 3 +++ Makefile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 360989b2f..468724e81 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,9 @@ List of major changes and improvements between releases ======================================================= +Yosys 0.57 .. Yosys 0.58-dev +-------------------------- + Yosys 0.56 .. Yosys 0.57 -------------------------- * New commands and options diff --git a/Makefile b/Makefile index 2b74548e8..fb4fb5776 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.57 +YOSYS_VER := 0.57+0 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) @@ -182,7 +182,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: -# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 9c447ad.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 3aca860.. | wc -l`/;" Makefile ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q)